From 67248781c04f4377b1139efe7923ca83e3daebd3 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 12:39:12 -0800 Subject: [PATCH 01/71] init restructure --- crates/analyzer/analyzer_like.rs | 82 ++ crates/analyzer/lib.rs | 1 + crates/graph/graph_elements.rs | 181 +++ crates/graph/graph_like.rs | 352 ++++++ crates/graph/lib.rs | 11 + crates/graph/nodes/block.rs | 68 ++ crates/graph/nodes/builtin.rs | 379 ++++++ crates/graph/nodes/concrete.rs | 849 ++++++++++++++ crates/graph/nodes/context/context_tys.rs | 96 ++ crates/graph/nodes/context/expr_ret.rs | 247 ++++ crates/graph/nodes/context/mod.rs | 0 crates/graph/nodes/context/node.rs | 1299 +++++++++++++++++++++ crates/graph/nodes/context/underlying.rs | 228 ++++ crates/graph/nodes/contract_ty.rs | 281 +++++ crates/graph/nodes/enum_ty.rs | 126 ++ crates/graph/nodes/err_ty.rs | 105 ++ crates/graph/nodes/func_ty.rs | 879 ++++++++++++++ crates/graph/nodes/mod.rs | 35 + crates/graph/nodes/msg.rs | 190 +++ crates/graph/nodes/struct_ty.rs | 199 ++++ crates/graph/nodes/ty_ty.rs | 77 ++ crates/graph/nodes/var_ty.rs | 236 ++++ crates/graph/search.rs | 267 +++++ crates/graph/var_type.rs | 771 ++++++++++++ crates/range/elem/concrete.rs | 119 ++ crates/range/elem/elem_enum.rs | 466 ++++++++ crates/range/elem/expr.rs | 92 ++ crates/range/elem/map_or_array.rs | 151 +++ crates/range/elem/mod.rs | 188 +++ crates/range/elem/reference.rs | 165 +++ crates/range/exec/add.rs | 112 ++ crates/range/exec/bitwise.rs | 173 +++ crates/range/exec/cast.rs | 257 ++++ crates/range/exec/concat.rs | 148 +++ crates/range/exec/div.rs | 148 +++ crates/range/exec/exp.rs | 86 ++ crates/range/exec/logical.rs | 61 + crates/range/exec/max.rs | 46 + crates/range/exec/min.rs | 45 + crates/range/exec/mod.rs | 1247 ++++++++++++++++++++ crates/range/exec/modulo.rs | 45 + crates/range/exec/mul.rs | 108 ++ crates/range/exec/ord.rs | 228 ++++ crates/range/exec/shift.rs | 165 +++ crates/range/exec/sub.rs | 150 +++ crates/range/mod.rs | 9 + crates/range/range_string.rs | 274 +++++ crates/range/solc_range.rs | 744 ++++++++++++ 48 files changed, 12186 insertions(+) create mode 100644 crates/analyzer/analyzer_like.rs create mode 100644 crates/analyzer/lib.rs create mode 100644 crates/graph/graph_elements.rs create mode 100644 crates/graph/graph_like.rs create mode 100644 crates/graph/lib.rs create mode 100644 crates/graph/nodes/block.rs create mode 100644 crates/graph/nodes/builtin.rs create mode 100644 crates/graph/nodes/concrete.rs create mode 100644 crates/graph/nodes/context/context_tys.rs create mode 100644 crates/graph/nodes/context/expr_ret.rs create mode 100644 crates/graph/nodes/context/mod.rs create mode 100644 crates/graph/nodes/context/node.rs create mode 100644 crates/graph/nodes/context/underlying.rs create mode 100644 crates/graph/nodes/contract_ty.rs create mode 100644 crates/graph/nodes/enum_ty.rs create mode 100644 crates/graph/nodes/err_ty.rs create mode 100644 crates/graph/nodes/func_ty.rs create mode 100644 crates/graph/nodes/mod.rs create mode 100644 crates/graph/nodes/msg.rs create mode 100644 crates/graph/nodes/struct_ty.rs create mode 100644 crates/graph/nodes/ty_ty.rs create mode 100644 crates/graph/nodes/var_ty.rs create mode 100644 crates/graph/search.rs create mode 100644 crates/graph/var_type.rs create mode 100644 crates/range/elem/concrete.rs create mode 100644 crates/range/elem/elem_enum.rs create mode 100644 crates/range/elem/expr.rs create mode 100644 crates/range/elem/map_or_array.rs create mode 100644 crates/range/elem/mod.rs create mode 100644 crates/range/elem/reference.rs create mode 100644 crates/range/exec/add.rs create mode 100644 crates/range/exec/bitwise.rs create mode 100644 crates/range/exec/cast.rs create mode 100644 crates/range/exec/concat.rs create mode 100644 crates/range/exec/div.rs create mode 100644 crates/range/exec/exp.rs create mode 100644 crates/range/exec/logical.rs create mode 100644 crates/range/exec/max.rs create mode 100644 crates/range/exec/min.rs create mode 100644 crates/range/exec/mod.rs create mode 100644 crates/range/exec/modulo.rs create mode 100644 crates/range/exec/mul.rs create mode 100644 crates/range/exec/ord.rs create mode 100644 crates/range/exec/shift.rs create mode 100644 crates/range/exec/sub.rs create mode 100644 crates/range/mod.rs create mode 100644 crates/range/range_string.rs create mode 100644 crates/range/solc_range.rs diff --git a/crates/analyzer/analyzer_like.rs b/crates/analyzer/analyzer_like.rs new file mode 100644 index 00000000..99d41f82 --- /dev/null +++ b/crates/analyzer/analyzer_like.rs @@ -0,0 +1,82 @@ +use graph::GraphLike; + +pub trait AnalyzerLike: GraphLike { + type Expr; + type ExprErr; + /// Gets the builtin functions map + fn builtin_fns(&self) -> &HashMap; + /// Mutably gets the builtin functions map + fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap; + /// Gets the builtin function nodes mapping + fn builtin_fn_nodes(&self) -> &HashMap; + /// Returns the configured max call depth + fn max_depth(&self) -> usize; + /// Returns the configured max fork width + fn max_width(&self) -> usize; + fn user_types(&self) -> &HashMap; + fn user_types_mut(&mut self) -> &mut HashMap; + fn parse_expr(&mut self, expr: &Self::Expr, parent: Option) -> NodeIdx; + fn msg(&mut self) -> MsgNode; + fn block(&mut self) -> BlockNode; + fn entry(&self) -> NodeIdx; + fn add_expr_err(&mut self, err: Self::ExprErr); + fn expr_errs(&self) -> Vec; + + fn builtin_fn_inputs(&self) -> &HashMap, Vec)>; + fn builtins(&self) -> &HashMap; + fn builtins_mut(&mut self) -> &mut HashMap; + + fn builtin_or_add(&mut self, builtin: Builtin) -> NodeIdx { + if let Some(idx) = self.builtins().get(&builtin) { + *idx + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins_mut().insert(builtin, idx); + idx + } + } + fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option + where + Self: std::marker::Sized, + { + if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { + Some(*idx) + } else if let Some(func) = self.builtin_fns().get(builtin_name) { + let (inputs, outputs) = self + .builtin_fn_inputs() + .get(builtin_name) + .expect("builtin func but no inputs") + .clone(); + let func_node = self.add_node(Node::Function(func.clone())); + let mut params_strs = vec![]; + inputs.into_iter().for_each(|input| { + let input_node = self.add_node(input); + params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); + self.add_edge(input_node, func_node, Edge::FunctionParam); + }); + outputs.into_iter().for_each(|output| { + let output_node = self.add_node(output); + self.add_edge(output_node, func_node, Edge::FunctionReturn); + }); + + self.add_edge(func_node, self.entry(), Edge::Func); + + self.builtin_fn_nodes_mut() + .insert(builtin_name.to_string(), func_node); + Some(func_node) + } else { + None + } + } + + + fn add_if_err(&mut self, err: Result) -> Option { + match err { + Ok(t) => Some(t), + Err(e) => { + self.add_expr_err(e); + None + } + } + } +} \ No newline at end of file diff --git a/crates/analyzer/lib.rs b/crates/analyzer/lib.rs new file mode 100644 index 00000000..24835819 --- /dev/null +++ b/crates/analyzer/lib.rs @@ -0,0 +1 @@ +pub mod analyzer_like; \ No newline at end of file diff --git a/crates/graph/graph_elements.rs b/crates/graph/graph_elements.rs new file mode 100644 index 00000000..4f5439fd --- /dev/null +++ b/crates/graph/graph_elements.rs @@ -0,0 +1,181 @@ +use crate::graph::GraphLike; +use crate::context::ContextVarNode; +use std::collections::HashMap; + +use crate::analyzer::AsDotStr; +use crate::context::ContextNode; +use crate::{ + context::{Context, ContextEdge, ContextVar}, + nodes::*, +}; +use lazy_static::lazy_static; +use petgraph::graph::*; +use solang_parser::pt::Identifier; + +pub type NodeIdx = NodeIndex; +pub type EdgeIdx = EdgeIndex; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Node { + Context(Context), + ContextVar(ContextVar), + ContextFork, + FunctionCall, + Builtin(Builtin), + VarType(VarType), + Entry, + SourceUnit(usize), + SourceUnitPart(usize, usize), + Contract(Contract), + Function(Function), + FunctionParam(FunctionParam), + FunctionReturn(FunctionReturn), + Struct(Struct), + Enum(Enum), + Error(Error), + ErrorParam(ErrorParam), + Field(Field), + Var(Var), + Ty(Ty), + Unresolved(Identifier), + Concrete(Concrete), + Msg(Msg), + Block(Block), +} + +pub fn as_dot_str(idx: NodeIdx, analyzer: &impl GraphLike) -> String { + use crate::Node::*; + match analyzer.node(idx) { + Context(_) => ContextNode::from(idx).as_dot_str(analyzer), + ContextVar(_) => ContextVarNode::from(idx).as_dot_str(analyzer), + ContextFork => "Context Fork".to_string(), + FunctionCall => "Function Call".to_string(), + Builtin(bi) => bi.as_string(analyzer).unwrap(), + VarType(v_ty) => v_ty.as_dot_str(analyzer), + Contract(_c) => ContractNode::from(idx).as_dot_str(analyzer), + Function(_f) => FunctionNode::from(idx).as_dot_str(analyzer), + FunctionParam(_fp) => FunctionParamNode::from(idx).as_dot_str(analyzer), + FunctionReturn(_fr) => FunctionReturnNode::from(idx).as_dot_str(analyzer), + Struct(_s) => StructNode::from(idx).as_dot_str(analyzer), + Enum(_e) => EnumNode::from(idx).as_dot_str(analyzer), + Field(_f) => FieldNode::from(idx).as_dot_str(analyzer), + Var(_v) => VarNode::from(idx).as_dot_str(analyzer), + Ty(_t) => TyNode::from(idx).as_dot_str(analyzer), + // Concrete(c) => c.as_human_string(), + e => format!("{e:?}"), + } +} + +impl Node { + pub fn dot_str_color(&self) -> String { + use crate::Node::*; + let c = match self { + Context(_) => TOKYO_NIGHT_COLORS.get("purple").unwrap(), + ContextVar(_) => TOKYO_NIGHT_COLORS.get("orange").unwrap(), + FunctionCall => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), + Contract(_c) => TOKYO_NIGHT_COLORS.get("green").unwrap(), + Function(_f) => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), + Struct(_s) => TOKYO_NIGHT_COLORS.get("yellow").unwrap(), + Enum(_e) => TOKYO_NIGHT_COLORS.get("yellow").unwrap(), + _ => TOKYO_NIGHT_COLORS.get("default").unwrap(), + }; + c.to_string() + } +} + +lazy_static! { + pub static ref TOKYO_NIGHT_COLORS: HashMap<&'static str, &'static str> = { + let mut m = HashMap::new(); + m.insert("red", "#f7768e"); + m.insert("orange", "#ff9e64"); + m.insert("yellow", "#e0af68"); + m.insert("green", "#9ece6a"); + m.insert("cyan", "#73daca"); + m.insert("teal", "#2ac3de"); + m.insert("darkblue", "#7aa2f7"); + m.insert("purple", "#bb9af7"); + m.insert("bg", "#1a1b26"); + m.insert("font", "#c0caf5"); + m.insert("deepred", "#703440"); + m.insert("default", "#565f89"); + m + }; +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum Edge { + Source, + Part, + Import, + Context(ContextEdge), + Contract, + InheritedContract, + Field, + Enum, + Struct, + Error, + ErrorParam, + Event, + Var, + Ty, + Func, + FunctionParam, + FunctionReturn, + FuncModifier(usize), + Modifier, + FallbackFunc, + Constructor, + ReceiveFunc, + LibraryFunction(NodeIdx), + BuiltinFunction, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum ContextEdge { + // Control flow + Context, + Subcontext, + ContextFork, + ContextMerge, + Call, + + // Context Variables + Variable, + InheritedVariable, + + AttrAccess, + Index, + IndexAccess, + StructAccess, + FuncAccess, + + // Variable incoming edges + Assign, + StorageAssign, + MemoryAssign, + Prev, + + // Control flow + Return, + Continue, + InputVariable, + ReturnAssign(bool), + + // Range analysis + Range, +} + + +#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] +pub enum GraphError { + NodeConfusion(String), + MaxStackDepthReached(String), + MaxStackWidthReached(String), + ChildRedefinition(String), + VariableUpdateInOldContext(String), + DetachedVariable(String), + ExpectedSingle(String), + StackLengthMismatch(String), + UnbreakableRecursion(String), +} + diff --git a/crates/graph/graph_like.rs b/crates/graph/graph_like.rs new file mode 100644 index 00000000..2edec838 --- /dev/null +++ b/crates/graph/graph_like.rs @@ -0,0 +1,352 @@ + + +pub trait AsDotStr { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String; +} + +/// A trait that constructs dot-like visualization strings (either mermaid or graphviz) +pub trait GraphLike { + fn graph_mut(&mut self) -> &mut Graph; + fn graph(&self) -> &Graph; + + fn add_node(&mut self, node: impl Into) -> NodeIdx { + self.graph_mut().add_node(node.into()) + } + + fn node(&self, node: impl Into) -> &Node { + self.graph() + .node_weight(node.into()) + .expect("Index not in graph") + } + + fn node_mut(&mut self, node: impl Into) -> &mut Node { + self.graph_mut() + .node_weight_mut(node.into()) + .expect("Index not in graph") + } + + fn add_edge( + &mut self, + from_node: impl Into, + to_node: impl Into, + edge: impl Into, + ) { + self.graph_mut() + .add_edge(from_node.into(), to_node.into(), edge.into()); + } +} + +impl GraphDot for T {} + +/// A trait that constructs dot-like visualization strings (either mermaid or graphviz) +pub trait GraphDot: GraphLike { + fn open_dot(&self) + where + Self: std::marker::Sized, + Self: AnalyzerLike, + { + use std::env::temp_dir; + use std::fs; + use std::io::Write; + use std::process::Command; + let temp_dir = temp_dir(); + let file_name = "dot.dot"; + let mut temp_path = temp_dir.clone(); + temp_path.push(file_name); + let temp_svg_filename: String = format!("{}/dot.svg", &temp_dir.to_string_lossy()); + + let mut file = fs::File::create(temp_path.clone()).unwrap(); + file.write_all(self.dot_str().as_bytes()).unwrap(); + Command::new("dot") + .arg("-Tsvg") + .arg(temp_path) + .arg("-o") + .arg(&temp_svg_filename) + .output() + .expect("You may need to install graphviz, check if command 'dot' is in your $PATH"); + Command::new("open") + .arg(&temp_svg_filename) + .spawn() + .expect("failed to execute process"); + } + + /// Creates a subgraph for visually identifying contexts and subcontexts + fn cluster_str( + &self, + node: NodeIdx, + cluster_num: usize, + is_killed: bool, + handled_nodes: Arc>>, + handled_edges: Arc>>>, + ) -> String { + if self + .graph() + .edges_directed(node, Direction::Outgoing) + .collect::>() + .is_empty() + { + return "".to_string(); + } + let new_graph = self.graph().filter_map( + |_idx, node| match node { + Node::ContextVar(_cvar) => { + // if !cvar.is_symbolic { + // None + // } else { + Some(node.clone()) + // } + } + _ => Some(node.clone()), + }, + |_idx, edge| Some(*edge), + ); + + let g = &G { graph: &new_graph }; + let children = g.children(node); + let children_edges = g.children_edges(node); + let mut cn = cluster_num + 1; + let child_node_str = children + .iter() + .map(|child| { + { + handled_nodes.lock().unwrap().insert(*child); + } + + if g.graph + .edges_directed(*child, Direction::Outgoing) + .collect::>() + .is_empty() + { + return "".to_string(); + } + let post_str = match self.node(*child) { + Node::Context(c) => { + cn += 2; + self.cluster_str( + *child, + cn, + c.killed.is_some(), + handled_nodes.clone(), + handled_edges.clone(), + ) + } + _ => "".to_string(), + }; + + format!( + " {} [label = \"{}\", color = \"{}\"]\n{}\n", + petgraph::graph::GraphIndex::index(child), + as_dot_str(*child, g).replace('\"', "\'"), + self.node(*child).dot_str_color(), + post_str + ) + }) + .collect::>() + .join(""); + + let edge_str = children_edges + .iter() + .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) + .map(|(from, to, edge, idx)| { + handled_edges.lock().unwrap().insert(*idx); + let from = petgraph::graph::GraphIndex::index(from); + let to = petgraph::graph::GraphIndex::index(to); + format!(" {from:} -> {to:} [label = \"{edge:?}\"]\n",) + }) + .collect::>() + .join(""); + format!( + " subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", + cluster_num, + if is_killed && cluster_num % 2 == 0 { + " bgcolor=\"#7a0b0b\"" + } else if is_killed { + " bgcolor=\"#e04646\"" + } else if cluster_num % 2 == 0 { + " bgcolor=\"#545e87\"" + } else { + " bgcolor=\"#1a1b26\"" + }, + format!( + " {} [label = \"{}\", color = \"{}\"]\n", + node.index(), + as_dot_str(node, g).replace('\"', "\'"), + self.node(node).dot_str_color() + ), + child_node_str, + edge_str, + ) + } + + /// Constructs a dot string + fn dot_str(&self) -> String + where + Self: std::marker::Sized, + Self: AnalyzerLike, + { + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26"; rankdir="BT""##; + dot_str.push(raw_start_str.to_string()); + let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); + let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); + let (nodes, edges) = ( + self.graph().node_indices().collect::>(), + self.graph().edge_indices().collect::>(), + ); + let mut cluster_num = 0; + let mut skip = BTreeSet::default(); + let nodes_str = nodes + .iter() + .filter_map(|node| { + if self + .graph() + .edges_directed(*node, Direction::Outgoing) + .collect::>() + .is_empty() + && !matches!(self.node(*node), Node::Entry) + { + skip.insert(*node); + return None; + } + if !handled_nodes.lock().unwrap().contains(node) { + match self.node(*node) { + Node::Function(_) => { + cluster_num += 2; + Some(self.cluster_str( + *node, + cluster_num, + false, + handled_nodes.clone(), + handled_edges.clone(), + )) + } + n => Some(format!( + "{} [label = \"{}\", color = \"{}\"]", + petgraph::graph::GraphIndex::index(node), + as_dot_str(*node, self).replace('\"', "\'"), + n.dot_str_color() + )), + } + } else { + None + } + }) + .collect::>() + .join("\n "); + let edges_str = edges + .into_iter() + .filter_map(|edge| { + if !handled_edges.lock().unwrap().contains(&edge) { + let (from, to) = self.graph().edge_endpoints(edge).unwrap(); + if skip.contains(&from) || skip.contains(&to) { + return None; + } + let from = from.index(); + let to = to.index(); + Some(format!( + "{from:} -> {to:} [label = \"{:?}\"]", + self.graph().edge_weight(edge).unwrap() + )) + } else { + None + } + }) + .collect::>() + .join("\n "); + + dot_str.push(nodes_str); + dot_str.push(edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + dot_str.join("\n") + } + + fn dot_str_no_tmps(&self) -> String + where + Self: std::marker::Sized, + Self: GraphLike + AnalyzerLike, + { + let new_graph = self.graph().filter_map( + |_idx, node| match node { + Node::ContextVar(cvar) => { + if !cvar.is_symbolic || cvar.tmp_of.is_some() { + None + } else { + Some(node.clone()) + } + } + _ => Some(node.clone()), + }, + |_idx, edge| Some(*edge), + ); + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26";"##; + dot_str.push(raw_start_str.to_string()); + let nodes_and_edges_str = format!( + "{:?}", + Dot::with_attr_getters( + &new_graph, + &[ + petgraph::dot::Config::GraphContentOnly, + petgraph::dot::Config::NodeNoLabel, + petgraph::dot::Config::EdgeNoLabel + ], + &|_graph, edge_ref| { + match edge_ref.weight() { + Edge::Context(edge) => format!("label = \"{edge:?}\""), + e => format!("label = \"{e:?}\""), + } + }, + &|_graph, (idx, node_ref)| { + let inner = match node_ref { + Node::ContextVar(cvar) => { + let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { + r.as_dot_str(self) + // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) + } else { + "".to_string() + }; + + format!( + "{} -- {} -- range: {}", + cvar.display_name, + cvar.ty.as_string(self).unwrap(), + range_str + ) + } + _ => as_dot_str(idx, &G { graph: &new_graph }), + }; + format!( + "label = \"{}\", color = \"{}\"", + inner.replace('\"', "\'"), + node_ref.dot_str_color() + ) + } + ) + ); + dot_str.push(nodes_and_edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + dot_str.join("\n") + } +} + +struct G<'a> { + pub graph: &'a Graph, +} + +impl GraphLike for G<'_> { + fn graph_mut(&mut self) -> &mut Graph { + panic!("Should call this") + } + + fn graph(&self) -> &Graph { + self.graph + } +} \ No newline at end of file diff --git a/crates/graph/lib.rs b/crates/graph/lib.rs new file mode 100644 index 00000000..4f37b450 --- /dev/null +++ b/crates/graph/lib.rs @@ -0,0 +1,11 @@ +mod graph_elements; +mod graph_like; +mod search; +mod var_type; + +pub mod nodes; + +pub use var_type::*; +pub use graph_elements::*; +pub use graph_like::*; +pub use search::*; diff --git a/crates/graph/nodes/block.rs b/crates/graph/nodes/block.rs new file mode 100644 index 00000000..e5cd8201 --- /dev/null +++ b/crates/graph/nodes/block.rs @@ -0,0 +1,68 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::GraphError; +use crate::analyzer::GraphLike; + +use crate::Node; +use crate::NodeIdx; +use ethers_core::types::Address; +use ethers_core::types::H256; +use ethers_core::types::U256; + +/// An index in the graph that references a Block node +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct BlockNode(pub usize); + +impl BlockNode { + /// Gets the underlying node data for the block environment + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Block, GraphError> { + match analyzer.node(*self) { + Node::Block(st) => Ok(st), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Msg but it was: {e:?}" + ))), + } + } +} + +impl AsDotStr for BlockNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + format!("block {{ {:?} }}", self.underlying(analyzer).unwrap()) + } +} + +impl From for NodeIdx { + fn from(val: BlockNode) -> Self { + val.0.into() + } +} + +impl From for BlockNode { + fn from(idx: NodeIdx) -> Self { + BlockNode(idx.index()) + } +} + +/// Represents block-based environment variables available in solidity. These can +/// be set in the configuration (TODO) - if they are not set they are assumed to be +/// in their types default full range (e.g.: `uint256 -> [0, 2**256 - 1]`). +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct Block { + /// The block's hash + pub hash: Option, + /// The block's basefee + pub basefee: Option, + /// The chain id + pub chainid: Option, + /// The block coinbase + pub coinbase: Option
, + /// The block difficulty + pub difficulty: Option, + /// The block gas limit + pub gaslimit: Option, + /// The block number + pub number: Option, + /// The block's prevrandao + pub prevrandao: Option, + /// The block's timestamp + pub timestamp: Option, +} diff --git a/crates/graph/nodes/builtin.rs b/crates/graph/nodes/builtin.rs new file mode 100644 index 00000000..865bbcf8 --- /dev/null +++ b/crates/graph/nodes/builtin.rs @@ -0,0 +1,379 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub struct BuiltInNode(pub usize); + +impl BuiltInNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Builtin, GraphError> { + match analyzer.node(*self) { + Node::Builtin(b) => Ok(b), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Builtin but it was: {e:?}" + ))), + } + } + + pub fn num_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let underlying = self.underlying(analyzer)?; + Ok(underlying.num_size()) + } + + pub fn implicitly_castable_to( + &self, + other: &Self, + analyzer: &impl GraphLike, + ) -> Result { + Ok(self + .underlying(analyzer)? + .implicitly_castable_to(other.underlying(analyzer)?)) + } + + pub fn max_size( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let m = self.underlying(analyzer)?.max_size(); + Ok(analyzer.builtin_or_add(m).into()) + } + + pub fn dynamic_underlying_ty( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match self.underlying(analyzer)? { + Builtin::Array(v_ty) | Builtin::SizedArray(_, v_ty) => { + v_ty.unresolved_as_resolved(analyzer) + } + Builtin::Mapping(_, v_ty) => v_ty.unresolved_as_resolved(analyzer), + Builtin::DynamicBytes | Builtin::Bytes(_) => Ok(VarType::BuiltIn( + analyzer.builtin_or_add(Builtin::Bytes(1)).into(), + Some(SolcRange::new( + Elem::from(Concrete::from(vec![0x00])), + Elem::from(Concrete::from(vec![0xff])), + vec![], + )), + )), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Builtin::Array but it was: {e:?}" + ))), + } + } + + pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + Ok(matches!(self.underlying(analyzer)?, Builtin::Mapping(_, _))) + } + + pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + Ok(matches!( + self.underlying(analyzer)?, + Builtin::SizedArray(_, _) + )) + } + + pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + match self.underlying(analyzer)? { + Builtin::SizedArray(s, _) => Ok(Some(*s)), + Builtin::Bytes(s) => Ok(Some(U256::from(*s))), + _ => Ok(None), + } + } + + pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_dyn()) + } + + pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_indexable()) + } + + pub fn zero_range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.zero_range()) + } +} + +impl From for BuiltInNode { + fn from(idx: NodeIdx) -> Self { + BuiltInNode(idx.index()) + } +} + +impl From for NodeIdx { + fn from(val: BuiltInNode) -> Self { + val.0.into() + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum Builtin { + Address, + AddressPayable, + Payable, + Bool, + String, + Int(u16), + Uint(u16), + Bytes(u8), + Rational, + DynamicBytes, + Array(VarType), + SizedArray(U256, VarType), + Mapping(VarType, VarType), + Func(Vec, Vec), +} + +impl Builtin { + pub fn unresolved_as_resolved( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match self { + Builtin::Array(n) => Ok(Builtin::Array(n.unresolved_as_resolved(analyzer)?)), + Builtin::SizedArray(s, n) => { + Ok(Builtin::SizedArray(*s, n.unresolved_as_resolved(analyzer)?)) + } + Builtin::Mapping(k, v) => Ok(Builtin::Mapping( + k.unresolved_as_resolved(analyzer)?, + v.unresolved_as_resolved(analyzer)?, + )), + _ => Ok(self.clone()), + } + } + + pub fn possible_builtins_from_ty_inf(&self) -> Vec { + let mut builtins = vec![]; + match self { + Builtin::Uint(size) => { + let mut s = *size; + while s > 0 { + builtins.push(Builtin::Uint(s)); + s -= 8; + } + } + Builtin::Int(size) => { + let mut s = *size; + while s > 0 { + builtins.push(Builtin::Int(s)); + s -= 8; + } + } + Builtin::Bytes(size) => { + let mut s = *size; + while s > 0 { + builtins.push(Builtin::Bytes(s)); + s -= 1; + } + } + _ => {} + } + builtins + } + + pub fn zero_range(&self) -> Option { + match self { + Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { + let zero = Concrete::Address(Address::from_slice(&[0x00; 20])); + Some(SolcRange::new(zero.clone().into(), zero.into(), vec![])) + } + Builtin::Bool => SolcRange::from(Concrete::from(false)), + Builtin::String => SolcRange::from(Concrete::from("".to_string())), + Builtin::Int(_) => SolcRange::from(Concrete::from(I256::from(0))), + Builtin::Uint(_) => SolcRange::from(Concrete::from(U256::from(0))), + Builtin::Bytes(s) => SolcRange::from(Concrete::Bytes(*s, H256::zero())), + Builtin::DynamicBytes | Builtin::Array(_) | Builtin::Mapping(_, _) => { + let zero = Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::zero())), + val: Default::default(), + loc: Loc::Implicit, + })); + Some(SolcRange::new(zero.clone(), zero, vec![])) + } + Builtin::SizedArray(s, _) => { + let sized = Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(*s)), + val: Default::default(), + loc: Loc::Implicit, + })); + Some(SolcRange::new(sized.clone(), sized, vec![])) + } + Builtin::Rational | Builtin::Func(_, _) => None, + } + } + pub fn try_from_ty( + ty: Type, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + use Type::*; + match ty { + Address => Some(Builtin::Address), + AddressPayable => Some(Builtin::AddressPayable), + Payable => Some(Builtin::Payable), + Bool => Some(Builtin::Bool), + String => Some(Builtin::String), + Int(size) => Some(Builtin::Int(size)), + Uint(size) => Some(Builtin::Uint(size)), + Bytes(size) => Some(Builtin::Bytes(size)), + Rational => Some(Builtin::Rational), + DynamicBytes => Some(Builtin::DynamicBytes), + Mapping { key, value, .. } => { + let key_idx = analyzer.parse_expr(&key, None); + let val_idx = analyzer.parse_expr(&value, None); + let key_var_ty = VarType::try_from_idx(analyzer, key_idx)?; + let val_var_ty = VarType::try_from_idx(analyzer, val_idx)?; + Some(Builtin::Mapping(key_var_ty, val_var_ty)) + } + Function { + params, + attributes: _, + returns, + } => { + let inputs = params + .iter() + .filter_map(|(_, param)| param.as_ref()) + .map(|param| analyzer.parse_expr(¶m.ty, None)) + .collect::>(); + let inputs = inputs + .iter() + .map(|idx| VarType::try_from_idx(analyzer, *idx).expect("Couldn't parse param")) + .collect::>(); + let mut outputs = vec![]; + if let Some((params, _attrs)) = returns { + let tmp_outputs = params + .iter() + .filter_map(|(_, param)| param.as_ref()) + .map(|param| analyzer.parse_expr(¶m.ty, None)) + .collect::>(); + outputs = tmp_outputs + .iter() + .map(|idx| { + VarType::try_from_idx(analyzer, *idx) + .expect("Couldn't parse output param") + }) + .collect::>(); + } + Some(Builtin::Func(inputs, outputs)) + } + } + } + + pub fn is_dyn(&self) -> bool { + matches!( + self, + Builtin::DynamicBytes + | Builtin::Array(..) + | Builtin::SizedArray(..) + | Builtin::Mapping(..) + | Builtin::String + ) + } + + pub fn requires_input(&self) -> bool { + matches!( + self, + Builtin::Array(..) | Builtin::SizedArray(..) | Builtin::Mapping(..) + ) + } + + pub fn num_size(&self) -> Option { + match self { + Builtin::Uint(size) => Some(*size), + Builtin::Int(size) => Some(*size), + _ => None, + } + } + + pub fn is_int(&self) -> bool { + matches!(self, Builtin::Int(_)) + } + + pub fn is_indexable(&self) -> bool { + matches!( + self, + Builtin::DynamicBytes + | Builtin::Array(..) + | Builtin::SizedArray(..) + | Builtin::Mapping(..) + | Builtin::Bytes(..) + | Builtin::String + ) + } + + pub fn implicitly_castable_to(&self, other: &Self) -> bool { + use Builtin::*; + match (self, other) { + (Address, Address) => true, + (Address, AddressPayable) => true, + (Address, Payable) => true, + (AddressPayable, Address) => true, + (AddressPayable, Payable) => true, + (AddressPayable, AddressPayable) => true, + (Payable, Address) => true, + (Payable, AddressPayable) => true, + (Payable, Payable) => true, + (Bool, Bool) => true, + (Rational, Rational) => true, + (DynamicBytes, DynamicBytes) => true, + (String, String) => true, + (Uint(from_size), Uint(to_size)) => from_size <= to_size, + (Int(from_size), Int(to_size)) => from_size <= to_size, + (Bytes(from_size), Bytes(to_size)) => from_size <= to_size, + _ => false, + } + } + + pub fn max_size(&self) -> Self { + use Builtin::*; + match self { + Uint(_) => Uint(256), + Int(_from_size) => Uint(256), + Bytes(_from_size) => Uint(32), + _ => self.clone(), + } + } + + pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + use Builtin::*; + match self { + Address => Ok("address".to_string()), + AddressPayable => Ok("address".to_string()), + Payable => Ok("address".to_string()), + Bool => Ok("bool".to_string()), + String => Ok("string".to_string()), + Int(size) => Ok(format!("int{size}")), + Uint(size) => Ok(format!("uint{size}")), + Bytes(size) => Ok(format!("bytes{size}")), + Rational => Ok("rational".to_string()), + DynamicBytes => Ok("bytes".to_string()), + Array(v_ty) => Ok(format!( + "{}[]", + v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)? + )), + SizedArray(s, v_ty) => Ok(format!( + "{}[{}]", + v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)?, + s + )), + Mapping(key_ty, v_ty) => Ok(format!( + "mapping ({} => {})", + key_ty + .unresolved_as_resolved(analyzer)? + .as_string(analyzer)?, + v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)? + )), + Func(inputs, outputs) => Ok(format!( + "function({}) returns ({})", + inputs + .iter() + .map(|input| input.as_string(analyzer).unwrap()) + .collect::>() + .join(", "), + outputs + .iter() + .map(|output| output.as_string(analyzer).unwrap()) + .collect::>() + .join(", ") + )), + } + } +} diff --git a/crates/graph/nodes/concrete.rs b/crates/graph/nodes/concrete.rs new file mode 100644 index 00000000..542c83f6 --- /dev/null +++ b/crates/graph/nodes/concrete.rs @@ -0,0 +1,849 @@ +use crate::analyzer::GraphError; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::Builtin; +use crate::VarType; +use crate::{Node, NodeIdx}; +use ethers_core::types::{Address, H256, I256, U256}; + +/// An index in the graph that references a [`Concrete`] node +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct ConcreteNode(pub usize); + +impl ConcreteNode { + /// Gets the underlying node data for the [`Concrete`] + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Concrete, GraphError> { + match analyzer.node(*self) { + Node::Concrete(c) => Ok(c), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Concrete but it was: {e:?}" + ))), + } + } + + pub fn max_size( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let c = self.underlying(analyzer)?.max_size(); + Ok(analyzer.add_node(Node::Concrete(c)).into()) + } + + pub fn dynamic_underlying_ty( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let builtin = self.underlying(analyzer)?.dynamic_underlying_ty().unwrap(); + let bn = analyzer.builtin_or_add(builtin); + let v_ty = VarType::try_from_idx(analyzer, bn).unwrap(); + Ok(v_ty) + } + + pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_dyn()) + } + + pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_sized_array()) + } + + pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.maybe_array_size()) + } + + pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_indexable()) + } +} + +impl From for ConcreteNode { + fn from(idx: NodeIdx) -> Self { + ConcreteNode(idx.index()) + } +} + +impl From for NodeIdx { + fn from(val: ConcreteNode) -> Self { + val.0.into() + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum DynCapacity { + Cap(U256), + Unlimited, +} + +/// EVM/Solidity basic concrete types +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Concrete { + /// An unsigned integer, in the form of (bits, value) + Uint(u16, U256), + /// A signed integer, in the form of (bits, value) + Int(u16, I256), + /// An fixed length bytes, in the form of (bytes, value) + Bytes(u8, H256), + /// A 20 byte address + Address(Address), + /// A boolean + Bool(bool), + /// A vector of bytes + DynBytes(Vec), + /// A string, (TODO: solidity doesn't enforce utf-8 encoding like rust. Likely this type + /// should be modeled with a `Vec` instead.) + String(String), + /// An array of concrete values + Array(Vec), +} + +impl From for Concrete { + fn from(u: U256) -> Self { + Concrete::Uint(256, u) + } +} + +impl From for Concrete { + fn from(u: I256) -> Self { + Concrete::Int(256, u) + } +} + +impl From> for Concrete { + fn from(u: Vec) -> Self { + Concrete::DynBytes(u) + } +} + +impl From for Concrete { + fn from(u: H256) -> Self { + Concrete::Bytes(32, u) + } +} + +impl From<[u8; N]> for Concrete { + fn from(u: [u8; N]) -> Self { + assert!(N <= 32); + let mut h = H256::default(); + h.assign_from_slice(&u[..]); + Concrete::Bytes(N.try_into().unwrap(), h) + } +} + +impl From
for Concrete { + fn from(u: Address) -> Self { + Concrete::Address(u) + } +} + +impl From for Concrete { + fn from(u: bool) -> Self { + Concrete::Bool(u) + } +} + +impl From for Concrete { + fn from(u: String) -> Self { + Concrete::String(u) + } +} + +impl> From> for Concrete { + fn from(u: Vec) -> Self { + Concrete::Array(u.into_iter().map(|t| t.into()).collect()) + } +} + +impl Concrete { + pub fn is_dyn(&self) -> bool { + matches!( + self, + Concrete::DynBytes(..) | Concrete::String(..) | Concrete::Array(..) + ) + } + + pub fn is_sized_array(&self) -> bool { + matches!(self, Concrete::DynBytes(..) | Concrete::Array(..)) + } + + pub fn dynamic_underlying_ty(&self) -> Option { + match self { + Concrete::DynBytes(_v) => Some(Builtin::Bytes(1)), + Concrete::Array(v) => v.first().map(|inner| inner.as_builtin()), + Concrete::String(_v) => Some(Builtin::Bytes(1)), + Concrete::Bytes(_, _) => Some(Builtin::Bytes(1)), + _ => None, + } + } + + pub fn maybe_array_size(&self) -> Option { + match self { + Concrete::DynBytes(v) => Some(U256::from(v.len())), + Concrete::Array(v) => Some(U256::from(v.len())), + Concrete::String(v) => Some(U256::from(v.len())), + Concrete::Bytes(s, _) => Some(U256::from(*s)), + _ => None, + } + } + + pub fn is_indexable(&self) -> bool { + self.is_dyn() || matches!(self, Concrete::Bytes(..)) + } + + /// Convert a U256 back into it's original type. This is used mostly + /// for range calculations to improve ergonomics. Basically + /// the EVM only operates on U256 words, so most of this should + /// be fine. + pub fn u256_as_original(&self, uint: U256) -> Self { + match self { + Concrete::Uint(size, _) => Concrete::Uint(*size, uint), + Concrete::Int(size, _) => Concrete::Int(*size, I256::from_raw(uint)), + Concrete::Bytes(size, _) => { + let mut h = H256::default(); + uint.to_big_endian(h.as_mut()); + Concrete::Bytes(*size, h) + } + Concrete::Address(_) => { + let mut bytes = [0u8; 32]; + uint.to_big_endian(&mut bytes); + Concrete::Address(Address::from_slice(&bytes[12..])) + } + Concrete::Bool(_) => { + if uint > U256::zero() { + Concrete::Bool(true) + } else { + Concrete::Bool(false) + } + } + e => todo!("Unsupported: {e:?}"), + } + } + + /// Cast from one concrete variant given another concrete variant + pub fn cast_from(self, other: &Self) -> Option { + self.cast(other.as_builtin()) + } + + /// Cast from one concrete variant given another concrete variant, but since its a literal + /// uint to bytesX are right padded + pub fn literal_cast_from(self, other: &Self) -> Option { + self.literal_cast(other.as_builtin()) + } + + pub fn equivalent_ty(&self, other: &Self) -> bool { + match (self, other) { + (Concrete::Uint(size, _), Concrete::Uint(other_size, _)) if size == other_size => true, + (Concrete::Int(size, _), Concrete::Int(other_size, _)) if size == other_size => true, + (Concrete::Bytes(size, _), Concrete::Bytes(other_size, _)) if size == other_size => { + true + } + (Concrete::Address(_), Concrete::Address(_)) => true, + (Concrete::Bool(_), Concrete::Bool(_)) => true, + (Concrete::DynBytes(_), Concrete::DynBytes(_)) => true, + (Concrete::String(_), Concrete::String(_)) => true, + (Concrete::Array(v0), Concrete::Array(v1)) => { + if v0.is_empty() || v1.is_empty() { + true + } else { + v0[0].equivalent_ty(&v1[0]) + } + } + _ => false, + } + } + + pub fn is_int(&self) -> bool { + matches!(self, Concrete::Int(_, _)) + } + + pub fn literal_cast(self, builtin: Builtin) -> Option { + match self { + Concrete::Uint(_, val) => match builtin { + Builtin::Bytes(size) => { + let mask = if size == 32 { + U256::MAX + } else { + U256::from(2).pow((size as u16 * 8).into()) - 1 + }; + + let h = H256::from_slice( + &(val & mask) + .0 + .iter() + .flat_map(|v| v.to_le_bytes()) + .collect::>()[..], + ); + Some(Concrete::Bytes(size, h)) + } + _ => self.cast(builtin), + }, + _ => self.cast(builtin), + } + } + + pub fn concat(self, other: &Self) -> Option { + match (self, other) { + (Concrete::String(a), Concrete::String(b)) => Some(Concrete::from(format!("{a}{b}"))), + (Concrete::DynBytes(mut a), Concrete::DynBytes(b)) => { + a.extend(b); + Some(Concrete::from(a)) + } + _ => None, + } + } + + /// Cast the concrete to another type as denoted by a [`Builtin`]. + pub fn cast(self, builtin: Builtin) -> Option { + match self { + Concrete::Uint(r_size, val) => { + match builtin { + Builtin::Address => { + let mut bytes = [0u8; 32]; + val.to_big_endian(&mut bytes); + Some(Concrete::Address(Address::from_slice(&bytes[12..]))) + } + Builtin::Uint(size) => { + // no op + if r_size == size { + Some(self) + } else { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + if val < mask { + Some(Concrete::Uint(size, val)) + } else { + Some(Concrete::Uint(size, mask)) + } + } + } + Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), + Builtin::Bytes(size) => { + let mask = if size == 32 { + U256::MAX + } else { + let v = U256::from(2).pow((size as u16 * 8).into()) - 1; + v << v.leading_zeros() + }; + + // let h = H256::from_slice(&(val & mask).0.iter().flat_map(|v| v.to_le_bytes()).collect::>()[..]); + let mut h = H256::default(); + (val & mask).to_big_endian(&mut h.0); + Some(Concrete::Bytes(size, h)) + } + Builtin::Bool => { + if val > U256::zero() { + Some(Concrete::from(true)) + } else { + Some(Concrete::from(false)) + } + } + _ => None, + } + } + Concrete::Int(r_size, val) => match builtin { + Builtin::Address => { + let mut bytes = [0u8; 32]; + val.to_big_endian(&mut bytes); + Some(Concrete::Address(Address::from_slice(&bytes[12..]))) + } + Builtin::Uint(size) => { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + Some(Concrete::Uint(size, val.into_raw() & mask)) + } + Builtin::Int(size) => { + // no op + if r_size == size { + Some(self) + } else { + let mask = if size == 256 { + U256::MAX / 2 + } else { + U256::from(2).pow((size - 1).into()) - 1 + }; + + let (sign, abs) = val.into_sign_and_abs(); + if abs < mask { + Some(Concrete::Int(size, val)) + } else { + Some(Concrete::Int( + size, + I256::checked_from_sign_and_abs(sign, mask).unwrap(), + )) + } + } + } + Builtin::Bytes(size) => { + let mask = if size == 32 { + U256::MAX + } else { + U256::from(2).pow((size as u16 * 8).into()) - 1 + }; + let mut h = H256::default(); + (val.into_raw() & mask).to_big_endian(h.as_mut()); + Some(Concrete::Bytes(size, h)) + } + Builtin::Bool => { + if val.abs() > I256::from(0i32) { + Some(Concrete::from(true)) + } else { + Some(Concrete::from(false)) + } + } + _ => None, + }, + Concrete::Bytes(cap, b) => match builtin { + Builtin::Address => Some(Concrete::Address(Address::from_slice(&b[12..]))), + Builtin::Uint(size) => { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + let val = U256::from_big_endian(b.as_bytes()); + Some(Concrete::Uint(size, val & mask)) + } + Builtin::Int(size) => { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + let val = U256::from_big_endian(b.as_bytes()); + Some(Concrete::Int(size, I256::from_raw(val & mask))) + } + Builtin::Bytes(size) => { + let mut h = H256::default(); + (0..size).for_each(|i| h.0[i as usize] = b.0[i as usize]); + Some(Concrete::Bytes(size, h)) + } + Builtin::DynamicBytes => { + let mut bytes = vec![0; cap.into()]; + b.0.into_iter() + .take(cap.into()) + .enumerate() + .for_each(|(i, b)| bytes[i] = b); + Some(Concrete::DynBytes(bytes)) + } + _ => None, + }, + Concrete::Address(a) => match builtin { + Builtin::Address => Some(self), + Builtin::Uint(size) => { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + let val = U256::from_big_endian(a.as_bytes()); + Some(Concrete::Uint(size, val & mask)) + } + Builtin::Int(size) => { + let mask = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(size.into()) - 1 + }; + let val = U256::from_big_endian(a.as_bytes()); + Some(Concrete::Int(size, I256::from_raw(val & mask))) + } + Builtin::Bytes(size) => { + let val = U256::from_big_endian(a.as_bytes()); + let mask = if size == 32 { + U256::MAX + } else { + U256::from(2).pow((size as u16 * 8).into()) - 1 + }; + + let mut h = H256::default(); + (val & mask).to_big_endian(h.as_mut()); + Some(Concrete::Bytes(size, h)) + } + _ => None, + }, + Concrete::String(s) => match builtin { + Builtin::Bytes(size) => { + let as_bytes = s.as_bytes(); + if as_bytes.len() <= size.into() { + let mut h = H256::default(); + as_bytes.iter().enumerate().for_each(|(i, byte)| { + h.0[i] = *byte; + }); + Some(Concrete::Bytes(size, h)) + } else { + None + } + } + Builtin::DynamicBytes => Some(Concrete::DynBytes(s.as_bytes().to_vec())), + _ => None, + }, + Concrete::DynBytes(ref b) => match builtin { + Builtin::Bytes(size) => { + if b.len() <= size.into() { + let mut h = H256::default(); + b.iter().enumerate().for_each(|(i, byte)| { + h.0[i] = *byte; + }); + Some(Concrete::Bytes(size, h)) + } else { + None + } + } + Builtin::DynamicBytes => Some(self), + Builtin::String => todo!(), + _ => None, + }, + Concrete::Bool(ref b) => match builtin { + Builtin::Bool => Some(self), + Builtin::Uint(_) => { + if *b { + Some(Concrete::from(U256::from(1))) + } else { + Some(Concrete::from(U256::zero())) + } + } + Builtin::Int(_) => { + if *b { + Some(Concrete::from(I256::from(1i32))) + } else { + Some(Concrete::from(I256::zero())) + } + } + _ => None, + }, + _ => None, + } + } + + /// Converts a concrete into a [`Builtin`]. + pub fn as_builtin(&self) -> Builtin { + match self { + Concrete::Uint(size, _) => Builtin::Uint(*size), + Concrete::Int(size, _) => Builtin::Int(*size), + Concrete::Bytes(size, _) => Builtin::Bytes(*size), + Concrete::Address(_) => Builtin::Address, + Concrete::Bool(_b) => Builtin::Bool, + Concrete::DynBytes(_) => Builtin::DynamicBytes, + Concrete::String(_) => Builtin::String, + _ => panic!("uncastable to builtin"), + } + } + + /// Converts a concrete into a `U256`. + pub fn into_u256(&self) -> Option { + match self { + Concrete::Uint(_, val) => Some(*val), + Concrete::Int(_, val) => { + if val >= &I256::from(0) { + Some(val.into_raw()) + } else { + None + } + } + Concrete::Bytes(_, b) => Some(U256::from_big_endian(b.as_bytes())), + Concrete::Address(a) => Some(U256::from_big_endian(a.as_bytes())), + Concrete::Bool(b) => { + if *b { + Some(1.into()) + } else { + Some(0.into()) + } + } + _ => None, + } + } + + pub fn max_size(&self) -> Self { + match self { + Concrete::Uint(_, val) => Concrete::Uint(256, *val), + Concrete::Int(_, val) => Concrete::Int(256, *val), + Concrete::Bytes(_, val) => Concrete::Bytes(32, *val), + _ => self.clone(), + } + } + + /// Gets the default max for a given concrete variant. + pub fn max(&self) -> Option { + match self { + Concrete::Uint(size, _) => { + let max = if *size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(*size)) - 1 + }; + Some(Concrete::Uint(*size, max)) + } + Concrete::Int(size, _) => { + let max: I256 = + I256::from_raw((U256::from(1u8) << U256::from(*size - 1)) - U256::from(1)); + Some(Concrete::Int(*size, max)) + } + Concrete::Bytes(size, _) => { + let size = *size as u16 * 8; + let max = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(size)) - 1 + }; + + let mut h = H256::default(); + max.to_big_endian(h.as_mut()); + Some(Concrete::Bytes((size / 8) as u8, h)) + } + Concrete::Address(_) => Some(Concrete::Address(Address::from_slice(&[0xff; 20]))), + Concrete::Bool(_) => Some(Concrete::Bool(true)), + _ => None, + } + } + + pub fn possible_builtins_from_ty_inf(&self) -> Vec { + let mut builtins = vec![]; + match self { + Concrete::Uint(_size, val) => { + let mut min_bits = (256 - val.leading_zeros()) as u16; + let mut s = 256; + while s > min_bits { + builtins.push(Builtin::Uint(s)); + s -= 8; + } + // now ints + min_bits = min_bits.saturating_sub(1); + let mut s = 255; + while s > min_bits { + builtins.push(Builtin::Int(s + 1)); + s = s.saturating_sub(8); + } + } + Concrete::Int(size, val) => { + // if we evaled it as a int, it must be negative + let (abs, is_min) = val.overflowing_abs(); + if is_min { + builtins.push(Builtin::Int(*size)) + } else { + let min_bits = (255 - abs.leading_zeros()) as u16; + let mut s = *size; + while s > min_bits { + builtins.push(Builtin::Int(s)); + s -= 8; + } + } + } + Concrete::Bytes(size, val) => { + let min_bytes: u8 = + val.as_fixed_bytes() + .iter() + .rev() + .enumerate() + .fold(0, |mut acc, (i, v)| { + if v != &0x00u8 { + acc = i as u8; + acc + } else { + acc + } + }); + let mut s = *size; + while s > min_bytes { + builtins.push(Builtin::Bytes(s)); + s -= 1; + } + } + _ => {} + } + builtins + } + + /// Gets the smallest increment for a given type + pub fn one(&self) -> Option { + match self { + Concrete::Uint(size, _) => Some(Concrete::Uint(*size, U256::from(1))), + Concrete::Int(size, _) => Some(Concrete::Int(*size, I256::from(1))), + Concrete::Bytes(size, _) => { + let mut b = [0x00; 32]; + b[0] = 0x01; + Some(Concrete::Bytes(size / 8, H256::from(b))) + } + Concrete::Address(_) => { + let mut b = [0x00; 20]; + b[19] = 0x01; + Some(Concrete::Address(Address::from_slice(&b))) + } + Concrete::Bool(_) => Some(Concrete::Bool(true)), + _ => None, + } + } + + /// Gets the default min for a given concrete variant. + pub fn min(&self) -> Option { + match self { + Concrete::Uint(size, _) => Some(Concrete::Uint(*size, 0.into())), + Concrete::Int(size, _) => { + let max = if size == &256u16 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*size - 1)) - I256::from(1) + }; + + let min = max * I256::from(-1i32) - I256::from(1i32); + Some(Concrete::Int(*size, min)) + } + Concrete::Bytes(size, _) => { + let min = U256::zero(); + let mut h = H256::default(); + min.to_big_endian(h.as_mut()); + Some(Concrete::Bytes(*size, h)) + } + Concrete::Address(_) => Some(Concrete::Address(Address::from_slice(&[0x00; 20]))), + Concrete::Bool(_) => Some(Concrete::Bool(false)), + Concrete::String(_) => Some(Concrete::String("".to_string())), + Concrete::DynBytes(_) => Some(Concrete::DynBytes(vec![])), + Concrete::Array(_) => Some(Concrete::Array(vec![])), + } + } + + /// Gets the size of some concrete type + pub fn int_size(&self) -> Option { + match self { + Concrete::Uint(size, _) => Some(*size), + Concrete::Int(size, _) => Some(*size), + Concrete::Bytes(size, _) => Some(*size as u16), + _ => None, + } + } + + /// If its `Concrete::Uint`, gets the value + pub fn uint_val(&self) -> Option { + match self { + Concrete::Uint(_, val) => Some(*val), + _ => None, + } + } + + /// If its `Concrete::Int`, gets the value + pub fn int_val(&self) -> Option { + match self { + Concrete::Int(_, val) => Some(*val), + _ => None, + } + } + + /// Converts to a string + pub fn as_string(&self) -> String { + match self { + Concrete::Uint(_, val) => val.to_string(), + Concrete::Int(_, val) => val.to_string(), + Concrete::Bytes(size, b) => format!( + "0x{}", + b.0.iter() + .take(*size as usize) + .map(|byte| format!("{byte:02x}")) + .collect::>() + .join("") + ), + Concrete::String(s) => s.to_string(), + Concrete::Bool(b) => b.to_string(), + Concrete::Address(a) => a.to_string(), + Concrete::DynBytes(a) => { + if a.is_empty() { + "0x".to_string() + } else { + hex::encode(a) + } + } + Concrete::Array(arr) => format!( + "[{}]", + arr.iter() + .map(|i| i.as_string()) + .collect::>() + .join(", ") + ), + } + } + + /// Converts to a human readable string. For integers, this means trying to find a + /// power of 2 that is close to the value. + pub fn as_human_string(&self) -> String { + match self { + Concrete::Uint(_, val) => { + let cutoff = U256::from(2).pow(U256::from(32)); + if val < &cutoff { + val.to_string() + } else { + for size in 32..=255 { + let pow2 = U256::from(2).pow(U256::from(size)); + if val < &pow2 { + let diff = pow2 - val; + if diff < cutoff { + return format!("2**{size} - {diff}"); + } + } else if *val == pow2 { + return format!("2**{size}"); + } else { + let diff = val - pow2; + if diff < cutoff { + return format!("2**{size} + {diff}"); + } + } + } + + let pow2 = U256::MAX; + if val < &pow2 { + let diff = pow2 - val; + if diff < cutoff { + return format!("2**{} - {}", 256, diff + 1); + } + } else if *val == pow2 { + return format!("2**{} - 1", 256); + } + + val.to_string() + } + } + Concrete::Int(size, val) => { + let cutoff = I256::from(2).pow(32); + if val < &cutoff && val > &(I256::from(-1i32) * cutoff) { + return val.to_string(); + } + + if val > &I256::from(0) { + let val = val.into_sign_and_abs().1; + Concrete::Uint(*size, val).as_human_string() + } else { + let val = val.into_sign_and_abs().1; + format!("-1 * {}", Concrete::Uint(*size, val).as_human_string()) + } + } + Concrete::Bytes(size, b) => { + format!( + "0x{}", + b.0.iter() + .take(*size as usize) + .map(|byte| format!("{byte:02x}")) + .collect::>() + .join("") + ) + } + Concrete::String(s) => s.to_string(), + Concrete::Bool(b) => b.to_string(), + Concrete::Address(a) => format!("{a:?}"), + Concrete::DynBytes(a) => { + if a.is_empty() { + "0x".to_string() + } else { + hex::encode(a) + } + } + Concrete::Array(arr) => format!( + "[{}]", + arr.iter() + .map(|i| i.as_human_string()) + .collect::>() + .join(", ") + ), + } + } +} diff --git a/crates/graph/nodes/context/context_tys.rs b/crates/graph/nodes/context/context_tys.rs new file mode 100644 index 00000000..7a8557b3 --- /dev/null +++ b/crates/graph/nodes/context/context_tys.rs @@ -0,0 +1,96 @@ + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum CallFork { + Call(ContextNode), + Fork(ContextNode, ContextNode), +} + +impl CallFork { + pub fn maybe_call(&self) -> Option { + match self { + CallFork::Call(c) => Some(*c), + _ => None, + } + } + + pub fn maybe_fork(&self) -> Option<(ContextNode, ContextNode)> { + match self { + CallFork::Fork(w1, w2) => Some((*w1, *w2)), + _ => None, + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum ContextEdge { + // Control flow + Context, + Subcontext, + ContextFork, + ContextMerge, + Call, + + // Context Variables + Variable, + InheritedVariable, + + AttrAccess, + Index, + IndexAccess, + StructAccess, + FuncAccess, + + // Variable incoming edges + Assign, + StorageAssign, + MemoryAssign, + Prev, + + // Control flow + Return, + Continue, + InputVariable, + ReturnAssign(bool), + + // Range analysis + Range, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ModifierState { + pub num: usize, + pub loc: Loc, + pub parent_fn: FunctionNode, + pub parent_caller_ctx: ContextNode, + pub parent_ctx: ContextNode, + pub renamed_inputs: BTreeMap, +} + +impl ModifierState { + pub fn new( + num: usize, + loc: Loc, + parent_fn: FunctionNode, + parent_ctx: ContextNode, + parent_caller_ctx: ContextNode, + renamed_inputs: BTreeMap, + ) -> Self { + Self { + num, + loc, + parent_fn, + parent_ctx, + parent_caller_ctx, + renamed_inputs, + } + } +} + +#[derive(Default, Debug, Clone, Eq, PartialEq)] +pub struct ContextCache { + pub vars: BTreeMap, + pub visible_funcs: Option>, + pub first_ancestor: Option, + pub associated_source: Option, + pub associated_contract: Option, +} \ No newline at end of file diff --git a/crates/graph/nodes/context/expr_ret.rs b/crates/graph/nodes/context/expr_ret.rs new file mode 100644 index 00000000..00640a60 --- /dev/null +++ b/crates/graph/nodes/context/expr_ret.rs @@ -0,0 +1,247 @@ +use crate::analyzer::AsDotStr; +use crate::context::GraphError; +use crate::{ContextVarNode, GraphLike, Node, NodeIdx, VarType}; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum KilledKind { + Ended, + Unreachable, + Revert, + ParseError, +} + +impl KilledKind { + pub fn analysis_str(&self) -> &str { + use KilledKind::*; + match self { + Ended => "Execution ended here successfully", + Unreachable => "Unsatisifiable bounds, therefore dead code", + Revert => "Execution guaranteed to revert here!", + ParseError => "Unexpected parse error. This is likely a bug or invalid solidity. See the `errors` section of the CLI output or rerun with `--debug` for more information", + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum ExprRet { + CtxKilled(KilledKind), + Null, + Single(NodeIdx), + SingleLiteral(NodeIdx), + Multi(Vec), +} + +impl ExprRet { + pub fn debug_str(&self, analyzer: &impl GraphLike) -> String { + match self { + ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => match analyzer.node(*inner) { + Node::ContextVar(_) => ContextVarNode::from(*inner).display_name(analyzer).unwrap(), + e => format!("{:?}", e), + }, + ExprRet::Multi(inner) => { + format!( + "[{}]", + inner + .iter() + .map(|i| i.debug_str(analyzer)) + .collect::>() + .join(", ") + ) + } + ExprRet::CtxKilled(kind) => format!("CtxKilled({:?}", kind), + ExprRet::Null => "".to_string(), + } + } + + pub fn take_one(&mut self) -> Result, GraphError> { + match self { + ExprRet::Single(..) | ExprRet::SingleLiteral(..) => { + let ret = self.clone(); + *self = ExprRet::Multi(vec![]); + Ok(Some(ret)) + } + ExprRet::Multi(ref mut inner) => { + let elem = inner.pop(); + Ok(elem) + } + e => Err(GraphError::ExpectedSingle(format!( + "Expected a single return got: {e:?}" + ))), + } + } + + pub fn literals_list(&self) -> Result, GraphError> { + match self { + ExprRet::SingleLiteral(..) => Ok(vec![true]), + ExprRet::Single(..) => Ok(vec![false]), + ExprRet::Multi(ref inner) => { + let mut list = vec![]; + inner.iter().try_for_each(|i| { + list.extend(i.literals_list()?); + Ok(()) + })?; + Ok(list) + } + e => Err(GraphError::ExpectedSingle(format!( + "Expected a single return got: {e:?}" + ))), + } + } + + pub fn expect_single(&self) -> Result { + match self { + ExprRet::Single(inner) => Ok(*inner), + ExprRet::SingleLiteral(inner) => Ok(*inner), + ExprRet::Multi(inner) if inner.len() == 1 => Ok(inner[0].expect_single()?), + e => Err(GraphError::ExpectedSingle(format!( + "Expected a single return got: {e:?}" + ))), + } + } + + pub fn expect_length(&self, len: usize) -> Result<(), GraphError> { + match self { + ExprRet::Single(_) | ExprRet::SingleLiteral(_) => { + if len == 1 { + Ok(()) + } else { + Err(GraphError::StackLengthMismatch(format!( + "Expected an element with {len} elements, return got: 1 element" + ))) + } + } + ExprRet::Multi(inner) => { + if inner.len() == len { + Ok(()) + } else { + Err(GraphError::StackLengthMismatch(format!( + "Expected an element with {len} elements, return got: {} elements", + inner.len() + ))) + } + } + ExprRet::CtxKilled(..) => Err(GraphError::StackLengthMismatch(format!( + "Expected an element with {len} elements, but context was killed" + ))), + ExprRet::Null if len != 0 => Err(GraphError::StackLengthMismatch(format!( + "Expected an element with {len} elements, return got: 0 elements", + ))), + _ => Ok(()), + } + } + + pub fn is_single(&self) -> bool { + match self { + ExprRet::Single(_inner) => true, + ExprRet::SingleLiteral(_inner) => true, + ExprRet::Multi(inner) => inner.len() == 1, + _ => false, + } + } + + pub fn is_killed(&self) -> bool { + matches!(self, ExprRet::CtxKilled(_)) + } + + pub fn killed_kind(&self) -> Option { + match self { + ExprRet::CtxKilled(k) => Some(*k), + ExprRet::Multi(multis) => multis.iter().find_map(|expr_ret| expr_ret.killed_kind()), + _ => None, + } + } + + pub fn has_fork(&self) -> bool { + false + } + + pub fn has_killed(&self) -> bool { + match self { + ExprRet::CtxKilled(_) => true, + ExprRet::Multi(multis) => multis.iter().any(|expr_ret| expr_ret.has_killed()), + _ => false, + } + } + + pub fn has_literal(&self) -> bool { + match self { + ExprRet::SingleLiteral(..) => true, + ExprRet::Multi(multis) => multis.iter().any(|expr_ret| expr_ret.has_literal()), + _ => false, + } + } + + pub fn expect_multi(self) -> Vec { + match self { + ExprRet::Multi(inner) => inner, + _ => panic!("Expected a multi return got single"), + } + } + + pub fn try_as_func_input_str(&self, analyzer: &impl GraphLike) -> String { + match self { + ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { + let idx = inner; + match VarType::try_from_idx(analyzer, *idx) { + Some(var_ty) => { + if let Ok(ty) = var_ty.unresolved_as_resolved(analyzer) { + format!("({})", ty.as_dot_str(analyzer)) + } else { + "".to_string() + } + } + None => "".to_string(), + } + } + ExprRet::Multi(inner) if !self.has_fork() => { + let mut strs = vec![]; + for ret in inner.iter() { + strs.push(ret.try_as_func_input_str(analyzer).replace(['(', ')'], "")); + } + format!("({})", strs.join(", ")) + } + e => todo!("here: {e:?}"), + } + } + + pub fn as_flat_vec(&self) -> Vec { + let mut idxs = vec![]; + match self { + ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => idxs.push(*idx), + ExprRet::Multi(inner) => { + idxs.extend( + inner + .iter() + .flat_map(|expr| expr.as_flat_vec()) + .collect::>(), + ); + } + _ => {} + } + idxs + } + + pub fn as_vec(&self) -> Vec { + match self { + s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => vec![s.clone()], + ExprRet::Multi(inner) => inner.clone(), + _ => { + vec![] + } + } + } + + pub fn flatten(self) -> Self { + match self { + ExprRet::Single(_) | ExprRet::SingleLiteral(_) => self, + ExprRet::Multi(inner) => { + if inner.len() == 1 { + inner[0].to_owned().flatten() + } else { + ExprRet::Multi(inner.into_iter().map(|i| i.flatten()).collect()) + } + } + _ => self, + } + } +} diff --git a/crates/graph/nodes/context/mod.rs b/crates/graph/nodes/context/mod.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/graph/nodes/context/node.rs b/crates/graph/nodes/context/node.rs new file mode 100644 index 00000000..f49764ce --- /dev/null +++ b/crates/graph/nodes/context/node.rs @@ -0,0 +1,1299 @@ + + + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +/// A wrapper of a node index that corresponds to a [`Context`] +pub struct ContextNode(pub usize); + +impl AsDotStr for ContextNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + format!("Context {{ {} }}", self.path(analyzer)) + } +} + +impl ContextNode { + // pub fn called_functions(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + // self.underlying(analyzer)?.children.iter().filter_map(|child| { + // match child.maybe_call()?.underlying(analyzer) { + // Ok(underlying) => { + // match (underlying.fn_call, underlying.ext_fn_call) { + // (Some(fn_call), _) => Some(Ok(fn_call)), + // (_, Some(ext_fn_call)) => Some(Ok(ext_fn_call)), + // (None, None) => None + // } + // } + // Err(_) => None + // } + // }).collect() + // } + + pub fn join( + &self, + _func: FunctionNode, + _mapping: &BTreeMap, + _analyzer: &mut (impl GraphLike + AnalyzerLike), + ) { + todo!("Joining not supported yet"); + // println!("joining"); + // if let Some(body_ctx) = func.maybe_body_ctx(analyzer) { + // let vars: Vec<_> = body_ctx.vars(analyzer).values().map(|var| var.latest_version(analyzer)).collect(); + // println!("vars: {vars:#?}"); + // let replacements: Vec<(ContextVarNode, ContextVarNode)> = mapping.iter().filter_map(|(input_var, param)| { + // vars.iter().find(|var| var.name(analyzer).unwrap() == param.name(analyzer).unwrap()).map(|var| { + // (*var, *input_var) + // }) + // }).collect(); + + // let mut mapping = BTreeMap::default(); + // replacements.into_iter().for_each(|(var, replacement)| { + // mapping.insert(var, replacement); + // let mut latest = var; + // while let Some(next) = latest.next_version(analyzer) { + // latest = next; + // mapping.insert(latest, replacement); + // } + // }); + + // println!("mapping: {mapping:#?}"); + + // vars.iter().for_each(|var| { + // let mut latest = *var; + // let mut range = latest.range(analyzer).unwrap().unwrap(); + // println!("var: {var:?}, depends on: {:#?}, {range:#?}", var.range_deps(analyzer)); + // range.uncache_range_min(); + // range.uncache_range_max(); + // mapping.iter().for_each(|(to_replace, replacement)| { + // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); + // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); + // }); + // latest.set_range(analyzer, range).unwrap(); + // while let Some(next) = latest.next_version(analyzer) { + // latest = next; + // let mut range = latest.range(analyzer).unwrap().unwrap(); + // range.uncache_range_min(); + // range.uncache_range_max(); + // mapping.iter().for_each(|(to_replace, replacement)| { + // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); + // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); + // }); + // latest.set_range(analyzer, range).unwrap(); + // } + // }); + + // } else { + // // need to process the function + // } + } + + pub fn is_ext_fn(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) + } + + pub fn add_var( + &self, + var: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let name = var.name(analyzer)?; + let vars = &mut self.underlying_mut(analyzer)?.cache.vars; + vars.insert(name, var); + Ok(()) + } + + pub fn first_ancestor( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { + Ok(first_ancestor) + } else if let Some(parent) = self.underlying(analyzer)?.parent_ctx { + let first = parent.first_ancestor(analyzer)?; + self.underlying_mut(analyzer)?.cache.first_ancestor = Some(first); + Ok(first) + } else { + Ok(*self) + } + } + + pub fn total_width( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + self.first_ancestor(analyzer)? + .number_of_live_edges(analyzer) + } + + pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.unchecked) + } + + pub fn set_unchecked( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.unchecked = true; + Ok(()) + } + + pub fn unset_unchecked( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.unchecked = false; + Ok(()) + } + + pub fn push_tmp_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + underlying_mut.tmp_expr.push(Some(expr_ret)); + Ok(()) + } + + pub fn append_tmp_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + match underlying_mut.tmp_expr.pop() { + Some(Some(s @ ExprRet::Single(_))) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(s @ ExprRet::SingleLiteral(_))) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(ExprRet::Multi(ref mut inner))) => { + inner.push(expr_ret); + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(inner.to_vec()))); + } + Some(Some(s @ ExprRet::Null)) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(ExprRet::CtxKilled(kind))) => { + underlying_mut.tmp_expr = vec![Some(ExprRet::CtxKilled(kind))]; + underlying_mut.expr_ret_stack = vec![ExprRet::CtxKilled(kind)]; + } + _ => { + underlying_mut.tmp_expr.push(Some(expr_ret)); + } + } + Ok(()) + } + + pub fn pop_tmp_expr( + &self, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { + Ok(Some(self.maybe_move_expr(expr, loc, analyzer)?)) + } else { + Ok(None) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn push_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + tracing::trace!( + "pushing: {}, existing: {:?}, path: {}", + expr_ret.debug_str(analyzer), + self.underlying(analyzer)? + .expr_ret_stack + .iter() + .map(|i| i.debug_str(analyzer)) + .collect::>(), + self.path(analyzer) + ); + let underlying_mut = self.underlying_mut(analyzer)?; + underlying_mut.expr_ret_stack.push(expr_ret); + Ok(()) + } + + pub fn maybe_move_expr( + &self, + expr: ExprRet, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match expr { + ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( + self.maybe_move_var(var.into(), loc, analyzer)?.into(), + )), + ExprRet::Single(var) => Ok(ExprRet::Single( + self.maybe_move_var(var.into(), loc, analyzer)?.into(), + )), + ExprRet::Multi(inner) => Ok(ExprRet::Multi( + inner + .iter() + .map(|i| self.maybe_move_expr(i.clone(), loc, analyzer)) + .collect::>()?, + )), + e => Ok(e), + } + } + + pub fn maybe_move_var( + &self, + var: ContextVarNode, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(ctx) = var.maybe_ctx(analyzer) { + if ctx != *self { + let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); + new_cvar.loc = Some(loc); + + let new_cvarnode = analyzer.add_node(Node::ContextVar(new_cvar)); + analyzer.add_edge(new_cvarnode, *self, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge( + new_cvarnode, + var.0, + Edge::Context(ContextEdge::InheritedVariable), + ); + Ok(new_cvarnode.into()) + } else { + Ok(var) + } + } else { + Ok(var) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn pop_expr( + &self, + _loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + tracing::trace!("popping var from: {}", self.path(analyzer)); + let underlying_mut = self.underlying_mut(analyzer)?; + + let new: Vec = Vec::with_capacity(5); + + let old = std::mem::replace(&mut underlying_mut.expr_ret_stack, new); + if old.is_empty() { + Ok(None) + } else { + Ok(Some(ExprRet::Multi(old))) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn pop_expr_latest( + &self, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + if let Some(elem) = underlying_mut.expr_ret_stack.pop() { + tracing::trace!( + "popping var {} from: {}", + elem.debug_str(analyzer), + self.path(analyzer) + ); + Ok(Some(self.maybe_move_expr(elem, loc, analyzer)?)) + } else { + Ok(None) + } + } + + pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + self.local_vars(analyzer) + .iter() + .flat_map(|(_name, var)| var.return_assignments(analyzer)) + .collect() + } + + pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + self.local_vars(analyzer) + .iter() + .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) + .collect() + } + + pub fn depth(&self, analyzer: &impl GraphLike) -> usize { + self.underlying(analyzer).unwrap().depth + } + + /// The path of the underlying context + pub fn path(&self, analyzer: &impl GraphLike) -> String { + self.underlying(analyzer).unwrap().path.clone() + } + + /// *All* subcontexts (including subcontexts of subcontexts, recursively) + pub fn subcontexts(&self, analyzer: &impl GraphLike) -> Vec { + let underlying = self.underlying(analyzer).unwrap(); + match underlying.child { + Some(CallFork::Call(c)) => vec![c], + Some(CallFork::Fork(w1, w2)) => vec![w1, w2], + None => vec![], + } + } + + /// Gets the associated contract for the function for the context + pub fn associated_contract( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + Ok(self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer) + .expect("No associated contract for context")) + } + + /// Tries to get the associated function for the context + pub fn maybe_associated_contract( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + Ok(self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer)) + } + + pub fn maybe_associated_source( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + let context = self.underlying(analyzer).unwrap(); + if let Some(src) = context.cache.associated_source { + Some(src) + } else if let Some(parent_ctx) = context.parent_ctx { + let src = parent_ctx.maybe_associated_source(analyzer)?; + self.underlying_mut(analyzer) + .unwrap() + .cache + .associated_source = Some(src); + Some(src) + } else { + let func = self.associated_fn(analyzer).unwrap(); + func.maybe_associated_source(analyzer) + } + } + + pub fn associated_source_unit_part( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(sup) = self + .associated_fn(analyzer)? + .maybe_associated_source_unit_part(analyzer) + { + Ok(sup) + } else { + Err(GraphError::NodeConfusion( + "Expected context to have an associated source but didnt".to_string(), + )) + } + } + + /// Gets visible functions + pub fn visible_modifiers( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())) + }; + if let Some(contract) = self.maybe_associated_contract(analyzer)? { + let mut modifiers = contract.modifiers(analyzer); + // extend with free floating functions + modifiers.extend( + analyzer + .search_children_depth(source, &Edge::Modifier, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>(), + ); + + // extend with inherited functions + let inherited_contracts = analyzer.search_children_exclude_via( + contract.0.into(), + &Edge::InheritedContract, + &[Edge::Func], + ); + modifiers.extend( + inherited_contracts + .into_iter() + .flat_map(|inherited_contract| { + ContractNode::from(inherited_contract).modifiers(analyzer) + }) + .collect::>(), + ); + + let mut mapping: BTreeMap> = BTreeMap::new(); + for modifier in modifiers.iter() { + let entry = mapping.entry(modifier.name(analyzer)?).or_default(); + entry.insert(*modifier); + } + mapping + .into_values() + .map(|modifier_set| { + let as_vec = modifier_set.iter().collect::>(); + + if as_vec.len() > 2 { + println!("{}", as_vec.iter().map(|i| i.name(analyzer).unwrap()).collect::>().join(", ")); + panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") + } else if as_vec.len() == 2 { + as_vec[0].get_overriding(as_vec[1], analyzer) + } else { + Ok(*as_vec[0]) + } + }) + .collect() + } else { + // we are in a free floating function, only look at free floating functions + let Some(source) = self.maybe_associated_source(analyzer) else { + return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())); + }; + Ok(analyzer + .search_children_depth(source, &Edge::Modifier, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>()) + } + } + + /// Gets visible functions + pub fn visible_funcs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + // TODO: filter privates + if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { + return Ok(vis.clone()); + } + if let Some(contract) = self.maybe_associated_contract(analyzer)? { + let mut mapping = contract.linearized_functions(analyzer); + // extend with free floating functions + mapping.extend( + analyzer + .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) + .into_iter() + .filter_map(|i| { + let fn_node = FunctionNode::from(i); + if let Ok(name) = fn_node.name(analyzer) { + if !mapping.contains_key(&name) { + Some((name, fn_node)) + } else { + None + } + } else { + None + } + }) + .collect::>(), + ); + let funcs: Vec<_> = mapping.values().copied().collect(); + self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); + Ok(funcs) + } else { + // we are in a free floating function, only look at free floating functions + let funcs = analyzer + .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>(); + + self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); + Ok(funcs) + } + } + + /// Gets all visible functions + pub fn source_funcs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Vec { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return vec![] + }; + analyzer + .search_children_exclude_via( + source, + &Edge::Func, + &[ + Edge::Context(ContextEdge::Context), + Edge::Context(ContextEdge::Variable), + ], + ) + .into_iter() + .map(FunctionNode::from) + .collect::>() + } + + /// Gets all visible structs + pub fn visible_structs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Vec { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return vec![] + }; + + analyzer + .search_children_exclude_via(source, &Edge::Struct, &[Edge::Func]) + .into_iter() + .map(StructNode::from) + .collect::>() + } + + /// Gets the associated function for the context + pub fn associated_fn(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + if let Some(fn_call) = underlying.fn_call { + Ok(fn_call) + } else if let Some(ext_fn_call) = underlying.ext_fn_call { + Ok(ext_fn_call) + } else { + Ok(underlying.parent_fn) + } + } + + /// Checks whether a function is external to the current context + pub fn is_fn_ext( + &self, + fn_node: FunctionNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match fn_node.maybe_associated_contract(analyzer) { + None => Ok(false), + Some(fn_ctrt) => { + if let Some(self_ctrt) = self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer) + { + Ok(Some(self_ctrt) != Some(fn_ctrt) + && !self_ctrt + .underlying(analyzer)? + .inherits + .iter() + .any(|inherited| *inherited == fn_ctrt)) + } else { + Ok(false) + } + } + } + } + + /// Gets the associated function name for the context + pub fn associated_fn_name(&self, analyzer: &impl GraphLike) -> Result { + self.associated_fn(analyzer)?.name(analyzer) + } + + /// Gets a mutable reference to the underlying context in the graph + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut (impl GraphLike + AnalyzerLike), + ) -> Result<&'a mut Context, GraphError> { + match analyzer.node_mut(*self) { + Node::Context(c) => Ok(c), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Context but it was: {e:?}" + ))), + } + } + + /// Gets an immutable reference to the underlying context in the graph + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Context, GraphError> { + match analyzer.node(*self) { + Node::Context(c) => Ok(c), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Context but it was: {e:?}" + ))), + } + } + + /// Gets a variable by name in the context + pub fn var_by_name(&self, analyzer: &impl GraphLike, name: &str) -> Option { + self.underlying(analyzer) + .unwrap() + .cache + .vars + .get(name) + .copied() + } + + pub fn var_by_name_or_recurse( + &self, + analyzer: &impl GraphLike, + name: &str, + ) -> Result, GraphError> { + if let Some(var) = self.var_by_name(analyzer, name) { + Ok(Some(var)) + } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { + parent.var_by_name_or_recurse(analyzer, name) + } else { + Ok(None) + } + } + + pub fn ancestor_in_fn( + &self, + analyzer: &impl GraphLike, + associated_fn: FunctionNode, + ) -> Result, GraphError> { + if let Some(ret) = self.underlying(analyzer)?.returning_ctx { + if ret.associated_fn(analyzer)? == associated_fn { + return Ok(Some(ret)); + } + } + + if let Some(parent) = self.underlying(analyzer)?.parent_ctx { + if parent.associated_fn(analyzer)? == associated_fn { + Ok(Some(parent)) + } else if let Some(mod_state) = &parent.underlying(analyzer)?.modifier_state { + if mod_state.parent_fn == associated_fn { + Ok(Some(parent)) + } else { + parent.ancestor_in_fn(analyzer, associated_fn) + } + } else { + parent.ancestor_in_fn(analyzer, associated_fn) + } + } else { + Ok(None) + } + } + + /// Gets all variables associated with a context + pub fn vars<'a>(&self, analyzer: &'a impl GraphLike) -> &'a BTreeMap { + &self.underlying(analyzer).unwrap().cache.vars + } + + /// Gets all variables associated with a context + pub fn local_vars<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> &'a BTreeMap { + self.vars(analyzer) + } + + /// Gets the latest version of a variable associated with a context + pub fn latest_var_by_name( + &self, + analyzer: &impl GraphLike, + name: &str, + ) -> Option { + self.var_by_name(analyzer, name) + .map(|var| var.latest_version(analyzer)) + } + + /// Reads the current temporary counter and increments the counter + pub fn new_tmp( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let context = self.underlying_mut(analyzer)?; + let ret = context.tmp_var_ctr; + context.tmp_var_ctr += 1; + Ok(ret) + } + + /// Returns all forks associated with the context + pub fn calls(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let descendents = self.descendents(analyzer)?; + Ok(descendents + .into_iter() + .filter_map(|c| c.maybe_call()) + .collect()) + } + + /// Returns all forks associated with the context + // pub fn forks(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + // todo!() + // let descendents = self.descendents(analyzer)?; + // Ok(descendents.into_iter().filter_map(|c| c.maybe_fork()).collect()) + // } + + // /// Returns all *live* forks associated with the context + // pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + // let forks = self.forks(analyzer)?; + // let mut live = vec![]; + // for fork in forks { + // if !fork.is_ended(analyzer)? { + // live.push(fork); + // } + // } + // Ok(live) + // } + + /// Returns tail contexts associated with the context + pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.live_edges(analyzer)?; + if call_edges.is_empty() && !call.is_ended(analyzer)? { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.live_edges(analyzer)?; + if fork_edges.is_empty() && !w1.is_ended(analyzer)? { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.live_edges(analyzer)?; + if fork_edges.is_empty() && !w2.is_ended(analyzer)? { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.reverted_edges(analyzer)?; + if call_edges.is_empty() && call.is_killed(analyzer)? { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.reverted_edges(analyzer)?; + if fork_edges.is_empty() && w1.is_killed(analyzer)? { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.reverted_edges(analyzer)?; + if fork_edges.is_empty() && w2.is_killed(analyzer)? { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.number_of_live_edges) + // if let Some(child) = self.underlying(analyzer)?.child { + // let mut edges = 0; + // match child { + // CallFork::Call(call) => { + // let call_edges = call.number_of_live_edges(analyzer)?; + // if call_edges == 0 && !call.is_ended(analyzer)? { + // edges += 1; + // } else { + // edges += call_edges; + // } + // } + // CallFork::Fork(w1, w2) => { + // let fork_edges = w1.number_of_live_edges(analyzer)?; + // if fork_edges == 0 && !w1.is_ended(analyzer)? { + // edges += 1; + // } else { + // edges += fork_edges; + // } + + // let fork_edges = w2.number_of_live_edges(analyzer)?; + // if fork_edges == 0 && !w2.is_ended(analyzer)? { + // edges += 1; + // } else { + // edges += fork_edges; + // } + // } + // } + // Ok(edges) + // } else { + // Ok(0) + // } + } + + /// Returns tail contexts associated with the context + pub fn all_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.all_edges(analyzer)?; + if call_edges.is_empty() { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.all_edges(analyzer)?; + if fork_edges.is_empty() { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.all_edges(analyzer)?; + if fork_edges.is_empty() { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut descendents = vec![child]; + match child { + CallFork::Call(c) => descendents.extend(c.descendents(analyzer)?), + CallFork::Fork(w1, w2) => { + descendents.extend(w1.descendents(analyzer)?); + descendents.extend(w2.descendents(analyzer)?); + } + } + Ok(descendents) + } else { + Ok(vec![]) + } + } + + /// Adds a fork to the context + pub fn set_child_fork( + &self, + w1: ContextNode, + w2: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + assert!(matches!(analyzer.node(w1), Node::Context(_))); + assert!(matches!(analyzer.node(w2), Node::Context(_))); + assert!(*self != w1 && *self != w2, "Tried to set child to self"); + let context = self.underlying_mut(analyzer)?; + if !context.set_child_fork(w1, w2) { + let child_str = match context.child { + Some(CallFork::Fork(w1, w2)) => { + format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) + } + Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), + None => unreachable!(), + }; + Err(GraphError::ChildRedefinition(format!( + "This is a bug. Tried to redefine a child context, parent:\n{}, current child:\n{},\nnew child: Fork({}, {})", + self.path(analyzer), + child_str, + w1.path(analyzer), + w2.path(analyzer), + ))) + } else { + Ok(()) + } + } + + /// Adds a child to the context + pub fn set_child_call( + &self, + call: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + assert!(matches!(analyzer.node(call), Node::Context(_))); + assert!(*self != call, "Tried to set child to self"); + let context = self.underlying_mut(analyzer)?; + if !context.set_child_call(call) { + let child_str = match context.child { + Some(CallFork::Fork(w1, w2)) => { + format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) + } + Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), + None => unreachable!(), + }; + tracing::trace!("Error setting child as a call"); + Err(GraphError::ChildRedefinition(format!( + "This is a bug. Tried to redefine a child context, parent: {}, current child: {}, new child: {}", + self.path(analyzer), + child_str, + call.path(analyzer) + ) + )) + } else { + Ok(()) + } + } + + pub fn delete_child( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + match child { + CallFork::Fork(w1, w2) => { + w1.propogate_end(analyzer)?; + w2.propogate_end(analyzer)?; + } + CallFork::Call(c) => { + c.propogate_end(analyzer)?; + } + } + } + let context = self.underlying_mut(analyzer)?; + context.delete_child(); + Ok(()) + } + + /// Kills the context by denoting it as killed. Recurses up the contexts and kills + /// parent contexts if all subcontexts of that context are killed + pub fn kill( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + kill_loc: Loc, + kill_kind: KilledKind, + ) -> Result<(), GraphError> { + tracing::trace!("killing: {}", self.path(analyzer)); + if let Some(child) = self.underlying(analyzer)?.child { + match child { + CallFork::Call(call) => { + if !call.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + call.kill(analyzer, kill_loc, kill_kind)?; + } + CallFork::Fork(w1, w2) => { + if !w1.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + + if !w2.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + + w1.kill(analyzer, kill_loc, kill_kind)?; + w2.kill(analyzer, kill_loc, kill_kind)?; + } + } + } + + let context = self.underlying_mut(analyzer)?; + let parent = context.parent_ctx; + if context.killed.is_none() { + context.killed = Some((kill_loc, kill_kind)); + } + + if let Some(parent_ctx) = parent { + parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; + } + + self.propogate_end(analyzer)?; + + Ok(()) + } + + /// Kills if and only if all subcontexts are killed + pub fn end_if_all_forks_ended( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + kill_loc: Loc, + kill_kind: KilledKind, + ) -> Result<(), GraphError> { + let all_edges = self.all_edges(analyzer)?; + let reverted_edges = self.reverted_edges(analyzer)?; + if reverted_edges.len() == all_edges.len() { + tracing::trace!("killing recursively: {}", self.path(analyzer)); + let context = self.underlying_mut(analyzer)?; + if context.ret.is_empty() { + if context.killed.is_none() { + context.killed = Some((kill_loc, kill_kind)); + } + if let Some(parent_ctx) = context.parent_ctx { + parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; + } + } + } + Ok(()) + } + + /// Gets parent list + pub fn parent_list(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let context = self.underlying(analyzer)?; + let mut parents = vec![]; + if let Some(parent_ctx) = context.parent_ctx { + parents.push(parent_ctx); + parents.extend(parent_ctx.parent_list(analyzer)?); + } + Ok(parents) + } + + pub fn recursive_calls( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + // Ok( + let calls = self.calls(analyzer)?; + Ok(calls + .iter() + .flat_map(|call| { + let mut inner_calls = call.recursive_calls(analyzer).unwrap(); + inner_calls.insert(0, *call); + inner_calls + }) + .collect::>()) + } + + /// Gets the lineage for a context + /// A lineage is of the form `[ancestor N, .. , ancestor0, SELF, call0, .., call N]`. It + /// gives the user a full picture of control flow + pub fn lineage( + &self, + _analyzer: &impl GraphLike, + _entry: bool, + ) -> Result, GraphError> { + todo!() + } + + pub fn terminal_child_list( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let calls = self.calls(analyzer)?; + if calls.is_empty() { + Ok(vec![*self]) + } else { + let mut children = vec![]; + + for child in calls.into_iter() { + children.extend(child.terminal_child_list(analyzer)?) + } + Ok(children) + } + } + + /// Returns whether the context is killed + pub fn is_killed(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.killed.is_some()) + } + + /// Returns whether the context is killed + pub fn is_ended(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) + } + + pub fn killed_or_ret(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + Ok(underlying.killed.is_some() + || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) + } + + /// Returns an option to where the context was killed + pub fn killed_loc( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.killed) + } + + /// Returns a map of variable dependencies for this context + pub fn ctx_deps( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.ctx_deps.clone()) + } + + /// Returns a vector of variable dependencies for this context + pub fn add_ctx_dep( + &self, + dep: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); + if dep.is_symbolic(analyzer)? { + let dep_name = dep.name(analyzer)?; + let underlying = self.underlying_mut(analyzer)?; + underlying.ctx_deps.insert(dep_name, dep); + } + Ok(()) + } + + pub fn add_return_node( + &self, + ret_stmt_loc: Loc, + ret: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.ret.push((ret_stmt_loc, ret)); + self.propogate_end(analyzer)?; + Ok(()) + } + + pub fn propogate_end( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying = &mut self.underlying_mut(analyzer)?; + let curr_live = underlying.number_of_live_edges; + underlying.number_of_live_edges = 0; + if let Some(parent) = self.underlying(analyzer)?.parent_ctx { + let live_edges = &mut parent.underlying_mut(analyzer)?.number_of_live_edges; + *live_edges = live_edges.saturating_sub(1 + curr_live); + parent.propogate_end(analyzer)?; + } + Ok(()) + } + + pub fn return_nodes( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.ret.clone()) + } + + pub fn as_string(&mut self) -> String { + "Context".to_string() + } + + pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { + let deps = self.ctx_deps(g)?; + #[derive(Debug, Copy, Clone)] + pub enum DepEdge { + Lhs, + Rhs, + } + + let mut gr: petgraph::Graph = + petgraph::Graph::default(); + deps.iter().try_for_each(|(_, dep)| { + let mapping = dep.graph_dependent_on(g)?; + mapping.into_iter().for_each(|(k, tmp)| { + let top = gr.add_node(k.into()); + let lhs = gr.add_node(tmp.lhs.into()); + gr.add_edge(top, lhs, DepEdge::Lhs); + if let Some(rhs) = tmp.rhs { + let rhs = gr.add_node(rhs.into()); + gr.add_edge(top, rhs, DepEdge::Rhs); + } + }); + Ok(()) + })?; + + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26";"##; + dot_str.push(raw_start_str.to_string()); + let nodes_and_edges_str = format!( + "{:?}", + Dot::with_attr_getters( + &gr, + &[ + petgraph::dot::Config::GraphContentOnly, + petgraph::dot::Config::NodeNoLabel, + petgraph::dot::Config::EdgeNoLabel + ], + &|_graph, edge_ref| { + let e = edge_ref.weight(); + format!("label = \"{e:?}\"") + }, + &|_graph, (idx, node_ref)| { + let inner = match g.node(*node_ref) { + Node::ContextVar(cvar) => { + let range_str = if let Some(r) = cvar.ty.ref_range(g).unwrap() { + r.as_dot_str(g) + // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) + } else { + "".to_string() + }; + + format!( + "{} -- {} -- range: {}", + cvar.display_name, + cvar.ty.as_string(g).unwrap(), + range_str + ) + } + _ => as_dot_str(idx, g), + }; + format!( + "label = \"{}\", color = \"{}\"", + inner.replace('\"', "\'"), + g.node(*node_ref).dot_str_color() + ) + } + ) + ); + dot_str.push(nodes_and_edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + let dot_str = dot_str.join("\n"); + + println!("{dot_str}"); + use std::env::temp_dir; + use std::fs; + use std::io::Write; + use std::process::Command; + let mut dir = temp_dir(); + let file_name = "dot.dot"; + dir.push(file_name); + + let mut file = fs::File::create(dir.clone()).unwrap(); + file.write_all(dot_str.as_bytes()).unwrap(); + Command::new("dot") + .arg("-Tsvg") + .arg(dir) + .arg("-o") + .arg("dot.svg") + .output() + .expect("failed to execute process"); + Command::new("open") + .arg("dot.svg") + .output() + .expect("failed to execute process"); + Ok(()) + } +} + +impl From for NodeIdx { + fn from(val: ContextNode) -> Self { + val.0.into() + } +} + +impl From for ContextNode { + fn from(idx: NodeIdx) -> Self { + ContextNode(idx.index()) + } +} \ No newline at end of file diff --git a/crates/graph/nodes/context/underlying.rs b/crates/graph/nodes/context/underlying.rs new file mode 100644 index 00000000..37df88d9 --- /dev/null +++ b/crates/graph/nodes/context/underlying.rs @@ -0,0 +1,228 @@ + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Context { + /// The function associated with this context + pub parent_fn: FunctionNode, + /// Whether this function call is actually a modifier call + pub modifier_state: Option, + /// An optional parent context (i.e. this context is a fork or subcontext of another previous context) + pub parent_ctx: Option, + pub returning_ctx: Option, + /// Variables whose bounds are required to be met for this context fork to exist. i.e. a conditional operator + /// like an if statement + pub ctx_deps: BTreeMap, + /// A string that represents the path taken from the root context (i.e. `fn_entry.fork.1`) + pub path: String, + /// Denotes whether this context was killed by an unsatisfiable require, assert, etc. statement + pub killed: Option<(Loc, KilledKind)>, + /// Denotes whether this context is a fork of another context + pub is_fork: bool, + /// Denotes whether this context is the result of a internal function call, and points to the FunctionNode + pub fn_call: Option, + /// Denotes whether this context is the result of a internal function call, and points to the FunctionNode + pub ext_fn_call: Option, + /// The child context. This is either of the form `Call(child_context)` or `Fork(world1, world2)`. Once + /// a child is defined we should *never* evaluate an expression in this context. + pub child: Option, + /// A counter for temporary variables - this lets a context create unique temporary variables + pub tmp_var_ctr: usize, + /// The location in source of the context + pub loc: Loc, + /// The return node and the return location + pub ret: Vec<(Loc, ContextVarNode)>, + /// Depth tracker + pub depth: usize, + /// Width tracker + pub width: usize, + pub tmp_expr: Vec>, + pub expr_ret_stack: Vec, + pub unchecked: bool, + pub number_of_live_edges: usize, + + // caching related things + pub cache: ContextCache, +} + +impl Context { + /// Creates a new context from a function + pub fn new(parent_fn: FunctionNode, fn_name: String, loc: Loc) -> Self { + Context { + parent_fn, + parent_ctx: None, + returning_ctx: None, + path: fn_name, + tmp_var_ctr: 0, + killed: None, + ctx_deps: Default::default(), + is_fork: false, + fn_call: None, + ext_fn_call: None, + child: None, + ret: vec![], + loc, + modifier_state: None, + depth: 0, + width: 0, + expr_ret_stack: Vec::with_capacity(5), + tmp_expr: vec![], + unchecked: false, + number_of_live_edges: 0, + cache: Default::default(), + } + } + + /// Creates a new subcontext from an existing context + pub fn new_subctx( + parent_ctx: ContextNode, + returning_ctx: Option, + loc: Loc, + fork_expr: Option<&str>, + fn_call: Option, + fn_ext: bool, + analyzer: &mut impl AnalyzerLike, + modifier_state: Option, + ) -> Result { + let mut depth = + parent_ctx.underlying(analyzer)?.depth + if fork_expr.is_some() { 0 } else { 1 }; + + let width = + parent_ctx.underlying(analyzer)?.width + if fork_expr.is_some() { 1 } else { 0 }; + + if analyzer.max_depth() < depth { + return Err(GraphError::MaxStackDepthReached(format!( + "Stack depth limit reached: {}", + depth - 1 + ))); + } + + let tw = parent_ctx.total_width(analyzer)?; + if analyzer.max_width() < tw { + return Err(GraphError::MaxStackWidthReached(format!( + "Stack width limit reached: {}", + width - 1 + ))); + } + + let (fn_name, ext_fn_call, fn_call) = if let Some(fn_call) = fn_call { + if fn_ext { + (fn_call.name(analyzer)?, Some(fn_call), None) + } else { + (fn_call.name(analyzer)?, None, Some(fn_call)) + } + } else if let Some(returning_ctx) = returning_ctx { + let fn_node = returning_ctx.associated_fn(analyzer)?; + (fn_node.name(analyzer)?, None, Some(fn_node)) + } else { + ("anonymous_fn_call".to_string(), None, None) + }; + + let path = format!( + "{}.{}", + parent_ctx.underlying(analyzer)?.path, + if let Some(ref fork_expr) = fork_expr { + format!("fork{{ {} }}", fork_expr) + } else if let Some(returning_ctx) = returning_ctx { + depth = depth.saturating_sub(2); + format!( + "resume{{ {} }}", + returning_ctx.associated_fn_name(analyzer)? + ) + } else { + fn_name + } + ); + + let parent_fn = parent_ctx.associated_fn(analyzer)?; + + parent_ctx.underlying_mut(analyzer)?.number_of_live_edges += 1; + + tracing::trace!("new subcontext path: {path}, depth: {depth}"); + Ok(Context { + parent_fn, + parent_ctx: Some(parent_ctx), + returning_ctx, + path, + is_fork: fork_expr.is_some(), + fn_call, + ext_fn_call, + ctx_deps: parent_ctx.underlying(analyzer)?.ctx_deps.clone(), + killed: None, + child: None, + tmp_var_ctr: parent_ctx.underlying(analyzer)?.tmp_var_ctr, + ret: vec![], + loc, + modifier_state, + depth, + width, + expr_ret_stack: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.expr_ret_stack.clone() + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.expr_ret_stack.clone() + } else { + vec![] + }, + tmp_expr: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.tmp_expr.clone() + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.tmp_expr.clone() + } else { + vec![] + }, + unchecked: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.unchecked + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.unchecked + } else { + false + }, + number_of_live_edges: 0, + cache: ContextCache { + vars: Default::default(), + visible_funcs: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone() + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.cache.visible_funcs.clone() + } else { + None + }, + first_ancestor: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.cache.first_ancestor + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.cache.first_ancestor + } else { + None + }, + associated_source: None, + associated_contract: None, + }, + }) + } + + /// Set the child context to a fork + pub fn set_child_fork(&mut self, world1: ContextNode, world2: ContextNode) -> bool { + if self.child.is_some() { + false + } else { + self.child = Some(CallFork::Fork(world1, world2)); + true + } + } + + /// Set the child context to a call + pub fn set_child_call(&mut self, call_ctx: ContextNode) -> bool { + if self.child.is_some() { + false + } else { + self.child = Some(CallFork::Call(call_ctx)); + true + } + } + + pub fn delete_child(&mut self) { + self.child = None; + } + + pub fn as_string(&mut self) -> String { + "Context".to_string() + } +} \ No newline at end of file diff --git a/crates/graph/nodes/contract_ty.rs b/crates/graph/nodes/contract_ty.rs new file mode 100644 index 00000000..e9654238 --- /dev/null +++ b/crates/graph/nodes/contract_ty.rs @@ -0,0 +1,281 @@ +use crate::analyzer::GraphError; +use crate::analyzer::Search; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::AsDotStr; +use crate::Edge; +use crate::FunctionNode; +use crate::Node; +use crate::NodeIdx; +use crate::StructNode; +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::pt::{ContractDefinition, ContractTy, Identifier, Loc}; +use std::collections::BTreeMap; + +/// An index in the graph that references a [`Contract`] node +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct ContractNode(pub usize); + +impl AsDotStr for ContractNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "{} {}", + underlying.ty, + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + }, + ) + } +} + +impl ContractNode { + /// Gets the underlying node data for the [`Contract`] + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Contract, GraphError> { + match analyzer.node(*self) { + Node::Contract(contract) => Ok(contract), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Contract but it was: {e:?}" + ))), + } + } + + pub fn super_contracts(&self, analyzer: &impl GraphLike) -> Vec { + analyzer + .graph() + .edges_directed((*self).into(), Direction::Incoming) + .filter(|edge| edge.weight() == &Edge::InheritedContract) + .map(|edge| ContractNode::from(edge.source())) + .collect() + } + + pub fn inherit(&self, inherits: Vec, analyzer: &mut (impl GraphLike + AnalyzerLike)) { + let src = self.associated_source(analyzer); + let all_contracts = analyzer.search_children_include_via( + src, + &Edge::Contract, + &[ + Edge::Import, + Edge::Part, + Edge::Contract, + Edge::InheritedContract, + ], + ); + // we unwrap the name call because we dont really wanna bubble up thru an iteration + inherits.iter().for_each(|inherited_name| { + let found = all_contracts + .iter() + .find(|contract| { + &ContractNode::from(**contract).name(analyzer).unwrap() == inherited_name + }) + .unwrap_or_else(|| { + panic!( + "Could not find inherited contract: {inherited_name} for contract {:?}", + self.name(analyzer) + ) + }); + analyzer.add_edge(*found, *self, Edge::InheritedContract); + }); + } + + pub fn direct_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { + self.underlying(analyzer).unwrap().inherits.clone() + } + + pub fn all_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { + let mut inherits = self.direct_inherited_contracts(analyzer); + inherits.extend( + inherits + .iter() + .flat_map(|i| i.direct_inherited_contracts(analyzer)) + .collect::>(), + ); + inherits.into_iter().collect::>() + } + + /// Gets the name from the underlying node data for the [`Contract`] + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed contract") + .name) + } + + /// Tries to Get the name from the underlying node data for the [`Contract`] + pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(ident) = self.underlying(analyzer)?.name.clone() { + Ok(Some(ident.name)) + } else { + Ok(None) + } + } + + /// Gets the sourcecode location from the underlying node data for the [`Contract`] + pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.loc) + } + + /// Gets all associated functions from the underlying node data for the [`Contract`] + pub fn funcs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + analyzer + .search_children_depth(self.0.into(), &Edge::Func, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect() + } + + pub fn funcs_mapping( + &self, + analyzer: &(impl GraphLike + Search + AnalyzerLike), + ) -> BTreeMap { + analyzer + .search_children_depth(self.0.into(), &Edge::Func, 1, 0) + .into_iter() + .map(|i| { + let fn_node = FunctionNode::from(i); + (fn_node.name(analyzer).unwrap(), fn_node) + }) + .collect::>() + } + + pub fn linearized_functions( + &self, + analyzer: &(impl GraphLike + Search + AnalyzerLike), + ) -> BTreeMap { + let mut mapping = self.funcs_mapping(analyzer); + self.direct_inherited_contracts(analyzer) + .iter() + .for_each(|inherited| { + inherited + .linearized_functions(analyzer) + .iter() + .for_each(|(name, func)| { + if !mapping.contains_key(name) { + mapping.insert(name.to_string(), *func); + } + }); + }); + mapping + } + + pub fn structs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + analyzer + .search_children_depth(self.0.into(), &Edge::Struct, 1, 0) + .into_iter() + .map(StructNode::from) + .collect() + } + + /// Gets all associated modifiers from the underlying node data for the [`Contract`] + pub fn modifiers(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + analyzer + .search_children_depth(self.0.into(), &Edge::Modifier, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect() + } + + pub fn associated_source_unit_part(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { + analyzer + .search_for_ancestor(self.0.into(), &Edge::Contract) + .expect("detached contract") + } + + pub fn associated_source(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { + let sup = self.associated_source_unit_part(analyzer); + analyzer + .search_for_ancestor(sup, &Edge::Part) + .expect("detached source unit part") + } +} + +impl From for NodeIdx { + fn from(val: ContractNode) -> Self { + val.0.into() + } +} + +impl From for ContractNode { + fn from(idx: NodeIdx) -> Self { + ContractNode(idx.index()) + } +} + +/// A solidity contract representation +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Contract { + /// Sourcecode location + pub loc: Loc, + /// The type of contract + pub ty: ContractTy, + /// An optional name in the form of an identifier (`(Loc, String)`) + pub name: Option, + /// A list of contracts that this contract inherits (TODO: inheritance linearization) + pub inherits: Vec, +} + +impl From for Node { + fn from(val: Contract) -> Self { + Node::Contract(val) + } +} + +impl Contract { + /// Constructs a new contract from a `ContractDefinition` with imports + pub fn from_w_imports( + con: ContractDefinition, + source: NodeIdx, + imports: &[(Option, String, String, usize)], + analyzer: &impl GraphLike, + ) -> (Contract, Vec) { + let mut inherits = vec![]; + let mut unhandled_inherits = vec![]; + con.base.iter().for_each(|base| { + let inherited_name = &base.name.identifiers[0].name; + let mut found = false; + for contract in analyzer + .search_children_exclude_via(source, &Edge::Contract, &[Edge::Func]) + .into_iter() + { + let name = ContractNode::from(contract).name(analyzer).unwrap(); + if &name == inherited_name { + inherits.push(ContractNode::from(contract)); + found = true; + break; + } + } + + if !found { + for entry in imports.iter().filter_map(|import| import.0) { + for contract in analyzer + .search_children_exclude_via(entry, &Edge::Contract, &[Edge::Func]) + .into_iter() + { + let name = ContractNode::from(contract).name(analyzer).unwrap(); + if &name == inherited_name { + inherits.push(ContractNode::from(contract)); + found = true; + break; + } + } + } + } + + if !found { + unhandled_inherits.push(inherited_name.clone()); + } + }); + ( + Contract { + loc: con.loc, + ty: con.ty, + name: con.name, + inherits, + }, + unhandled_inherits, + ) + } +} diff --git a/crates/graph/nodes/enum_ty.rs b/crates/graph/nodes/enum_ty.rs new file mode 100644 index 00000000..eaf55308 --- /dev/null +++ b/crates/graph/nodes/enum_ty.rs @@ -0,0 +1,126 @@ +use crate::analyzer::GraphError; +use crate::analyzer::GraphLike; +use crate::range::SolcRange; +use crate::AsDotStr; +use crate::Concrete; +use crate::Node; +use crate::NodeIdx; +use ethers_core::types::U256; +use solang_parser::pt::{EnumDefinition, Identifier, Loc}; + +/// An index in the graph that references a [`Enum`] node +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct EnumNode(pub usize); + +impl AsDotStr for EnumNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "enum {} {{ {} }}", + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + }, + "..." + ) + } +} + +impl EnumNode { + /// Gets the underlying node data for the [`Enum`] + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Enum, GraphError> { + match analyzer.node(*self) { + Node::Enum(e) => Ok(e), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Contract but it was: {e:?}" + ))), + } + } + + /// Gets the name of the enum from the underlying node data for the [`Enum`] + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed contract") + .name) + } + + pub fn variants(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.variants()) + } + + pub fn maybe_default_range( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let variants = self.variants(analyzer)?; + if !variants.is_empty() { + let min = Concrete::from(variants.first().unwrap().clone()).into(); + let max = Concrete::from(variants.last().unwrap().clone()).into(); + Ok(Some(SolcRange::new(min, max, vec![]))) + } else { + Ok(None) + } + } + + pub fn range_from_variant( + &self, + variant: String, + analyzer: &impl GraphLike, + ) -> Result { + let variants = self.variants(analyzer)?; + assert!(variants.contains(&variant)); + let val = U256::from(variants.iter().position(|v| v == &variant).unwrap()); + let min = Concrete::from(val).into(); + let max = Concrete::from(val).into(); + Ok(SolcRange::new(min, max, vec![])) + } +} + +impl From for NodeIdx { + fn from(val: EnumNode) -> Self { + val.0.into() + } +} + +impl From for EnumNode { + fn from(idx: NodeIdx) -> Self { + EnumNode(idx.index()) + } +} + +/// A solidity enum representation +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Enum { + pub loc: Loc, + pub name: Option, + pub values: Vec>, +} + +impl Enum { + pub fn variants(&self) -> Vec { + self.values + .iter() + .map(|ident| ident.clone().unwrap().name) + .collect() + } +} + +impl From for Node { + fn from(val: Enum) -> Self { + Node::Enum(val) + } +} + +impl From for Enum { + fn from(enu: EnumDefinition) -> Enum { + Enum { + loc: enu.loc, + name: enu.name, + values: enu.values, + } + } +} diff --git a/crates/graph/nodes/err_ty.rs b/crates/graph/nodes/err_ty.rs new file mode 100644 index 00000000..1830035d --- /dev/null +++ b/crates/graph/nodes/err_ty.rs @@ -0,0 +1,105 @@ +use crate::analyzer::GraphError; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::AsDotStr; +use crate::{Node, NodeIdx}; +use solang_parser::pt::{ErrorDefinition, ErrorParameter, Expression, Identifier, Loc}; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct ErrorNode(pub usize); +impl ErrorNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Error, GraphError> { + match analyzer.node(*self) { + Node::Error(err) => Ok(err), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Var but it was: {e:?}" + ))), + } + } +} +impl AsDotStr for ErrorNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "error {}", + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + }, + ) + } +} + +impl From for NodeIdx { + fn from(val: ErrorNode) -> Self { + val.0.into() + } +} + +impl From for ErrorNode { + fn from(idx: NodeIdx) -> Self { + ErrorNode(idx.index()) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Error { + pub loc: Loc, + pub name: Option, +} + +impl From for Node { + fn from(val: Error) -> Self { + Node::Error(val) + } +} + +impl From for Error { + fn from(con: ErrorDefinition) -> Error { + Error { + loc: con.loc, + name: con.name, + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct ErrorParamNode(pub usize); + +impl From for ErrorParamNode { + fn from(idx: NodeIdx) -> Self { + ErrorParamNode(idx.index()) + } +} + +impl From for NodeIdx { + fn from(val: ErrorParamNode) -> Self { + val.0.into() + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ErrorParam { + pub loc: Loc, + pub ty: NodeIdx, + pub name: Option, +} + +impl From for Node { + fn from(val: ErrorParam) -> Self { + Node::ErrorParam(val) + } +} + +impl ErrorParam { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + param: ErrorParameter, + ) -> Self { + ErrorParam { + loc: param.loc, + ty: analyzer.parse_expr(¶m.ty, None), + name: param.name, + } + } +} diff --git a/crates/graph/nodes/func_ty.rs b/crates/graph/nodes/func_ty.rs new file mode 100644 index 00000000..cbcd9f12 --- /dev/null +++ b/crates/graph/nodes/func_ty.rs @@ -0,0 +1,879 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::GraphError; +use crate::analyzer::Search; +use crate::context::{ContextEdge, ContextNode}; +use crate::nodes::ContractNode; +use crate::range::SolcRange; +use crate::Edge; +use crate::VarType; +use crate::{ + analyzer::{AnalyzerLike, GraphLike}, + Node, NodeIdx, +}; +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::helpers::CodeLocation; +use solang_parser::pt::ParameterList; +use solang_parser::pt::Statement; +use solang_parser::pt::Type; +use solang_parser::pt::VariableDefinition; +use solang_parser::pt::{ + Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, + Parameter, StorageLocation, Visibility, +}; +use std::collections::BTreeMap; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct FunctionNode(pub usize); +impl FunctionNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Function, GraphError> { + match analyzer.node(*self) { + Node::Function(func) => Ok(func), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Function but it was: {e:?}" + ))), + } + } + + pub fn body_loc(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(body_stmt) = &self.underlying(analyzer)?.body { + Ok(Some(body_stmt.loc())) + } else { + Ok(None) + } + } + + pub fn definition_loc(&self, analyzer: &impl GraphLike) -> Result { + let underlying = &self.underlying(analyzer)?; + Ok(underlying.loc) + } + + /// Gets an ordered list of modifiers for a given function + pub fn modifiers(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> Vec { + if let Some(mods) = &self.underlying(analyzer).unwrap().cache.modifiers { + mods.values().copied().collect() + } else { + let mods = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter_map(|edge| { + if let Edge::FuncModifier(order) = *edge.weight() { + Some((order, FunctionNode::from(edge.source()))) + } else { + None + } + }) + .collect::>(); + self.underlying_mut(analyzer).unwrap().cache.modifiers = Some(mods.clone()); + mods.values().copied().collect() + } + } + + pub fn modifiers_set(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.modifiers_set) + } + + pub fn modifier_input_vars( + &self, + mod_num: usize, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let modifiers = self.underlying(analyzer)?.modifiers_as_base(); + if let Some(modifier) = modifiers.get(mod_num) { + if let Some(args) = &modifier.args { + Ok(args.to_vec()) + } else { + Ok(vec![]) + } + } else { + Ok(vec![]) + } + } + + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut (impl GraphLike + AnalyzerLike), + ) -> Result<&'a mut Function, GraphError> { + match analyzer.node_mut(*self) { + Node::Function(func) => Ok(func), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Function but it was: {e:?}" + ))), + } + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + match self.underlying(analyzer)?.ty { + FunctionTy::Constructor => Ok(format!( + "constructor({})", + self.params(analyzer) + .iter() + .map(|param| { param.ty_str(analyzer).unwrap() }) + .collect::>() + .join(", ") + )), + FunctionTy::Receive => Ok("receive()".to_string()), + FunctionTy::Fallback => Ok("fallback()".to_string()), + _ => Ok(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed function") + .name), + } + } + + pub fn loc_specified_name( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(con) = self.maybe_associated_contract(analyzer) { + Ok(format!("{}.{}", con.name(analyzer)?, self.name(analyzer)?)) + } else { + self.name(analyzer) + } + } + + pub fn body_ctx(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> ContextNode { + if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { + body_ctx + } else { + let body_ctx = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::Context(ContextEdge::Context) == *edge.weight()) + .map(|edge| ContextNode::from(edge.source())) + .take(1) + .next() + .expect("No context for function"); + + self.underlying_mut(analyzer).unwrap().cache.body_ctx = Some(body_ctx); + body_ctx + } + } + + pub fn maybe_body_ctx( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { + Some(body_ctx) + } else { + let body_ctx = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::Context(ContextEdge::Context) == *edge.weight()) + .map(|edge| ContextNode::from(edge.source())) + .take(1) + .next(); + if let Some(b) = body_ctx { + self.underlying_mut(analyzer).unwrap().cache.body_ctx = Some(b); + } + + body_ctx + } + } + + pub fn maybe_associated_contract( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + if let Some(maybe_contract) = self + .underlying(analyzer) + .unwrap() + .cache + .maybe_associated_contract + { + maybe_contract + } else { + let contract = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| { + matches!( + *edge.weight(), + Edge::Func + | Edge::Modifier + | Edge::Constructor + | Edge::ReceiveFunc + | Edge::FallbackFunc + ) + }) + .filter_map(|edge| { + let node = edge.target(); + match analyzer.node(node) { + Node::Contract(_) => Some(ContractNode::from(node)), + _ => None, + } + }) + .take(1) + .next(); + self.underlying_mut(analyzer) + .unwrap() + .cache + .maybe_associated_contract = Some(contract); + contract + } + } + + pub fn maybe_associated_source_unit_part( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + if let Some(sup) = self + .underlying(analyzer) + .unwrap() + .cache + .associated_source_unit_part + { + Some(sup) + } else { + let parent = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| { + matches!( + *edge.weight(), + Edge::Func + | Edge::Modifier + | Edge::Constructor + | Edge::ReceiveFunc + | Edge::FallbackFunc + ) + }) + .map(|edge| edge.target()) + .take(1) + .next()?; + let sup = match analyzer.node(parent) { + Node::Contract(_) => { + ContractNode::from(parent).associated_source_unit_part(analyzer) + } + Node::SourceUnitPart(..) => parent, + _e => return None, + }; + self.underlying_mut(analyzer) + .unwrap() + .cache + .associated_source_unit_part = Some(sup); + Some(sup) + } + } + + pub fn associated_source(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> NodeIdx { + if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { + src + } else { + let sup = self + .maybe_associated_source_unit_part(analyzer) + .expect("No associated source unit part"); + let src = analyzer + .search_for_ancestor(sup, &Edge::Part) + .expect("detached function"); + self.underlying_mut(analyzer) + .unwrap() + .cache + .associated_source = Some(src); + src + } + } + + pub fn maybe_associated_source( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { + Some(src) + } else { + let sup = self.maybe_associated_source_unit_part(analyzer)?; + let src = analyzer.search_for_ancestor(sup, &Edge::Part)?; + self.underlying_mut(analyzer) + .unwrap() + .cache + .associated_source = Some(src); + Some(src) + } + } + + pub fn params(&self, analyzer: &impl GraphLike) -> Vec { + if let Some(params) = &self.underlying(analyzer).unwrap().cache.params { + params.to_vec() + } else { + let mut params = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::FunctionParam == *edge.weight()) + .map(|edge| FunctionParamNode::from(edge.source())) + .collect::>(); + params.sort_by(|a, b| { + a.underlying(analyzer) + .unwrap() + .order + .cmp(&b.underlying(analyzer).unwrap().order) + }); + params + } + } + + pub fn set_params_and_ret( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying = self.underlying(analyzer)?.clone(); + let mut params_strs = vec![]; + let params = underlying + .params + .into_iter() + .enumerate() + .filter_map(|(i, (_loc, input))| { + if let Some(input) = input { + let param = FunctionParam::new(analyzer, input, i); + let input_node = analyzer.add_node(param); + params_strs.push( + FunctionParamNode::from(input_node) + .ty_str(analyzer) + .unwrap(), + ); + analyzer.add_edge(input_node, *self, Edge::FunctionParam); + Some(input_node.into()) + } else { + None + } + }) + .collect(); + let rets = underlying + .returns + .into_iter() + .filter_map(|(_loc, output)| { + if let Some(output) = output { + let ret = FunctionReturn::new(analyzer, output); + let output_node = analyzer.add_node(ret); + analyzer.add_edge(output_node, *self, Edge::FunctionReturn); + Some(output_node.into()) + } else { + None + } + }) + .collect(); + + let underlying_mut = self.underlying_mut(analyzer)?; + if let Some(ref mut name) = underlying_mut.name { + name.name = format!("{}({})", name.name, params_strs.join(", ")); + } + underlying_mut.cache.params = Some(params); + underlying_mut.cache.returns = Some(rets); + Ok(()) + } + + pub fn returns<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> impl Iterator + 'a { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::FunctionReturn == *edge.weight()) + .map(|edge| FunctionReturnNode::from(edge.source())) + } + + pub fn is_public_or_ext(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.attributes.iter().any(|attr| { + matches!( + attr, + FunctionAttribute::Visibility(Visibility::Public(_)) + | FunctionAttribute::Visibility(Visibility::External(_)) + ) + })) + } + + pub fn get_overriding( + &self, + other: &Self, + analyzer: &impl GraphLike, + ) -> Result { + let self_attrs = &self.underlying(analyzer)?.attributes; + let other_attrs = &other.underlying(analyzer)?.attributes; + let self_virt_over_attr = self_attrs.iter().find(|attr| { + // TODO: grab the override specifier if needed? + matches!( + attr, + FunctionAttribute::Virtual(_) | FunctionAttribute::Override(_, _) + ) + }); + let other_virt_over_attr = other_attrs.iter().find(|attr| { + // TODO: grab the override specifier if needed? + matches!( + attr, + FunctionAttribute::Virtual(_) | FunctionAttribute::Override(_, _) + ) + }); + match (self_virt_over_attr, other_virt_over_attr) { + (Some(FunctionAttribute::Virtual(_)), Some(FunctionAttribute::Virtual(_))) => Ok(*self), + (Some(FunctionAttribute::Virtual(_)), Some(FunctionAttribute::Override(_, _))) => { + Ok(*other) + } + (Some(FunctionAttribute::Override(_, _)), Some(FunctionAttribute::Virtual(_))) => { + Ok(*self) + } + (Some(FunctionAttribute::Override(_, _)), Some(FunctionAttribute::Override(_, _))) => { + Ok(*self) + } + (_, _) => Ok(*self), + } + } +} + +impl AsDotStr for FunctionNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let inputs = self + .params(analyzer) + .iter() + .map(|param_node: &FunctionParamNode| param_node.as_dot_str(analyzer)) + .collect::>() + .join(", "); + + let attrs = self + .underlying(analyzer) + .unwrap() + .attributes + .iter() + .map(|attr| match attr { + FunctionAttribute::Mutability(inner) => format!("{inner}"), + FunctionAttribute::Visibility(inner) => format!("{inner}"), + FunctionAttribute::Virtual(_) => "virtual".to_string(), + FunctionAttribute::Immutable(_) => "immutable".to_string(), + FunctionAttribute::Override(_, _) => "override".to_string(), + _ => "".to_string(), + }) + .collect::>() + .join(" "); + format!( + "{} {}({}) {}", + self.underlying(analyzer).unwrap().ty, + self.name(analyzer).unwrap(), + inputs, + attrs + ) + } +} + +impl From for NodeIdx { + fn from(val: FunctionNode) -> Self { + val.0.into() + } +} + +impl From for FunctionNode { + fn from(idx: NodeIdx) -> Self { + FunctionNode(idx.index()) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Function { + pub loc: Loc, + pub ty: FunctionTy, + pub name: Option, + pub name_loc: Loc, + pub attributes: Vec, + pub body: Option, + pub params: ParameterList, + pub returns: ParameterList, + pub modifiers_set: bool, + pub cache: FunctionCache, +} + +#[derive(Debug, Clone, Eq, PartialEq, Default)] +pub struct FunctionCache { + pub returns: Option>, + pub params: Option>, + pub body_ctx: Option, + pub modifiers: Option>, + pub maybe_associated_contract: Option>, + pub associated_source: Option, + pub associated_source_unit_part: Option, +} + +impl Default for Function { + fn default() -> Self { + Self { + loc: Loc::Implicit, + ty: FunctionTy::Function, + name: None, + name_loc: Loc::Implicit, + attributes: vec![], + body: None, + params: vec![], + returns: vec![], + modifiers_set: false, + cache: Default::default(), + } + } +} + +impl Function { + pub fn modifiers_as_base(&self) -> Vec<&Base> { + self.attributes + .iter() + .filter_map(|attr| match attr { + FunctionAttribute::BaseOrModifier(_, base) => Some(base), + _ => None, + }) + .collect() + } +} + +impl From for Node { + fn from(val: Function) -> Self { + Node::Function(val) + } +} + +impl From for Function { + fn from(func: FunctionDefinition) -> Function { + Function { + loc: func.loc, + ty: func.ty, + name: func.name, + name_loc: func.name_loc, + attributes: func.attributes, + body: func.body, + params: func.params, + returns: func.returns, + modifiers_set: false, + cache: Default::default(), + } + } +} + +pub fn var_def_to_ret(expr: Expression) -> (Loc, Option) { + match expr { + Expression::Type(ty_loc, ref ty) => match ty { + Type::Mapping { value: v_ty, .. } => var_def_to_ret(*v_ty.clone()), + Type::Address + | Type::AddressPayable + | Type::Payable + | Type::Bool + | Type::String + | Type::Int(_) + | Type::Uint(_) + | Type::Bytes(_) + | Type::Rational + | Type::DynamicBytes => ( + ty_loc, + Some(Parameter { + loc: ty_loc, + ty: expr, + storage: None, + name: None, + }), + ), + e => panic!("Unsupported type: {e:?}"), + }, + Expression::ArraySubscript(_loc, sub_expr, _) => { + // its an array, add the index as a parameter + var_def_to_ret(*sub_expr) + } + e => ( + Loc::Implicit, + Some(Parameter { + loc: Loc::Implicit, + ty: e, + storage: None, + name: None, + }), + ), + } +} +pub fn var_def_to_params(expr: Expression) -> Vec<(Loc, Option)> { + let mut params = vec![]; + match expr { + Expression::Type(ty_loc, ref ty) => { + match ty { + Type::Mapping { + loc, + key: key_ty, + value: v_ty, + .. + } => { + params.push(( + ty_loc, + Some(Parameter { + loc: *loc, + ty: *key_ty.clone(), + storage: None, + name: None, + }), + )); + params.extend(var_def_to_params(*v_ty.clone())); + } + Type::Address + | Type::AddressPayable + | Type::Payable + | Type::Bool + | Type::String + | Type::Int(_) + | Type::Uint(_) + | Type::Bytes(_) + | Type::Rational + | Type::DynamicBytes => { + // if !is_recursion { + // params.push((ty_loc, Some(Parameter { + // loc: ty_loc, + // ty: expr, + // storage: None, + // name: None, + // }))); + // } + } + e => panic!("Unsupported type: {e:?}"), + } + } + Expression::ArraySubscript(loc, sub_expr, _) => { + // its an array, add the index as a parameter + params.push(( + loc, + Some(Parameter { + loc, + ty: Expression::Type(loc, Type::Uint(256)), + storage: None, + name: None, + }), + )); + params.extend(var_def_to_params(*sub_expr)); + } + _e => {} + } + + params +} + +impl From for Function { + fn from(var: VariableDefinition) -> Function { + let ret = var_def_to_ret(var.ty.clone()); + Function { + loc: var.loc, + ty: FunctionTy::Function, + name: var.name.clone(), + name_loc: var.loc, + attributes: vec![FunctionAttribute::Visibility(Visibility::Public(Some( + var.loc, + )))], + body: None, + params: var_def_to_params(var.ty), + returns: vec![ret], + modifiers_set: true, + cache: Default::default(), + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct FunctionParamNode(pub usize); + +impl AsDotStr for FunctionParamNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) + .expect("Non-typeable as type"); + format!( + "{}{}{}", + var_ty.as_dot_str(analyzer), + if let Some(stor) = &self.underlying(analyzer).unwrap().storage { + format!(" {stor} ") + } else { + "".to_string() + }, + if let Some(name) = self.maybe_name(analyzer).unwrap() { + name + } else { + "".to_string() + } + ) + } +} + +impl FunctionParamNode { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> Result<&'a FunctionParam, GraphError> { + match analyzer.node(*self) { + Node::FunctionParam(param) => Ok(param), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be FunctionParam but it was: {e:?}" + ))), + } + } + + pub fn name(&self, analyzer: &'_ impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed function parameter") + .name) + } + + pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(ident) = self.underlying(analyzer)?.name.clone() { + Ok(Some(ident.name)) + } else { + Ok(None) + } + } + + pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let ty_node = self.underlying(analyzer)?.ty; + if let Some(var_ty) = VarType::try_from_idx(analyzer, ty_node) { + Ok(var_ty.range(analyzer)?) + } else { + Ok(None) + } + } + + pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.loc) + } + + pub fn ty_str(&self, analyzer: &impl GraphLike) -> Result { + let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer)?.ty).ok_or( + GraphError::NodeConfusion("Non-typeable as type".to_string()), + )?; + Ok(var_ty.as_dot_str(analyzer)) + } + + pub fn ty(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.ty) + } +} + +impl From for NodeIdx { + fn from(val: FunctionParamNode) -> Self { + val.0.into() + } +} + +impl From for FunctionParamNode { + fn from(idx: NodeIdx) -> Self { + FunctionParamNode(idx.index()) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct FunctionParam { + pub loc: Loc, + pub ty: NodeIdx, + pub order: usize, + pub storage: Option, + pub name: Option, +} + +impl From for Node { + fn from(val: FunctionParam) -> Self { + Node::FunctionParam(val) + } +} + +impl FunctionParam { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + param: Parameter, + order: usize, + ) -> Self { + FunctionParam { + loc: param.loc, + ty: analyzer.parse_expr(¶m.ty, None), + order, + storage: param.storage, + name: param.name, + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct FunctionReturnNode(pub usize); + +impl AsDotStr for FunctionReturnNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) + .expect("Non-typeable as type"); + format!( + "{}{}{}", + var_ty.as_dot_str(analyzer), + if let Some(stor) = &self.underlying(analyzer).unwrap().storage { + format!(" {stor} ") + } else { + "".to_string() + }, + if let Some(name) = self.maybe_name(analyzer).unwrap() { + name + } else { + "".to_string() + } + ) + } +} + +impl FunctionReturnNode { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> Result<&'a FunctionReturn, GraphError> { + match analyzer.node(*self) { + Node::FunctionReturn(ret) => Ok(ret), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be FunctionReturn but it was: {e:?}" + ))), + } + } + + pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(ident) = self.underlying(analyzer)?.name.clone() { + Ok(Some(ident.name)) + } else { + Ok(None) + } + } + + pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.loc) + } +} + +impl From for NodeIdx { + fn from(val: FunctionReturnNode) -> Self { + val.0.into() + } +} + +impl From for FunctionReturnNode { + fn from(idx: NodeIdx) -> Self { + FunctionReturnNode(idx.index()) + } +} + +impl From for Node { + fn from(val: FunctionReturn) -> Self { + Node::FunctionReturn(val) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct FunctionReturn { + pub loc: Loc, + pub ty: NodeIdx, + pub storage: Option, + pub name: Option, +} + +impl FunctionReturn { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + param: Parameter, + ) -> Self { + FunctionReturn { + loc: param.loc, + ty: analyzer.parse_expr(¶m.ty, None), + storage: param.storage, + name: param.name, + } + } +} diff --git a/crates/graph/nodes/mod.rs b/crates/graph/nodes/mod.rs new file mode 100644 index 00000000..1f47295b --- /dev/null +++ b/crates/graph/nodes/mod.rs @@ -0,0 +1,35 @@ +mod contract_ty; +pub use contract_ty::*; + +mod enum_ty; +pub use enum_ty::*; + +mod struct_ty; +pub use struct_ty::*; + +mod func_ty; +pub use func_ty::*; + +mod err_ty; +pub use err_ty::*; + +mod var_ty; +pub use var_ty::*; + +mod ty_ty; +pub use ty_ty::*; + +mod concrete; +pub use concrete::*; + +mod msg; +pub use msg::*; + +mod block; +pub use block::*; + +mod builtin; +pub use builtin::*; + +mod context; +pub use context::*; \ No newline at end of file diff --git a/crates/graph/nodes/msg.rs b/crates/graph/nodes/msg.rs new file mode 100644 index 00000000..b7f24095 --- /dev/null +++ b/crates/graph/nodes/msg.rs @@ -0,0 +1,190 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::nodes::GraphError; +use crate::Builtin; +use crate::Concrete; +use crate::ContextNode; +use crate::ContextVar; + +use crate::Node; +use crate::NodeIdx; +use ethers_core::types::Address; +use ethers_core::types::U256; +use solang_parser::pt::Loc; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct MsgNode(pub usize); + +impl MsgNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Msg, GraphError> { + match analyzer.node(*self) { + Node::Msg(st) => Ok(st), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Msg but it was: {e:?}" + ))), + } + } +} + +impl AsDotStr for MsgNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + format!("msg {{ {:?} }}", self.underlying(analyzer).unwrap()) + } +} + +impl From for NodeIdx { + fn from(val: MsgNode) -> Self { + val.0.into() + } +} + +impl From for MsgNode { + fn from(idx: NodeIdx) -> Self { + MsgNode(idx.index()) + } +} + +#[derive(Debug, Clone, Default, Eq, PartialEq)] +pub struct Msg { + pub data: Option>, + pub sender: Option
, + pub sig: Option<[u8; 4]>, + pub value: Option, + pub origin: Option
, + pub gasprice: Option, + pub gaslimit: Option, +} + +impl Msg { + pub fn context_var_from_str( + &self, + elem: &str, + loc: Loc, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let (node, name) = match elem { + "data" => { + if let Some(d) = self.data.clone() { + let c = Concrete::from(d); + (analyzer.add_node(Node::Concrete(c)), "msg.data".to_string()) + } else { + let b = Builtin::DynamicBytes; + let node = analyzer.builtin_or_add(b); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "msg.data".to_string(); + var.display_name = "msg.data".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "sender" => { + if let Some(d) = self.sender { + let c = Concrete::from(d); + ( + analyzer.add_node(Node::Concrete(c)), + "msg.sender".to_string(), + ) + } else { + let node = analyzer.builtin_or_add(Builtin::Address); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "msg.sender".to_string(); + var.display_name = "msg.sender".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "sig" => { + if let Some(d) = self.sig { + let c = Concrete::from(d); + (analyzer.add_node(Node::Concrete(c)), "msg.sig".to_string()) + } else { + let node = analyzer.builtin_or_add(Builtin::Bytes(4)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "msg.sig".to_string(); + var.display_name = "msg.sig".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "value" => { + if let Some(d) = self.value { + let c = Concrete::from(d); + ( + analyzer.add_node(Node::Concrete(c)), + "msg.value".to_string(), + ) + } else { + let node = analyzer.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "msg.value".to_string(); + var.display_name = "msg.value".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "origin" => { + if let Some(d) = self.origin { + let c = Concrete::from(d); + ( + analyzer.add_node(Node::Concrete(c)), + "tx.origin".to_string(), + ) + } else { + let node = analyzer.builtin_or_add(Builtin::Address); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "tx.origin".to_string(); + var.display_name = "tx.origin".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "gasprice" => { + if let Some(d) = self.gasprice { + let c = Concrete::from(d); + ( + analyzer.add_node(Node::Concrete(c)), + "tx.gasprice".to_string(), + ) + } else { + let node = analyzer.builtin_or_add(Builtin::Uint(64)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.name = "tx.gasprice".to_string(); + var.display_name = "tx.gasprice".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + "gaslimit" => { + if let Some(d) = self.gaslimit { + let c = Concrete::from(d); + (analyzer.add_node(Node::Concrete(c)), "".to_string()) + } else { + let node = analyzer.builtin_or_add(Builtin::Uint(64)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; + var.is_tmp = false; + var.is_symbolic = true; + return Ok(var); + } + } + e => { + return Err(GraphError::NodeConfusion(format!( + "Unknown msg attribute: {e:?}" + ))) + } + }; + + let mut var = ContextVar::new_from_concrete(loc, ctx, node.into(), analyzer)?; + var.name = name.clone(); + var.display_name = name; + var.is_tmp = false; + var.is_symbolic = true; + Ok(var) + } +} diff --git a/crates/graph/nodes/struct_ty.rs b/crates/graph/nodes/struct_ty.rs new file mode 100644 index 00000000..2ede9a0f --- /dev/null +++ b/crates/graph/nodes/struct_ty.rs @@ -0,0 +1,199 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::nodes::GraphError; +use crate::Edge; + +use crate::Node; +use crate::NodeIdx; +use crate::VarType; +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableDeclaration}; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct StructNode(pub usize); + +impl StructNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Struct, GraphError> { + match analyzer.node(*self) { + Node::Struct(st) => Ok(st), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Struct but it was: {e:?}" + ))), + } + } + + pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.loc) + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .as_ref() + .expect("Struct wasn't named") + .to_string()) + } + + pub fn fields(&self, analyzer: &impl GraphLike) -> Vec { + let mut fields: Vec<_> = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::Field == *edge.weight()) + .map(|edge| FieldNode::from(edge.source())) + .collect(); + fields.sort_by(|a, b| a.0.cmp(&b.0)); + fields + } + + pub fn find_field(&self, analyzer: &impl GraphLike, ident: &Identifier) -> Option { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::Field == *edge.weight()) + .map(|edge| FieldNode::from(edge.source())) + .find(|field_node| field_node.name(analyzer).unwrap() == ident.name) + } +} + +impl AsDotStr for StructNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "struct {} {{ {} }}", + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + }, + self.fields(analyzer) + .iter() + .map(|field_node| { field_node.as_dot_str(analyzer) }) + .collect::>() + .join("; ") + ) + } +} + +impl From for NodeIdx { + fn from(val: StructNode) -> Self { + val.0.into() + } +} + +impl From for StructNode { + fn from(idx: NodeIdx) -> Self { + StructNode(idx.index()) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Struct { + pub loc: Loc, + pub name: Option, +} + +impl Struct { + pub fn maybe_from_node(node: Node) -> Option { + match node { + Node::Struct(s) => Some(s), + _ => None, + } + } +} + +impl From for Node { + fn from(val: Struct) -> Self { + Node::Struct(val) + } +} + +impl From for Struct { + fn from(con: StructDefinition) -> Struct { + Struct { + loc: con.loc, + name: con.name, + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct FieldNode(pub usize); + +impl FieldNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Field, GraphError> { + match analyzer.node(*self) { + Node::Field(field) => Ok(field), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Field but it was: {e:?}" + ))), + } + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .as_ref() + .expect("Struct wasn't named") + .to_string()) + } +} + +impl AsDotStr for FieldNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "{} {}", + if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { + var_ty.as_dot_str(analyzer) + } else { + "".to_string() + }, + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + } + ) + } +} + +impl From for FieldNode { + fn from(idx: NodeIdx) -> Self { + FieldNode(idx.index()) + } +} + +impl From for NodeIdx { + fn from(val: FieldNode) -> Self { + val.0.into() + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Field { + pub loc: Loc, + pub ty: NodeIdx, + pub name: Option, +} + +impl From for Node { + fn from(val: Field) -> Self { + Node::Field(val) + } +} + +impl Field { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + var_def: VariableDeclaration, + ) -> Field { + let ty_idx = analyzer.parse_expr(&var_def.ty, None); + Field { + loc: var_def.loc, + ty: ty_idx, + name: var_def.name, + } + } +} diff --git a/crates/graph/nodes/ty_ty.rs b/crates/graph/nodes/ty_ty.rs new file mode 100644 index 00000000..83b76527 --- /dev/null +++ b/crates/graph/nodes/ty_ty.rs @@ -0,0 +1,77 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::{AnalyzerLike, GraphLike}; +use crate::nodes::GraphError; +use crate::Node; +use crate::NodeIdx; +use crate::VarType; +use solang_parser::pt::{Expression, Identifier, Loc, TypeDefinition}; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct TyNode(pub usize); +impl TyNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Ty, GraphError> { + match analyzer.node(*self) { + Node::Ty(ty) => Ok(ty), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be TypeNode but it was: {e:?}" + ))), + } + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.name.to_string()) + } +} + +impl From for NodeIdx { + fn from(val: TyNode) -> Self { + val.0.into() + } +} + +impl From for TyNode { + fn from(idx: NodeIdx) -> Self { + TyNode(idx.index()) + } +} + +impl AsDotStr for TyNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "{} {}", + if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { + var_ty.as_dot_str(analyzer) + } else { + "".to_string() + }, + underlying.name.name, + ) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Ty { + pub loc: Loc, + pub ty: NodeIdx, + pub name: Identifier, +} + +impl From for Node { + fn from(val: Ty) -> Self { + Node::Ty(val) + } +} + +impl Ty { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + ty: TypeDefinition, + ) -> Ty { + Ty { + loc: ty.loc, + ty: analyzer.parse_expr(&ty.ty, None), + name: ty.name, + } + } +} diff --git a/crates/graph/nodes/var_ty.rs b/crates/graph/nodes/var_ty.rs new file mode 100644 index 00000000..c15d1285 --- /dev/null +++ b/crates/graph/nodes/var_ty.rs @@ -0,0 +1,236 @@ +use crate::analyzer::Search; +use crate::nodes::GraphError; + +use crate::ContractNode; +use crate::VarType; +use crate::{ + analyzer::{AnalyzerLike, AsDotStr, GraphLike}, + Node, NodeIdx, +}; +use crate::{ContextVar, Edge}; +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::pt::{ + Expression, Identifier, Loc, VariableAttribute, VariableDefinition, Visibility, +}; + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct VarNode(pub usize); + +impl VarNode { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Var, GraphError> { + match analyzer.node(*self) { + Node::Var(func) => Ok(func), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Var but it was: {e:?}" + ))), + } + } + + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut impl GraphLike, + ) -> Result<&'a mut Var, GraphError> { + match analyzer.node_mut(*self) { + Node::Var(func) => Ok(func), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Var but it was: {e:?}" + ))), + } + } + + pub fn parse_initializer( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + parent: NodeIdx, + ) -> Result<(), GraphError> { + if let Some(expr) = self.underlying(analyzer)?.initializer_expr.clone() { + tracing::trace!("Parsing variable initializer"); + let init = analyzer.parse_expr(&expr, Some(parent)); + let underlying = self.underlying(analyzer)?.clone(); + let mut set = false; + if let Some(ty) = VarType::try_from_idx(analyzer, underlying.ty) { + if let Some(initer) = VarType::try_from_idx(analyzer, init) { + if let Some(initer) = initer.try_cast(&ty, analyzer)? { + set = true; + self.underlying_mut(analyzer)?.initializer = Some(initer.ty_idx()); + } + } + } + + if !set { + self.underlying_mut(analyzer)?.initializer = Some(init); + } + } + Ok(()) + } + + pub fn maybe_associated_contract(&self, analyzer: &impl GraphLike) -> Option { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| matches!(*edge.weight(), Edge::Var)) + .filter_map(|edge| { + let node = edge.target(); + match analyzer.node(node) { + Node::Contract(_) => Some(ContractNode::from(node)), + _ => None, + } + }) + .take(1) + .next() + .map(ContractNode::from) + } + + pub fn maybe_associated_source_unit_part(&self, analyzer: &impl GraphLike) -> Option { + if let Some(con) = self.maybe_associated_contract(analyzer) { + Some(con.associated_source_unit_part(analyzer)) + } else { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| matches!(*edge.weight(), Edge::Var)) + .filter_map(|edge| { + let node = edge.target(); + match analyzer.node(node) { + Node::SourceUnitPart(..) => Some(node), + _ => None, + } + }) + .take(1) + .next() + } + } + + pub fn maybe_associated_source(&self, analyzer: &(impl GraphLike + Search)) -> Option { + let sup = self.maybe_associated_source_unit_part(analyzer)?; + analyzer.search_for_ancestor(sup, &Edge::Part) + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed function") + .name) + } + + pub fn const_value( + &self, + loc: Loc, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let attrs = &self.underlying(analyzer)?.attrs; + if attrs + .iter() + .any(|attr| matches!(attr, VariableAttribute::Constant(_))) + { + if let Some(init) = self.underlying(analyzer)?.initializer { + if let Some(ty) = VarType::try_from_idx(analyzer, init) { + return Ok(Some(ContextVar { + loc: Some(loc), + name: self.name(analyzer)?, + display_name: self.name(analyzer)?, + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty, + })); + } + } + } + Ok(None) + } +} + +impl AsDotStr for VarNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "{}{} {}", + if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { + var_ty.as_dot_str(analyzer) + } else { + "".to_string() + }, + underlying + .attrs + .iter() + .map(|attr| { + match attr { + VariableAttribute::Visibility(vis) => format!(" {vis}"), + VariableAttribute::Constant(_) => " constant".to_string(), + VariableAttribute::Immutable(_) => " immutable".to_string(), + VariableAttribute::Override(_, _) => " override".to_string(), + } + }) + .collect::>() + .join(" "), + if let Some(name) = &underlying.name { + name.name.clone() + } else { + "".to_string() + } + ) + } +} + +impl From for NodeIdx { + fn from(val: VarNode) -> Self { + val.0.into() + } +} + +impl From for VarNode { + fn from(idx: NodeIdx) -> Self { + VarNode(idx.index()) + } +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Var { + pub loc: Loc, + pub ty: NodeIdx, + pub attrs: Vec, + pub name: Option, + pub initializer: Option, + pub initializer_expr: Option, + pub in_contract: bool, +} + +impl From for Node { + fn from(val: Var) -> Self { + Node::Var(val) + } +} + +impl Var { + pub fn new( + analyzer: &mut (impl GraphLike + AnalyzerLike), + var: VariableDefinition, + in_contract: bool, + ) -> Var { + tracing::trace!("Parsing Var type"); + let ty = analyzer.parse_expr(&var.ty, None); + Var { + loc: var.loc, + ty, + attrs: var.attrs, + name: var.name, + initializer: None, + initializer_expr: var.initializer, + in_contract, + } + } + + pub fn is_public(&self) -> bool { + self.attrs.iter().any(|var_attr| { + matches!( + var_attr, + VariableAttribute::Visibility(Visibility::Public(_)) + ) + }) + } +} diff --git a/crates/graph/search.rs b/crates/graph/search.rs new file mode 100644 index 00000000..1f860aa9 --- /dev/null +++ b/crates/graph/search.rs @@ -0,0 +1,267 @@ + +impl Search for T where T: GraphLike {} + + +/// A trait for searching through a graph +pub trait Search: GraphLike { + /// Given a start node, search for an ancestor via an edge type + fn search_for_ancestor(&self, start: NodeIdx, edge_ty: &Edge) -> Option { + let edges = self.graph().edges_directed(start, Direction::Outgoing); + if let Some(edge) = edges.clone().find(|edge| edge.weight() == edge_ty) { + Some(edge.target()) + } else { + edges + .map(|edge| edge.target()) + .filter_map(|node| self.search_for_ancestor(node, edge_ty)) + .take(1) + .next() + } + } + + /// Given a start node, search for an ancestor via a set of edge types + fn search_for_ancestor_multi(&self, start: NodeIdx, edge_tys: &[Edge]) -> Option { + let edges = self.graph().edges_directed(start, Direction::Outgoing); + if let Some(edge) = edges.clone().find(|edge| edge_tys.contains(edge.weight())) { + Some(edge.target()) + } else { + edges + .map(|edge| edge.target()) + .filter_map(|node| self.search_for_ancestor_multi(node, edge_tys)) + .take(1) + .next() + } + } + /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a set of these + /// + /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d + /// + /// This function would build a set { b, d } if we are looking for `my_edge` and start at a. + fn search_children(&self, start: NodeIdx, edge_ty: &Edge) -> BTreeSet { + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .flat_map(|edge| self.search_children(edge.source(), edge_ty)) + .collect::>(), + ); + this_children + } + + fn find_child_exclude_via( + &self, + start: NodeIdx, + edge_ty: &Edge, + exclude_edges: &[Edge], + find_fn: &impl Fn(NodeIdx, &Self) -> Option, + ) -> Option { + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|edge| !exclude_edges.contains(edge.weight())); + if let Some(node) = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .find(|node| find_fn(*node, self).is_some()) + { + Some(node) + } else { + edges + .clone() + .map(|edge| edge.source()) + .find_map(|node| self.find_child_exclude_via(node, edge_ty, exclude_edges, find_fn)) + } + } + + fn search_children_exclude_via( + &self, + start: NodeIdx, + edge_ty: &Edge, + exclude_edges: &[Edge], + ) -> BTreeSet { + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|edge| !exclude_edges.contains(edge.weight())); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .flat_map(|edge| { + self.search_children_exclude_via(edge.source(), edge_ty, exclude_edges) + }) + .collect::>(), + ); + this_children + } + + fn search_children_include_via( + &self, + start: NodeIdx, + edge_ty: &Edge, + include_edges: &[Edge], + ) -> BTreeSet { + let mut edges: Vec<_> = self + .graph() + .edges_directed(start, Direction::Incoming) + .collect(); + edges = edges + .into_iter() + .filter(|edge| include_edges.contains(edge.weight())) + .collect::>(); + let mut this_children: BTreeSet = edges + .iter() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .clone() + .iter() + .flat_map(|edge| { + self.search_children_include_via(edge.source(), edge_ty, include_edges) + }) + .collect::>(), + ); + this_children + } + + fn search_children_depth( + &self, + start: NodeIdx, + edge_ty: &Edge, + max_depth: usize, + curr_depth: usize, + ) -> BTreeSet { + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + if curr_depth < max_depth { + this_children.extend( + edges + .flat_map(|edge| { + self.search_children_depth( + edge.source(), + edge_ty, + max_depth, + curr_depth + 1, + ) + }) + .collect::>(), + ); + } + this_children + } + + /// Gets all children recursively + fn children(&self, start: NodeIdx) -> BTreeSet { + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = + edges.clone().map(|edge| edge.source()).collect(); + + this_children.extend( + edges + .flat_map(|edge| self.children(edge.source())) + .collect::>(), + ); + this_children + } + + /// Gets all children edges recursively + fn children_edges( + &self, + start: NodeIdx, + ) -> BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> { + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children_edges: BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> = edges + .clone() + .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) + .collect(); + + this_children_edges.extend( + edges + .flat_map(|edge| self.children_edges(edge.source())) + .collect::)>>(), + ); + this_children_edges + } + + /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a mapping of these + /// + /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d + /// + /// This function would build a map { a: [b], c: [d] } if we are looking for `my_edge` and start at a. + fn nodes_with_children( + &self, + start: NodeIdx, + edge_ty: &Edge, + ) -> Option>> { + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut map: BTreeMap> = Default::default(); + + let this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + if !this_children.is_empty() { + map.insert(start, this_children); + } + map.extend( + edges + .filter_map(|edge| self.nodes_with_children(edge.source(), edge_ty)) + .flatten() + .collect::>>(), + ); + if map.is_empty() { + None + } else { + Some(map) + } + } +} \ No newline at end of file diff --git a/crates/graph/var_type.rs b/crates/graph/var_type.rs new file mode 100644 index 00000000..4c1fb701 --- /dev/null +++ b/crates/graph/var_type.rs @@ -0,0 +1,771 @@ + + + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum VarType { + User(TypeNode, Option), + BuiltIn(BuiltInNode, Option), + Concrete(ConcreteNode), +} + +impl AsDotStr for VarType { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + self.as_string(analyzer).unwrap() + } +} + +impl VarType { + pub fn set_range(&mut self, new_range: SolcRange) -> Result<(), GraphError> { + match self { + VarType::User(TypeNode::Enum(_), ref mut r) + | VarType::User(TypeNode::Contract(_), ref mut r) + | VarType::User(TypeNode::Ty(_), ref mut r) + | VarType::BuiltIn(_, ref mut r) => { + *r = Some(new_range); + Ok(()) + } + _ => Err(GraphError::NodeConfusion( + "This type cannot have a range".to_string(), + )), + } + } + + pub fn possible_builtins_from_ty_inf(&self, analyzer: &impl GraphLike) -> Vec { + match self { + Self::BuiltIn(bn, _) => bn + .underlying(analyzer) + .unwrap() + .possible_builtins_from_ty_inf(), + Self::Concrete(c) => c + .underlying(analyzer) + .unwrap() + .possible_builtins_from_ty_inf(), + _ => vec![], + } + } + + pub fn ty_idx(&self) -> NodeIdx { + match self { + Self::User(ty_node, _) => (*ty_node).into(), + Self::BuiltIn(bn, _) => (*bn).into(), + Self::Concrete(c) => (*c).into(), + } + } + + pub fn is_dyn_builtin(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::BuiltIn(node, _) => node.is_dyn(analyzer), + _ => Ok(false), + } + } + + pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { + match self { + VarType::User(TypeNode::Unresolved(n), _) => match analyzer.node(*n) { + Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( + "Expected the type \"{}\" to be resolved by now", + ident.name + ))), + _ => { + if let Some(ty) = VarType::try_from_idx(analyzer, *n) { + Ok(ty) + } else { + Err(GraphError::NodeConfusion( + "Tried to type a non-typeable element".to_string(), + )) + } + } + }, + _ => Ok(self.clone()), + } + } + + pub fn concrete_to_builtin( + &mut self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + if let VarType::Concrete(cnode) = self { + let c = cnode.underlying(analyzer)?.clone(); + match c { + crate::Concrete::Uint(ref size, _) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::Uint(*size))), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::Int(ref size, _) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::Int(*size))), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::Bool(_) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bool)), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::Address(_) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::Address)), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::Bytes(ref s, _) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bytes(*s))), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::String(_) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::String)), + SolcRange::from(c), + ); + *self = new_ty; + } + crate::Concrete::DynBytes(_) => { + let new_ty = VarType::BuiltIn( + BuiltInNode::from(analyzer.builtin_or_add(Builtin::DynamicBytes)), + SolcRange::from(c), + ); + *self = new_ty; + } + // Concrete::Array(Vec), + _ => {} + } + } + Ok(()) + } + + pub fn try_from_idx(analyzer: &impl GraphLike, node: NodeIdx) -> Option { + // get node, check if typeable and convert idx into vartype + match analyzer.node(node) { + Node::VarType(a) => Some(a.clone()), + Node::Builtin(b) => Some(VarType::BuiltIn( + node.into(), + SolcRange::try_from_builtin(b), + )), + Node::Contract(_) => Some(VarType::User( + TypeNode::Contract(node.into()), + SolcRange::try_from_builtin(&Builtin::Address), + )), + Node::Function(_) => Some(VarType::User(TypeNode::Func(node.into()), None)), + Node::Struct(_) => Some(VarType::User(TypeNode::Struct(node.into()), None)), + Node::Enum(enu) => { + let variants = enu.variants(); + let range = if !variants.is_empty() { + let min = Concrete::from(U256::zero()).into(); + let max = Concrete::from(U256::from(variants.len() - 1)).into(); + Some(SolcRange::new(min, max, vec![])) + } else { + None + }; + Some(VarType::User(TypeNode::Enum(node.into()), range)) + } + Node::Unresolved(_n) => Some(VarType::User(TypeNode::Unresolved(node), None)), + Node::Concrete(_) => Some(VarType::Concrete(node.into())), + Node::ContextVar(cvar) => Some(cvar.ty.clone()), + Node::Var(var) => VarType::try_from_idx(analyzer, var.ty), + Node::Ty(ty) => { + let range = SolcRange::try_from_builtin( + BuiltInNode::from(ty.ty).underlying(analyzer).unwrap(), + )?; + Some(VarType::User(TypeNode::Ty(node.into()), Some(range))) + } + Node::FunctionParam(inner) => VarType::try_from_idx(analyzer, inner.ty), + Node::Error(..) + | Node::ContextFork + | Node::FunctionCall + | Node::FunctionReturn(..) + | Node::ErrorParam(..) + | Node::Field(..) + | Node::SourceUnitPart(..) + | Node::SourceUnit(..) + | Node::Entry + | Node::Context(..) + | Node::Msg(_) + | Node::Block(_) => None, + } + } + + pub fn requires_input(&self, analyzer: &impl GraphLike) -> Result { + match self { + VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.requires_input()), + _ => Ok(false), + } + } + + pub fn try_cast( + self, + other: &Self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + match (self, other) { + (l, Self::User(TypeNode::Ty(ty), o_r)) => { + let t = Self::BuiltIn(BuiltInNode::from(ty.underlying(analyzer)?.ty), o_r.clone()); + l.try_cast(&t, analyzer) + } + (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Contract(cn), _)) => { + match from_bn.underlying(analyzer)? { + Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { + Ok(Some(Self::User(TypeNode::Contract(*cn), sr))) + } + _ => Ok(None), + } + } + (Self::User(TypeNode::Contract(_cn), sr), Self::BuiltIn(to_bn, _)) => { + match to_bn.underlying(analyzer)? { + Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { + Ok(Some(Self::BuiltIn(*to_bn, sr))) + } + _ => Ok(None), + } + } + (Self::BuiltIn(from_bn, sr), Self::BuiltIn(to_bn, _)) => { + if from_bn.implicitly_castable_to(to_bn, analyzer)? { + Ok(Some(Self::BuiltIn(*to_bn, sr))) + } else { + Ok(None) + } + } + (Self::Concrete(from_c), Self::BuiltIn(to_bn, _)) => { + let c = from_c.underlying(analyzer)?.clone(); + let b = to_bn.underlying(analyzer)?; + if let Some(casted) = c.cast(b.clone()) { + let node = analyzer.add_node(Node::Concrete(casted)); + Ok(Some(Self::Concrete(node.into()))) + } else { + Ok(None) + } + } + (Self::Concrete(from_c), Self::Concrete(to_c)) => { + let c = from_c.underlying(analyzer)?.clone(); + let to_c = to_c.underlying(analyzer)?; + if let Some(casted) = c.cast_from(to_c) { + let node = analyzer.add_node(Node::Concrete(casted)); + Ok(Some(Self::Concrete(node.into()))) + } else { + Ok(None) + } + } + _ => Ok(None), + } + } + + pub fn try_literal_cast( + self, + other: &Self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + match (self, other) { + (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Ty(ty), _)) => { + if ty.underlying(analyzer)?.ty == from_bn.into() { + Ok(Some(Self::User(TypeNode::Ty(*ty), sr))) + } else { + Ok(None) + } + } + (Self::Concrete(from_c), Self::User(TypeNode::Ty(ty), _)) => { + let concrete_underlying = from_c.underlying(analyzer)?.clone(); + let as_bn = analyzer.builtin_or_add(concrete_underlying.as_builtin()); + if ty.underlying(analyzer)?.ty == as_bn { + Ok(Some(Self::User( + TypeNode::Ty(*ty), + SolcRange::from(concrete_underlying), + ))) + } else { + Ok(None) + } + } + (Self::BuiltIn(from_bn, sr), Self::BuiltIn(to_bn, _)) => { + if from_bn.implicitly_castable_to(to_bn, analyzer)? { + Ok(Some(Self::BuiltIn(*to_bn, sr))) + } else { + Ok(None) + } + } + (Self::Concrete(from_c), Self::BuiltIn(to_bn, _)) => { + let c = from_c.underlying(analyzer)?.clone(); + let b = to_bn.underlying(analyzer)?; + if let Some(casted) = c.literal_cast(b.clone()) { + let node = analyzer.add_node(Node::Concrete(casted)); + Ok(Some(Self::Concrete(node.into()))) + } else { + Ok(None) + } + } + (Self::Concrete(from_c), Self::Concrete(to_c)) => { + let c = from_c.underlying(analyzer)?.clone(); + let to_c = to_c.underlying(analyzer)?; + if let Some(casted) = c.literal_cast_from(to_c) { + let node = analyzer.add_node(Node::Concrete(casted)); + Ok(Some(Self::Concrete(node.into()))) + } else { + Ok(None) + } + } + _ => Ok(None), + } + } + + pub fn implicitly_castable_to( + &self, + other: &Self, + analyzer: &impl GraphLike, + ) -> Result { + match (self, other) { + (Self::BuiltIn(from_bn, _), Self::BuiltIn(to_bn, _)) => { + from_bn.implicitly_castable_to(to_bn, analyzer) + } + (Self::Concrete(from_c), Self::BuiltIn(_to_bn, _)) => { + todo!("here, {from_c:?}") + } + _ => Ok(false), + } + } + + pub fn max_size( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match self { + Self::BuiltIn(from_bn, _r) => { + let bn = from_bn.max_size(analyzer)?; + Ok(Self::BuiltIn( + bn, + SolcRange::try_from_builtin(bn.underlying(analyzer)?), + )) + } + Self::Concrete(from_c) => Ok(Self::Concrete(from_c.max_size(analyzer)?)), + _ => Ok(self.clone()), + } + } + + pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + match self { + Self::User(_, Some(range)) => Ok(Some(range.clone())), + Self::BuiltIn(_, Some(range)) => Ok(Some(range.clone())), + Self::BuiltIn(bn, None) => Ok(SolcRange::try_from_builtin(bn.underlying(analyzer)?)), + Self::Concrete(cnode) => Ok(SolcRange::from(cnode.underlying(analyzer)?.clone())), + _ => Ok(None), + } + } + + pub fn ref_range( + &self, + analyzer: &impl GraphLike, + ) -> Result>, GraphError> { + match self { + Self::User(_, Some(range)) => Ok(Some(std::borrow::Cow::Borrowed(range))), + Self::BuiltIn(_, Some(range)) => Ok(Some(std::borrow::Cow::Borrowed(range))), + Self::BuiltIn(bn, None) => { + if let Some(r) = SolcRange::try_from_builtin(bn.underlying(analyzer)?) { + Ok(Some(std::borrow::Cow::Owned(r))) + } else { + Ok(None) + } + } + Self::Concrete(cnode) => { + if let Some(r) = SolcRange::from(cnode.underlying(analyzer)?.clone()) { + Ok(Some(std::borrow::Cow::Owned(r))) + } else { + Ok(None) + } + } + _ => Ok(None), + } + } + + pub fn delete_range_result( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + match self { + Self::User(TypeNode::Contract(_), _) => { + let zero = Concrete::Address(Address::from_slice(&[0x00; 20])); + Ok(Some(SolcRange::new( + zero.clone().into(), + zero.into(), + vec![], + ))) + } + Self::User(TypeNode::Enum(enum_node), _) => { + if let Some(first) = enum_node.variants(analyzer)?.first() { + let zero = Concrete::from(first.clone()); + Ok(Some(SolcRange::new( + zero.clone().into(), + zero.into(), + vec![], + ))) + } else { + Ok(None) + } + } + Self::User(TypeNode::Ty(ty), _) => { + BuiltInNode::from(ty.underlying(analyzer)?.ty).zero_range(analyzer) + } + Self::BuiltIn(bn, None) => bn.zero_range(analyzer), + Self::Concrete(cnode) => Ok(cnode.underlying(analyzer)?.as_builtin().zero_range()), + _ => Ok(None), + } + } + + pub fn default_range( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + match self { + Self::User(TypeNode::Contract(_), _) => { + Ok(SolcRange::try_from_builtin(&Builtin::Address)) + } + Self::User(TypeNode::Enum(enu), _) => enu.maybe_default_range(analyzer), + Self::User(TypeNode::Ty(ty), _) => Ok(SolcRange::try_from_builtin( + BuiltInNode::from(ty.underlying(analyzer)?.ty).underlying(analyzer)?, + )), + Self::BuiltIn(bn, _) => Ok(SolcRange::try_from_builtin(bn.underlying(analyzer)?)), + Self::Concrete(cnode) => Ok(SolcRange::from(cnode.underlying(analyzer)?.clone())), + _ => Ok(None), + } + } + + pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::Concrete(_) => Ok(true), + Self::User(TypeNode::Func(_), _) => Ok(false), + _ => { + if let Some(range) = self.ref_range(analyzer)? { + let min = range.evaled_range_min(analyzer)?; + let max = range.evaled_range_max(analyzer)?; + Ok(min.range_eq(&max)) + } else { + Ok(false) + } + } + } + } + + pub fn func_node(&self, _analyzer: &impl GraphLike) -> Option { + match self { + Self::User(TypeNode::Func(func_node), _) => Some(*func_node), + _ => None, + } + } + + pub fn evaled_range( + &self, + analyzer: &impl GraphLike, + ) -> Result, Elem)>, GraphError> { + Ok(self.ref_range(analyzer)?.map(|range| { + ( + range.evaled_range_min(analyzer).unwrap(), + range.evaled_range_max(analyzer).unwrap(), + ) + })) + } + + pub fn try_match_index_dynamic_ty( + &self, + index: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + match self { + Self::BuiltIn(_node, None) => Ok(None), + Self::BuiltIn(node, Some(r)) => { + if let Builtin::Bytes(size) = node.underlying(analyzer)? { + if r.is_const(analyzer)? && index.is_const(analyzer)? { + let Some(min) = r.evaled_range_min(analyzer)?.maybe_concrete() else { + return Ok(None); + }; + let Concrete::Bytes(_, val) = min.val else { + return Ok(None); + }; + let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() else { + return Ok(None) + }; + let Concrete::Uint(_, idx) = idx.val else { + return Ok(None); + }; + if idx.low_u32() < (*size as u32) { + let mut h = H256::default(); + h.0[0] = val.0[idx.low_u32() as usize]; + let ret_val = Concrete::Bytes(1, h); + let node = analyzer.add_node(Node::Concrete(ret_val)); + return Ok(Some(node)); + } + } + Ok(None) + } else { + // check if the index exists as a key + let min = r.range_min(); + if let Some(map) = min.dyn_map() { + let name = index.name(analyzer)?; + let is_const = index.is_const(analyzer)?; + if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { + Elem::Dynamic(Dynamic { idx, .. }) => match analyzer.node(*idx) { + Node::ContextVar(_) => { + let cvar = ContextVarNode::from(*idx); + cvar.name(analyzer).unwrap() == name + } + _ => false, + }, + c @ Elem::Concrete(..) if is_const => { + let index_val = index.evaled_range_min(analyzer).unwrap().unwrap(); + index_val.range_eq(c) + } + _ => false, + }) { + if let Some(idx) = val.node_idx() { + return Ok(idx.into()); + } else if let Some(c) = val.concrete() { + let cnode = analyzer.add_node(Node::Concrete(c)); + return Ok(cnode.into()); + } + } + } + Ok(None) + } + } + Self::Concrete(node) => { + if index.is_const(analyzer)? { + let idx = index + .evaled_range_min(analyzer) + .unwrap() + .unwrap() + .concrete() + .unwrap() + .uint_val() + .unwrap(); + match node.underlying(analyzer)? { + Concrete::Bytes(size, val) => { + if idx.low_u32() < (*size as u32) { + let mut h = H256::default(); + h.0[0] = val.0[idx.low_u32() as usize]; + let ret_val = Concrete::Bytes(1, h); + let node = analyzer.add_node(Node::Concrete(ret_val)); + return Ok(Some(node)); + } + } + Concrete::DynBytes(elems) => { + if idx.low_u32() < (elems.len() as u32) { + let mut h = H256::default(); + h.0[0] = elems[idx.low_u32() as usize]; + let ret_val = Concrete::Bytes(1, h); + let node = analyzer.add_node(Node::Concrete(ret_val)); + return Ok(Some(node)); + } + } + Concrete::String(st) => { + if idx.low_u32() < (st.len() as u32) { + let mut h = H256::default(); + h.0[0] = st.as_bytes()[idx.low_u32() as usize]; + let ret_val = Concrete::Bytes(1, h); + let node = analyzer.add_node(Node::Concrete(ret_val)); + return Ok(Some(node)); + } + } + Concrete::Array(elems) => { + if idx.low_u32() < (elems.len() as u32) { + let elem = &elems[idx.low_u32() as usize]; + let node = analyzer.add_node(Node::Concrete(elem.clone())); + return Ok(Some(node)); + } + } + _ => {} + } + } + Ok(None) + } + _ => Ok(None), + } + } + + pub fn get_index_dynamic_ty( + &self, + index: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { + Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) + } else { + match self { + Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), + Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Builtin but it was: {e:?}" + ))), + } + } + } + + pub fn dynamic_underlying_ty( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match self { + Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), + Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Builtin but it was: {e:?}" + ))), + } + } + + pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::BuiltIn(node, _) => Ok(node.is_mapping(analyzer)?), + _ => Ok(false), + } + } + + pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::BuiltIn(node, _) => node.is_sized_array(analyzer), + Self::Concrete(node) => node.is_sized_array(analyzer), + _ => Ok(false), + } + } + + pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + match self { + Self::BuiltIn(node, _) => node.maybe_array_size(analyzer), + Self::Concrete(node) => node.maybe_array_size(analyzer), + _ => Ok(None), + } + } + + pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::BuiltIn(node, _) => Ok(node.is_dyn(analyzer)?), + Self::Concrete(node) => Ok(node.is_dyn(analyzer)?), + _ => Ok(false), + } + } + + pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + match self { + Self::BuiltIn(node, _) => Ok(node.is_indexable(analyzer)?), + Self::Concrete(node) => Ok(node.is_indexable(analyzer)?), + _ => Ok(false), + } + } + + pub fn ty_eq(&self, other: &Self, analyzer: &impl GraphLike) -> Result { + match (self, other) { + (VarType::User(s, _), VarType::User(o, _)) => { + Ok(s.unresolved_as_resolved(analyzer)? == o.unresolved_as_resolved(analyzer)?) + } + (VarType::BuiltIn(s, _), VarType::BuiltIn(o, _)) => { + match (s.underlying(analyzer)?, o.underlying(analyzer)?) { + (Builtin::Array(l), Builtin::Array(r)) => Ok(l + .unresolved_as_resolved(analyzer)? + == r.unresolved_as_resolved(analyzer)?), + (Builtin::SizedArray(l_size, l), Builtin::SizedArray(r_size, r)) => Ok(l + .unresolved_as_resolved(analyzer)? + == r.unresolved_as_resolved(analyzer)? + && l_size == r_size), + (Builtin::Mapping(lk, lv), Builtin::Mapping(rk, rv)) => Ok(lk + .unresolved_as_resolved(analyzer)? + == rk.unresolved_as_resolved(analyzer)? + && lv.unresolved_as_resolved(analyzer)? + == rv.unresolved_as_resolved(analyzer)?), + (l, r) => Ok(l == r), + } + } + (VarType::Concrete(s), VarType::Concrete(o)) => Ok(s + .underlying(analyzer)? + .equivalent_ty(o.underlying(analyzer)?)), + _ => Ok(false), + } + } + + pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + match self { + VarType::User(ty_node, _) => ty_node.as_string(analyzer), + VarType::BuiltIn(bn, _) => match analyzer.node(*bn) { + Node::Builtin(bi) => bi.as_string(analyzer), + _ => unreachable!(), + }, + VarType::Concrete(c) => c.underlying(analyzer)?.as_builtin().as_string(analyzer), + } + } + + pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { + match self { + VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.is_int()), + VarType::Concrete(c) => Ok(c.underlying(analyzer)?.is_int()), + _ => Ok(false), + } + } + + pub fn as_builtin(&self, analyzer: &impl GraphLike) -> Result { + match self { + VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.clone()), + VarType::Concrete(c) => Ok(c.underlying(analyzer)?.as_builtin()), + e => Err(GraphError::NodeConfusion(format!( + "Expected to be builtin castable but wasnt: {e:?}" + ))), + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum TypeNode { + Contract(ContractNode), + Struct(StructNode), + Enum(EnumNode), + Ty(TyNode), + Func(FunctionNode), + Unresolved(NodeIdx), +} + +impl TypeNode { + pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + match self { + TypeNode::Contract(n) => n.name(analyzer), + TypeNode::Struct(n) => n.name(analyzer), + TypeNode::Enum(n) => n.name(analyzer), + TypeNode::Ty(n) => n.name(analyzer), + TypeNode::Func(n) => Ok(format!("function {}", n.name(analyzer)?)), + TypeNode::Unresolved(n) => Ok(format!("UnresolvedType<{:?}>", analyzer.node(*n))), + } + } + + pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { + match self { + TypeNode::Unresolved(n) => match analyzer.node(*n) { + Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( + "Expected the type \"{}\" to be resolved by now", + ident.name + ))), + Node::Contract(..) => Ok(TypeNode::Contract((*n).into())), + Node::Struct(..) => Ok(TypeNode::Struct((*n).into())), + Node::Enum(..) => Ok(TypeNode::Enum((*n).into())), + Node::Ty(..) => Ok(TypeNode::Ty((*n).into())), + Node::Function(..) => Ok(TypeNode::Func((*n).into())), + _ => Err(GraphError::NodeConfusion( + "Tried to type a non-typeable element".to_string(), + )), + }, + _ => Ok(*self), + } + } +} + +impl From for NodeIdx { + fn from(val: TypeNode) -> Self { + match val { + TypeNode::Contract(n) => n.into(), + TypeNode::Struct(n) => n.into(), + TypeNode::Enum(n) => n.into(), + TypeNode::Ty(n) => n.into(), + TypeNode::Func(n) => n.into(), + TypeNode::Unresolved(n) => n, + } + } +} diff --git a/crates/range/elem/concrete.rs b/crates/range/elem/concrete.rs new file mode 100644 index 00000000..38c31542 --- /dev/null +++ b/crates/range/elem/concrete.rs @@ -0,0 +1,119 @@ + +/// A concrete value for a range element +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeConcrete { + pub val: T, + pub loc: Loc, +} + +impl From for RangeConcrete { + fn from(c: Concrete) -> Self { + Self { + val: c, + loc: Loc::Implicit, + } + } +} + +impl RangeElem for RangeConcrete { + // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { + // Elem::Concrete(self.clone()) + // } + + fn range_eq(&self, other: &Self) -> bool { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(self_val), Some(other_val)) => self_val == other_val, + _ => match (&self.val, &other.val) { + (Concrete::Int(_, s), Concrete::Int(_, o)) => s == o, + (Concrete::DynBytes(s), Concrete::DynBytes(o)) => s == o, + (Concrete::String(s), Concrete::String(o)) => s == o, + (Concrete::DynBytes(s), Concrete::String(o)) => s == o.as_bytes(), + (Concrete::String(s), Concrete::DynBytes(o)) => s.as_bytes() == o, + (Concrete::Array(a), Concrete::Array(b)) => { + if a.len() == b.len() { + a.iter().zip(b.iter()).all(|(a, b)| { + let a = RangeConcrete { + val: a.clone(), + loc: self.loc, + }; + + let b = RangeConcrete { + val: b.clone(), + loc: other.loc, + }; + + a.range_eq(&b) + }) + } else { + false + } + } + _ => false, + }, + } + } + + fn range_ord(&self, other: &Self) -> Option { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), + (Some(_), _) => { + match other.val { + Concrete::Int(_, _) => { + // if we couldnt convert an int to uint, its negative + // so self must be > other + Some(std::cmp::Ordering::Greater) + } + _ => None, + } + } + (_, Some(_)) => { + match self.val { + Concrete::Int(_, _) => { + // if we couldnt convert an int to uint, its negative + // so self must be < other + Some(std::cmp::Ordering::Less) + } + _ => None, + } + } + _ => { + match (&self.val, &other.val) { + // two negatives + (Concrete::Int(_, s), Concrete::Int(_, o)) => Some(s.cmp(o)), + (Concrete::DynBytes(b0), Concrete::DynBytes(b1)) => Some(b0.cmp(b1)), + _ => None, + } + } + } + } + + fn dependent_on(&self) -> Vec { + vec![] + } + fn update_deps(&mut self, _mapping: &BTreeMap) {} + + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + + fn maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + fn minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + + fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + + fn cache_maximize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + Ok(()) + } + + fn cache_minimize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + Ok(()) + } + fn uncache(&mut self) {} +} \ No newline at end of file diff --git a/crates/range/elem/elem_enum.rs b/crates/range/elem/elem_enum.rs new file mode 100644 index 00000000..0b4428c3 --- /dev/null +++ b/crates/range/elem/elem_enum.rs @@ -0,0 +1,466 @@ + +/// A core range element. +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum Elem { + /// A range element that is a reference to another node + Reference(Reference), + /// A concrete range element of type `T`. e.g.: some number like `10` + ConcreteDyn(Box>), + /// A concrete range element of type `T`. e.g.: some number like `10` + Concrete(RangeConcrete), + /// A range element that is an expression composed of other range elements + Expr(RangeExpr), + /// A null range element useful in range expressions that dont have a rhs + Null, +} + +impl std::fmt::Display for Elem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::ConcreteDyn(..) => write!(f, "range_elem"), + Elem::Concrete(RangeConcrete { val, .. }) => { + write!(f, "{}", val.as_string()) + } + Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => { + write!(f, "({} {} {})", op.to_string(), lhs, rhs) + } + _ => write!(f, ""), + } + } +} + +impl From for Elem { + fn from(c: Concrete) -> Self { + Elem::Concrete(RangeConcrete { + val: c, + loc: Loc::Implicit, + }) + } +} + +impl From for Elem { + fn from(c: ContextVarNode) -> Self { + Elem::Reference(Reference::new(c.into())) + } +} + +impl From for Elem { + fn from(idx: NodeIdx) -> Self { + Elem::Reference(Reference::new(idx)) + } +} + +impl Elem { + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + match self { + Self::Reference(d) => d.idx == node_idx, + Self::Concrete(_) => false, + Self::Expr(expr) => expr.contains_node(node_idx), + Self::ConcreteDyn(d) => d.contains_node(node_idx), + Self::Null => false, + } + } + + pub fn dyn_map(&self) -> Option<&BTreeMap> { + match self { + Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), + _ => None, + } + } + + pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { + match self { + Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), + _ => None, + } + } + + /// Creates a new range element that is a cast from one type to another + pub fn cast(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Cast, other); + Elem::Expr(expr) + } + + pub fn concat(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Concat, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the minimum of two range elements + pub fn min(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Min, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the maximum of two range elements + pub fn max(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Max, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of equality of two range elements + pub fn eq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Eq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of inequality of two range elements + pub fn neq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Neq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is one range element to the power of another + pub fn pow(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Exp, other); + Elem::Expr(expr) + } +} + +impl From for Elem { + fn from(dy: Reference) -> Self { + Elem::Reference(dy) + } +} + +impl From> for Elem { + fn from(c: RangeConcrete) -> Self { + Elem::Concrete(c) + } +} + +impl Elem { + pub fn node_idx(&self) -> Option { + match self { + Self::Reference(Reference { idx, .. }) => Some(*idx), + _ => None, + } + } + + pub fn concrete(&self) -> Option { + match self { + Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), + _ => None, + } + } + + pub fn is_negative( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result { + let res = match self { + Elem::Concrete(RangeConcrete { + val: Concrete::Int(_, val), + .. + }) if val < &I256::zero() => true, + Elem::Reference(dy) => { + if maximize { + dy.maximize(analyzer)?.is_negative(maximize, analyzer)? + } else { + dy.minimize(analyzer)?.is_negative(maximize, analyzer)? + } + } + Elem::Expr(expr) => { + if maximize { + expr.maximize(analyzer)?.is_negative(maximize, analyzer)? + } else { + expr.minimize(analyzer)?.is_negative(maximize, analyzer)? + } + } + _ => false, + }; + Ok(res) + } + + pub fn pre_evaled_is_negative(&self) -> bool { + matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) + } + + pub fn maybe_concrete(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + + pub fn maybe_range_dyn(&self) -> Option> { + match self { + Elem::ConcreteDyn(a) => Some(*a.clone()), + _ => None, + } + } +} + +impl RangeElem for Elem { + fn range_eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), + _ => false, + } + } + + fn range_ord(&self, other: &Self) -> Option { + match (self, other) { + (Self::Concrete(a), Self::Concrete(b)) => { + let ord = a.range_ord(b); + if ord.is_none() { + println!("couldnt compare: {a:?} {b:?}"); + } + + ord + } + _ => None, + } + } + + fn dependent_on(&self) -> Vec { + match self { + Self::Reference(d) => d.dependent_on(), + Self::Concrete(_) => vec![], + Self::Expr(expr) => expr.dependent_on(), + Self::ConcreteDyn(d) => d.dependent_on(), + Self::Null => vec![], + } + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + match self { + Self::Reference(d) => d.update_deps(mapping), + Self::Concrete(_) => {} + Self::Expr(expr) => expr.update_deps(mapping), + Self::ConcreteDyn(d) => d.update_deps(mapping), + Self::Null => {} + } + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + match self { + Self::Reference(ref mut d) => { + if d.idx == node_idx { + d.idx = new_idx + } + } + Self::Concrete(_) => {} + Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx), + Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx), + Self::Null => {} + } + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.maximize(analyzer)?, + Concrete(inner) => inner.maximize(analyzer)?, + ConcreteDyn(inner) => inner.maximize(analyzer)?, + Expr(expr) => expr.maximize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.minimize(analyzer)?, + Concrete(inner) => inner.minimize(analyzer)?, + ConcreteDyn(inner) => inner.minimize(analyzer)?, + Expr(expr) => expr.minimize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.simplify_maximize(analyzer)?, + Concrete(inner) => inner.simplify_maximize(analyzer)?, + ConcreteDyn(inner) => inner.simplify_maximize(analyzer)?, + Expr(expr) => expr.simplify_maximize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.simplify_minimize(analyzer)?, + Concrete(inner) => inner.simplify_minimize(analyzer)?, + ConcreteDyn(inner) => inner.simplify_minimize(analyzer)?, + Expr(expr) => expr.simplify_minimize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_maximize(analyzer), + Concrete(inner) => inner.cache_maximize(analyzer), + ConcreteDyn(inner) => inner.cache_maximize(analyzer), + Expr(expr) => expr.cache_maximize(analyzer), + Null => Ok(()), + } + } + + fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_minimize(analyzer), + Concrete(inner) => inner.cache_minimize(analyzer), + ConcreteDyn(inner) => inner.cache_minimize(analyzer), + Expr(expr) => expr.cache_minimize(analyzer), + Null => Ok(()), + } + } + fn uncache(&mut self) { + use Elem::*; + match self { + Reference(dy) => dy.uncache(), + Concrete(inner) => inner.uncache(), + ConcreteDyn(inner) => inner.uncache(), + Expr(expr) => expr.uncache(), + Null => {} + } + } +} + +impl Add for Elem { + type Output = Self; + + fn add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(false), other); + Self::Expr(expr) + } +} + +impl Sub for Elem { + type Output = Self; + + fn sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(false), other); + Self::Expr(expr) + } +} + +impl Mul for Elem { + type Output = Self; + + fn mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(false), other); + Self::Expr(expr) + } +} + +impl Div for Elem { + type Output = Self; + + fn div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(false), other); + Self::Expr(expr) + } +} + +impl Shl for Elem { + type Output = Self; + + fn shl(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shl, other); + Self::Expr(expr) + } +} + +impl Shr for Elem { + type Output = Self; + + fn shr(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shr, other); + Self::Expr(expr) + } +} + +impl Rem for Elem { + type Output = Self; + + fn rem(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mod, other); + Self::Expr(expr) + } +} + +impl BitAnd for Elem { + type Output = Self; + + fn bitand(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitAnd, other); + Self::Expr(expr) + } +} + +impl BitOr for Elem { + type Output = Self; + + fn bitor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitOr, other); + Self::Expr(expr) + } +} + +impl BitXor for Elem { + type Output = Self; + + fn bitxor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitXor, other); + Self::Expr(expr) + } +} + +impl Elem { + pub fn wrapping_add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(true), other); + Self::Expr(expr) + } + pub fn wrapping_sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(true), other); + Self::Expr(expr) + } + pub fn wrapping_mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(true), other); + Self::Expr(expr) + } + pub fn wrapping_div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(true), other); + Self::Expr(expr) + } + + /// Creates a logical AND of two range elements + pub fn and(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::And, other); + Self::Expr(expr) + } + + /// Creates a logical OR of two range elements + pub fn or(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Or, other); + Self::Expr(expr) + } + + pub fn maybe_elem_min(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::min(val)?)), + _ => None, + } + } + + pub fn maybe_elem_max(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::max(val)?)), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/elem/expr.rs b/crates/range/elem/expr.rs new file mode 100644 index 00000000..0d2644b0 --- /dev/null +++ b/crates/range/elem/expr.rs @@ -0,0 +1,92 @@ +/// A range expression composed of other range [`Elem`] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeExpr { + pub maximized: Option>, + pub minimized: Option>, + pub lhs: Box>, + pub op: RangeOp, + pub rhs: Box>, +} + +impl RangeExpr { + /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. + pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { + RangeExpr { + maximized: None, + minimized: None, + lhs: Box::new(lhs), + op, + rhs: Box::new(rhs), + } + } + + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) + } +} + +impl RangeElem for RangeExpr { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn range_ord(&self, _other: &Self) -> Option { + todo!() + } + + fn dependent_on(&self) -> Vec { + let mut deps = self.lhs.dependent_on(); + deps.extend(self.rhs.dependent_on()); + deps + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + self.lhs.update_deps(mapping); + self.rhs.update_deps(mapping); + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + self.lhs.filter_recursion(node_idx, new_idx); + self.rhs.filter_recursion(node_idx, new_idx); + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + Ok(*cached) + } else { + self.exec_op(true, analyzer) + } + } + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + Ok(*cached) + } else { + self.exec_op(false, analyzer) + } + } + + fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + self.simplify_exec_op(true, analyzer) + } + fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + self.simplify_exec_op(false, analyzer) + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.cache_exec_op(true, g)?; + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.cache_exec_op(false, g)?; + } + Ok(()) + } + + fn uncache(&mut self) { + self.uncache_exec(); + } +} \ No newline at end of file diff --git a/crates/range/elem/map_or_array.rs b/crates/range/elem/map_or_array.rs new file mode 100644 index 00000000..f9a5ff6d --- /dev/null +++ b/crates/range/elem/map_or_array.rs @@ -0,0 +1,151 @@ +/// A concrete value for a range element +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeDyn { + pub minimized: Option>, + pub maximized: Option>, + pub len: Elem, + pub val: BTreeMap, Elem>, + pub loc: Loc, +} +impl RangeDyn { + pub fn set_len(&mut self, new_len: Elem) { + self.len = new_len; + } + + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + self.len.contains_node(node_idx) + // || self.val.iter().any(|(k, v)| k.contains_node(node_idx) || v.contains_node(node_idx)) + } +} + +impl RangeElem for RangeDyn { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn range_ord(&self, _other: &Self) -> Option { + todo!() + } + + fn dependent_on(&self) -> Vec { + let mut deps: Vec = self.len.dependent_on(); + deps.extend( + self.val + .iter() + .flat_map(|(_, val)| val.dependent_on()) + .collect::>(), + ); + deps + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + self.len.update_deps(mapping); + self.val + .iter_mut() + .for_each(|(_, val)| val.update_deps(mapping)); + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + self.len.filter_recursion(node_idx, new_idx); + self.val = self + .val + .clone() + .into_iter() + .map(|(mut k, mut v)| { + k.filter_recursion(node_idx, new_idx); + v.filter_recursion(node_idx, new_idx); + (k, v) + }) + .collect(); + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + return Ok(*cached); + } + + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.maximize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.maximize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + return Ok(*cached); + } + + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.minimize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.minimize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.simplify_maximize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.simplify_maximize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.simplify_minimize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.simplify_minimize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + } + Ok(()) + } + + fn uncache(&mut self) { + self.minimized = None; + self.maximized = None; + } +} \ No newline at end of file diff --git a/crates/range/elem/mod.rs b/crates/range/elem/mod.rs new file mode 100644 index 00000000..826c8f0f --- /dev/null +++ b/crates/range/elem/mod.rs @@ -0,0 +1,188 @@ +use crate::analyzer::GraphError; +use crate::analyzer::GraphLike; +use crate::context::ContextVarNode; +use crate::range::elem_ty::Elem; +use crate::range::elem_ty::RangeExpr; + +use crate::NodeIdx; +use std::collections::BTreeMap; + +mod concrete; +mod elem_enum; +mod expr; +mod map_or_array; +mod reference; + + +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum MinMaxed { + Minimized(Box>), + Maximized(Box>), +} + +/// An operation to be performed on a range element +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum RangeOp { + /// Addition + Add(bool), + /// Multiplication + Mul(bool), + /// Subtraction + Sub(bool), + /// Division + Div(bool), + /// Modulos + Mod, + /// Minimum + Min, + /// Maximum + Max, + /// Less than + Lt, + /// Less than or equal + Lte, + /// Geater than + Gt, + /// Greater than or equal + Gte, + /// Equal + Eq, + /// Not Equal + Neq, + /// Logical Not + Not, + /// Bitwise shift left + Shl, + /// Bitwise shift right + Shr, + /// Logical AND + And, + /// Logical OR + Or, + /// Catch-all requirement statement + Where, + /// Cast from one type to another + Cast, + /// Bitwise AND + BitAnd, + /// Bitwise OR + BitOr, + /// Bitwise XOR + BitXor, + /// Bitwise Not + BitNot, + /// Exponentiation + Exp, + /// Concatenation + Concat, +} + +impl RangeOp { + /// Attempts to return the inverse range operation (e.g.: `RangeOp::Add => RangeOp::Sub`) + pub fn inverse(self) -> Option { + use RangeOp::*; + match self { + Add(i) => Some(Sub(i)), + Mul(i) => Some(Div(i)), + Sub(i) => Some(Add(i)), + Div(i) => Some(Mul(i)), + Shl => Some(Shr), + Shr => Some(Shl), + Eq => Some(Neq), + Neq => Some(Eq), + _ => None, // e => panic!("tried to inverse unreversable op: {:?}", e), + } + } + + pub fn require_parts(self) -> Option<(Self, Self, (Self, Self))> { + use RangeOp::*; + let t = match self { + Eq => (Eq, Neq, (Neq, Eq)), + Neq => (Neq, Eq, (Eq, Neq)), + Lte => (Lte, Gte, (Gte, Lte)), + Gte => (Gte, Lte, (Lte, Gte)), + Gt => (Gt, Lt, (Lt, Gt)), + Lt => (Lt, Gt, (Gt, Lt)), + _ => return None, + }; + Some(t) + } +} + +impl ToString for RangeOp { + fn to_string(&self) -> String { + use RangeOp::*; + match self { + Add(..) => "+".to_string(), + Mul(..) => "*".to_string(), + Sub(..) => "-".to_string(), + Div(..) => "/".to_string(), + Shl => "<<".to_string(), + Shr => ">>".to_string(), + Mod => "%".to_string(), + Exp => "**".to_string(), + Min => "min".to_string(), + Max => "max".to_string(), + Lt => "<".to_string(), + Gt => ">".to_string(), + Lte => "<=".to_string(), + Gte => ">=".to_string(), + Eq => "==".to_string(), + Neq => "!=".to_string(), + Not => "!".to_string(), + And => "&&".to_string(), + Or => "||".to_string(), + Where => "where".to_string(), + Cast => "cast".to_string(), + BitAnd => "&".to_string(), + BitOr => "|".to_string(), + BitXor => "^".to_string(), + BitNot => "~".to_string(), + Concat => "concat".to_string(), + } + } +} + +pub trait RangeElem { + /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + fn uncache(&mut self); + /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) + fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) + fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + /// Checks if two range elements are equal + fn range_eq(&self, other: &Self) -> bool; + /// Tries to compare the ordering of two range elements + fn range_ord(&self, other: &Self) -> Option; + /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). + fn range_op(lhs: Elem, rhs: Elem, op: RangeOp) -> Elem + where + Self: Sized, + { + Elem::Expr(RangeExpr::new(lhs, op, rhs)) + } + /// Traverses the range expression and finds all nodes that are dynamically pointed to + /// and returns it in a vector. + fn dependent_on(&self) -> Vec; + /// Traverses the range expression and updates stale pointers from older versions + /// of a variable to a newer version. + /// + /// e.g.: `uint256 z = x + 100`, followed by `require(x < 100)`. Initially, + /// without the `require` statement, `z`'s max is `2**256 - 1`, but with + /// the introduction of the `require` statement, we do a little backtracking + /// and can update `z`'s max to be `200`. + fn update_deps(&mut self, mapping: &BTreeMap); + /// Attempts to replace range elements that form a cyclic dependency by replacing + /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now + /// but in theory it can make sense. + /// + /// e.g.: take the basic expression `x + y`, in normal checked solidity math + /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a + /// cyclic dependency. + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); +} diff --git a/crates/range/elem/reference.rs b/crates/range/elem/reference.rs new file mode 100644 index 00000000..8fd6d5dc --- /dev/null +++ b/crates/range/elem/reference.rs @@ -0,0 +1,165 @@ +/// A dynamic range element value +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct Reference { + /// Index of the node that is referenced + pub idx: NodeIdx, + pub minimized: Option>, + pub maximized: Option>, +} + +impl Reference { + pub fn new(idx: NodeIdx) -> Self { + Self { + idx, + minimized: None, + maximized: None, + } + } +} + +impl RangeElem for Reference { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn range_ord(&self, _other: &Self) -> Option { + todo!() + } + + fn dependent_on(&self) -> Vec { + vec![ContextVarNode::from(self.idx)] + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { + self.idx = NodeIdx::from(new.0); + } + } + + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + return Ok(*cached); + } + + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + range.evaled_range_max(analyzer) + } else { + Ok(Elem::Reference(self.clone())) + } + } + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + val: concrete_node.underlying(analyzer)?.clone(), + loc: cvar.loc.unwrap_or(Loc::Implicit), + })), + _e => Ok(Elem::Reference(self.clone())), + } + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + return Ok(*cached); + } + + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + range.evaled_range_min(analyzer) + } else { + Ok(Elem::Reference(self.clone())) + } + } + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + val: concrete_node.underlying(analyzer)?.clone(), + loc: cvar.loc.unwrap_or(Loc::Implicit), + })), + _e => Ok(Elem::Reference(self.clone())), + } + } + + fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + // let cvar = ContextVarNode::from(self.idx); + // if cvar.is_symbolic(analyzer)? { + Ok(Elem::Reference(self.clone())) + // } + // if !cvar.is_tmp(analyzer)? { + // return Ok(Elem::Reference(self.clone())) + // } + // let cvar = cvar.underlying(analyzer)?; + // match &cvar.ty { + // VarType::User(TypeNode::Contract(_), maybe_range) + // | VarType::User(TypeNode::Enum(_), maybe_range) + // | VarType::User(TypeNode::Ty(_), maybe_range) + // | VarType::BuiltIn(_, maybe_range) => { + // if let Some(range) = maybe_range { + // range.simplified_range_max(analyzer) + // } else { + // Ok(Elem::Reference(self.clone())) + // } + // } + // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + // val: concrete_node.underlying(analyzer)?.clone(), + // loc: cvar.loc.unwrap_or(Loc::Implicit), + // })), + // _e => Ok(Elem::Reference(self.clone())), + // } + } + fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + // let cvar = ContextVarNode::from(self.idx); + // if cvar.is_symbolic(analyzer)? { + Ok(Elem::Reference(self.clone())) + // } + // if !cvar.is_tmp(analyzer)? { + // return Ok(Elem::Reference(self.clone())) + // } + // let cvar = cvar.underlying(analyzer)?; + + // match &cvar.ty { + // VarType::User(TypeNode::Contract(_), maybe_range) + // | VarType::User(TypeNode::Enum(_), maybe_range) + // | VarType::User(TypeNode::Ty(_), maybe_range) + // | VarType::BuiltIn(_, maybe_range) => { + // if let Some(range) = maybe_range { + // range.simplified_range_min(analyzer) + // } else { + // Ok(Elem::Reference(self.clone())) + // } + // } + // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + // val: concrete_node.underlying(analyzer)?.clone(), + // loc: cvar.loc.unwrap_or(Loc::Implicit), + // })), + // _e => Ok(Elem::Reference(self.clone())), + // } + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + } + Ok(()) + } + + fn uncache(&mut self) { + self.minimized = None; + self.maximized = None; + } +} \ No newline at end of file diff --git a/crates/range/exec/add.rs b/crates/range/exec/add.rs new file mode 100644 index 00000000..01c1b73c --- /dev/null +++ b/crates/range/exec/add.rs @@ -0,0 +1,112 @@ +pub trait RangeAdd { + /// Perform addition between two range elements + fn range_add(&self, other: &Rhs) -> Option>; + fn range_wrapping_add(&self, other: &Rhs) -> Option>; +} + +impl RangeAdd for RangeConcrete { + fn range_add(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let max = Concrete::max(&self.val).unwrap(); + let max_uint = max.into_u256().unwrap(); + Some(Elem::Concrete(RangeConcrete { + val: self + .val + .u256_as_original(lhs_val.saturating_add(rhs_val).min(max_uint)), + loc: self.loc, + })) + } + _ => { + match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + // neg_v guaranteed to be negative here + if neg_v.into_raw() > *val { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + neg_v.saturating_add(I256::from_raw(*val)), + ), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: self + .val + .u256_as_original(val.saturating_sub(neg_v.into_raw())), + loc: self.loc, + })) + } + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) + - I256::from(1) + }; + let min = max * I256::from(-1i32) - I256::from(1i32); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.saturating_add(*r).max(min)), + loc: self.loc, + })) + } + _ => None, + } + } + } + } + fn range_wrapping_add(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: self + .val + .u256_as_original(lhs_val.overflowing_add(rhs_val).0), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + I256::from_raw(neg_v.into_raw().overflowing_add(*val).0), + ), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.overflowing_add(*r).0), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeAdd for Elem { + fn range_add(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), + (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { + Some(other.clone()) + } + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + _ => None, + } + } + fn range_wrapping_add(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), + (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { + Some(other.clone()) + } + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/bitwise.rs b/crates/range/exec/bitwise.rs new file mode 100644 index 00000000..4ac5a776 --- /dev/null +++ b/crates/range/exec/bitwise.rs @@ -0,0 +1,173 @@ +pub trait RangeBitwise { + /// Perform a bitwise AND + fn range_bit_and(&self, other: &Rhs) -> Option>; + /// Perform a bitwise OR + fn range_bit_or(&self, other: &Rhs) -> Option>; + /// Perform a bitwise XOR + fn range_bit_xor(&self, other: &Rhs) -> Option>; + /// Perform a bitwise NOT + fn range_bit_not(&self) -> Option>; +} + +impl RangeBitwise for RangeConcrete { + fn range_bit_and(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, *a & *b), + loc: self.loc, + })) + } + (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, *a & *b), + loc: self.loc, + })) + } + (Concrete::Uint(s, a), Concrete::Int(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, *a & b.into_raw()), + loc: self.loc, + })) + } + (Concrete::Int(s, a), Concrete::Uint(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, a.into_raw() & *b), + loc: self.loc, + })) + } + (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*size, a & b), + loc: self.loc, + })) + } + _ => None, + } + } + + fn range_bit_or(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, *a | *b), + loc: self.loc, + })) + } + (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, *a | *b), + loc: self.loc, + })) + } + (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*size, a | b), + loc: self.loc, + })) + } + _ => None, + } + } + + fn range_bit_xor(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, *a ^ *b), + loc: self.loc, + })) + } + (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, *a ^ *b), + loc: self.loc, + })) + } + (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let size = if s > s2 { s } else { s2 }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*size, a ^ b), + loc: self.loc, + })) + } + _ => None, + } + } + + fn range_bit_not(&self) -> Option> { + match &self.val { + Concrete::Uint(size, a) => { + let max = Concrete::max(&self.val).unwrap().uint_val().unwrap(); + let val = U256( + a.0.into_iter() + .map(|i| !i) + .collect::>() + .try_into() + .unwrap(), + ); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, val & max), + loc: self.loc, + })) + } + Concrete::Int(size, a) => { + let (val, _) = a.overflowing_neg(); + let (val, _) = val.overflowing_sub(1.into()); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, val), + loc: self.loc, + })) + } + Concrete::Bytes(s, a) => { + let mut h = H256::default(); + (0..*s).for_each(|i| { + h.0[i as usize] = !a.0[i as usize]; + }); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*s, h), + loc: self.loc, + })) + } + _ => None, + } + } +} + +impl RangeBitwise for Elem { + fn range_bit_and(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_and(b), + _ => None, + } + } + fn range_bit_or(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_or(b), + _ => None, + } + } + fn range_bit_xor(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_xor(b), + _ => None, + } + } + + fn range_bit_not(&self) -> Option> { + match self { + Elem::Concrete(a) => a.range_bit_not(), + _ => None, + } + } +} diff --git a/crates/range/exec/cast.rs b/crates/range/exec/cast.rs new file mode 100644 index 00000000..ec122be9 --- /dev/null +++ b/crates/range/exec/cast.rs @@ -0,0 +1,257 @@ +pub trait RangeCast { + /// Perform a cast on an element to the type of the right hand side + fn range_cast(&self, other: &Rhs) -> Option>; +} + +impl RangeCast for RangeConcrete { + fn range_cast(&self, other: &Self) -> Option> { + Some(Elem::Concrete(RangeConcrete { + val: self.val.clone().cast_from(&other.val)?, + loc: self.loc, + })) + } +} + +impl RangeCast>> for RangeConcrete { + fn range_cast(&self, other: &Box>) -> Option> { + match (self.val.clone(), other.val.iter().take(1).next()) { + ( + Concrete::Bytes(size, val), + Some(( + _, + Elem::Concrete(Self { + val: Concrete::Bytes(..), + .. + }), + )), + ) + | (Concrete::Bytes(size, val), None) => { + let mut existing = other.val.clone(); + let new = val + .0 + .iter() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(size))), + val: existing, + loc: other.loc, + }))) + } + ( + Concrete::DynBytes(val), + Some(( + _, + Elem::Concrete(Self { + val: Concrete::Bytes(..), + .. + }), + )), + ) + | (Concrete::DynBytes(val), None) => { + let mut existing = other.val.clone(); + let new = val + .iter() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(val.len()))), + val: existing, + loc: other.loc, + }))) + } + ( + Concrete::String(val), + Some(( + _, + Elem::Concrete(Self { + val: Concrete::String(..), + .. + }), + )), + ) + | (Concrete::String(val), None) => { + let mut existing = other.val.clone(); + let new = val + .chars() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let mut bytes = [0x00; 32]; + v.encode_utf8(&mut bytes[..]); + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(val.len()))), + val: existing, + loc: other.loc, + }))) + } + _e => None, + } + } +} + +impl RangeCast> for RangeDyn { + fn range_cast(&self, other: &Self) -> Option> { + let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); + let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); + match (val, o_val) { + ( + Some(( + _, + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + Some(( + _, + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + ) + | ( + Some(( + _, + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + None, + ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + ( + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + )), + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + )), + ) + | ( + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + )), + None, + ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + ( + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + )), + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + )), + ) + | ( + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + )), + None, + ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), + (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + _e => None, + } + } +} + +impl RangeCast> for RangeDyn { + fn range_cast(&self, other: &RangeConcrete) -> Option> { + let (_k, val): (_, &Elem) = self.val.iter().take(1).next()?; + let o_val = &other.val; + // println!("HERE {:?} {:?} {:?}", k, val, o_val); + match (val, o_val) { + ( + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(1, ..), + .. + }), + Concrete::Bytes(size, _), + ) => { + let mut h = H256::default(); + for (i, (_, val)) in self.val.iter().take(*size as usize).enumerate() { + match val { + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(1, v), + .. + }) => { + // consume as many as we can + h.0[i] = v.0[0]; + } + _ => break, + } + } + Some(Elem::Concrete(Concrete::Bytes(*size, h).into())) + } + _e => None, + } + } +} + +impl RangeCast for Elem { + fn range_cast(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_cast(b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { + // super dumb type stuff here that makes it so we have to specify + as RangeCast>::range_cast(a, b) + } + (Elem::ConcreteDyn(a), Elem::Concrete(b)) => a.range_cast(b), + (Elem::Concrete(a), Elem::ConcreteDyn(b)) => a.range_cast(b), + _e => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/concat.rs b/crates/range/exec/concat.rs new file mode 100644 index 00000000..194506e2 --- /dev/null +++ b/crates/range/exec/concat.rs @@ -0,0 +1,148 @@ +pub trait RangeConcat { + /// Perform a cast on an element to the type of the right hand side + fn range_concat(&self, other: &Rhs) -> Option>; +} + +impl RangeConcat for RangeConcrete { + fn range_concat(&self, other: &Self) -> Option> { + Some(Elem::Concrete(RangeConcrete { + val: self.val.clone().concat(&other.val)?, + loc: self.loc, + })) + } +} + +impl RangeConcat> for RangeDyn { + fn range_concat(&self, other: &RangeConcrete) -> Option> { + match (other.val.clone(), self.val.iter().take(1).next()) { + ( + Concrete::DynBytes(val), + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + ) + | (Concrete::DynBytes(val), None) => { + let last = self.len.clone(); + let mut existing = self.val.clone(); + let new = val + .iter() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let idx = last.clone() + idx; + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(val.len()))), + val: existing, + loc: other.loc, + }))) + } + ( + Concrete::String(val), + Some(( + _, + Elem::Concrete(RangeConcrete { + val: Concrete::String(..), + .. + }), + )), + ) + | (Concrete::String(val), None) => { + let last = self.len.clone(); + let mut existing = self.val.clone(); + let new = val + .chars() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let idx = last.clone() + idx; + let mut bytes = [0x00; 32]; + v.encode_utf8(&mut bytes[..]); + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(val.len()))), + val: existing, + loc: other.loc, + }))) + } + _e => None, + } + } +} + +impl RangeConcat> for RangeDyn { + fn range_concat(&self, other: &Self) -> Option> { + let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); + let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); + match (val, o_val) { + ( + Some(( + _, + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + Some(( + _, + &Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + )), + ) => { + let last = self.len.clone(); + let mut existing = self.val.clone(); + let other_vals = other + .val + .clone() + .into_iter() + .map(|(i, v)| (i + last.clone(), v)) + .collect::>(); + + existing.extend(other_vals); + Some(Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: self.len.clone() + other.len.clone(), + val: existing, + loc: other.loc, + }))) + } + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), + (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + _e => None, + } + } +} + +impl RangeConcat for Elem { + fn range_concat(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_concat(b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_concat(&**b), + (Elem::Concrete(c), Elem::ConcreteDyn(d)) + | (Elem::ConcreteDyn(d), Elem::Concrete(c)) => d.range_concat(c), + _e => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/div.rs b/crates/range/exec/div.rs new file mode 100644 index 00000000..f1eb12c7 --- /dev/null +++ b/crates/range/exec/div.rs @@ -0,0 +1,148 @@ +pub trait RangeDiv { + /// Perform division between two range elements + fn range_div(&self, other: &Rhs) -> Option>; + + fn range_wrapping_div(&self, other: &Rhs) -> Option>; +} + +impl RangeDiv for RangeConcrete { + fn range_div(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val == 0.into() { + None + } else { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val / rhs_val), + loc: self.loc, + })) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + if neg_v == &I256::from(0) { + None + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), + ), + loc: self.loc, + })) + } + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + if val == &U256::from(0) { + None + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), + loc: self.loc, + })) + } + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + if r == &I256::from(0) { + None + } else { + let (val, overflow) = l.overflowing_div(*r); + if overflow { + None + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, val), + loc: self.loc, + })) + } + } + } + _ => None, + }, + } + } + + fn range_wrapping_div(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val == 0.into() { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(U256::zero()), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val / rhs_val), + loc: self.loc, + })) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + if neg_v == &I256::from(0) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from(0i32)), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), + ), + loc: self.loc, + })) + } + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + if val == &U256::from(0) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from(0i32)), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), + loc: self.loc, + })) + } + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + if r == &I256::from(0) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from(0i32)), + loc: self.loc, + })) + } else { + let (val, overflow) = l.overflowing_div(*r); + if overflow { + None + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, val), + loc: self.loc, + })) + } + } + } + _ => None, + }, + } + } +} + +impl RangeDiv for Elem { + fn range_div(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), + _ => None, + } + } + + fn range_wrapping_div(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), + _ => None, + } + } +} diff --git a/crates/range/exec/exp.rs b/crates/range/exec/exp.rs new file mode 100644 index 00000000..6ef682cf --- /dev/null +++ b/crates/range/exec/exp.rs @@ -0,0 +1,86 @@ +pub trait RangeExp { + /// Perform exponentiation between two range elements + fn range_exp(&self, other: &Rhs) -> Option>; +} + +impl RangeExp for RangeConcrete { + fn range_exp(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let max = Concrete::max(&self.val).unwrap(); + if let Some(num) = lhs_val.checked_pow(rhs_val) { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(num.min(max.into_u256().unwrap())), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(max.into_u256().unwrap()), + loc: self.loc, + })) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let pow2 = val % U256::from(2) == 0.into(); + if val > &U256::from(u32::MAX) { + if pow2 { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::max(&self.val).unwrap(), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::min(&self.val).unwrap(), + loc: self.loc, + })) + } + } else { + let min = Concrete::min(&self.val).unwrap().int_val().unwrap(); + let max = Concrete::max(&self.val).unwrap().int_val().unwrap(); + + if let Some(num) = neg_v.checked_pow(val.as_u32()) { + if pow2 { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, num.min(max)), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, num.max(min)), + loc: self.loc, + })) + } + } else if pow2 { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::max(&self.val).unwrap(), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::min(&self.val).unwrap(), + loc: self.loc, + })) + } + } + } + _ => None, + }, + } + } +} + +impl RangeExp for Elem { + fn range_exp(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_exp(b), + (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { + Some(Elem::from(Concrete::from(U256::from(1)))) + } + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { + Some(other.clone()) + } + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/logical.rs b/crates/range/exec/logical.rs new file mode 100644 index 00000000..0f26c602 --- /dev/null +++ b/crates/range/exec/logical.rs @@ -0,0 +1,61 @@ +pub trait RangeUnary { + /// Perform a logical NOT + fn range_not(&self) -> Option>; + /// Perform a logical AND + fn range_and(&self, other: &Rhs) -> Option>; + /// Perform a logical OR + fn range_or(&self, other: &Rhs) -> Option>; +} + +impl RangeUnary for RangeConcrete { + fn range_not(&self) -> Option> { + match self.val { + Concrete::Bool(b) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(!b), + loc: self.loc, + })), + _ => None, + } + } + + fn range_and(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(*a && *b), + loc: self.loc, + })), + _ => None, + } + } + + fn range_or(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(*a || *b), + loc: self.loc, + })), + _ => None, + } + } +} + +impl RangeUnary for Elem { + fn range_not(&self) -> Option> { + match self { + Elem::Concrete(a) => a.range_not(), + _ => None, + } + } + fn range_and(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_and(b), + _ => None, + } + } + fn range_or(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_or(b), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/max.rs b/crates/range/exec/max.rs new file mode 100644 index 00000000..2d6aa7a9 --- /dev/null +++ b/crates/range/exec/max.rs @@ -0,0 +1,46 @@ + +pub trait RangeMax { + /// Take the maximum of two range elements + fn range_max(&self, other: &Rhs) -> Option>; +} + +impl RangeMax for RangeConcrete { + fn range_max(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val.max(rhs_val)), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*lhs_size, *val), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, _), Concrete::Uint(_, val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*lhs_size, *val), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *l.max(r)), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeMax for Elem { + fn range_max(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_max(b), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/min.rs b/crates/range/exec/min.rs new file mode 100644 index 00000000..faafb73c --- /dev/null +++ b/crates/range/exec/min.rs @@ -0,0 +1,45 @@ +pub trait RangeMin { + /// Take the minimum of two range elements + fn range_min(&self, other: &Rhs) -> Option>; +} + +impl RangeMin for RangeConcrete { + fn range_min(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val.min(rhs_val)), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, _), Concrete::Int(_, neg_v)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *neg_v), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *neg_v), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *l.min(r)), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeMin for Elem { + fn range_min(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_min(b), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/mod.rs b/crates/range/exec/mod.rs new file mode 100644 index 00000000..e2ea46a6 --- /dev/null +++ b/crates/range/exec/mod.rs @@ -0,0 +1,1247 @@ + + +/// For execution of operations to be performed on range expressions +pub trait ExecOp { + /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side + /// and right-hand-side + fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError> { + self.exec(self.spread(analyzer)?, maximize) + } + + fn exec( + &self, + parts: (Elem, Elem, Elem, Elem), + maximize: bool, + ) -> Result, GraphError>; + /// Cache execution + fn cache_exec_op( + &mut self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result<(), GraphError>; + + fn spread( + &self, + analyzer: &impl GraphLike, + ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; + + fn simplify_spread( + &self, + analyzer: &impl GraphLike, + ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; + + fn uncache_exec(&mut self); + + fn simplify_exec_op( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError>; + + /// Attempts to simplify an expression (i.e. just apply constant folding) + fn simplify_exec( + &self, + parts: (Elem, Elem, Elem, Elem), + maximize: bool, + ) -> Result, GraphError> { + self.exec(parts, maximize) + } +} + +impl ExecOp for RangeExpr { + fn cache_exec_op( + &mut self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result<(), GraphError> { + self.lhs.cache_minimize(analyzer)?; + self.lhs.cache_maximize(analyzer)?; + self.rhs.cache_minimize(analyzer)?; + self.rhs.cache_maximize(analyzer)?; + let res = self.exec_op(maximize, analyzer)?; + if maximize { + self.maximized = Some(MinMaxed::Maximized(Box::new(res))); + } else { + self.minimized = Some(MinMaxed::Minimized(Box::new(res))); + } + Ok(()) + } + + fn uncache_exec(&mut self) { + self.lhs.uncache(); + self.rhs.uncache(); + } + + fn simplify_exec_op( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let parts = self.simplify_spread(analyzer)?; + self.exec(parts, maximize) + } + + fn spread( + &self, + analyzer: &impl GraphLike, + ) -> Result< + ( + Elem, + Elem, + Elem, + Elem, + ), + GraphError, + > { + let lhs_min = self.lhs.minimize(analyzer)?; + let lhs_max = self.lhs.maximize(analyzer)?; + let rhs_min = self.rhs.minimize(analyzer)?; + let rhs_max = self.rhs.maximize(analyzer)?; + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) + } + + fn simplify_spread( + &self, + analyzer: &impl GraphLike, + ) -> Result< + ( + Elem, + Elem, + Elem, + Elem, + ), + GraphError, + > { + let lhs_min = self.lhs.simplify_minimize(analyzer)?; + let lhs_max = self.lhs.simplify_maximize(analyzer)?; + let rhs_min = self.rhs.simplify_minimize(analyzer)?; + let rhs_max = self.rhs.simplify_maximize(analyzer)?; + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) + } + + fn exec( + &self, + (lhs_min, lhs_max, rhs_min, rhs_max): ( + Elem, + Elem, + Elem, + Elem, + ), + maximize: bool, + ) -> Result, GraphError> { + tracing::trace!( + "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", + self.lhs, + self.op.to_string(), + self.rhs, + lhs_min, + lhs_max, + rhs_min, + rhs_max + ); + + let lhs_min_neg = lhs_min.pre_evaled_is_negative(); + let lhs_max_neg = lhs_max.pre_evaled_is_negative(); + let rhs_min_neg = rhs_min.pre_evaled_is_negative(); + let rhs_max_neg = rhs_max.pre_evaled_is_negative(); + + let res = match self.op { + RangeOp::Add(unchecked) => { + if unchecked { + let candidates = vec![ + lhs_min.range_wrapping_add(&rhs_min), + lhs_min.range_wrapping_add(&rhs_max), + lhs_max.range_wrapping_add(&rhs_min), + lhs_max.range_wrapping_add(&rhs_max), + lhs_max.range_add(&rhs_max), + lhs_min.range_add(&rhs_min), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value + the largest value + lhs_max + .range_add(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } else { + lhs_min + .range_add(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Sub(unchecked) => { + if unchecked { + let candidates = vec![ + lhs_min.range_wrapping_sub(&rhs_min), + lhs_min.range_wrapping_sub(&rhs_max), + lhs_max.range_wrapping_sub(&rhs_min), + lhs_max.range_wrapping_sub(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value - the smallest value + lhs_max + .range_sub(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } else { + // if we are minimizing, the smallest value will always be smallest value - largest value + lhs_min + .range_sub(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Mul(unchecked) => { + if unchecked { + let candidates = vec![ + lhs_min.range_wrapping_mul(&rhs_min), + lhs_min.range_wrapping_mul(&rhs_max), + lhs_max.range_wrapping_mul(&rhs_min), + lhs_max.range_wrapping_mul(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, and both mins are negative and both maxes are positive, + // we dont know which will be larger of the two (i.e. -1*2**255 * -1*2**255 > 100*100) + match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + (true, true, true, true) => { + // all negative, will be min * min because those are furthest from 0 resulting in the + // largest positive value + lhs_min + .range_mul(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + (true, false, true, false) => { + // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller + match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { + (Some(min_expr), Some(max_expr)) => { + match min_expr.range_ord(&max_expr) { + Some(std::cmp::Ordering::Less) => max_expr, + Some(std::cmp::Ordering::Greater) => min_expr, + _ => max_expr, + } + } + (None, Some(max_expr)) => max_expr, + (Some(min_expr), None) => min_expr, + (None, None) => Elem::Expr(self.clone()), + } + } + (_, false, _, false) => { + // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value + lhs_max + .range_mul(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + (false, false, true, true) => { + // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + lhs_min + .range_mul(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + (true, true, false, false) => { + // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + lhs_max + .range_mul(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + (true, _, true, _) => lhs_min + .range_mul(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())), + (false, true, _, _) | (_, _, false, true) => { + panic!("unsatisfiable range") + } + } + } else { + match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + (false, false, false, false) => { + // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value + lhs_min + .range_mul(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + (true, true, true, true) => { + // all negative, will be max * max because those are closest to 0 resulting in the + // smallest positive value + lhs_max + .range_mul(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + (true, false, true, false) => { + // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller + match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { + (Some(min_expr), Some(max_expr)) => { + match min_expr.range_ord(&max_expr) { + Some(std::cmp::Ordering::Less) => min_expr, + Some(std::cmp::Ordering::Greater) => max_expr, + _ => min_expr, + } + } + (None, Some(max_expr)) => max_expr, + (Some(min_expr), None) => min_expr, + (None, None) => Elem::Expr(self.clone()), + } + } + (true, _, _, false) => { + // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value + lhs_min + .range_mul(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + (_, false, _, true) => { + // just lhs has a positive value, most negative will be lhs_max, rhs_max + lhs_max + .range_mul(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + (false, false, true, false) => lhs_max + .range_mul(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())), + (false, true, _, _) | (_, _, false, true) => { + panic!("unsatisfiable range") + } + } + } + } + RangeOp::Div(_unchecked) => { + let mut candidates = vec![ + lhs_min.range_div(&rhs_min), + lhs_min.range_div(&rhs_max), + lhs_max.range_div(&rhs_min), + lhs_max.range_div(&rhs_max), + ]; + + let one = Elem::from(Concrete::from(U256::from(1))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_div(&one)); + candidates.push(lhs_max.range_div(&one)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_div(&negative_one)); + candidates.push(lhs_max.range_div(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger + // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // max_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // min_expr + // } + // _ => { + // max_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (false, false, true, true) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, false, false) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, false, _) => { + // // lhs is positive, rhs min is positive, guaranteed to give largest + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, false) => { + // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, true, _) => { + // // at this point, its either all trues, or a single false + // // given that, to maximize, the only way to get a positive value is to use the most negative values + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (false, false, false, false) => { + // // smallest number will be lhs_min / rhs_min since both are positive + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, true) => { + // // smallest number will be lhs_max / rhs_min since both are negative + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, false) => { + // // The way to maintain most negative value is lhs_min / rhs_max, all others would go + // // positive or guaranteed to be closer to 0 + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger + // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // min_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // max_expr + // } + // _ => { + // min_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (_, false, true, _) => { + // // We are going negative here, so it will be most positive / least negative + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, _) => { + // // We are going negative here, so it will be most negative / least positive + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + // RangeOp::Mod => { + // lhs.range_mod(&rhs).unwrap_or(Elem::Expr(self.clone())) + // } + RangeOp::Min => { + let candidates = vec![ + lhs_min.range_min(&rhs_min), + lhs_min.range_min(&rhs_max), + lhs_max.range_min(&rhs_min), + lhs_max.range_min(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // // counter-intuitively, we want the maximum value from a call to minimum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the minimum values but getting the larger of the minimum + // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + RangeOp::Max => { + let candidates = vec![ + lhs_min.range_max(&rhs_min), + lhs_min.range_max(&rhs_max), + lhs_max.range_max(&rhs_min), + lhs_max.range_max(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (_, true, _, true) | (_, false, _, false) => { + // // counter-intuitively, we want the minimum value from a call to maximum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the maximum values but getting the smaller of the maximum + // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, true) => { + // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, _, false) => { + // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + RangeOp::Gt => { + if maximize { + lhs_max + .range_gt(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } else { + lhs_min + .range_gt(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Lt => { + if maximize { + lhs_min + .range_lt(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } else { + lhs_max + .range_lt(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Gte => { + if maximize { + lhs_max + .range_gte(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } else { + lhs_min + .range_gte(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Lte => { + if maximize { + lhs_min + .range_lte(&rhs_max) + .unwrap_or(Elem::Expr(self.clone())) + } else { + lhs_max + .range_lte(&rhs_min) + .unwrap_or(Elem::Expr(self.clone())) + } + } + RangeOp::Eq => { + let loc = if let Some(c) = lhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = lhs_max.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_max.maybe_concrete() { + c.loc + } else { + Loc::Implicit + }; + + if maximize { + // check for any overlap + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + + // if lhs max is less than the rhs min, it has to be false + if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + + // if lhs min is greater than the rhs max, it has to be false + if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + + // lhs_max >= rhs_min + // lhs_min <= rhs_max + // therefore its possible to set some value to true here + if lhs_max_rhs_min_ord.is_some() && lhs_min_rhs_max_ord.is_some() { + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }) + } else { + Elem::Expr(self.clone()) + } + } else { + // check if either lhs element is *not* contained by rhs + match ( + // check if lhs is constant + lhs_min.range_ord(&lhs_max), + // check if rhs is constant + rhs_min.range_ord(&rhs_max), + // check if lhs is equal to rhs + lhs_min.range_ord(&rhs_min), + ) { + ( + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + ) => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }), + // if any of those are not equal, we can construct + // an element that is true + _ => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + }), + } + } + } + RangeOp::Neq => { + let loc = if let Some(c) = lhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = lhs_max.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_max.maybe_concrete() { + c.loc + } else { + Loc::Implicit + }; + if maximize { + // check if either lhs element is *not* contained by rhs + match ( + // check if lhs is constant + lhs_min.range_ord(&lhs_max), + // check if rhs is constant + rhs_min.range_ord(&rhs_max), + // check if lhs is equal to rhs + lhs_min.range_ord(&rhs_min), + ) { + ( + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + ) => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + }), + // if any of those are not equal, we can construct + // an element that is true + _ => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }), + } + } else { + // if they are constants and equal, we can stop here + // (rhs min == rhs max) == (lhs min == lhs max ) + if let ( + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + ) = ( + // check if lhs is constant + lhs_min.range_ord(&lhs_max), + // check if rhs is constant + rhs_min.range_ord(&rhs_max), + // check if lhs is equal to rhs + lhs_min.range_ord(&rhs_min), + ) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + + // they aren't constants, check if there is any overlap + match ( + // check if lhs minimum is contained within the right hand side + // this means the values could be equal + // effectively: + // rhs min <= lhs min <= rhs max + lhs_min.range_ord(&rhs_min), + lhs_min.range_ord(&rhs_max), + ) { + (_, Some(std::cmp::Ordering::Equal)) + | (Some(std::cmp::Ordering::Equal), _) + | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })) + } + _ => {} + } + + match ( + // check if the lhs maximum is contained within the right hand side + // effectively: + // rhs min <= lhs max <= rhs max + lhs_max.range_ord(&rhs_min), + lhs_max.range_ord(&rhs_max), + ) { + (_, Some(std::cmp::Ordering::Equal)) + | (Some(std::cmp::Ordering::Equal), _) + | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })) + } + _ => {} + } + + Elem::Expr(self.clone()) + } + } + RangeOp::Shl => { + let candidates = vec![ + lhs_min.range_shl(&rhs_min), + lhs_min.range_shl(&rhs_max), + lhs_max.range_shl(&rhs_min), + lhs_max.range_shl(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Shr => { + let candidates = vec![ + lhs_min.range_shr(&rhs_min), + lhs_min.range_shr(&rhs_max), + lhs_max.range_shr(&rhs_min), + lhs_max.range_shr(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::And => { + let candidates = vec![ + lhs_min.range_and(&rhs_min), + lhs_min.range_and(&rhs_max), + lhs_max.range_and(&rhs_min), + lhs_max.range_and(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Or => { + let candidates = vec![ + lhs_min.range_or(&rhs_min), + lhs_min.range_or(&rhs_max), + lhs_max.range_or(&rhs_min), + lhs_max.range_or(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Not => { + assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); + let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Cast => { + // the weird thing about cast is that we really dont know until after the cast due to sizing things + // so we should just try them all then compare + let candidates = vec![ + lhs_min.range_cast(&rhs_min), + lhs_min.range_cast(&rhs_max), + lhs_max.range_cast(&rhs_min), + lhs_max.range_cast(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Exp => { + // TODO: improve with smarter stuff + let candidates = vec![ + lhs_min.range_exp(&rhs_min), + lhs_min.range_exp(&rhs_max), + lhs_max.range_exp(&rhs_min), + lhs_max.range_exp(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitAnd => { + let mut candidates = vec![ + lhs_min.range_bit_and(&rhs_min), + lhs_min.range_bit_and(&rhs_max), + lhs_max.range_bit_and(&rhs_min), + lhs_max.range_bit_and(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_and(&zero)); + candidates.push(lhs_max.range_bit_and(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_and(&negative_one)); + candidates.push(lhs_max.range_bit_and(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitOr => { + let mut candidates = vec![ + lhs_min.range_bit_or(&rhs_min), + lhs_min.range_bit_or(&rhs_max), + lhs_max.range_bit_or(&rhs_min), + lhs_max.range_bit_or(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_or(&zero)); + candidates.push(lhs_max.range_bit_or(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_or(&negative_one)); + candidates.push(lhs_max.range_bit_or(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitXor => { + let mut candidates = vec![ + lhs_min.range_bit_xor(&rhs_min), + lhs_min.range_bit_xor(&rhs_max), + lhs_max.range_bit_xor(&rhs_min), + lhs_max.range_bit_xor(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + // if the rhs contains zero, in xor, thats just itself + candidates.push(lhs_max.range_bit_xor(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_xor(&negative_one)); + candidates.push(lhs_max.range_bit_xor(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitNot => { + let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + + let min_contains = matches!( + lhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + lhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + match lhs_min { + Elem::Concrete( + r @ RangeConcrete { + val: Concrete::Uint(..), + .. + }, + ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), + Elem::Concrete( + r @ RangeConcrete { + val: Concrete::Int(..), + .. + }, + ) => candidates.push(Some(Elem::from(Concrete::min(&r.val).unwrap()))), + _ => {} + } + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Concat => { + // TODO: improve with smarter stuff + let candidates = vec![ + lhs_min.range_concat(&rhs_min), + lhs_min.range_concat(&rhs_max), + lhs_max.range_concat(&rhs_min), + lhs_max.range_concat(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(Elem::Expr(self.clone())); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + _ => Elem::Expr(self.clone()), + }; + Ok(res) + } +} diff --git a/crates/range/exec/modulo.rs b/crates/range/exec/modulo.rs new file mode 100644 index 00000000..5e1278ef --- /dev/null +++ b/crates/range/exec/modulo.rs @@ -0,0 +1,45 @@ +pub trait RangeMod { + /// Perform modulo between two range elements + fn range_mod(&self, other: &Rhs) -> Option>; +} + +impl RangeMod for RangeConcrete { + fn range_mod(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val % rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from_raw(*val) % *neg_v), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *neg_v % I256::from_raw(*val)), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, *l % *r), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeMod for Elem { + fn range_mod(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mod(b), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/mul.rs b/crates/range/exec/mul.rs new file mode 100644 index 00000000..6a9da09b --- /dev/null +++ b/crates/range/exec/mul.rs @@ -0,0 +1,108 @@ +pub trait RangeMul { + /// Perform multiplication between two range elements + fn range_mul(&self, other: &Rhs) -> Option>; + fn range_wrapping_mul(&self, other: &Rhs) -> Option>; +} + +impl RangeMul for RangeConcrete { + fn range_mul(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let max = Concrete::max(&self.val).unwrap(); + let res = lhs_val + .saturating_mul(rhs_val) + .min(max.into_u256().unwrap()); + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(res), + loc: self.loc, + })) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) + }; + let min = max * I256::from(-1i32) - I256::from(1i32); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + neg_v.saturating_mul(I256::from_raw(*val)).max(min), + ), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) + }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.saturating_mul(*r).min(max)), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_wrapping_mul(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let _max = Concrete::max(&self.val).unwrap(); + let res = lhs_val.overflowing_mul(rhs_val).0; + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(res), + loc: self.loc, + })) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + neg_v.overflowing_mul(I256::from_raw(*val)).0, + ), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.overflowing_mul(*r).0), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeMul for Elem { + fn range_mul(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mul(b), + (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { + Some(other.clone()) + } + _ => None, + } + } + + fn range_wrapping_mul(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_mul(b), + (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { + Some(other.clone()) + } + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/ord.rs b/crates/range/exec/ord.rs new file mode 100644 index 00000000..cd9b9431 --- /dev/null +++ b/crates/range/exec/ord.rs @@ -0,0 +1,228 @@ +pub trait RangeOrd { + /// Perform a logical equality test + fn range_ord_eq(&self, other: &Rhs) -> Option>; + /// Perform a logical inequality test + fn range_neq(&self, other: &Rhs) -> Option>; + /// Perform a logical greater than test + fn range_gt(&self, other: &Rhs) -> Option>; + /// Perform a logical less than test + fn range_lt(&self, other: &Rhs) -> Option>; + /// Perform a logical greater than or equal test + fn range_gte(&self, other: &Rhs) -> Option>; + /// Perform a logical less than or equal test + fn range_lte(&self, other: &Rhs) -> Option>; +} + +impl RangeOrd for RangeConcrete { + fn range_ord_eq(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val == rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_, _), Concrete::Int(_, _)) + | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l == r), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_neq(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val != rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_, _), Concrete::Int(_, _)) + | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l != r), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_gt(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val > rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l > r), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_lt(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val < rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l < r), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_gte(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val >= rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l >= r), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_lte(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(lhs_val <= rhs_val), + loc: self.loc, + })), + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: self.loc, + })) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(l <= r), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeOrd for Elem { + fn range_ord_eq(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_ord_eq(b), + _ => None, + } + } + fn range_neq(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_neq(b), + _ => None, + } + } + fn range_gt(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gt(b), + _ => None, + } + } + + fn range_lt(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lt(b), + _ => None, + } + } + + fn range_gte(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gte(b), + _ => None, + } + } + + fn range_lte(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lte(b), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/exec/shift.rs b/crates/range/exec/shift.rs new file mode 100644 index 00000000..c54cd8af --- /dev/null +++ b/crates/range/exec/shift.rs @@ -0,0 +1,165 @@ +pub trait RangeShift { + /// Perform a bitwise shift left + fn range_shl(&self, other: &Rhs) -> Option>; + /// Perform a bitwise shift right + fn range_shr(&self, other: &Rhs) -> Option>; +} + +impl RangeShift for RangeConcrete { + fn range_shl(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val > 256.into() { + return Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(U256::zero()), + loc: self.loc, + })); + } + let max = Concrete::max(&self.val).unwrap().into_u256().unwrap(); + if self.val.int_val().is_some() { + // ints get weird treatment because they can push into the negatives + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + self.val.int_size().unwrap(), + I256::from_raw(lhs_val << rhs_val), + ), + loc: self.loc, + })) + } else if rhs_val > lhs_val.leading_zeros().into() { + Some(Elem::Concrete(RangeConcrete { + val: max.into(), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original((lhs_val << rhs_val).min(max)), + loc: self.loc, + })) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + if val == &U256::zero() { + return Some(Elem::Concrete(self.clone())); + } + + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) + }; + + let min = max * I256::from(-1i32) - I256::from(1i32); + let (abs, is_min) = neg_v.overflowing_abs(); + if is_min { + if val > &U256::zero() { + Some(Elem::from(self.clone())) + } else { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::zero()), + loc: self.loc, + })) + } + } else if val > &U256::from(abs.leading_zeros()) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::zero()), + loc: self.loc, + })) + } else { + let raw = I256::from_raw(abs.into_raw() << val); + let as_int = if raw == I256::MIN { + raw + } else { + I256::from(-1i32) * raw + }; + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, as_int.max(min)), + loc: self.loc, + })) + } + } + _ => None, + }, + } + } + + fn range_shr(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val == U256::zero() { + Some(Elem::Concrete(self.clone())) + } else if rhs_val > U256::from(256) { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(U256::zero()), + loc: self.loc, + })) + } else { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val >> rhs_val), + loc: self.loc, + })) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + if val == &U256::zero() { + Some(Elem::Concrete(self.clone())) + } else if val > &U256::from(*lhs_size) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from(-1i32)), + loc: self.loc, + })) + } else { + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) + - I256::from(1) + }; + let min = max * I256::from(-1i32) - I256::from(1i32); + + let (abs, is_min) = neg_v.overflowing_abs(); + let bits = if is_min { + 255 + } else { + 255 - abs.leading_zeros() + }; + + if val >= &U256::from(bits) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, I256::from(-1i32)), + loc: self.loc, + })) + } else { + let shr_val = abs.into_raw() >> val; + let as_int = I256::from_raw(shr_val); + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + (I256::from(-1i32) * as_int).max(min), + ), + loc: self.loc, + })) + } + } + } + _ => None, + }, + } + } +} + +impl RangeShift for Elem { + fn range_shl(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_shl(b), + _ => None, + } + } + fn range_shr(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_shr(b), + _ => None, + } + } +} diff --git a/crates/range/exec/sub.rs b/crates/range/exec/sub.rs new file mode 100644 index 00000000..da7c3750 --- /dev/null +++ b/crates/range/exec/sub.rs @@ -0,0 +1,150 @@ +pub trait RangeSub { + /// Perform subtraction between two range elements + fn range_sub(&self, other: &Rhs) -> Option>; + fn range_wrapping_sub(&self, other: &Rhs) -> Option>; +} + +impl RangeSub for RangeConcrete { + fn range_sub(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if lhs_val > rhs_val { + let val = lhs_val.saturating_sub(rhs_val); + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(val), + loc: self.loc, + })) + } else { + match self.val { + Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(size, val.saturating_sub(I256::from_raw(rhs_val))), + loc: self.loc, + })), + _ => { + // TODO: this should cause a revert + let val = lhs_val.saturating_sub(rhs_val); + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(val), + loc: self.loc, + })) + } + } + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + let max = if *lhs_size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(*lhs_size)) - 1 + }; + Some(Elem::Concrete(RangeConcrete { + val: self + .val + .u256_as_original(val.saturating_add(neg_v.into_raw()).min(max)), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let max = if *lhs_size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) + }; + + let min = max * I256::from(-1i32) - I256::from(1i32); + + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + neg_v.saturating_sub(I256::from_raw(*val).max(min)), + ), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.saturating_sub(*r)), + loc: self.loc, + })) + } + _ => None, + }, + } + } + + fn range_wrapping_sub(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if lhs_val > rhs_val { + let val = lhs_val.overflowing_sub(rhs_val).0; + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(val), + loc: self.loc, + })) + } else { + match self.val { + Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + size, + val.overflowing_sub(I256::from_raw(rhs_val)).0, + ), + loc: self.loc, + })), + _ => { + let val = lhs_val.overflowing_sub(rhs_val).0; + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(val), + loc: self.loc, + })) + } + } + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, val), Concrete::Int(_, neg_v)) => { + Some(Elem::Concrete(RangeConcrete { + val: self + .val + .u256_as_original(val.overflowing_add(neg_v.into_raw()).0), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int( + *lhs_size, + I256::from_raw(neg_v.into_raw().overflowing_sub(*val).0), + ), + loc: self.loc, + })) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Int(*lhs_size, l.overflowing_sub(*r).0), + loc: self.loc, + })) + } + _ => None, + }, + } + } +} + +impl RangeSub for Elem { + fn range_sub(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + _ => None, + } + } + + fn range_wrapping_sub(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/range/mod.rs b/crates/range/mod.rs new file mode 100644 index 00000000..2cfa78e4 --- /dev/null +++ b/crates/range/mod.rs @@ -0,0 +1,9 @@ +mod elem; +mod exec; +mod solc_range; +mod range_string; + +pub use elem::*; +pub use exec::*; +pub use solc_range::*; +pub use range_string::*; diff --git a/crates/range/range_string.rs b/crates/range/range_string.rs new file mode 100644 index 00000000..eb73511d --- /dev/null +++ b/crates/range/range_string.rs @@ -0,0 +1,274 @@ +use crate::analyzer::GraphLike; +use crate::context::ContextVarNode; +use crate::range::elem::RangeElem; +use crate::range::elem::RangeOp; +use crate::range::elem_ty::Reference; +use crate::range::elem_ty::RangeExpr; +use crate::range::Elem; +use crate::range::RangeDyn; +use crate::Concrete; + +use std::collections::BTreeMap; + +use solang_parser::pt::Loc; + +/// A range element string consisting of a string and a location +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct RangeElemString { + pub s: String, + pub loc: Loc, +} + +impl RangeElemString { + /// Creates a new range element string from a string and a location + pub fn new(s: String, loc: Loc) -> Self { + Self { s, loc } + } +} + +/// A range string consisting of stringified range elements +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct RangeString { + pub min: RangeElemString, + pub max: RangeElemString, +} + +impl RangeString { + /// Creates a new range string from a min and max [`RangeElemString`] + pub fn new(min: RangeElemString, max: RangeElemString) -> Self { + Self { min, max } + } +} + +/// String related functions for ranges +pub trait ToRangeString { + /// Gets the definition string of the range element + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString; + /// Converts a range to a human string + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString; +} + +impl ToRangeString for Elem { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + match self { + Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), + Elem::Reference(Reference { idx, .. }) => { + let cvar = ContextVarNode::from(*idx) + .first_version(analyzer) + .underlying(analyzer) + .unwrap(); + RangeElemString::new(cvar.display_name.clone(), cvar.loc.unwrap_or(Loc::Implicit)) + } + Elem::ConcreteDyn(rd) => rd.def_string(analyzer), + Elem::Expr(expr) => expr.def_string(analyzer), + Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + } + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + match self { + Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), + Elem::Reference(Reference { idx, .. }) => { + let as_var = ContextVarNode::from(*idx); + let name = as_var.display_name(analyzer).unwrap(); + RangeElemString::new(name, as_var.loc(analyzer).unwrap()) + } + Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), + Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), + Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + } + } +} + +impl ToRangeString for RangeDyn { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + let displayed_vals = self + .val + .iter() + .take(20) + .map(|(key, val)| (key.minimize(analyzer).unwrap(), val)) + .collect::>(); + + let val_str = displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + + RangeElemString::new( + format!( + "{{len: {}, indices: [{}]}}", + self.len.to_range_string(false, analyzer).s, + val_str + ), + self.loc, + ) + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + let val_str = if self.val.len() > 10 { + let displayed_vals = self + .val + .iter() + .take(5) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + let val_str_head = displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + + let displayed_vals_tail = self + .val + .iter() + .rev() + .take(5) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + let val_str_tail = displayed_vals_tail + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + format!("{val_str_head} ... {val_str_tail}") + } else { + let displayed_vals = self + .val + .iter() + .take(10) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", ") + }; + + RangeElemString::new( + format!( + "{{len: {}, indices: {{{}}}}}", + self.len.to_range_string(maximize, analyzer).s, + val_str + ), + self.loc, + ) + } +} + +impl ToRangeString for RangeExpr { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + self.lhs.def_string(analyzer) + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); + let lhs_str = match *self.lhs { + Elem::Expr(_) => { + let new_str = format!("({})", lhs_r_str.s); + RangeElemString::new(new_str, lhs_r_str.loc) + } + _ => lhs_r_str, + }; + + let rhs_r_str = self.rhs.to_range_string(maximize, analyzer); + + let rhs_str = match *self.rhs { + Elem::Expr(_) => { + let new_str = format!("({})", rhs_r_str.s); + RangeElemString::new(new_str, rhs_r_str.loc) + } + _ => rhs_r_str, + }; + + if matches!(self.op, RangeOp::Min | RangeOp::Max) { + RangeElemString::new( + format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), + lhs_str.loc, + ) + } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { + let rhs = if maximize { + self.rhs.maximize(analyzer).unwrap() + } else { + self.rhs.minimize(analyzer).unwrap() + }; + + match rhs { + Elem::Concrete(c) => RangeElemString::new( + format!( + "{}({})", + c.val.as_builtin().as_string(analyzer).unwrap(), + lhs_str.s + ), + lhs_str.loc, + ), + _ => RangeElemString::new( + format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), + lhs_str.loc, + ), + } + } else if matches!(self.op, RangeOp::BitNot) { + let lhs = if maximize { + self.lhs.maximize(analyzer).unwrap() + } else { + self.lhs.minimize(analyzer).unwrap() + }; + + match lhs { + Elem::Concrete(_c) => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), + _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), + } + } else { + RangeElemString::new( + format!("{} {} {}", lhs_str.s, self.op.to_string(), rhs_str.s), + lhs_str.loc, + ) + } + } +} diff --git a/crates/range/solc_range.rs b/crates/range/solc_range.rs new file mode 100644 index 00000000..33d01683 --- /dev/null +++ b/crates/range/solc_range.rs @@ -0,0 +1,744 @@ +use crate::analyzer::AsDotStr; +use crate::analyzer::GraphError; +use crate::analyzer::GraphLike; +use crate::context::ContextNode; +use crate::context::ContextVarNode; +use crate::range::elem::RangeElem; +use crate::range::elem::RangeOp; + +use crate::range::elem_ty::Elem; +use crate::range::elem_ty::RangeConcrete; +use crate::range::elem_ty::RangeDyn; +use crate::range::range_string::ToRangeString; +use crate::Builtin; +use crate::Concrete; + +use crate::NodeIdx; +use ethers_core::types::Address; +use ethers_core::types::H256; +use ethers_core::types::I256; +use ethers_core::types::U256; +use std::collections::BTreeMap; + +use solang_parser::pt::Loc; + +#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct SolcRange { + pub min: Elem, + pub min_cached: Option>, + pub max: Elem, + pub max_cached: Option>, + pub exclusions: Vec>, +} + +impl AsDotStr for SolcRange { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + format!( + "[{}, {}] excluding: [{}]", + self.evaled_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s, + self.evaled_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s, + self.exclusions + .iter() + .map(|excl| excl.to_range_string(false, analyzer).s) + .collect::>() + .join(", ") + ) + } +} + +impl From for SolcRange { + fn from(b: bool) -> Self { + let val = Elem::Concrete(RangeConcrete { + val: Concrete::Bool(b), + loc: Loc::Implicit, + }); + Self::new(val.clone(), val, vec![]) + } +} + +impl SolcRange { + pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { + Self { + min, + min_cached: None, + max, + max_cached: None, + exclusions, + } + } + + pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + let min = self.evaled_range_min(analyzer)?; + let max = self.evaled_range_max(analyzer)?; + Ok(min.range_eq(&max)) + } + + pub fn min_is_negative(&self, analyzer: &impl GraphLike) -> Result { + self.min.is_negative(false, analyzer) + } + + pub fn default_bool() -> Self { + let min = Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: Loc::Implicit, + }); + let max = Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: Loc::Implicit, + }); + Self::new(min, max, vec![]) + } + pub fn from(c: Concrete) -> Option { + match c { + c @ Concrete::Uint(_, _) + | c @ Concrete::Int(_, _) + | c @ Concrete::Bool(_) + | c @ Concrete::Address(_) + | c @ Concrete::Bytes(_, _) => Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: c.clone(), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: c, + loc: Loc::Implicit, + }), + vec![], + )), + Concrete::String(s) => { + let val = s + .chars() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let mut bytes = [0x00; 32]; + v.encode_utf8(&mut bytes[..]); + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + let r = Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(s.len()))), + val, + loc: Loc::Implicit, + })); + Some(SolcRange::new(r.clone(), r, vec![])) + } + Concrete::DynBytes(b) => { + let val = b + .iter() + .enumerate() + .map(|(i, v)| { + let idx = Elem::from(Concrete::from(U256::from(i))); + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (idx, v) + }) + .collect::>(); + let r = Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::from(b.len()))), + val, + loc: Loc::Implicit, + })); + Some(SolcRange::new(r.clone(), r, vec![])) + } + _e => None, + } + } + + pub fn try_from_builtin(builtin: &Builtin) -> Option { + match builtin { + Builtin::Uint(size) => { + if *size == 256 { + Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, 0.into()), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, U256::MAX), + loc: Loc::Implicit, + }), + vec![], + )) + } else { + Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, 0.into()), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(*size, U256::from(2).pow(U256::from(*size)) - 1), + loc: Loc::Implicit, + }), + vec![], + )) + } + } + Builtin::Int(size) => { + if *size == 256 { + Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, I256::MIN), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, I256::MAX), + loc: Loc::Implicit, + }), + vec![], + )) + } else { + let max: I256 = + I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1); + let min = max * I256::from(-1i32) - I256::from(1i32); + Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, min), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Int(*size, max), + loc: Loc::Implicit, + }), + vec![], + )) + } + } + Builtin::Bool => Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc: Loc::Implicit, + }), + vec![], + )), + Builtin::Address | Builtin::Payable | Builtin::AddressPayable => Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Address(Address::from_slice(&[0x00; 20])), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Address(Address::from_slice(&[0xff; 20])), + loc: Loc::Implicit, + }), + vec![], + )), + Builtin::Bytes(size) => { + let v: Vec<_> = (0..32u8) + .map(|i| if i < *size { 0xff } else { 0x00 }) + .collect(); + Some(SolcRange::new( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*size, H256::from_slice(&[0x00; 32])), + loc: Loc::Implicit, + }), + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(*size, H256::from_slice(&v[..])), + loc: Loc::Implicit, + }), + vec![], + )) + } + Builtin::ReferenceBytes + | Builtin::String + | Builtin::Array(_) + | Builtin::Mapping(_, _) => Some(SolcRange::new( + Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::zero())), + val: Default::default(), + loc: Loc::Implicit, + })), + Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(U256::MAX)), + val: Default::default(), + loc: Loc::Implicit, + })), + vec![], + )), + Builtin::SizedArray(s, _) => Some(SolcRange::new( + Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(*s)), + val: Default::default(), + loc: Loc::Implicit, + })), + Elem::ConcreteDyn(Box::new(RangeDyn { + minimized: None, + maximized: None, + len: Elem::from(Concrete::from(*s)), + val: Default::default(), + loc: Loc::Implicit, + })), + vec![], + )), + _ => None, + } + } + + pub fn lte_dyn(self, other: ContextVarNode) -> Self { + Self::new(self.min, self.max.min(Elem::from(other)), self.exclusions) + } + + pub fn gte_dyn(self, other: ContextVarNode) -> Self { + Self::new(self.min.max(Elem::from(other)), self.max, self.exclusions) + } + + pub fn lt_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min, + self.max.min( + Elem::from(other) + - Elem::Concrete(RangeConcrete { + val: U256::from(1).into(), + loc: Loc::Implicit, + }), + ), + self.exclusions, + ) + } + + pub fn gt_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.max( + Elem::from(other) + + Elem::Concrete(RangeConcrete { + val: U256::from(1).into(), + loc: Loc::Implicit, + }), + ), + self.max, + self.exclusions, + ) + } + + pub fn dyn_fn_from_op(op: RangeOp) -> &'static dyn Fn(SolcRange, ContextVarNode) -> SolcRange { + match op { + RangeOp::Add(false) => &Self::add_dyn, + RangeOp::Add(true) => &Self::wrapping_add_dyn, + RangeOp::Sub(false) => &Self::sub_dyn, + RangeOp::Sub(true) => &Self::wrapping_sub_dyn, + RangeOp::Mul(false) => &Self::mul_dyn, + RangeOp::Mul(true) => &Self::wrapping_mul_dyn, + RangeOp::Div(false) => &Self::div_dyn, + RangeOp::Div(true) => &Self::wrapping_mul_dyn, + RangeOp::Shr => &Self::shr_dyn, + RangeOp::Shl => &Self::shl_dyn, + RangeOp::Mod => &Self::mod_dyn, + RangeOp::Min => &Self::min_dyn, + RangeOp::Max => &Self::max_dyn, + RangeOp::Lt => &Self::lt_dyn, + RangeOp::Lte => &Self::lte_dyn, + RangeOp::Gt => &Self::gt_dyn, + RangeOp::Gte => &Self::gte_dyn, + RangeOp::Eq => &Self::eq_dyn, + RangeOp::Neq => &Self::neq_dyn, + RangeOp::Exp => &Self::exp_dyn, + RangeOp::BitAnd => &Self::bit_and_dyn, + RangeOp::BitOr => &Self::bit_or_dyn, + RangeOp::BitXor => &Self::bit_xor_dyn, + // RangeOp::And => ( + // &Self::and_dyn, + // (DynSide::Min, DynSide::Max), + // ), + // RangeOp::Or => ( + // &Self::or_dyn, + // (DynSide::Min, DynSide::Max), + // ), + e => unreachable!("Comparator operations shouldn't exist in a range: {:?}", e), + } + } + + pub fn add_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min + Elem::from(other), + self.max + Elem::from(other), + self.exclusions, + ) + } + + pub fn wrapping_add_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.wrapping_add(Elem::from(other)), + self.max.wrapping_add(Elem::from(other)), + self.exclusions, + ) + } + + pub fn sub_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min - Elem::from(other), + self.max - Elem::from(other), + self.exclusions, + ) + } + + pub fn wrapping_sub_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.wrapping_sub(Elem::from(other)), + self.max.wrapping_sub(Elem::from(other)), + self.exclusions, + ) + } + + pub fn mul_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min * Elem::from(other), + self.max * Elem::from(other), + self.exclusions, + ) + } + + pub fn wrapping_mul_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.wrapping_mul(Elem::from(other)), + self.max.wrapping_mul(Elem::from(other)), + self.exclusions, + ) + } + + pub fn exp_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.pow(Elem::from(other)), + self.max.pow(Elem::from(other)), + self.exclusions, + ) + } + + pub fn bit_and_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min & Elem::from(other), + self.max & Elem::from(other), + self.exclusions, + ) + } + + pub fn bit_or_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min | Elem::from(other), + self.max | Elem::from(other), + self.exclusions, + ) + } + + pub fn bit_xor_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min ^ Elem::from(other), + self.max ^ Elem::from(other), + self.exclusions, + ) + } + + pub fn div_dyn(self, other: ContextVarNode) -> Self { + let elem = Elem::from(other); + Self::new(self.min / elem.clone(), self.max / elem, self.exclusions) + } + + pub fn wrapping_div_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.wrapping_div(Elem::from(other)), + self.max.wrapping_div(Elem::from(other)), + self.exclusions, + ) + } + + pub fn shl_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min << Elem::from(other), + self.max << Elem::from(other), + self.exclusions, + ) + } + + pub fn shr_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min >> Elem::from(other), + self.max >> Elem::from(other), + self.exclusions, + ) + } + + pub fn mod_dyn(self, other: ContextVarNode) -> Self { + let elem = Elem::from(other); + Self::new( + Elem::from(Concrete::from(U256::zero())), + elem.clone() - Elem::from(Concrete::from(U256::from(1))).cast(elem), + self.exclusions, + ) + } + + pub fn min_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.min(Elem::from(other)), + self.max.min(Elem::from(other)), + self.exclusions, + ) + } + + pub fn max_dyn(self, other: ContextVarNode) -> Self { + Self::new( + self.min.max(Elem::from(other)), + self.max.max(Elem::from(other)), + self.exclusions, + ) + } + + pub fn eq_dyn(self, other: ContextVarNode) -> Self { + let min = self.min.eq(Elem::from(other)); + let max = self.max.eq(Elem::from(other)); + Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) + } + + pub fn neq_dyn(self, other: ContextVarNode) -> Self { + let min = self.min.neq(Elem::from(other)); + let max = self.max.neq(Elem::from(other)); + Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) + } +} + +impl Range for SolcRange { + type ElemTy = Elem; + fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy> { + std::borrow::Cow::Borrowed(&self.min) + } + fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy> { + std::borrow::Cow::Borrowed(&self.max) + } + fn range_min_mut(&mut self) -> &mut Self::ElemTy { + &mut self.min + } + fn range_max_mut(&mut self) -> &mut Self::ElemTy { + &mut self.max + } + + fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + if self.min_cached.is_none() { + let min = self.range_min_mut(); + min.cache_minimize(analyzer)?; + self.min_cached = Some(self.range_min().minimize(analyzer)?); + } + if self.max_cached.is_none() { + let max = self.range_max_mut(); + max.cache_maximize(analyzer)?; + self.max_cached = Some(self.range_max().maximize(analyzer)?); + } + Ok(()) + } + + fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result { + if let Some(cached) = &self.min_cached { + Ok(cached.clone()) + } else { + self.range_min().minimize(analyzer) + } + } + + fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result { + if let Some(cached) = &self.max_cached { + Ok(cached.clone()) + } else { + self.range_max().maximize(analyzer) + } + } + + fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result { + println!("simplified range min"); + self.range_min().simplify_minimize(analyzer) + } + fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result { + println!("simplified range max"); + self.range_max().simplify_maximize(analyzer) + } + fn range_exclusions(&self) -> Vec { + self.exclusions.clone() + } + fn set_range_min(&mut self, new: Self::ElemTy) { + self.min_cached = None; + self.min = new; + } + fn set_range_max(&mut self, new: Self::ElemTy) { + self.max_cached = None; + self.max = new; + } + + fn add_range_exclusion(&mut self, new: Self::ElemTy) { + if !self.exclusions.contains(&new) { + self.exclusions.push(new); + } + } + fn set_range_exclusions(&mut self, new: Vec) { + self.exclusions = new; + } + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { + self.min.filter_recursion(self_idx, new_idx); + } + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { + self.max.filter_recursion(self_idx, new_idx); + } +} + +pub trait Range { + type ElemTy: RangeElem + Clone; + fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; + fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; + fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result; + fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result; + fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; + fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy>; + fn uncache_range_min(&mut self) { + self.range_min_mut().uncache(); + } + fn uncache_range_max(&mut self) { + self.range_max_mut().uncache(); + } + fn range_min_mut(&mut self) -> &mut Self::ElemTy; + fn range_max_mut(&mut self) -> &mut Self::ElemTy; + fn range_exclusions(&self) -> Vec + where + Self: std::marker::Sized; + fn set_range_min(&mut self, new: Self::ElemTy); + fn set_range_max(&mut self, new: Self::ElemTy); + fn set_range_exclusions(&mut self, new: Vec) + where + Self: std::marker::Sized; + fn add_range_exclusion(&mut self, new: Self::ElemTy) + where + Self: std::marker::Sized; + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + fn dependent_on(&self) -> Vec { + let mut deps = self.range_min().dependent_on(); + deps.extend(self.range_max().dependent_on()); + deps + } + + fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphLike) { + let deps = self.dependent_on(); + let mapping: BTreeMap = deps + .into_iter() + .filter(|dep| !dep.is_const(analyzer).unwrap()) + .map(|dep| { + let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); + if latest == node { + if let Some(prev) = latest.previous_version(analyzer) { + (dep, prev) + } else { + (dep, dep) + } + } else { + (dep, latest) + } + }) + .collect(); + + let mut min = self.range_min().into_owned(); + let mut max = self.range_max().into_owned(); + min.update_deps(&mapping); + max.update_deps(&mapping); + self.set_range_min(min); + self.set_range_max(max); + } +} + +pub trait RangeEval>: Range { + fn sat(&self, analyzer: &impl GraphLike) -> bool; + fn unsat(&self, analyzer: &impl GraphLike) -> bool { + !self.sat(analyzer) + } + fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool; + fn contains_elem(&self, other: &T, analyzer: &impl GraphLike) -> bool; + fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool; +} + +impl RangeEval> for SolcRange { + fn sat(&self, analyzer: &impl GraphLike) -> bool { + matches!( + self.evaled_range_min(analyzer) + .unwrap() + .range_ord(&self.evaled_range_max(analyzer).unwrap()), + None | Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ) + } + + fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + let min_contains = matches!( + self.evaled_range_min(analyzer) + .unwrap() + .range_ord(&other.evaled_range_min(analyzer).unwrap()), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + self.evaled_range_max(analyzer) + .unwrap() + .range_ord(&other.evaled_range_max(analyzer).unwrap()), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + min_contains && max_contains + } + + fn contains_elem(&self, other: &Elem, analyzer: &impl GraphLike) -> bool { + let min_contains = match self + .evaled_range_min(analyzer) + .unwrap() + .range_ord(&other.minimize(analyzer).unwrap()) + { + Some(std::cmp::Ordering::Less) => true, + Some(std::cmp::Ordering::Equal) => return true, + _ => false, + }; + + let max_contains = match self + .evaled_range_max(analyzer) + .unwrap() + .range_ord(&other.maximize(analyzer).unwrap()) + { + Some(std::cmp::Ordering::Greater) => true, + Some(std::cmp::Ordering::Equal) => return true, + _ => false, + }; + + min_contains && max_contains + } + + fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + let lhs_min = self.evaled_range_min(analyzer).unwrap(); + let rhs_max = other.evaled_range_max(analyzer).unwrap(); + + match lhs_min.range_ord(&rhs_max) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = self.evaled_range_max(analyzer).unwrap(); + let rhs_min = other.evaled_range_min(analyzer).unwrap(); + matches!( + lhs_max.range_ord(&rhs_min), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) + } + Some(std::cmp::Ordering::Equal) => true, + _ => false, + } + } +} \ No newline at end of file From 628558a338a6a031fc017b5377ffe58c3879f1b7 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 13:02:28 -0800 Subject: [PATCH 02/71] more restructuring --- crates/analyzer/analyzers/bounds.rs | 318 ++++ .../analyzer/analyzers/func_analyzer/mod.rs | 378 ++++ .../analyzers/func_analyzer/report_display.rs | 92 + crates/analyzer/analyzers/mod.rs | 176 ++ crates/analyzer/analyzers/var_analyzer/mod.rs | 266 +++ .../analyzers/var_analyzer/report_display.rs | 106 ++ crates/cli/Cargo.lock | 1616 +++++++++++++++++ crates/cli/Cargo.toml | 23 + crates/cli/src/main.rs | 355 ++++ crates/graph/nodes/context/context_tys.rs | 35 - crates/pyrometer/builtin_fns.rs | 816 +++++++++ crates/pyrometer/lib.rs | 1134 ++++++++++++ crates/queries/mod.rs | 2 + crates/queries/storage_write/access.rs | 93 + crates/queries/storage_write/mod.rs | 5 + crates/queries/storage_write/target.rs | 156 ++ crates/queries/taint.rs | 68 + crates/solc_expressions/array.rs | 183 ++ crates/solc_expressions/bin_op.rs | 797 ++++++++ crates/solc_expressions/cmp.rs | 469 +++++ crates/solc_expressions/cond_op.rs | 194 ++ crates/solc_expressions/env.rs | 449 +++++ .../func_call/internal_call.rs | 287 +++ .../func_call/intrinsic_call.rs | 1060 +++++++++++ crates/solc_expressions/func_call/mod.rs | 1174 ++++++++++++ crates/solc_expressions/func_call/modifier.rs | 34 + .../func_call/namespaced_call.rs | 372 ++++ crates/solc_expressions/lib.rs | 190 ++ crates/solc_expressions/list.rs | 111 ++ crates/solc_expressions/literal.rs | 226 +++ crates/solc_expressions/loops.rs | 93 + crates/solc_expressions/member_access.rs | 1092 +++++++++++ crates/solc_expressions/require.rs | 1503 +++++++++++++++ crates/solc_expressions/variable.rs | 135 ++ crates/solc_expressions/yul/mod.rs | 343 ++++ crates/solc_expressions/yul/yul_cond_op.rs | 365 ++++ crates/solc_expressions/yul/yul_funcs.rs | 656 +++++++ shared/src/context/mod.rs | 1529 ---------------- 38 files changed, 15337 insertions(+), 1564 deletions(-) create mode 100644 crates/analyzer/analyzers/bounds.rs create mode 100644 crates/analyzer/analyzers/func_analyzer/mod.rs create mode 100644 crates/analyzer/analyzers/func_analyzer/report_display.rs create mode 100644 crates/analyzer/analyzers/mod.rs create mode 100644 crates/analyzer/analyzers/var_analyzer/mod.rs create mode 100644 crates/analyzer/analyzers/var_analyzer/report_display.rs create mode 100644 crates/cli/Cargo.lock create mode 100644 crates/cli/Cargo.toml create mode 100644 crates/cli/src/main.rs create mode 100644 crates/pyrometer/builtin_fns.rs create mode 100644 crates/pyrometer/lib.rs create mode 100644 crates/queries/mod.rs create mode 100644 crates/queries/storage_write/access.rs create mode 100644 crates/queries/storage_write/mod.rs create mode 100644 crates/queries/storage_write/target.rs create mode 100644 crates/queries/taint.rs create mode 100644 crates/solc_expressions/array.rs create mode 100644 crates/solc_expressions/bin_op.rs create mode 100644 crates/solc_expressions/cmp.rs create mode 100644 crates/solc_expressions/cond_op.rs create mode 100644 crates/solc_expressions/env.rs create mode 100644 crates/solc_expressions/func_call/internal_call.rs create mode 100644 crates/solc_expressions/func_call/intrinsic_call.rs create mode 100644 crates/solc_expressions/func_call/mod.rs create mode 100644 crates/solc_expressions/func_call/modifier.rs create mode 100644 crates/solc_expressions/func_call/namespaced_call.rs create mode 100644 crates/solc_expressions/lib.rs create mode 100644 crates/solc_expressions/list.rs create mode 100644 crates/solc_expressions/literal.rs create mode 100644 crates/solc_expressions/loops.rs create mode 100644 crates/solc_expressions/member_access.rs create mode 100644 crates/solc_expressions/require.rs create mode 100644 crates/solc_expressions/variable.rs create mode 100644 crates/solc_expressions/yul/mod.rs create mode 100644 crates/solc_expressions/yul/yul_cond_op.rs create mode 100644 crates/solc_expressions/yul/yul_funcs.rs diff --git a/crates/analyzer/analyzers/bounds.rs b/crates/analyzer/analyzers/bounds.rs new file mode 100644 index 00000000..2ea3d72a --- /dev/null +++ b/crates/analyzer/analyzers/bounds.rs @@ -0,0 +1,318 @@ +use crate::analyzers::FunctionVarsBoundAnalysis; +use crate::analyzers::VarBoundAnalysis; + +use crate::analyzers::LocSpan; +use crate::analyzers::{LocStrSpan, ReportConfig}; + +use shared::analyzer::GraphLike; +use shared::{ + context::*, + range::{range_string::*, Range, RangeEval, SolcRange}, +}; + +use ariadne::{Color, Fmt, Label, Span}; +use solang_parser::pt::StorageLocation; +use std::collections::{BTreeMap, BTreeSet}; + +pub static MIN_COLOR: Color = Color::Fixed(111); +pub static MAX_COLOR: Color = Color::Fixed(106); + +#[derive(PartialEq, Eq, Clone)] +pub struct AnalysisItem { + pub init: bool, + pub order: i32, + pub name: String, + pub loc: LocStrSpan, + pub storage: Option, + pub ctx: ContextNode, + pub ctx_conditionals: Vec<(String, Vec)>, + pub parts: Vec, + pub unsat: bool, +} + +#[derive(PartialEq, Eq, Clone, Debug, Hash)] +pub struct StrippedAnalysisItem { + pub init: bool, + pub order: i32, + pub name: String, + pub loc: LocSpan, + // pub storage: Option, + pub ctx: ContextNode, + pub ctx_conditionals: Vec<(String, Vec)>, + pub parts: Vec, + pub unsat: bool, +} + +impl From for StrippedAnalysisItem { + fn from(ai: AnalysisItem) -> Self { + Self { + init: ai.init, + order: ai.order, + name: ai.name, + loc: LocSpan(ai.loc.1), + // storage: ai.storage, + ctx: ai.ctx, + ctx_conditionals: ai.ctx_conditionals, + parts: ai.parts, + unsat: ai.unsat, + } + } +} + +impl PartialOrd for StrippedAnalysisItem { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for StrippedAnalysisItem { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.loc.0.cmp(&other.loc.0) + } +} + +#[derive(Default, Clone, Debug, Hash)] +pub struct OrderedAnalysis { + pub analyses: BTreeMap>, +} + +impl OrderedAnalysis { + pub fn from_bound_analysis(ba: VarBoundAnalysis, analyzer: &impl GraphLike) -> Self { + let mut analyses: BTreeMap> = Default::default(); + if let Some(init) = ba.init_item(analyzer) { + let source: usize = *LocSpan(init.loc.1).source(); + let mut set = BTreeSet::new(); + set.insert(init.into()); + analyses.insert(source, set); + } + ba.bound_changes + .iter() + .enumerate() + .for_each(|(i, bound_change)| { + let (parts, unsat) = range_parts(analyzer, &ba.report_config, &bound_change.1); + let item = StrippedAnalysisItem { + init: false, + name: ba.var_display_name.clone(), + loc: LocSpan(bound_change.0 .1), + order: i as i32, + // storage: ba.storage.clone(), + ctx: ba.ctx, + ctx_conditionals: ba.conditionals(analyzer), + parts, + unsat, + }; + + let entry = analyses + .entry(*LocSpan(bound_change.0 .1).source()) + .or_default(); + entry.insert(item); + }); + Self { analyses } + } + + pub fn from_func_analysis(fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphLike) -> Self { + let mut analyses = Self::default(); + fvba.vars_by_ctx.iter().for_each(|(_ctx, bas)| { + bas.iter().for_each(|ba| { + analyses.extend(Self::from_bound_analysis(ba.clone(), analyzer)); + }) + }); + analyses + } + + pub fn extend(&mut self, other: Self) { + other.analyses.into_iter().for_each(|(key, set)| { + let entry = self.analyses.entry(key).or_default(); + entry.extend(set); + }); + } +} + +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Hash)] +pub enum RangePart { + Equal(String), + Inclusion(String, String), + Exclusion(Vec), +} + +impl RangePart { + pub fn to_cli_string(self) -> String { + match self { + RangePart::Equal(val) => format!(" == {}", val), + RangePart::Inclusion(min, max) => { + format!(" ∈ [ {}, {} ]", min.fg(MIN_COLOR), max.fg(MAX_COLOR)) + } + RangePart::Exclusion(parts) => format!( + "&& ∉ {{{}}}", + parts + .into_iter() + .map(|p| p.to_cli_string()) + .collect::>() + .join(", ") + ) + .fg(Color::Red) + .to_string(), + } + } + + pub fn to_normal_string(&self) -> String { + match self { + e @ RangePart::Equal(_) => format!(" == {}", e.to_string()), + e @ RangePart::Inclusion(..) => format!(" ∈ {}", e.to_string()), + e @ RangePart::Exclusion(_) => format!("&& ∉ {{{}}}", e.to_string()), + } + } +} + +impl Into> for AnalysisItem { + fn into(self) -> ariadne::Label { + let (color, order, priority) = if self.init { + (Color::Magenta, self.order, -1) + } else { + ( + match self.storage { + Some(StorageLocation::Memory(..)) => Color::Blue, + Some(StorageLocation::Storage(..)) => Color::Green, + Some(StorageLocation::Calldata(..)) => Color::White, + None => Color::Cyan, + }, + self.order, + 0, + ) + }; + + Label::new(self.loc) + .with_message(format!( + "{}\"{}\"{}{}", + match self.storage { + Some(StorageLocation::Memory(..)) => "Memory var ", + Some(StorageLocation::Storage(..)) => "Storage var ", + Some(StorageLocation::Calldata(..)) => "Calldata var ", + None => "", + }, + self.name, + self.parts + .into_iter() + .map(|part| part.to_cli_string()) + .collect::>() + .join(" "), + if self.unsat { + " - unsatisfiable range, unreachable".fg(Color::Red) + } else { + "".fg(Color::Red) + } + )) + .with_color(color) + .with_order(order) + .with_priority(priority) + } +} + +impl ToString for StrippedAnalysisItem { + fn to_string(&self) -> String { + format!( + "{}{}{}", + // match self.storage { + // Some(StorageLocation::Memory(..)) => "Memory var ", + // Some(StorageLocation::Storage(..)) => "Storage var ", + // Some(StorageLocation::Calldata(..)) => "Calldata var ", + // None => "", + // }, + self.name, + self.parts + .iter() + .map(|part| part.to_normal_string()) + .collect::>() + .join(" "), + if self.unsat { + " - unsatisfiable range, unreachable" + } else { + "" + } + ) + } +} + +impl ToString for RangePart { + fn to_string(&self) -> String { + match self { + RangePart::Equal(inner) => inner.to_string(), + RangePart::Inclusion(min, max) => format!("[ {}, {} ]", min, max), + RangePart::Exclusion(inner) => format!( + "{{{}}}", + inner + .iter() + .map(|part| part.to_string()) + .collect::>() + .join(", ") + ), + } + } +} + +/// Creates an Vec<[RangePart]> from a range based on the current [ReportConfig] +pub fn range_parts( + analyzer: &impl GraphLike, + report_config: &ReportConfig, + range: &SolcRange, +) -> (Vec, bool) { + let mut parts = vec![]; + let min = if report_config.eval_bounds { + range + .evaled_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s + } else if report_config.simplify_bounds { + range + .simplified_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s + } else { + range.range_min().to_range_string(false, analyzer).s + }; + let max = if report_config.eval_bounds { + range + .evaled_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s + } else if report_config.simplify_bounds { + range + .simplified_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s + } else { + range.range_max().to_range_string(true, analyzer).s + }; + + if min == max { + parts.push(RangePart::Equal(min)); + } else { + parts.push(RangePart::Inclusion(min, max)); + } + + let range_excl = range.range_exclusions(); + if !range_excl.is_empty() { + parts.push(RangePart::Exclusion({ + let mut excls = range_excl + .iter() + .map(|range| { + let min = range.to_range_string(false, analyzer).s; + let max = range.to_range_string(true, analyzer).s; + if min == max { + RangePart::Equal(min) + } else { + RangePart::Inclusion(min, max) + } + }) + .collect::>(); + excls.dedup(); + excls + })); + } + let unsat = range.unsat(analyzer); + (parts, unsat) +} diff --git a/crates/analyzer/analyzers/func_analyzer/mod.rs b/crates/analyzer/analyzers/func_analyzer/mod.rs new file mode 100644 index 00000000..3ff556b1 --- /dev/null +++ b/crates/analyzer/analyzers/func_analyzer/mod.rs @@ -0,0 +1,378 @@ +use crate::analyzers::range_parts; +use crate::analyzers::VarBoundAnalysis; +use crate::analyzers::VarBoundAnalyzer; + +use crate::analyzers::{LocStrSpan, ReportConfig, ReportDisplay}; +use ariadne::ReportKind; +use std::collections::BTreeSet; + +use shared::analyzer::GraphLike; +use shared::{ + analyzer::{AnalyzerLike, Search}, + context::*, +}; + +use ariadne::{Color, Config, Fmt, Label, Report, Span}; +use solang_parser::pt::CodeLocation; +use std::collections::BTreeMap; + +mod report_display; +pub use report_display::*; + +#[derive(Debug, Clone)] +pub struct FunctionVarsBoundAnalysis { + /// Entry context location string span + pub ctx_loc: LocStrSpan, + /// Entry context + pub ctx: ContextNode, + /// If the context was killed (i.e. a `return` or `revert` of some kind), the location string span + pub ctx_killed: Option<(LocStrSpan, KilledKind)>, + /// The report configuration + pub report_config: ReportConfig, + /// Mapping of context node (i.e. for the lineage of the entry context) to a vector of bound analyses + pub vars_by_ctx: BTreeMap>, +} + +impl<'a> FunctionVarsBoundAnalysis { + pub fn as_cli_compat( + self, + file_mapping: &'a BTreeMap, + ) -> CLIFunctionVarsBoundAnalysis<'a> { + CLIFunctionVarsBoundAnalysis::new(file_mapping, self) + } + + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Bounds", Color::Cyan) + } + + pub fn reports_for_forks( + &self, + file_mapping: &'a BTreeMap, + analyzer: &impl GraphLike, + ) -> Vec> { + let mut handled_ctx_switches = BTreeSet::default(); + let reports = self + .vars_by_ctx + .iter() + .map(|(ctx, analyses)| { + // sort by display name instead of normal name + let deps = ctx.ctx_deps(analyzer).unwrap(); + let deps = deps + .values() + .map(|var| (var.display_name(analyzer).unwrap(), var)) + .collect::>(); + // create the bound strings + let bounds_string = deps + .iter() + .enumerate() + .filter_map(|(i, (name, cvar))| { + let range = cvar.ref_range(analyzer).unwrap()?; + let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); + let ret = parts.into_iter().fold( + format!("{}. {name}", i + 1), + |mut acc, part| { + acc = format!("{acc}{}", part.to_cli_string()); + acc + }, + ); + Some(format!("{ret}\n")) + }) + .collect::>() + .join(""); + let mut report = Report::build( + self.report_kind(), + self.ctx_loc.source(), + self.ctx_loc.start(), + ) + .with_message(format!( + "Bounds for subcontext: {}{}{}, killed: {:?}", + ctx.path(analyzer).fg(Color::Cyan), + if bounds_string.is_empty() { + "" + } else { + " where:\n" + }, + bounds_string.fg(Color::Yellow), + ctx.underlying(analyzer).unwrap().killed + )) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4) + .with_multiline_arrows(false), + ); + + let mut self_handled = false; + let mut added_bodies = vec![]; + let mut labels: Vec<_> = analyses + .iter() + .flat_map(|analysis| { + let mut labels = analysis.labels(analyzer); + labels.extend( + analysis + .spanned_ctx_info + .clone() + .into_iter() + .filter_map(|ctx_switch| { + let mut is_self = false; + if ctx_switch.ctx == *ctx + || ctx_switch.ctx.underlying(analyzer).unwrap().depth == 0 + { + self_handled = true; + is_self = true; + } + + if let Some(body) = ctx_switch.func_body_span { + if added_bodies.contains(&body) { + return None; + } + added_bodies.push(body.clone()); + if is_self { + Some( + Label::new(body) + .with_message("Entry function call") + .with_color(Color::White) + .with_priority(-2) + .with_order(-2), + ) + } else { + Some( + Label::new(body) + .with_message("Function call") + .with_color(Color::Fixed(140)) + .with_priority(-2) + .with_order(-2), + ) + } + } else { + if added_bodies.contains(&ctx_switch.func_span) { + return None; + } + added_bodies.push(ctx_switch.func_span.clone()); + if is_self { + Some( + Label::new(ctx_switch.func_span) + .with_message("Entry function call") + .with_color(Color::White) + .with_priority(-2) + .with_order(-2), + ) + } else { + Some( + Label::new(ctx_switch.func_span) + .with_message("Function call") + .with_color(Color::Fixed(140)) + .with_priority(-2) + .with_order(-2), + ) + } + } + }) + .collect::>(), + ); + + analysis.spanned_ctx_info.iter().for_each(|ctx_switch| { + if !handled_ctx_switches.contains(ctx_switch) { + handled_ctx_switches.insert(ctx_switch); + if ctx_switch.ctx != *ctx { + labels.extend( + ctx_switch + .ctx + .return_nodes(analyzer) + .unwrap() + .into_iter() + .filter_map(|(loc, var)| { + let range = var.ref_range(analyzer).unwrap()?; + let (parts, _unsat) = range_parts( + analyzer, + &self.report_config, + &range, + ); + Some( + Label::new(LocStrSpan::new(file_mapping, loc)) + .with_message( + format!( + "returns: \"{}\"{}", + var.display_name(analyzer).unwrap(), + parts + .into_iter() + .map(|i| i.to_cli_string()) + .collect::>() + .join(", ") + ) + .fg(Color::Yellow), + ) + .with_color(Color::Yellow) + .with_order(50), + ) + }) + .collect::>(), + ); + } + if ctx_switch.ctx == *ctx { + if let Some((killed_loc, kind)) = &ctx_switch.killed_loc { + labels.push( + Label::new(killed_loc.clone()) + .with_message(kind.analysis_str()) + .with_color(Color::Red) + .with_priority(10), + ); + } + self_handled = true; + } + } + }); + labels + }) + .collect(); + + if let Some((killed_span, kind)) = &self.ctx_killed { + if !self_handled { + labels.push( + Label::new(killed_span.clone()) + .with_message(kind.analysis_str().fg(Color::Red)) + .with_color(Color::Red), + ); + } + } + + labels.extend( + ctx.return_nodes(analyzer) + .unwrap() + .into_iter() + .filter_map(|(loc, var)| { + let range = var.ref_range(analyzer).unwrap()?; + let (parts, _unsat) = + range_parts(analyzer, &self.report_config, &range); + Some( + Label::new(LocStrSpan::new(file_mapping, loc)) + .with_message( + format!( + "returns: \"{}\"{}", + var.display_name(analyzer).unwrap(), + parts + .into_iter() + .map(|i| i.to_cli_string()) + .collect::>() + .join(", ") + ) + .fg(Color::Yellow), + ) + .with_color(Color::Yellow) + .with_order(50), + ) + }) + .collect::>(), + ); + if !self_handled { + if let Some(body) = ctx + .associated_fn(analyzer) + .unwrap() + .underlying(analyzer) + .unwrap() + .body + .as_ref() + { + report.add_label( + Label::new(LocStrSpan::new(file_mapping, body.loc())) + .with_message("Entry function call") + .with_priority(-2) + .with_order(-2), + ); + } + } + + report.add_labels(labels); + report.finish() + }) + .collect::>>(); + reports + } +} + +impl FunctionVarsBoundAnalyzer for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} +pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerLike + Sized { + fn bounds_for_all<'a>( + &'a self, + file_mapping: &'a BTreeMap, + ctx: ContextNode, + report_config: ReportConfig, + ) -> FunctionVarsBoundAnalysis { + let mut edges = ctx.all_edges(self).unwrap(); + if edges.is_empty() { + edges.push(ctx); + } + let lineage_analyses = edges + .iter() + .filter_map(|fork| { + if !report_config.show_unreachables + && matches!( + fork.underlying(self).unwrap().killed, + Some((_, KilledKind::Unreachable)) + ) + { + return None; + } + if !report_config.show_nonreverts + && matches!(fork.underlying(self).unwrap().killed, None) + { + return None; + } + if !report_config.show_reverts + && matches!( + fork.underlying(self).unwrap().killed, + Some((_, KilledKind::Revert)) + ) + { + return None; + } + let mut parents = fork.parent_list(self).unwrap(); + parents.reverse(); + parents.push(*fork); + let mut vars = ctx.vars(self).values().collect::>(); + vars.extend( + parents + .iter() + .flat_map(|parent| parent.vars(self).values().collect::>()) + .collect::>(), + ); + vars.sort_by_key(|a| a.name(self)); + vars.dedup_by(|a, b| a.name(self) == b.name(self)); + Some(( + *fork, + vars.iter() + .filter_map(|var| { + let is_ret = var.is_return_node_in_any(&parents, self); + if is_ret + | report_config.show_tmps + | (report_config.show_consts && var.is_const(self).unwrap()) + | (report_config.show_symbolics && var.is_symbolic(self).unwrap()) + { + Some(self.bounds_for_var_in_family_tree( + file_mapping, + parents.clone(), + var.name(self).unwrap(), + report_config, + )) + } else { + None + } + }) + .collect::>(), + )) + }) + .collect::>>(); + + FunctionVarsBoundAnalysis { + ctx_loc: LocStrSpan::new(file_mapping, ctx.underlying(self).unwrap().loc), + ctx, + ctx_killed: ctx + .killed_loc(self) + .unwrap() + .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), + vars_by_ctx: lineage_analyses, + report_config, + } + } +} diff --git a/crates/analyzer/analyzers/func_analyzer/report_display.rs b/crates/analyzer/analyzers/func_analyzer/report_display.rs new file mode 100644 index 00000000..0f54d0c1 --- /dev/null +++ b/crates/analyzer/analyzers/func_analyzer/report_display.rs @@ -0,0 +1,92 @@ +use crate::analyzers::func_analyzer::*; +use crate::analyzers::{LocStrSpan, ReportDisplay}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; +use shared::analyzer::GraphLike; +use std::collections::BTreeMap; + +pub struct CLIFunctionVarsBoundAnalysis<'a> { + pub file_mapping: &'a BTreeMap, + pub func_var_bound_analysis: FunctionVarsBoundAnalysis, +} + +impl<'a> CLIFunctionVarsBoundAnalysis<'a> { + pub fn new( + file_mapping: &'a BTreeMap, + func_var_bound_analysis: FunctionVarsBoundAnalysis, + ) -> Self { + Self { + file_mapping, + func_var_bound_analysis, + } + } +} + +impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Bounds", Color::Cyan) + } + fn msg(&self, analyzer: &impl GraphLike) -> String { + format!( + "Bounds for function: {}", + format!( + "function {}", + self.func_var_bound_analysis + .ctx + .associated_fn_name(analyzer) + .unwrap() + ) + .fg(Color::Cyan) + ) + } + + fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { + vec![] + } + + fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + let mut report = Report::build( + self.report_kind(), + self.func_var_bound_analysis.ctx_loc.source(), + self.func_var_bound_analysis.ctx_loc.start(), + ) + .with_message(self.msg(analyzer)) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ); + + report.add_labels(self.labels(analyzer)); + if let Some((killed_span, kind)) = &self.func_var_bound_analysis.ctx_killed { + report = report.with_label( + Label::new(killed_span.clone()) + .with_message(kind.analysis_str().fg(Color::Red)) + .with_color(Color::Red), + ); + } + + let mut reports = vec![report.finish()]; + + reports.extend( + self.func_var_bound_analysis + .reports_for_forks(self.file_mapping, analyzer), + ); + + reports + } + + fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + for report in reports.iter() { + report.print(&mut src).unwrap(); + } + } + + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + reports.iter().for_each(|report| { + report.eprint(&mut src).unwrap(); + }); + } +} diff --git a/crates/analyzer/analyzers/mod.rs b/crates/analyzer/analyzers/mod.rs new file mode 100644 index 00000000..9414cbc3 --- /dev/null +++ b/crates/analyzer/analyzers/mod.rs @@ -0,0 +1,176 @@ +pub mod bounds; + +use crate::AnalyzerLike; +use crate::GraphLike; +use ariadne::{Cache, Label, Report, ReportKind, Span}; +use bounds::*; +use shared::analyzer::Search; +use solang_parser::pt::Loc; +use std::collections::BTreeMap; + +mod func_analyzer; +pub use func_analyzer::*; +mod var_analyzer; +pub use var_analyzer::*; + +pub trait ContextAnalyzer: + AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer +{ +} +impl ContextAnalyzer for T where + T: AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer +{ +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct LocSpan(pub Loc); + +impl Default for LocSpan { + fn default() -> Self { + LocSpan(Loc::Implicit) + } +} + +impl Span for LocSpan { + type SourceId = usize; + fn source(&self) -> &Self::SourceId { + match self.0 { + Loc::File(ref f, _, _) => f, + Loc::Implicit => &0, + _ => todo!("handle non file loc"), + } + } + + fn start(&self) -> usize { + match self.0 { + Loc::File(_, start, _) => start, + Loc::Implicit => 0, + _ => todo!("handle non file loc"), + } + } + + fn end(&self) -> usize { + match self.0 { + Loc::File(_, _, end) => end, + Loc::Implicit => 0, + _ => todo!("handle non file loc"), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct LocStrSpan(pub String, pub Loc); + +impl Default for LocStrSpan { + fn default() -> Self { + LocStrSpan("".to_string(), Loc::Implicit) + } +} + +impl LocStrSpan { + pub fn new(file_mapping: &BTreeMap, loc: Loc) -> Self { + let source = match loc { + Loc::File(ref f, _, _) => f, + Loc::Implicit => &0, + _ => todo!("handle non file loc"), + }; + LocStrSpan( + file_mapping + .get(source) + .expect("No file for num") + .to_string(), + loc, + ) + } +} + +impl Span for LocStrSpan { + type SourceId = String; + fn source(&self) -> &Self::SourceId { + &self.0 + } + + fn start(&self) -> usize { + match self.1 { + Loc::File(_, start, _) => start, + Loc::Implicit => 0, + _ => todo!("handle non file loc"), + } + } + + fn end(&self) -> usize { + match self.1 { + Loc::File(_, _, end) => end, + Loc::Implicit => 0, + _ => todo!("handle non file loc"), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub struct ReportConfig { + pub eval_bounds: bool, + pub simplify_bounds: bool, + pub show_tmps: bool, + pub show_consts: bool, + pub show_symbolics: bool, + pub show_initial_bounds: bool, + pub show_all_lines: bool, + pub show_reverts: bool, + pub show_unreachables: bool, + pub show_nonreverts: bool, +} + +impl ReportConfig { + pub fn new( + eval_bounds: bool, + simplify_bounds: bool, + show_tmps: bool, + show_consts: bool, + show_symbolics: bool, + show_initial_bounds: bool, + show_all_lines: bool, + show_reverts: bool, + show_unreachables: bool, + show_nonreverts: bool, + ) -> Self { + Self { + eval_bounds, + simplify_bounds, + show_tmps, + show_consts, + show_symbolics, + show_initial_bounds, + show_all_lines, + show_reverts, + show_unreachables, + show_nonreverts, + } + } +} + +impl Default for ReportConfig { + fn default() -> Self { + Self { + eval_bounds: true, + simplify_bounds: false, + show_tmps: false, + show_consts: false, + show_symbolics: true, + show_initial_bounds: false, + show_all_lines: false, + show_reverts: false, + show_unreachables: false, + show_nonreverts: true, + } + } +} + +pub trait ReportDisplay { + fn report_kind(&self) -> ReportKind; + fn msg(&self, analyzer: &impl GraphLike) -> String; + fn labels(&self, analyzer: &impl GraphLike) -> Vec>; + fn reports(&self, analyzer: &impl GraphLike) -> Vec>; + fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); + fn eprint_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); +} diff --git a/crates/analyzer/analyzers/var_analyzer/mod.rs b/crates/analyzer/analyzers/var_analyzer/mod.rs new file mode 100644 index 00000000..0f0fb23f --- /dev/null +++ b/crates/analyzer/analyzers/var_analyzer/mod.rs @@ -0,0 +1,266 @@ +use crate::analyzers::range_parts; +use crate::analyzers::AnalysisItem; +use crate::analyzers::RangePart; +use crate::analyzers::{LocStrSpan, ReportConfig}; +use shared::analyzer::GraphLike; +use shared::{ + analyzer::{AnalyzerLike, Search}, + context::*, + range::{Range, SolcRange}, +}; +use std::collections::BTreeSet; + +use solang_parser::pt::{CodeLocation, StorageLocation}; +use std::collections::BTreeMap; + +mod report_display; +pub use report_display::*; + +#[derive(PartialOrd, Eq, PartialEq, Ord, Clone, Debug)] +pub struct CtxSwitch { + pub ctx: ContextNode, + pub func_span: LocStrSpan, + pub func_body_span: Option, + pub killed_loc: Option<(LocStrSpan, KilledKind)>, +} + +#[derive(Debug, Clone)] +pub struct VarBoundAnalysis { + /// The context to analyze + pub ctx: ContextNode, + /// The variable's name + pub var_name: String, + /// The variable's display name + pub var_display_name: String, + /// The variable definition and optionally it's initial range + pub var_def: (LocStrSpan, Option), + /// The function defintion + pub func_span: LocStrSpan, + /// Storage type of the variable + pub storage: Option, + /// Vector of bound changes and their location + pub bound_changes: Vec<(LocStrSpan, SolcRange)>, + /// Report configuration + pub report_config: ReportConfig, + /// Spanned (context nodes, function name span, return spans) + pub spanned_ctx_info: BTreeSet, + /// Location where context was killed + pub ctx_killed: Option<(LocStrSpan, KilledKind)>, +} + +impl Default for VarBoundAnalysis { + fn default() -> Self { + Self { + ctx: ContextNode(0), + var_name: Default::default(), + var_display_name: Default::default(), + var_def: Default::default(), + func_span: Default::default(), + bound_changes: Default::default(), + report_config: Default::default(), + storage: None, + ctx_killed: None, + spanned_ctx_info: Default::default(), + } + } +} + +impl VarBoundAnalysis { + pub fn conditionals(&self, analyzer: &impl GraphLike) -> Vec<(String, Vec)> { + let deps = self.ctx.ctx_deps(analyzer).unwrap(); + let deps = deps + .values() + .map(|var| (var.display_name(analyzer).unwrap(), var)) + .collect::>(); + // create the bound strings + deps.iter() + .enumerate() + .filter_map(|(_i, (_name, cvar))| { + let range = cvar.ref_range(analyzer).unwrap()?; + let parts = range_parts(analyzer, &self.report_config, &range).0; + Some((cvar.display_name(analyzer).unwrap(), parts)) + }) + .collect() + } + + /// Creates an [AnalysisItem] if there is a initial bound for a variable + pub fn init_item(&self, analyzer: &impl GraphLike) -> Option { + let mut parts = vec![]; + let mut unsat = false; + if let Some(init_range) = &self.var_def.1 { + (parts, unsat) = range_parts(analyzer, &self.report_config, init_range) + } + if parts.is_empty() { + None + } else { + Some(AnalysisItem { + init: true, + order: -1, + name: self.var_display_name.clone(), + loc: self.var_def.0.clone(), + storage: self.storage.clone(), + ctx: self.ctx, + ctx_conditionals: self.conditionals(analyzer), + parts, + unsat, + }) + } + } +} + +impl VarBoundAnalyzer for T where T: Search + AnalyzerLike + Sized {} +pub trait VarBoundAnalyzer: Search + AnalyzerLike + Sized { + /// Given a lineage of a context (first element being the youngest, last element being the oldest), + /// generate a bound analysis for a variable throughout the lineage + fn bounds_for_var_in_family_tree( + &self, + file_mapping: &'_ BTreeMap, + ordered_ctxs: Vec, + var_name: String, + report_config: ReportConfig, + ) -> VarBoundAnalysis { + let mut inherited = None; + ordered_ctxs + .into_iter() + .filter_map(|ctx| Some((ctx, ctx.var_by_name(self, &var_name)?))) + .for_each(|(_ctx, cvar)| { + let analysis = self.bounds_for_var_node( + &inherited, + file_mapping, + &var_name, + cvar, + report_config, + inherited.is_some(), + ); + inherited = Some(analysis); + }); + inherited.unwrap_or_default() + } + + /// Analyzes the bounds for a variable up to the provided node + fn bounds_for_var_node( + &self, + inherited: &Option, + file_mapping: &'_ BTreeMap, + var_name: &str, + cvar: ContextVarNode, + report_config: ReportConfig, + is_subctx: bool, + ) -> VarBoundAnalysis { + let mut curr = cvar.first_version(self); + + let ctx = cvar.ctx(self); + let (func_span, func_body_span) = + if let Some(fn_call) = ctx.underlying(self).unwrap().fn_call { + ( + LocStrSpan::new(file_mapping, fn_call.underlying(self).unwrap().loc), + fn_call + .underlying(self) + .unwrap() + .body + .as_ref() + .map(|body| LocStrSpan::new(file_mapping, body.loc())), + ) + } else if let Some(ext_fn_call) = ctx.underlying(self).unwrap().ext_fn_call { + ( + LocStrSpan::new(file_mapping, ext_fn_call.underlying(self).unwrap().loc), + ext_fn_call + .underlying(self) + .unwrap() + .body + .as_ref() + .map(|body| LocStrSpan::new(file_mapping, body.loc())), + ) + } else { + let fn_call = ctx.associated_fn(self).unwrap(); + ( + LocStrSpan::new(file_mapping, fn_call.underlying(self).unwrap().loc), + fn_call + .underlying(self) + .unwrap() + .body + .as_ref() + .map(|body| LocStrSpan::new(file_mapping, body.loc())), + ) + }; + + let mut ba: VarBoundAnalysis = if let Some(inherited) = inherited { + let mut new_ba = inherited.clone(); + let ctx_switch = CtxSwitch { + ctx, + func_span, + func_body_span, + killed_loc: ctx + .killed_loc(self) + .unwrap() + .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), + }; + + new_ba.spanned_ctx_info.insert(ctx_switch); + + new_ba + } else { + VarBoundAnalysis { + ctx, + var_name: var_name.to_string(), + var_display_name: cvar.display_name(self).unwrap(), + func_span, + var_def: ( + LocStrSpan::new(file_mapping, curr.loc(self).unwrap()), + if !is_subctx { + curr.range(self).unwrap() + } else { + None + }, + ), + bound_changes: vec![], + report_config, + storage: curr.underlying(self).unwrap().storage.clone(), + ctx_killed: ctx + .killed_loc(self) + .unwrap() + .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), + ..Default::default() + } + }; + + if let Some(curr_range) = curr.ref_range(self).unwrap() { + let mut cr_min = curr_range.evaled_range_min(self).unwrap(); + let mut cr_max = curr_range.evaled_range_max(self).unwrap(); + let mut cr_excl = curr_range.range_exclusions(); + while let Some(next) = curr.next_version(self) { + if let Some(next_range) = next.ref_range(self).unwrap() { + let nr_min = next_range.evaled_range_min(self).unwrap(); + let nr_max = next_range.evaled_range_max(self).unwrap(); + let nr_excl = &next_range.exclusions; + + // check if there was a bound change + if report_config.show_all_lines + || nr_min != cr_min + || nr_max != cr_max + || nr_excl != &cr_excl + { + cr_min = nr_min; + cr_max = nr_max; + cr_excl = nr_excl.to_vec(); + let new = ( + LocStrSpan::new(file_mapping, next.loc(self).unwrap()), + next_range.into_owned(), + ); + if !ba.bound_changes.contains(&new) { + ba.bound_changes.push(new); + } + } + } + + if next == cvar { + break; + } else { + curr = next; + } + } + } + + ba + } +} diff --git a/crates/analyzer/analyzers/var_analyzer/report_display.rs b/crates/analyzer/analyzers/var_analyzer/report_display.rs new file mode 100644 index 00000000..66210180 --- /dev/null +++ b/crates/analyzer/analyzers/var_analyzer/report_display.rs @@ -0,0 +1,106 @@ +use crate::analyzers::{LocStrSpan, ReportDisplay}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; +use shared::analyzer::GraphLike; + +use crate::analyzers::var_analyzer::*; + +impl ReportDisplay for VarBoundAnalysis { + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Bounds", Color::Cyan) + } + fn msg(&self, analyzer: &impl GraphLike) -> String { + format!( + "Bounds for {} in {}:", + self.var_display_name, + self.ctx.underlying(analyzer).unwrap().path + ) + } + fn labels(&self, analyzer: &impl GraphLike) -> Vec> { + let mut labels = if self.report_config.show_initial_bounds { + if let Some(init_item) = self.init_item(analyzer) { + vec![init_item.into()] + } else { + vec![] + } + } else { + vec![] + }; + + labels.extend( + self.bound_changes + .iter() + .enumerate() + .map(|(i, bound_change)| { + let (parts, unsat) = + range_parts(analyzer, &self.report_config, &bound_change.1); + AnalysisItem { + init: false, + name: self.var_display_name.clone(), + loc: bound_change.0.clone(), + order: i as i32, + storage: self.storage.clone(), + ctx: self.ctx, + ctx_conditionals: self.conditionals(analyzer), + parts, + unsat, + } + .into() + }) + .collect::>(), + ); + + labels + } + + fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + let mut report = Report::build( + self.report_kind(), + self.var_def.0.source(), + self.var_def.0.start(), + ) + .with_message(self.msg(analyzer)) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ); + + report.add_labels(self.labels(analyzer)); + + if let Some((killed_span, kind)) = &self.ctx_killed { + report = report.with_label( + Label::new(killed_span.clone()) + .with_message(kind.analysis_str().fg(Color::Red)) + .with_color(Color::Red), + ); + } + + let reports = vec![report.finish()]; + + // if self.report_config.show_subctxs { + // reports.extend( + // self.sub_ctxs + // .iter() + // .flat_map(|analysis| analysis.reports(analyzer)) + // .collect::>(), + // ); + // } + + reports + } + + fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = self.reports(analyzer); + reports.into_iter().for_each(|report| { + report.print(&mut src).unwrap(); + }); + } + + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = self.reports(analyzer); + reports.into_iter().for_each(|report| { + report.eprint(&mut src).unwrap(); + }); + } +} diff --git a/crates/cli/Cargo.lock b/crates/cli/Cargo.lock new file mode 100644 index 00000000..16ae4bf4 --- /dev/null +++ b/crates/cli/Cargo.lock @@ -0,0 +1,1616 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "ariadne" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +dependencies = [ + "serde", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "clap" +version = "4.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "cli" +version = "0.1.0" +dependencies = [ + "ariadne", + "clap", + "pyrometer", + "shared", +] + +[[package]] +name = "const-oid" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +dependencies = [ + "log", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" +dependencies = [ + "arrayvec", + "bytes", + "chrono", + "elliptic-curve", + "ethabi", + "generic-array", + "hex", + "k256", + "open-fastrlp", + "rand", + "rlp", + "rlp-derive", + "serde", + "serde_json", + "strum", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", + "sha3", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" +dependencies = [ + "ascii-canvas", + "atty", + "bit-set", + "diff", + "ena", + "itertools", + "lalrpop-util", + "petgraph", + "pico-args", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "parity-scale-codec" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_macros", + "phf_shared 0.11.1", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared 0.11.1", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +dependencies = [ + "phf_generator", + "phf_shared 0.11.1", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyrometer" +version = "0.1.0" +dependencies = [ + "ariadne", + "ethers-core", + "hex", + "petgraph", + "shared", + "solang-parser", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "scale-info" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "ethers-core", + "hex", + "lazy_static", + "petgraph", + "solang-parser", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "solang-parser" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff87dae6cdccacdbf3b19e99b271083556e808de0f59c74a01482f64fdbc61fc" +dependencies = [ + "itertools", + "lalrpop", + "lalrpop-util", + "phf", + "serde", + "unicode-xid", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" + +[[package]] +name = "toml_edit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +dependencies = [ + "indexmap", + "nom8", + "toml_datetime", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 00000000..9ac847ea --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "cli" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.1.4", features = ["derive"] } +pyrometer = { path = "../" } +shared = { path = "../shared" } +ariadne = "0.2.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } +petgraph = "0.6.2" + +[[bin]] +name = "pyrometer" +path = "src/main.rs" + + +[profile.release] +debug = true \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 00000000..5449ab71 --- /dev/null +++ b/crates/cli/src/main.rs @@ -0,0 +1,355 @@ +use crate::analyzers::ReportConfig; +use ariadne::sources; +use clap::{ArgAction, Parser, ValueHint}; +use pyrometer::context::analyzers::FunctionVarsBoundAnalyzer; +use pyrometer::{ + context::{analyzers::ReportDisplay, *}, + Analyzer, +}; + +use shared::nodes::FunctionNode; + +use shared::Edge; +use shared::{ + analyzer::{GraphLike, Search}, + nodes::ContractNode, +}; +use tracing_subscriber::prelude::*; + +use std::collections::{BTreeMap, HashMap}; +use std::path::PathBuf; + +use std::env::{self}; +use std::fs; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// The path to the solidity file to process + #[clap(value_hint = ValueHint::FilePath, value_name = "PATH")] + pub path: String, + /// The path to the `remappings.txt` as per the output of `forge remappings` + #[clap(long, short)] + pub remappings: Option, + /// Limit the output to just contracts that start with the name passed. i.e. `--contracts "MyCon"` woudl match "MyContract", "MyCon2", .. etc. + /// + /// Can be passed multiple times, i.e. `--contract "MyCon" --contract "MyOtherContract"` + #[clap(long, short)] + pub contracts: Vec, + /// Limit the output to just functions that start with the name passed. i.e. `--funcs "myFunc"` would match "myFunction", "myFunc2", .. etc. + /// + /// Can be passed multiple times, i.e. `--funcs "myFunc" --funcs "myOtherFunc"` + #[clap(long, short)] + pub funcs: Vec, + /// Verbosity of the bounds analysis + /// + /// Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv). + /// + /// Verbosity levels: + /// + /// 0: Print return value changes + /// 1: Print storage variable changes, input variable changes, and return value changes + /// 2: Print all previous values as well as temporary values + /// 3: Print all previous values as well as initial values + /// 4: Print all previous values as well as constants + /// 5: Print all previous values for all successful branches and reverting branches + /// 6: Print all previous values for all successful branches, reverting branches, and unreachable branches + #[clap(long, short, verbatim_doc_comment, action = ArgAction::Count)] + pub verbosity: u8, + /// Whether to print out a dot string of the analyzed contracts + #[clap(long, short, default_value = "false")] + pub dot: bool, + /// Whether to generate and open a dot visualization of the analyzed contracts + #[clap(long, short, default_value = "false")] + pub open_dot: bool, + /// Whether to evaluate variables down to their intervals or to keep them symbolic/relational to other variables + #[clap(long, short)] + pub eval: Option, + /// Whether to simplify expressions down to variables down to their intervals or to keep them symbolic/relational to other variables + #[clap(long, short)] + pub simplify: Option, + /// Whether to show initial values in the bounds analysis output + #[clap(long)] + pub show_inits: Option, + /// Show reverting paths + #[clap(long)] + pub show_reverts: Option, + /// Show unreachable paths + #[clap(long)] + pub show_unreachables: Option, + /// Show non-revert paths + #[clap(long)] + pub show_nonreverts: Option, + // #[clap(long, short)] + // pub access_query: Vec, + // #[clap(long, short)] + // pub query: Vec, + // #[clap(long, short)] + // pub write_query: Vec, + /// A debugging command to prevent bound analysis printing. Useful for debugging parse errors during development. Only prints out parse errors + /// then ends the program + #[clap(long)] + pub debug: bool, +} + +pub fn subscriber() { + tracing_subscriber::Registry::default() + .with(tracing_subscriber::filter::EnvFilter::from_default_env()) + .with(tracing_subscriber::fmt::layer()) + .init() +} + +fn main() { + subscriber(); + let args = Args::parse(); + let path_str = args.path.to_string(); + let verbosity = args.verbosity; + let config = match verbosity { + 0 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: false, + show_consts: false, + show_symbolics: false, + show_initial_bounds: args.show_inits.unwrap_or(false), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(false), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 1 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: false, + show_consts: false, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(false), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(false), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 2 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: false, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(false), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(false), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 3 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: false, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(true), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(false), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 4 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: true, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(true), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(false), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 5 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: true, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(true), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(true), + show_unreachables: args.show_unreachables.unwrap_or(false), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + 6 => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: true, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(true), + show_all_lines: false, + show_reverts: args.show_reverts.unwrap_or(true), + show_unreachables: args.show_unreachables.unwrap_or(true), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + _ => ReportConfig { + eval_bounds: args.eval.unwrap_or(true), + simplify_bounds: args.simplify.unwrap_or(false), + show_tmps: true, + show_consts: true, + show_symbolics: true, + show_initial_bounds: args.show_inits.unwrap_or(true), + show_all_lines: true, + show_reverts: args.show_reverts.unwrap_or(true), + show_unreachables: args.show_unreachables.unwrap_or(true), + show_nonreverts: args.show_nonreverts.unwrap_or(true), + }, + }; + + let sol = fs::read_to_string(args.path.clone()).expect("Could not find file"); + + let mut analyzer = Analyzer { + root: env::current_dir().unwrap(), + ..Default::default() + }; + if args.remappings.is_some() { + let remappings = args.remappings.unwrap(); + analyzer.set_remappings_and_root(remappings); + } + let t0 = std::time::Instant::now(); + let (maybe_entry, mut all_sources) = + analyzer.parse(&sol, &PathBuf::from(args.path.clone()), true); + let parse_time = t0.elapsed().as_millis(); + + println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); + + all_sources.push((maybe_entry, args.path, sol, 0)); + let entry = maybe_entry.unwrap(); + + let mut file_mapping: BTreeMap<_, _> = vec![(0usize, path_str)].into_iter().collect(); + file_mapping.extend( + all_sources + .iter() + .map(|(_entry, name, _src, num)| (*num, name.clone())) + .collect::>(), + ); + + let mut source_map = sources( + all_sources + .iter() + .map(|(_entry, name, src, _num)| (name.clone(), src)) + .collect::>(), + ); + + // let t = petgraph::algo::toposort(&analyzer.graph, None); + analyzer.print_errors(&file_mapping, &mut source_map); + + if args.open_dot { + analyzer.open_dot() + } + + if args.dot { + println!("{}", analyzer.dot_str_no_tmps()); + } + + if args.debug { + return; + } + + let all_contracts = analyzer + .search_children(entry, &Edge::Contract) + .into_iter() + .map(ContractNode::from) + .collect::>(); + let _t1 = std::time::Instant::now(); + if args.contracts.is_empty() { + let funcs = analyzer.search_children(entry, &Edge::Func); + for func in funcs.into_iter() { + if !args.funcs.is_empty() { + if args.funcs.iter().any(|analyze_for| { + FunctionNode::from(func) + .name(&analyzer) + .unwrap() + .starts_with(analyze_for) + }) { + if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { + let analysis = analyzer + .bounds_for_all(&file_mapping, ctx, config) + .as_cli_compat(&file_mapping); + analysis.print_reports(&mut source_map, &analyzer); + } + } + } else if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { + let analysis = analyzer + .bounds_for_all(&file_mapping, ctx, config) + .as_cli_compat(&file_mapping); + analysis.print_reports(&mut source_map, &analyzer); + } + } + } else { + all_contracts + .iter() + .filter(|contract| { + let name: String = contract.name(&analyzer).unwrap(); + args.contracts.contains(&name) + }) + .collect::>() + .iter() + .for_each(|contract| { + let funcs = contract.funcs(&analyzer); + for func in funcs.into_iter() { + if !args.funcs.is_empty() { + if args.funcs.contains(&func.name(&analyzer).unwrap()) { + let ctx = func.body_ctx(&mut analyzer); + let analysis = analyzer + .bounds_for_all(&file_mapping, ctx, config) + .as_cli_compat(&file_mapping); + analysis.print_reports(&mut source_map, &analyzer); + } + } else { + let ctx = func.body_ctx(&mut analyzer); + let analysis = analyzer + .bounds_for_all(&file_mapping, ctx, config) + .as_cli_compat(&file_mapping); + analysis.print_reports(&mut source_map, &analyzer); + } + } + }); + } + + // args.query.iter().for_each(|query| { + // analyzer.taint_query(entry, query.to_string()); + // println!(); + // }); + + // args.access_query.iter().for_each(|query| { + // let split: Vec<&str> = query.split('.').collect(); + // analyzer + // .access_query( + // entry, + // &file_mapping, + // config, + // split[0].to_string(), + // split[1].to_string(), + // ) + // .print_reports(&mut source_map, &analyzer); + // println!(); + // }); + + // args.write_query.iter().for_each(|query| { + // let split: Vec<&str> = query.split('.').collect(); + // if let Some(report) = analyzer.func_query( + // entry, + // &file_mapping, + // config, + // split[0].to_string(), + // split[1].to_string(), + // split[2].to_string(), + // SolcRange::new( + // Concrete::Bool(true).into(), + // Concrete::Bool(true).into(), + // vec![], + // ), + // ) { + // report.print_reports(&mut source_map, &analyzer); + // } + // println!(); + // }); +} diff --git a/crates/graph/nodes/context/context_tys.rs b/crates/graph/nodes/context/context_tys.rs index 7a8557b3..d61b06cc 100644 --- a/crates/graph/nodes/context/context_tys.rs +++ b/crates/graph/nodes/context/context_tys.rs @@ -21,41 +21,6 @@ impl CallFork { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum ContextEdge { - // Control flow - Context, - Subcontext, - ContextFork, - ContextMerge, - Call, - - // Context Variables - Variable, - InheritedVariable, - - AttrAccess, - Index, - IndexAccess, - StructAccess, - FuncAccess, - - // Variable incoming edges - Assign, - StorageAssign, - MemoryAssign, - Prev, - - // Control flow - Return, - Continue, - InputVariable, - ReturnAssign(bool), - - // Range analysis - Range, -} - #[derive(Debug, Clone, Eq, PartialEq)] pub struct ModifierState { pub num: usize, diff --git a/crates/pyrometer/builtin_fns.rs b/crates/pyrometer/builtin_fns.rs new file mode 100644 index 00000000..f6832307 --- /dev/null +++ b/crates/pyrometer/builtin_fns.rs @@ -0,0 +1,816 @@ +use crate::Builtin; +use crate::{Function, FunctionParam, FunctionReturn}; +use shared::analyzer::{AnalyzerLike, GraphLike}; +use solang_parser::pt::{FunctionAttribute, Identifier, Loc, StorageLocation, Visibility}; +use std::collections::HashMap; + +macro_rules! builtin_fn { + ($($field:ident : $value:expr),* $(,)?) => { + Function { + $( + $field: $value, + )* + ..Default::default() + } + } +} + +// A list of all Solidity builtins functions +pub fn builtin_fns() -> HashMap { + let funcs = [ + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "wrap".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "unwrap".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "concat".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "addmod".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "mulmod".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "balance".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "code".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "push".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "pop".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "ecrecover".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "type".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "assert".to_string(), + }), + name_loc: Loc::Builtin, + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "require".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "require_str".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "revert".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "revert_str".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "selfdestruct".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "keccak256".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "ripemd160".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "sha256".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "gasleft".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "blockhash".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.decode".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.encode".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.encodePacked".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.encodeWithSelector".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.encodeWithSignature".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "abi.encodeCall".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "delegatecall".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "call".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "staticcall".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "transfer".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + builtin_fn!( + name: Some(Identifier { + loc: Loc::Builtin, + name: "send".to_string(), + }), + attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( + Loc::Builtin, + )))], + ), + ]; + funcs + .into_iter() + .map(|func| (func.name.clone().expect("").name, func)) + .collect() +} + +pub fn builtin_fns_inputs( + analyzer: &mut (impl GraphLike + AnalyzerLike), +) -> HashMap, Vec)> { + let funcs = [ + ("wrap", vec![], vec![]), + ("unwrap", vec![], vec![]), + ( + "addmod", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + storage: None, + name: None, + }], + ), + ( + "mulmod", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 0, + storage: None, + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + storage: None, + name: None, + }], + ), + ( + "balance", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + storage: None, + name: None, + }], + ), + ( + "code", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: None, + name: None, + }], + ), + ( + "codehash", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: None, + name: None, + }], + ), + ("concat", vec![], vec![]), + ("push", vec![], vec![]), + ("pop", vec![], vec![]), + ( + "ecrecover", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + order: 1, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + order: 2, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(8)), + order: 3, + storage: None, + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + storage: None, + name: None, + }], + ), + ("type", vec![], vec![]), + ( + "assert", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bool), + order: 0, + storage: None, + name: None, + }], + vec![], + ), + ( + "require", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bool), + order: 0, + storage: None, + name: None, + }], + vec![], + ), + ( + "require_str", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bool), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::String), + order: 1, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }, + ], + vec![], + ), + ("revert", vec![], vec![]), + ( + "revert_str", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::String), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![], + ), + ( + "selfdestruct", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }], + vec![], + ), + ( + "keccak256", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + storage: None, + name: None, + }], + ), + ( + "ripemd160", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(20)), + storage: None, + name: None, + }], + ), + ( + "sha256", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + storage: None, + name: None, + }], + ), + ( + "gasleft", + vec![], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(64)), + storage: None, + name: None, + }], + ), + ( + "blockhash", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(64)), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(32)), + storage: None, + name: None, + }], + ), + ( + "abi.decode", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 0, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + vec![], + ), + ( + "abi.encode", + vec![], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "abi.encodePacked", + vec![], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "abi.encodeWithSelector", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bytes(4)), + order: 0, + storage: None, + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "abi.encodeWithSignature", + vec![FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::String), + order: 0, + storage: None, + name: None, + }], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ("abi.encodeCall", vec![], vec![]), + ( + "delegatecall", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 1, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "call", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 1, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "staticcall", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + order: 1, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::DynamicBytes), + storage: Some(StorageLocation::Memory(Loc::Implicit)), + name: None, + }], + ), + ( + "transfer", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 1, + storage: None, + name: None, + }, + ], + vec![], + ), + ( + "send", + vec![ + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Address), + order: 0, + storage: None, + name: None, + }, + FunctionParam { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Uint(256)), + order: 1, + storage: None, + name: None, + }, + ], + vec![FunctionReturn { + loc: Loc::Builtin, + ty: analyzer.builtin_or_add(Builtin::Bool), + storage: None, + name: None, + }], + ), + ]; + + funcs + .into_iter() + .map(|(name, inputs, outputs)| (name.to_string(), (inputs, outputs))) + .collect() +} diff --git a/crates/pyrometer/lib.rs b/crates/pyrometer/lib.rs new file mode 100644 index 00000000..3d67b73b --- /dev/null +++ b/crates/pyrometer/lib.rs @@ -0,0 +1,1134 @@ +use crate::analyzers::LocStrSpan; +use crate::context::exprs::IntoExprErr; +use crate::exprs::ExprErr; +use ariadne::Source; +use ethers_core::types::U256; +use shared::analyzer::*; +use shared::context::ContextNode; +use shared::context::ExprRet; +use shared::context::{Context, ContextEdge}; +use shared::nodes::*; +use shared::{Edge, Node, NodeIdx}; +use solang_parser::diagnostics::Diagnostic; +use solang_parser::helpers::CodeLocation; +use solang_parser::pt::Identifier; +use solang_parser::pt::Import; +use std::collections::BTreeMap; + +use std::ffi::OsString; +use std::path::Path; + +use solang_parser::pt::{ + ContractDefinition, ContractPart, EnumDefinition, ErrorDefinition, Expression, + FunctionDefinition, FunctionTy, SourceUnit, SourceUnitPart, StructDefinition, TypeDefinition, + Using, UsingList, VariableDefinition, +}; +use std::path::PathBuf; +use std::{collections::HashMap, fs}; + +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; +use petgraph::{graph::*, Directed}; + +mod builtin_fns; + +pub mod context; +// pub mod range; +use context::*; +pub use shared; + +#[derive(Debug, Clone, Default)] +pub struct FinalPassItem { + pub funcs: Vec, + pub usings: Vec<(Using, NodeIdx)>, + pub inherits: Vec<(ContractNode, Vec)>, + pub vars: Vec<(VarNode, NodeIdx)>, +} +impl FinalPassItem { + pub fn new( + funcs: Vec, + usings: Vec<(Using, NodeIdx)>, + inherits: Vec<(ContractNode, Vec)>, + vars: Vec<(VarNode, NodeIdx)>, + ) -> Self { + Self { + funcs, + usings, + inherits, + vars, + } + } +} + +#[derive(Debug, Clone)] +pub struct Analyzer { + /// The root path of the contract to be analyzed + pub root: PathBuf, + /// Solidity remappings - as would be passed into the solidity compiler + pub remappings: Vec<(String, String)>, + /// Imported sources - the canonicalized string to the entry source element index + pub imported_srcs: BTreeMap>, + /// Since we use a staged approach to analysis, we analyze all user types first then go through and patch up any missing or unresolved + /// parts of a contract (i.e. we parsed a struct which is used as an input to a function signature, we have to know about the struct) + pub final_pass_items: Vec, + /// The next file number to use when parsing a new file + pub file_no: usize, + /// The index of the current `msg` node + pub msg: MsgNode, + /// The index of the current `block` node + pub block: BlockNode, + /// The underlying graph holding all of the elements of the contracts + pub graph: Graph, + /// The entry node - this is the root of the dag, all relevant things should eventually point back to this (otherwise can be discarded) + pub entry: NodeIdx, + /// A mapping of a solidity builtin to the index in the graph + pub builtins: HashMap, + /// A mapping of a user type's name to the index in the graph (i.e. `struct A` would mapped `A` -> index) + pub user_types: HashMap, + /// A mapping of solidity builtin function to a [Function] struct, i.e. `ecrecover` -> `Function { name: "ecrecover", ..}` + pub builtin_fns: HashMap, + /// A mapping of solidity builtin functions to their indices in the graph + pub builtin_fn_nodes: HashMap, + /// A mapping of solidity builtin function names to their parameters and returns, i.e. `ecrecover` -> `([hash, r, s, v], [signer])` + pub builtin_fn_inputs: HashMap, Vec)>, + /// Accumulated errors that happened while analyzing + pub expr_errs: Vec, + /// The maximum depth to analyze to (i.e. call depth) + pub max_depth: usize, + /// The maximum number of forks throughout the lifetime of the analysis. + pub max_width: usize, + /// Dummy function used during parsing to attach contexts to for more complex first-pass parsing (i.e. before `final_pass`) + pub parse_fn: FunctionNode, +} + +impl Default for Analyzer { + fn default() -> Self { + let mut a = Self { + root: Default::default(), + remappings: Default::default(), + imported_srcs: Default::default(), + final_pass_items: Default::default(), + file_no: 0, + msg: MsgNode(0), + block: BlockNode(0), + graph: Default::default(), + entry: NodeIndex::from(0), + builtins: Default::default(), + user_types: Default::default(), + builtin_fns: builtin_fns::builtin_fns(), + builtin_fn_nodes: Default::default(), + builtin_fn_inputs: Default::default(), + expr_errs: Default::default(), + max_depth: 1024, + max_width: 2_i32.pow(14) as usize, + parse_fn: NodeIdx::from(0).into(), + }; + a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); + + let msg = Msg::default(); + let block = Block::default(); + let msg = a.graph.add_node(Node::Msg(msg)).into(); + let block = a.graph.add_node(Node::Block(block)).into(); + a.msg = msg; + a.block = block; + a.entry = a.add_node(Node::Entry); + let pf = Function { + name: Some(Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".into(), + }), + ..Default::default() + }; + let parser_fn = FunctionNode::from(a.add_node(pf)); + a.add_edge(parser_fn, a.entry, Edge::Func); + a.parse_fn = parser_fn; + a + } +} + +impl GraphLike for Analyzer { + fn graph_mut(&mut self) -> &mut Graph { + &mut self.graph + } + + fn graph(&self) -> &Graph { + &self.graph + } +} + +impl AnalyzerLike for Analyzer { + type Expr = Expression; + type ExprErr = ExprErr; + + fn builtin_fn_nodes(&self) -> &HashMap { + &self.builtin_fn_nodes + } + + fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap { + &mut self.builtin_fn_nodes + } + + fn max_depth(&self) -> usize { + self.max_depth + } + + fn max_width(&self) -> usize { + self.max_width + } + + fn add_expr_err(&mut self, err: ExprErr) { + if !self.expr_errs.contains(&err) { + self.expr_errs.push(err); + } + } + + fn expr_errs(&self) -> Vec { + self.expr_errs.clone() + } + + fn entry(&self) -> NodeIdx { + self.entry + } + + fn msg(&mut self) -> MsgNode { + self.msg + } + + fn block(&mut self) -> BlockNode { + self.block + } + + fn builtin_fns(&self) -> &HashMap { + &self.builtin_fns + } + + fn builtin_fn_inputs(&self) -> &HashMap, Vec)> { + &self.builtin_fn_inputs + } + + fn builtins(&self) -> &HashMap { + &self.builtins + } + fn builtins_mut(&mut self) -> &mut HashMap { + &mut self.builtins + } + fn user_types(&self) -> &HashMap { + &self.user_types + } + fn user_types_mut(&mut self) -> &mut HashMap { + &mut self.user_types + } + + fn parse_expr(&mut self, expr: &Expression, parent: Option) -> NodeIdx { + use Expression::*; + match expr { + Type(_loc, ty) => { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(idx) = self.builtins.get(&builtin) { + *idx + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins.insert(builtin, idx); + idx + } + } else if let Some(idx) = self.complicated_parse(expr, parent) { + self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) + .unwrap_or(0.into()) + } else { + 0.into() + } + } + Variable(ident) => { + if let Some(idx) = self.user_types.get(&ident.name) { + *idx + } else { + let node = self.add_node(Node::Unresolved(ident.clone())); + self.user_types.insert(ident.name.clone(), node); + node + } + } + ArraySubscript(_loc, ty_expr, None) => { + let inner_ty = self.parse_expr(ty_expr, parent); + if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { + let dyn_b = Builtin::Array(var_type); + if let Some(idx) = self.builtins.get(&dyn_b) { + *idx + } else { + let idx = self.add_node(Node::Builtin(dyn_b.clone())); + self.builtins.insert(dyn_b, idx); + idx + } + } else { + inner_ty + } + } + ArraySubscript(loc, ty_expr, Some(idx_expr)) => { + let inner_ty = self.parse_expr(ty_expr, parent); + let idx = self.parse_expr(idx_expr, parent); + if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { + let res = ConcreteNode::from(idx) + .underlying(self) + .into_expr_err(*loc) + .cloned(); + if let Some(concrete) = self.add_if_err(res) { + if let Some(size) = concrete.uint_val() { + let dyn_b = Builtin::SizedArray(size, var_type); + if let Some(idx) = self.builtins.get(&dyn_b) { + *idx + } else { + let idx = self.add_node(Node::Builtin(dyn_b.clone())); + self.builtins.insert(dyn_b, idx); + idx + } + } else { + inner_ty + } + } else { + inner_ty + } + } else { + inner_ty + } + } + NumberLiteral(_loc, integer, exponent, _unit) => { + let int = U256::from_dec_str(integer).unwrap(); + let val = if !exponent.is_empty() { + let exp = U256::from_dec_str(exponent).unwrap(); + int * U256::from(10).pow(exp) + } else { + int + }; + + self.add_node(Node::Concrete(Concrete::Uint(256, val))) + } + _ => { + if let Some(idx) = self.complicated_parse(expr, parent) { + self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) + .unwrap_or(0.into()) + } else { + 0.into() + } + } + } + } +} + +impl Analyzer { + pub fn complicated_parse( + &mut self, + expr: &Expression, + parent: Option, + ) -> Option { + tracing::trace!("Parsing required compile-time evaluation"); + + let ctx = if let Some(parent) = parent { + let pf = Function { + name: Some(Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".into(), + }), + ..Default::default() + }; + let parser_fn = FunctionNode::from(self.add_node(pf)); + self.add_edge(parser_fn, parent, Edge::Func); + + let dummy_ctx = Context::new(parser_fn, "".to_string(), expr.loc()); + let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); + self.add_edge(ctx, parser_fn, Edge::Context(ContextEdge::Context)); + ctx + } else { + let dummy_ctx = Context::new(self.parse_fn, "".to_string(), expr.loc()); + let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); + self.add_edge(ctx, self.entry(), Edge::Context(ContextEdge::Context)); + ctx + }; + + let full_stmt = solang_parser::pt::Statement::Return(expr.loc(), Some(expr.clone())); + self.parse_ctx_statement(&full_stmt, false, Some(ctx)); + let edges = self.add_if_err(ctx.all_edges(self).into_expr_err(expr.loc()))?; + if edges.len() == 1 { + let res = edges[0].return_nodes(self).into_expr_err(expr.loc()); + + let res = self.add_if_err(res); + + if let Some(res) = res { + res.last().map(|last| ExprRet::Single(last.1.into())) + } else { + None + } + } else if edges.is_empty() { + let res = ctx.return_nodes(self).into_expr_err(expr.loc()); + + let res = self.add_if_err(res); + + if let Some(res) = res { + res.last().map(|last| ExprRet::Single(last.1.into())) + } else { + None + } + } else { + self.add_expr_err(ExprErr::ParseError(expr.loc(), "Expected this to be compile-time evaluatable, but it was nondeterministic likely due to an external call via an interface".to_string())); + None + } + } + + pub fn set_remappings_and_root(&mut self, remappings_path: String) { + self.root = PathBuf::from(&remappings_path) + .parent() + .unwrap() + .to_path_buf(); + let remappings_file = fs::read_to_string(remappings_path) + .map_err(|err| err.to_string()) + .expect("Remappings file not found"); + + self.remappings = remappings_file + .lines() + .map(|x| x.trim()) + .filter(|x| !x.is_empty()) + .map(|x| x.split_once('=').expect("Invalid remapping")) + .map(|(name, path)| (name.to_owned(), path.to_owned())) + .collect(); + } + + pub fn print_errors( + &self, + file_mapping: &'_ BTreeMap, + mut src: &mut impl Cache, + ) { + if self.expr_errs.is_empty() { + } else { + self.expr_errs.iter().for_each(|error| { + let str_span = LocStrSpan::new(file_mapping, error.loc()); + let report = Report::build(ReportKind::Error, str_span.source(), str_span.start()) + .with_message(error.report_msg()) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ) + .with_label( + Label::new(str_span) + .with_color(Color::Red) + .with_message(format!("{}", error.msg().fg(Color::Red))), + ); + report.finish().print(&mut src).unwrap(); + }); + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse( + &mut self, + src: &str, + current_path: &Path, + entry: bool, + ) -> ( + Option, + Vec<(Option, String, String, usize)>, + ) { + // tracing::trace!("parsing: {:?}", current_path); + let file_no = self.file_no; + let mut imported = vec![]; + match solang_parser::parse(src, file_no) { + Ok((source_unit, _comments)) => { + let parent = self.add_node(Node::SourceUnit(file_no)); + self.add_edge(parent, self.entry, Edge::Source); + let final_pass_part = self.parse_source_unit( + source_unit, + file_no, + parent, + &mut imported, + current_path, + ); + self.final_pass_items.push(final_pass_part); + if entry { + self.final_pass(); + } + + (Some(parent), imported) + } + Err(diagnostics) => { + print_diagnostics_report(src, current_path, diagnostics).unwrap(); + panic!("Failed to parse Solidity code for {current_path:?}."); + } + } + } + + pub fn final_pass(&mut self) { + let elems = self.final_pass_items.clone(); + elems.iter().for_each(|final_pass_item| { + final_pass_item + .inherits + .iter() + .for_each(|(contract, inherits)| { + contract.inherit(inherits.to_vec(), self); + }); + final_pass_item.funcs.iter().for_each(|func| { + // add params now that parsing is done + func.set_params_and_ret(self).unwrap(); + }); + + final_pass_item + .usings + .iter() + .for_each(|(using, scope_node)| { + self.parse_using(using, *scope_node); + }); + final_pass_item.vars.iter().for_each(|(var, parent)| { + let loc = var.underlying(self).unwrap().loc; + let res = var.parse_initializer(self, *parent).into_expr_err(loc); + let _ = self.add_if_err(res); + }); + }); + + elems.into_iter().for_each(|final_pass_item| { + final_pass_item.funcs.into_iter().for_each(|func| { + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(body, false, Some(func)); + } + }); + }); + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_source_unit( + &mut self, + source_unit: SourceUnit, + file_no: usize, + parent: NodeIdx, + imported: &mut Vec<(Option, String, String, usize)>, + current_path: &Path, + ) -> FinalPassItem { + let mut all_funcs = vec![]; + let mut all_usings = vec![]; + let mut all_inherits = vec![]; + let mut all_vars = vec![]; + source_unit + .0 + .iter() + .enumerate() + .for_each(|(unit_part, source_unit_part)| { + let (_sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( + source_unit_part, + file_no, + unit_part, + parent, + imported, + current_path, + ); + all_funcs.extend(funcs); + all_usings.extend(usings); + all_inherits.extend(inherits); + all_vars.extend(vars); + }); + FinalPassItem::new(all_funcs, all_usings, all_inherits, all_vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_source_unit_part( + &mut self, + sup: &SourceUnitPart, + file_no: usize, + unit_part: usize, + parent: NodeIdx, + imported: &mut Vec<(Option, String, String, usize)>, + current_path: &Path, + ) -> ( + NodeIdx, + Vec, + Vec<(Using, NodeIdx)>, + Vec<(ContractNode, Vec)>, + Vec<(VarNode, NodeIdx)>, + ) { + use SourceUnitPart::*; + + let sup_node = self.add_node(Node::SourceUnitPart(file_no, unit_part)); + self.add_edge(sup_node, parent, Edge::Part); + + let mut func_nodes = vec![]; + let mut usings = vec![]; + let mut inherits = vec![]; + let mut vars = vec![]; + + match sup { + ContractDefinition(def) => { + let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = + self.parse_contract_def(def, parent, imported); + self.add_edge(node, sup_node, Edge::Contract); + func_nodes.extend(funcs); + usings.extend(con_usings); + inherits.push((node, unhandled_inherits)); + vars.extend(unhandled_vars); + } + StructDefinition(def) => { + let node = self.parse_struct_def(def); + self.add_edge(node, sup_node, Edge::Struct); + } + EnumDefinition(def) => { + let node = self.parse_enum_def(def); + self.add_edge(node, sup_node, Edge::Enum); + } + ErrorDefinition(def) => { + let node = self.parse_err_def(def); + self.add_edge(node, sup_node, Edge::Error); + } + VariableDefinition(def) => { + let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); + if let Some(func) = maybe_func { + func_nodes.push(self.handle_func(func, None)); + } + + if needs_final_pass { + vars.push((node, parent)); + } + + self.add_edge(node, sup_node, Edge::Var); + } + FunctionDefinition(def) => { + let node = self.parse_func_def(def, None); + func_nodes.push(node); + self.add_edge(node, sup_node, Edge::Func); + } + TypeDefinition(def) => { + let node = self.parse_ty_def(def); + self.add_edge(node, sup_node, Edge::Ty); + } + EventDefinition(_def) => todo!(), + Annotation(_anno) => todo!(), + Using(using) => usings.push((*using.clone(), parent)), + StraySemicolon(_loc) => todo!(), + PragmaDirective(_, _, _) => {} + ImportDirective(import) => { + imported.extend(self.parse_import(import, current_path, parent)) + } + } + (sup_node, func_nodes, usings, inherits, vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_import( + &mut self, + import: &Import, + current_path: &Path, + parent: NodeIdx, + ) -> Vec<(Option, String, String, usize)> { + match import { + Import::Plain(import_path, _) => { + tracing::trace!("parse_import, path: {:?}", import_path); + let remapping = self + .remappings + .iter() + .find(|x| import_path.string.starts_with(&x.0)); + + let remapped = if let Some((name, path)) = remapping { + self.root.join(path).join( + import_path + .string + .replacen(name, "", 1) + .trim_start_matches('/'), + ) + } else { + current_path + .parent() + .unwrap() + .join(import_path.string.clone()) + }; + + let canonical = fs::canonicalize(&remapped) + .unwrap_or_else(|_| panic!( + "Could not find file: {remapped:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" + } else { "" } + ) + ); + let canonical_str_path = canonical.as_os_str(); + if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { + if let Some(o_e) = other_entry { + self.add_edge(*o_e, parent, Edge::Import); + } + return vec![]; + } + + let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { + panic!( + "Could not find file for dependency: {canonical:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input (where `remappings.txt` is the output of `forge remappings > remappings.txt`)" + } else { "" } + ) + }); + self.file_no += 1; + let file_no = self.file_no; + // breaks recursion issues + self.imported_srcs.insert(canonical_str_path.into(), None); + let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); + self.imported_srcs + .insert(canonical_str_path.into(), maybe_entry); + if let Some(other_entry) = maybe_entry { + self.add_edge(other_entry, parent, Edge::Import); + } + + inner_sources.push(( + maybe_entry, + remapped.to_str().unwrap().to_owned(), + sol.to_string(), + file_no, + )); + inner_sources + } + Import::Rename(import_path, _elems, _) => { + tracing::trace!("parse_import, path: {:?}, Rename", import_path); + let remapping = self + .remappings + .iter() + .find(|x| import_path.string.starts_with(&x.0)); + + let remapped = if let Some((name, path)) = remapping { + self.root.join(path).join( + import_path + .string + .replacen(name, "", 1) + .trim_start_matches('/'), + ) + } else { + current_path + .parent() + .unwrap() + .join(import_path.string.clone()) + }; + + let canonical = fs::canonicalize(&remapped).unwrap_or_else(|_| panic!( + "Could not find file: {remapped:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" + } else { "" } + ) + ); + let canonical_str_path = canonical.as_os_str(); + if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { + if let Some(o_e) = other_entry { + self.add_edge(*o_e, parent, Edge::Import); + } + return vec![]; + } + + let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { + panic!( + "Could not find file for dependency: {canonical:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" + } else { "" } + ) + }); + self.file_no += 1; + let file_no = self.file_no; + + // breaks recursion issues + self.imported_srcs.insert(canonical_str_path.into(), None); + let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); + self.imported_srcs + .insert(canonical_str_path.into(), maybe_entry); + if let Some(other_entry) = maybe_entry { + self.add_edge(other_entry, parent, Edge::Import); + } + + inner_sources.push(( + maybe_entry, + remapped.to_str().unwrap().to_owned(), + sol.to_string(), + file_no, + )); + inner_sources + } + e => todo!("import {:?}", e), + } + } + + // #[tracing::instrument(name = "parse_contract_def", skip_all, fields(name = format!("{:?}", contract_def.name)))] + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_contract_def( + &mut self, + contract_def: &ContractDefinition, + source: NodeIdx, + imports: &[(Option, String, String, usize)], + ) -> ( + ContractNode, + Vec, + Vec<(Using, NodeIdx)>, + Vec, + Vec<(VarNode, NodeIdx)>, + ) { + tracing::trace!( + "Parsing contract {}", + if let Some(ident) = &contract_def.name { + ident.name.clone() + } else { + "interface".to_string() + } + ); + use ContractPart::*; + + let (contract, unhandled_inherits) = + Contract::from_w_imports(contract_def.clone(), source, imports, self); + + let inherits = contract.inherits.clone(); + let con_name = contract.name.clone().unwrap().name; + let con_node: ContractNode = + if let Some(user_ty_node) = self.user_types.get(&con_name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Contract(contract); + user_ty_node.into() + } else { + let node = self.add_node(Node::Contract(contract)); + self.user_types.insert(con_name, node); + node.into() + }; + + inherits.iter().for_each(|contract_node| { + self.add_edge(*contract_node, con_node, Edge::InheritedContract); + }); + let mut usings = vec![]; + let mut func_nodes = vec![]; + let mut vars = vec![]; + contract_def.parts.iter().for_each(|cpart| match cpart { + StructDefinition(def) => { + let node = self.parse_struct_def(def); + self.add_edge(node, con_node, Edge::Struct); + } + EnumDefinition(def) => { + let node = self.parse_enum_def(def); + self.add_edge(node, con_node, Edge::Enum); + } + ErrorDefinition(def) => { + let node = self.parse_err_def(def); + self.add_edge(node, con_node, Edge::Error); + } + VariableDefinition(def) => { + let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, true); + if let Some(func) = maybe_func { + func_nodes.push(self.handle_func(func, Some(con_node))); + } + + if needs_final_pass { + vars.push((node, con_node.into())); + } + + self.add_edge(node, con_node, Edge::Var); + } + FunctionDefinition(def) => { + let node = self.parse_func_def(def, Some(con_node)); + func_nodes.push(node); + } + TypeDefinition(def) => { + let node = self.parse_ty_def(def); + self.add_edge(node, con_node, Edge::Ty); + } + EventDefinition(_def) => {} + Annotation(_anno) => todo!(), + Using(using) => usings.push((*using.clone(), con_node.0.into())), + StraySemicolon(_loc) => todo!(), + }); + (con_node, func_nodes, usings, unhandled_inherits, vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_using(&mut self, using_def: &Using, scope_node: NodeIdx) { + tracing::trace!("Parsing \"using\" {:?}", using_def); + let Some(ref using_def_ty) = using_def.ty else { + self.add_expr_err(ExprErr::Todo(using_def.loc(), "Using statements with wildcards currently unsupported".to_string())); + return; + }; + let maybe_cvar_idx = self.parse_expr(using_def_ty, None); + let ty_idx = match VarType::try_from_idx(self, maybe_cvar_idx) { + Some(v_ty) => v_ty.ty_idx(), + None => { + self.add_expr_err(ExprErr::Unresolved( + using_def.loc(), + "Unable to deduce the type for which to apply the `using` statement to" + .to_string(), + )); + return; + } + }; + + match &using_def.list { + UsingList::Library(ident_paths) => { + ident_paths.identifiers.iter().for_each(|ident| { + if let Some(hopefully_contract) = self.user_types.get(&ident.name) { + match self.node(*hopefully_contract) { + Node::Contract(_) => { + let funcs = ContractNode::from(*hopefully_contract).funcs(self); + let relevant_funcs: Vec<_> = funcs + .iter() + .filter_map(|func| { + let first_param: FunctionParamNode = + *func.params(self).iter().take(1).next()?; + let param_ty = first_param.ty(self).unwrap(); + if param_ty == ty_idx { + Some(func) + } else { + None + } + }) + .copied() + .collect(); + relevant_funcs.iter().for_each(|func| { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + }); + } + _ => self.add_expr_err(ExprErr::ParseError( + using_def.loc(), + "Tried to use a non-contract as a contract in a `using` statement" + .to_string(), + )), + } + } else { + panic!("Cannot find library contract {}", ident.name); + } + }); + } + UsingList::Functions(vec_ident_paths) => { + vec_ident_paths.iter().for_each(|ident_paths| { + if ident_paths.path.identifiers.len() == 2 { + if let Some(hopefully_contract) = + self.user_types.get(&ident_paths.path.identifiers[0].name) + { + if let Some(func) = ContractNode::from(*hopefully_contract) + .funcs(self) + .iter() + .find(|func| { + func.name(self) + .unwrap() + .starts_with(&ident_paths.path.identifiers[1].name) + }) + { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + } else { + panic!( + "Cannot find library function {}.{}", + ident_paths.path.identifiers[0].name, + ident_paths.path.identifiers[1].name + ); + } + } else { + panic!( + "Cannot find library contract {}", + ident_paths.path.identifiers[0].name + ); + } + } else { + // looking for free floating function + let funcs = match self.node(scope_node) { + Node::Contract(_) => self.search_children( + ContractNode::from(scope_node).associated_source(self), + &Edge::Func, + ), + Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), + _ => unreachable!(), + }; + if let Some(func) = funcs.iter().find(|func| { + FunctionNode::from(**func) + .name(self) + .unwrap() + .starts_with(&ident_paths.path.identifiers[0].name) + }) { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + } else { + panic!( + "Cannot find library function {}", + ident_paths.path.identifiers[0].name + ); + } + } + }); + } + UsingList::Error => todo!(), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_enum_def(&mut self, enum_def: &EnumDefinition) -> EnumNode { + tracing::trace!("Parsing enum {:?}", enum_def); + let enu = Enum::from(enum_def.clone()); + let name = enu.name.clone().expect("Enum was not named").name; + + // check if we have an unresolved type by the same name + let enu_node: EnumNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Enum(enu); + user_ty_node.into() + } else { + let node = self.add_node(enu); + self.user_types.insert(name, node); + node.into() + }; + + enu_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_struct_def(&mut self, struct_def: &StructDefinition) -> StructNode { + tracing::trace!("Parsing struct {:?}", struct_def.name); + let strukt = Struct::from(struct_def.clone()); + + let name = strukt.name.clone().expect("Struct was not named").name; + + // check if we have an unresolved type by the same name + let strukt_node: StructNode = + if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Struct(strukt); + user_ty_node.into() + } else { + let node = self.add_node(strukt); + self.user_types.insert(name, node); + node.into() + }; + + struct_def.fields.iter().for_each(|field| { + let f = Field::new(self, field.clone()); + let field_node = self.add_node(f); + self.add_edge(field_node, strukt_node, Edge::Field); + }); + strukt_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_err_def(&mut self, err_def: &ErrorDefinition) -> ErrorNode { + tracing::trace!("Parsing error {:?}", err_def); + let err_node = ErrorNode(self.add_node(Error::from(err_def.clone())).index()); + err_def.fields.iter().for_each(|field| { + let param = ErrorParam::new(self, field.clone()); + let field_node = self.add_node(param); + self.add_edge(field_node, err_node, Edge::ErrorParam); + }); + err_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_func_def( + &mut self, + func_def: &FunctionDefinition, + con_node: Option, + ) -> FunctionNode { + let func = Function::from(func_def.clone()); + tracing::trace!( + "Parsing function {:?}", + func.name + .clone() + .unwrap_or_else(|| solang_parser::pt::Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".to_string() + }) + .name + ); + self.handle_func(func, con_node) + } + + pub fn handle_func(&mut self, func: Function, con_node: Option) -> FunctionNode { + match func.ty { + FunctionTy::Constructor => { + let node = self.add_node(func); + let func_node = node.into(); + + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::Constructor); + } + func_node + } + FunctionTy::Fallback => { + let node = self.add_node(func); + let func_node = node.into(); + + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::FallbackFunc); + } + + func_node + } + FunctionTy::Receive => { + // receive function cannot have input/output + let node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::ReceiveFunc); + } + FunctionNode::from(node) + } + FunctionTy::Function => { + let fn_node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(fn_node, con_node, Edge::Func); + } + fn_node.into() + } + FunctionTy::Modifier => { + let fn_node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(fn_node, con_node, Edge::Modifier); + } + fn_node.into() + } + } + } + + pub fn parse_var_def( + &mut self, + var_def: &VariableDefinition, + in_contract: bool, + ) -> (VarNode, Option, bool) { + tracing::trace!("Parsing variable definition: {:?}", var_def.name); + let var = Var::new(self, var_def.clone(), in_contract); + let mut func = None; + if var.is_public() { + func = Some(Function::from(var_def.clone())); + } + let needs_final_pass = var.initializer_expr.is_some(); + let var_node = VarNode::from(self.add_node(var)); + self.user_types + .insert(var_node.name(self).unwrap(), var_node.into()); + (var_node, func, needs_final_pass) + } + + pub fn parse_ty_def(&mut self, ty_def: &TypeDefinition) -> TyNode { + tracing::trace!("Parsing type definition"); + let ty = Ty::new(self, ty_def.clone()); + let name = ty.name.name.clone(); + let ty_node: TyNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Ty(ty); + user_ty_node.into() + } else { + let node = self.add_node(Node::Ty(ty)); + self.user_types.insert(name, node); + node.into() + }; + ty_node + } +} + +/// Print the report of parser's diagnostics +pub fn print_diagnostics_report( + content: &str, + path: &Path, + diagnostics: Vec, +) -> std::io::Result<()> { + let filename = path.file_name().unwrap().to_string_lossy().to_string(); + for diag in diagnostics { + let (start, end) = (diag.loc.start(), diag.loc.end()); + let mut report = Report::build(ReportKind::Error, &filename, start) + .with_message(format!("{:?}", diag.ty)) + .with_label( + Label::new((&filename, start..end)) + .with_color(Color::Red) + .with_message(format!("{}", diag.message.fg(Color::Red))), + ); + + for note in diag.notes { + report = report.with_note(note.message); + } + + report.finish().print((&filename, Source::from(content)))?; + } + Ok(()) +} diff --git a/crates/queries/mod.rs b/crates/queries/mod.rs new file mode 100644 index 00000000..18fde10f --- /dev/null +++ b/crates/queries/mod.rs @@ -0,0 +1,2 @@ +pub mod storage_write; +pub mod taint; diff --git a/crates/queries/storage_write/access.rs b/crates/queries/storage_write/access.rs new file mode 100644 index 00000000..86efab45 --- /dev/null +++ b/crates/queries/storage_write/access.rs @@ -0,0 +1,93 @@ +use crate::analyzers::{VarBoundAnalyzer, *}; +use shared::{ + analyzer::*, + context::ContextNode, + nodes::{TypeNode, VarType}, + NodeIdx, +}; + +use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone)] +pub struct AccessStorageWriteReport { + pub msgs: Vec, +} + +impl AccessStorageWriteReport { + pub fn new(msgs: Vec) -> Self { + Self { msgs } + } +} + +impl ReportDisplay for AccessStorageWriteReport { + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Access Analysis", Color::Green) + } + fn msg(&self, _analyzer: &impl GraphLike) -> String { + self.msgs.join(";\n") + } + + fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { + vec![] + } + + fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + let report = Report::build(self.report_kind(), "".to_string(), 0) + .with_message(self.msg(analyzer)) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ); + vec![report.finish()] + } + + fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + for report in reports.iter() { + report.print(&mut *src).unwrap(); + } + } + + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + reports.iter().for_each(|report| { + report.eprint(&mut src).unwrap(); + }); + } +} + +impl AccessStorageWriteQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} +pub trait AccessStorageWriteQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { + #[allow(clippy::too_many_arguments)] + fn access_query( + &self, + _entry: NodeIdx, + _file_mapping: &'_ BTreeMap, + _report_config: ReportConfig, + _contract_name: String, + _storage_var_name: String, + ) -> AccessStorageWriteReport { + todo!() + } + + fn recurse(&self, ctx: ContextNode, storage_var_name: String) -> Vec { + if let Some(cvar) = ctx.var_by_name(self, &storage_var_name) { + match cvar.ty(self).unwrap() { + VarType::User(TypeNode::Struct(s_node), _) => { + let fields = s_node + .fields(self) + .iter() + .map(|field| format!("{}.{}", storage_var_name, field.name(self).unwrap())) + .collect(); + fields + } + _ => vec![storage_var_name], + } + } else { + vec![storage_var_name] + } + } +} diff --git a/crates/queries/storage_write/mod.rs b/crates/queries/storage_write/mod.rs new file mode 100644 index 00000000..17f8adc3 --- /dev/null +++ b/crates/queries/storage_write/mod.rs @@ -0,0 +1,5 @@ +mod access; +pub use access::*; + +mod target; +pub use target::*; diff --git a/crates/queries/storage_write/target.rs b/crates/queries/storage_write/target.rs new file mode 100644 index 00000000..d244f04d --- /dev/null +++ b/crates/queries/storage_write/target.rs @@ -0,0 +1,156 @@ +use crate::analyzers::{VarBoundAnalyzer, *}; +use shared::{ + analyzer::*, + range::{range_string::ToRangeString, Range, SolcRange}, + NodeIdx, +}; + +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone)] +pub struct StorageRangeReport { + pub target: SolcRange, + pub write_loc: Option, + pub analysis: VarBoundAnalysis, +} + +impl ReportDisplay for StorageRangeReport { + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Storage Write Query", Color::Green) + } + fn msg(&self, analyzer: &impl GraphLike) -> String { + let bounds_string = self + .analysis + .ctx + .ctx_deps(analyzer) + .unwrap() + .iter() + .filter_map(|(_name, cvar)| { + let min = if self.analysis.report_config.eval_bounds { + cvar.range(analyzer) + .unwrap()? + .evaled_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s + } else if self.analysis.report_config.simplify_bounds { + cvar.range(analyzer) + .unwrap()? + .simplified_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s + } else { + cvar.range(analyzer) + .unwrap()? + .range_min() + .to_range_string(false, analyzer) + .s + }; + + let max = if self.analysis.report_config.eval_bounds { + cvar.range(analyzer) + .unwrap()? + .evaled_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s + } else if self.analysis.report_config.simplify_bounds { + cvar.range(analyzer) + .unwrap()? + .simplified_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s + } else { + cvar.range(analyzer) + .unwrap()? + .range_max() + .to_range_string(true, analyzer) + .s + }; + + Some(format!( + "\"{}\" ∈ {{{}, {}}}", + cvar.display_name(analyzer).unwrap(), + min, + max, + )) + }) + .collect::>() + .join(" ∧ "); + format!( + "Found storage write that could lead to target value in ctx {}: \"{}\" ∈ {{{}, {}}}{}{} ", + self.analysis.ctx.path(analyzer), + self.analysis.var_name, + self.target + .evaled_range_min(analyzer).unwrap() .to_range_string(false, analyzer) + .s, + self.target + .evaled_range_max(analyzer).unwrap() .to_range_string(true, analyzer) + .s, + if bounds_string.is_empty() { + "" + } else { + ", where " + }, + bounds_string.fg(Color::Yellow) + ) + } + + fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { + vec![] + } + + fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + let mut report = Report::build( + self.analysis.report_kind(), + self.analysis.var_def.0.source(), + self.analysis.var_def.0.start(), + ) + .with_message(self.msg(analyzer)) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ); + + report.add_labels(self.analysis.labels(analyzer)); + + let reports = vec![report.finish()]; + reports + } + + fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + for report in reports.iter() { + report.print(&mut *src).unwrap(); + } + } + + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + reports.iter().for_each(|report| { + report.eprint(&mut src).unwrap(); + }); + } +} + +impl StorageRangeQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} +pub trait StorageRangeQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { + #[allow(clippy::too_many_arguments)] + fn func_query( + &mut self, + _entry: NodeIdx, + _file_mapping: &'_ BTreeMap, + _report_config: ReportConfig, + _contract_name: String, + _func_name: String, + _storage_var_name: String, + _target: SolcRange, + ) -> Option { + todo!() + } +} diff --git a/crates/queries/taint.rs b/crates/queries/taint.rs new file mode 100644 index 00000000..83d03571 --- /dev/null +++ b/crates/queries/taint.rs @@ -0,0 +1,68 @@ +use crate::analyzers::{VarBoundAnalyzer, *}; +use shared::context::CallFork; + +use shared::{analyzer::*, NodeIdx}; + +use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; + +#[derive(Debug, Clone)] +pub struct TaintReport { + pub msgs: Vec, +} + +impl TaintReport { + pub fn new(msgs: Vec) -> Self { + Self { msgs } + } +} + +impl ReportDisplay for TaintReport { + fn report_kind(&self) -> ReportKind { + ReportKind::Custom("Taint Analysis", Color::Green) + } + fn msg(&self, _analyzer: &impl GraphLike) -> String { + self.msgs.join(";\n") + } + + fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { + vec![] + } + + fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + let report = Report::build(self.report_kind(), "".to_string(), 0) + .with_message(self.msg(analyzer)) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ); + vec![report.finish()] + } + + fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + for report in reports.iter() { + report.print(&mut *src).unwrap(); + } + } + + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + let reports = &self.reports(analyzer); + reports.iter().for_each(|report| { + report.eprint(&mut src).unwrap(); + }); + } +} + +impl TaintQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} +pub trait TaintQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { + #[allow(clippy::too_many_arguments)] + fn taint_query(&self, _entry: NodeIdx, _contract_name: String) { + todo!() + } + + fn recurse_children(&self, _child: CallFork) { + todo!() + } +} diff --git a/crates/solc_expressions/array.rs b/crates/solc_expressions/array.rs new file mode 100644 index 00000000..2acc730b --- /dev/null +++ b/crates/solc_expressions/array.rs @@ -0,0 +1,183 @@ +use crate::context::ExprErr; +use crate::context::IntoExprErr; +use crate::{ + context::exprs::{member_access::MemberAccess, require::Require}, + Builtin, ContextBuilder, Edge, Node, VarType, +}; +use shared::{analyzer::AnalyzerLike, context::*, range::elem::RangeOp}; +use solang_parser::helpers::CodeLocation; +use solang_parser::pt::{Expression, Loc}; + +impl Array for T where T: AnalyzerLike + Sized {} +pub trait Array: AnalyzerLike + Sized { + /// Gets the array type + #[tracing::instrument(level = "trace", skip_all)] + fn array_ty(&mut self, ty_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(ty_expr, ctx)?; + self.apply_to_edges(ctx, ty_expr.loc(), &|analyzer, ctx, loc| { + if let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_ty(ctx, ty_expr, ret) + } else { + Err(ExprErr::NoLhs( + loc, + "No array specified for getting array type".to_string(), + )) + } + }) + } + + fn match_ty( + &mut self, + ctx: ContextNode, + ty_expr: &Expression, + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(inner_ty) | ExprRet::SingleLiteral(inner_ty) => { + if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { + let dyn_b = Builtin::Array(var_type); + if let Some(idx) = self.builtins().get(&dyn_b) { + ctx.push_expr(ExprRet::Single(*idx), self) + .into_expr_err(ty_expr.loc())?; + } else { + let idx = self.add_node(Node::Builtin(dyn_b.clone())); + self.builtins_mut().insert(dyn_b, idx); + ctx.push_expr(ExprRet::Single(idx), self) + .into_expr_err(ty_expr.loc())?; + } + Ok(()) + } else { + Err(ExprErr::ArrayTy(ty_expr.loc(), "Expected to be able to convert to a var type from an index to determine array type. This is a bug. Please report it at github.com/nascentxyz/pyrometer.".to_string())) + } + } + ExprRet::Multi(inner) => { + inner + .into_iter() + .map(|i| self.match_ty(ctx, ty_expr, i)) + .collect::, ExprErr>>()?; + Ok(()) + } + ExprRet::CtxKilled(kind) => { + ctx.kill(self, ty_expr.loc(), kind) + .into_expr_err(ty_expr.loc())?; + Ok(()) + } + ExprRet::Null => Ok(()), + } + } + + /// Indexes into an array + #[tracing::instrument(level = "trace", skip_all)] + fn index_into_array( + &mut self, + loc: Loc, + ty_expr: &Expression, + index_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!("Indexing into array"); + self.parse_ctx_expr(index_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(index_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Could not find the index variable".to_string())) + }; + if matches!(index_tys, ExprRet::CtxKilled(_)) { + ctx.push_expr(index_tys, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(ty_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(inner_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Could not find the array".to_string())) + }; + if matches!(inner_tys, ExprRet::CtxKilled(_)) { + ctx.push_expr(inner_tys, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.index_into_array_inner( + ctx, + loc, + inner_tys.flatten(), + index_tys.clone().flatten(), + ) + }) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn index_into_array_inner( + &mut self, + ctx: ContextNode, + loc: Loc, + inner_paths: ExprRet, + index_paths: ExprRet, + ) -> Result<(), ExprErr> { + match (inner_paths, index_paths) { + (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), + (_, ExprRet::CtxKilled(kind)) => { + ctx.kill(self, loc, kind).into_expr_err(loc) + } + (ExprRet::CtxKilled(kind), _) => { + ctx.kill(self, loc, kind).into_expr_err(loc) + } + (ExprRet::Single(parent), ExprRet::Single(index)) | (ExprRet::Single(parent), ExprRet::SingleLiteral(index)) => { + let index = ContextVarNode::from(index).latest_version(self); + let parent = ContextVarNode::from(parent).latest_version(self); + let idx = self.advance_var_in_ctx(index, loc, ctx)?; + if !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { + let len_var = self.tmp_length(parent, ctx, loc).latest_version(self); + self.handle_require_inner( + ctx, + loc, + &ExprRet::Single(len_var.latest_version(self).into()), + &ExprRet::Single(idx.latest_version(self).into()), + RangeOp::Gt, + RangeOp::Lt, + (RangeOp::Lte, RangeOp::Gte), + )?; + } + + let name = format!("{}[{}]", parent.name(self).into_expr_err(loc)?, index.name(self).into_expr_err(loc)?); + + if let Some(index_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + let index_var = index_var.latest_version(self); + let index_var = self.advance_var_in_ctx(index_var, loc, ctx)?; + ctx.push_expr(ExprRet::Single(index_var.into()), self).into_expr_err(loc)?; + Ok(()) + } else { + let ty = parent.ty(self).into_expr_err(loc)?.clone(); + let ty = ty.get_index_dynamic_ty(index, self).into_expr_err(loc)?; + let index_var = ContextVar { + loc: Some(loc), + name: name.clone(), + display_name: format!( + "{}[{}]", + parent.display_name(self).into_expr_err(loc)?, + index.display_name(self).into_expr_err(loc)? + ), + storage: parent.storage(self).into_expr_err(loc)?.clone(), + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty, + }; + + let idx_node = self.add_node(Node::ContextVar(index_var)); + self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); + self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; + self.add_edge(index, idx_node, Edge::Context(ContextEdge::Index)); + + ctx.push_expr(ExprRet::Single(idx_node), self).into_expr_err(loc)?; + Ok(()) + } + } + e => Err(ExprErr::ArrayIndex(loc, format!("Expected single expr evaluation of index expression, but was: {e:?}. This is a bug. Please report it at github.com/nascentxyz/pyrometer."))), + } + } +} diff --git a/crates/solc_expressions/bin_op.rs b/crates/solc_expressions/bin_op.rs new file mode 100644 index 00000000..22804398 --- /dev/null +++ b/crates/solc_expressions/bin_op.rs @@ -0,0 +1,797 @@ +use crate::context::exprs::require::Require; +use crate::context::exprs::IntoExprErr; +use crate::context::{ContextBuilder, ExprErr}; +use ethers_core::types::{I256, U256}; + +use shared::range::elem::RangeElem; +use shared::range::elem_ty::RangeExpr; +use shared::{ + analyzer::AnalyzerLike, + context::*, + nodes::{BuiltInNode, Builtin, Concrete, VarType}, + range::{ + elem::RangeOp, + elem_ty::{Dynamic, Elem}, + Range, RangeEval, SolcRange, + }, + Edge, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl BinOp for T where T: AnalyzerLike + Sized {} +pub trait BinOp: AnalyzerLike + Sized { + /// Evaluate and execute a binary operation expression + #[tracing::instrument(level = "trace", skip_all)] + fn op_expr( + &mut self, + loc: Loc, + lhs_expr: &Expression, + rhs_expr: &Expression, + ctx: ContextNode, + op: RangeOp, + assign: bool, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(rhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Binary operation had no right hand side".to_string())) + }; + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let rhs_paths = rhs_paths.flatten(); + let rhs_ctx = ctx; + analyzer.parse_ctx_expr(lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, format!("Binary operation had no left hand side, Expr: {lhs_expr:#?}, rhs ctx: {}, curr ctx: {}", rhs_ctx.path(analyzer), ctx.path(analyzer)))) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let lhs_paths = lhs_paths.flatten(); + analyzer.op_match(ctx, loc, &lhs_paths, &rhs_paths, op, assign) + }) + }) + } + + fn op_match( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: &ExprRet, + op: RangeOp, + assign: bool, + ) -> Result<(), ExprErr> { + match (lhs_paths, rhs_paths) { + (ExprRet::Null, _) => Err(ExprErr::NoLhs( + loc, + "No left hand side provided for binary operation".to_string(), + )), + (_, ExprRet::Null) => Err(ExprErr::NoRhs( + loc, + "No right hand side provided for binary operation".to_string(), + )), + (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + lhs_cvar.try_increase_size(self).into_expr_err(loc)?; + rhs_cvar.try_increase_size(self).into_expr_err(loc)?; + ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { + ContextVarNode::from(*lhs) + .cast_from(&ContextVarNode::from(*rhs), self) + .into_expr_err(loc)?; + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { + ContextVarNode::from(*rhs) + .cast_from(&ContextVarNode::from(*lhs), self) + .into_expr_err(loc)?; + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (lhs @ ExprRet::Single(..), ExprRet::Multi(rhs_sides)) => { + rhs_sides + .iter() + .map(|expr_ret| self.op_match(ctx, loc, lhs, expr_ret, op, assign)) + .collect::, ExprErr>>()?; + Ok(()) + } + (ExprRet::Multi(lhs_sides), rhs @ ExprRet::Single(..)) => { + lhs_sides + .iter() + .map(|expr_ret| self.op_match(ctx, loc, expr_ret, rhs, op, assign)) + .collect::, ExprErr>>()?; + Ok(()) + } + (_, ExprRet::CtxKilled(kind)) => ctx.kill(self, loc, *kind).into_expr_err(loc), + (ExprRet::CtxKilled(kind), _) => ctx.kill(self, loc, *kind).into_expr_err(loc), + (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled combination in binop: {lhs_sides:?} {rhs_sides:?}"), + )), + (l, r) => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled combination in binop: {l:?} {r:?}"), + )), + } + } + + /// Execute a binary operation after parsing the expressions + #[tracing::instrument(level = "trace", skip_all)] + fn op( + &mut self, + loc: Loc, + lhs_cvar: ContextVarNode, + rhs_cvar: ContextVarNode, + ctx: ContextNode, + op: RangeOp, + assign: bool, + ) -> Result { + tracing::trace!( + "binary op: {} {} {}, assign: {}", + lhs_cvar.display_name(self).into_expr_err(loc)?, + op.to_string(), + rhs_cvar.display_name(self).into_expr_err(loc)?, + assign + ); + + let unchecked = match op { + RangeOp::Add(u) | RangeOp::Sub(u) | RangeOp::Mul(u) | RangeOp::Div(u) => u, + _ => false, + }; + + let new_lhs = if assign { + self.advance_var_in_ctx(lhs_cvar, loc, ctx)? + } else { + let mut new_lhs_underlying = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} {} {})", + ctx.new_tmp(self).into_expr_err(loc)?, + lhs_cvar.name(self).into_expr_err(loc)?, + op.to_string(), + rhs_cvar.name(self).into_expr_err(loc)? + ), + display_name: format!( + "({} {} {})", + lhs_cvar.display_name(self).into_expr_err(loc)?, + op.to_string(), + rhs_cvar.display_name(self).into_expr_err(loc)? + ), + storage: None, + is_tmp: true, + is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)? + || rhs_cvar.is_symbolic(self).into_expr_err(loc)?, + is_return: false, + tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), + ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), + }; + + // will potentially mutate the ty from concrete to builtin with a concrete range + new_lhs_underlying + .ty + .concrete_to_builtin(self) + .into_expr_err(loc)?; + + let new_var = self.add_node(Node::ContextVar(new_lhs_underlying)); + ctx.add_var(new_var.into(), self).into_expr_err(loc)?; + self.add_edge(new_var, ctx, Edge::Context(ContextEdge::Variable)); + ContextVarNode::from(new_var) + }; + + let mut new_rhs = rhs_cvar.latest_version(self); + + let expr = Elem::Expr(RangeExpr::::new( + Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), + op, + Elem::from(Dynamic::new(rhs_cvar.latest_version(self).into())), + )); + + // TODO: change to only hit this path if !uncheck + + // TODO: If one of lhs_cvar OR rhs_cvar are not symbolic, + // apply the requirement on the symbolic expression side instead of + // ignoring the case where + + // if lhs_cvar.is_symbolic(self) && new_rhs.is_symbolic(self) { + if !unchecked { + match op { + RangeOp::Div(..) | RangeOp::Mod => { + if new_rhs.is_const(self).into_expr_err(loc)? { + if new_rhs + .evaled_range_min(self) + .into_expr_err(loc)? + .expect("No range?") + .range_eq(&Elem::from(Concrete::from(U256::zero()))) + { + let res = ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc); + let _ = self.add_if_err(res); + + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { + let tmp_rhs = self.advance_var_in_ctx(new_rhs, loc, ctx)?; + let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); + let var = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + zero_node.into(), + self, + ); + let zero_node = self.add_node(Node::ContextVar(var.into_expr_err(loc)?)); + + if self + .require( + tmp_rhs, + zero_node.into(), + ctx, + loc, + RangeOp::Neq, + RangeOp::Eq, + (RangeOp::Eq, RangeOp::Neq), + )? + .is_none() + { + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} != 0)", + ctx.new_tmp(self).into_expr_err(loc)?, + tmp_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} != 0)", + tmp_rhs.display_name(self).into_expr_err(loc)?, + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new( + new_lhs, + RangeOp::Gt, + Some(zero_node.into()), + )), + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + + let range = tmp_rhs + .ref_range(self) + .into_expr_err(loc)? + .expect("No range?"); + if range.min_is_negative(self).into_expr_err(loc)? { + let mut range_excls = range.range_exclusions(); + let excl = Elem::from(Concrete::from(I256::zero())); + if !range_excls.contains(&excl) { + range_excls.push(excl); + } + tmp_rhs + .set_range_exclusions(self, range_excls) + .into_expr_err(loc)?; + } else { + // the new min is max(1, rhs.min) + let min = Elem::max( + Elem::from(Dynamic::new(new_rhs.into())), + // tmp_rhs + // .range_min(self) + // .into_expr_err(loc)? + // .unwrap_or_else(|| { + // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) + // }), + Elem::from(Concrete::from(U256::from(1))).cast( + Elem::from(Dynamic::new(tmp_rhs.into())), // .range_min(self) + // .into_expr_err(loc)? + // .expect("No range minimum?"), + ), + ); + + tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; + new_rhs = tmp_rhs; + } + } + } + RangeOp::Sub(..) => { + let lhs_cvar = lhs_cvar.latest_version(self); + if lhs_cvar.is_const(self).into_expr_err(loc)? { + if !lhs_cvar.is_int(self).into_expr_err(loc)? { + if let (Some(lmax), Some(rmin)) = ( + lhs_cvar.evaled_range_max(self).into_expr_err(loc)?, + rhs_cvar.evaled_range_min(self).into_expr_err(loc)?, + ) { + if matches!( + lmax.range_ord(&rmin), + Some(std::cmp::Ordering::Less) + | Some(std::cmp::Ordering::Equal) + ) { + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + } + } + } else if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { + let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; + if self + .require( + tmp_lhs, + new_rhs, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + // the new min is max(lhs.min, rhs.min) + let min = Elem::max( + Elem::from(Dynamic::new(lhs_cvar.into())), + // .range_min(self) + // .into_expr_err(loc)? + // .unwrap_or_else(|| { + // panic!( + // "No range minimum: {:?}", + // tmp_lhs.ty(self).unwrap().as_dot_str(self) + // ) + // }), + Elem::from(rhs_cvar), + ); + tmp_lhs.set_range_min(self, min).into_expr_err(loc)?; + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} >= {})", + ctx.new_tmp(self).into_expr_err(loc)?, + tmp_lhs.name(self).into_expr_err(loc)?, + new_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} >= {})", + tmp_lhs.display_name(self).unwrap(), + new_rhs.display_name(self).unwrap(), + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new( + tmp_lhs, + RangeOp::Gte, + Some(new_rhs), + )), + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + } + } + RangeOp::Add(..) => { + let lhs_cvar = lhs_cvar.latest_version(self); + if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { + let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; + + // the new max is min(lhs.max, (2**256 - rhs.min)) + let max = Elem::min( + Elem::from(Dynamic::new(lhs_cvar.into())), + // .range_max(self) + // .into_expr_err(loc)? + // .expect("No range max?"), + Elem::from(Concrete::from(U256::MAX)) - Elem::from(rhs_cvar), + ); + + tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; + + let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); + let tmp_max = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + max_node.into(), + self, + ); + let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); + + let tmp_rhs = self.op( + loc, + max_node.into(), + new_rhs, + ctx, + RangeOp::Sub(false), + false, + )?; + + if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { + return Ok(tmp_rhs); + } + + let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; + + if self + .require( + tmp_lhs, + tmp_rhs.into(), + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} <= 2**256 - 1 - {})", + ctx.new_tmp(self).into_expr_err(loc)?, + tmp_lhs.name(self).into_expr_err(loc)?, + new_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} <= 2**256 - 1 - {})", + tmp_lhs.display_name(self).unwrap(), + new_rhs.display_name(self).unwrap(), + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new( + tmp_lhs, + RangeOp::Lte, + Some(tmp_rhs.into()), + )), + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + } + } + RangeOp::Mul(..) => { + let lhs_cvar = lhs_cvar.latest_version(self); + if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { + let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; + + // the new max is min(lhs.max, (2**256 / max(1, rhs.min))) + let max = Elem::min( + Elem::from(Dynamic::new(lhs_cvar.into())), + // .range_max(self) + // .into_expr_err(loc)? + // .expect("No range max?"), + Elem::from(Concrete::from(U256::MAX)) + / Elem::max( + Elem::from(Concrete::from(U256::from(1))), + Elem::from(rhs_cvar), + ), + ); + + tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; + + let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); + let tmp_max = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + max_node.into(), + self, + ); + let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); + + let tmp_rhs = + self.op(loc, max_node.into(), new_rhs, ctx, RangeOp::Div(true), true)?; + + if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { + return Ok(tmp_rhs); + } + + let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; + + if self + .require( + tmp_lhs, + tmp_rhs.into(), + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} <= (2**256 - 1) / {})", + ctx.new_tmp(self).into_expr_err(loc)?, + tmp_lhs.name(self).into_expr_err(loc)?, + new_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} <= (2**256 - 1) / {})", + tmp_lhs.display_name(self).unwrap(), + new_rhs.display_name(self).unwrap(), + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new( + tmp_lhs, + RangeOp::Lte, + Some(tmp_rhs.into()), + )), + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + } + } + RangeOp::Exp => { + if new_rhs.is_const(self).into_expr_err(loc)? { + if matches!( + new_rhs + .evaled_range_min(self) + .into_expr_err(loc)? + .expect("No range") + .range_ord(&Elem::from(Concrete::from(U256::zero()))), + Some(std::cmp::Ordering::Less) + ) { + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { + let tmp_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; + // the new min is max(lhs.min, rhs.min) + let min = Elem::max( + Elem::from(Dynamic::new(rhs_cvar.into())), + // .range_min(self) + // .into_expr_err(loc)? + // .expect("No range minimum?"), + Elem::from(Concrete::from(U256::zero())), + ); + + tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; + + let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); + let tmp_zero = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + zero_node.into(), + self, + ); + let zero_node = + self.add_node(Node::ContextVar(tmp_zero.into_expr_err(loc)?)); + + if self + .require( + tmp_rhs, + zero_node.into(), + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(ExprRet::CtxKilled(KilledKind::Revert)); + } + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} >= 0)", + ctx.new_tmp(self).into_expr_err(loc)?, + tmp_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} >= 0)", + tmp_rhs.display_name(self).into_expr_err(loc)?, + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new( + tmp_rhs, + RangeOp::Gte, + Some(zero_node.into()), + )), + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + new_rhs = tmp_rhs; + } + } + _ => {} + } + } + + // let lhs_range = if let Some(lhs_range) = new_lhs.range(self).into_expr_err(loc)? { + // lhs_range + // } else { + // new_rhs + // .range(self) + // .into_expr_err(loc)? + // .expect("Neither lhs nor rhs had a usable range") + // }; + + // let func = SolcRange::dyn_fn_from_op(op); + // let new_range = func(lhs_range, new_rhs); + new_lhs + .set_range_min(self, expr.clone()) + .into_expr_err(loc)?; + new_lhs.set_range_max(self, expr).into_expr_err(loc)?; + + // last ditch effort to prevent exponentiation from having a minimum of 1 instead of 0. + // if the lhs is 0 check if the rhs is also 0, otherwise set minimum to 0. + if matches!(op, RangeOp::Exp) { + if let (Some(old_lhs_range), Some(rhs_range)) = ( + lhs_cvar + .latest_version(self) + .ref_range(self) + .into_expr_err(loc)?, + new_rhs.ref_range(self).into_expr_err(loc)?, + ) { + let zero = Elem::from(Concrete::from(U256::zero())); + let zero_range = SolcRange::new(zero.clone(), zero.clone(), vec![]); + // We have to check if the the lhs and the right hand side contain the zero range. + // If they both do, we have to set the minimum to zero due to 0**0 = 1, but 0**x = 0. + // This is technically a slight widening of the interval and could be improved. + if old_lhs_range.contains(&zero_range, self) + && rhs_range.contains(&zero_range, self) + { + new_lhs.set_range_min(self, zero).into_expr_err(loc)?; + } + } + } + Ok(ExprRet::Single(new_lhs.into())) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn bit_not( + &mut self, + loc: Loc, + lhs_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(lhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + }; + + if matches!(lhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.bit_not_inner(ctx, loc, lhs.flatten()) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn bit_not_inner( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_expr: ExprRet, + ) -> Result<(), ExprErr> { + match lhs_expr { + ExprRet::CtxKilled(kind) => { + ctx.kill(self, loc, kind).into_expr_err(loc)?; + ctx.push_expr(lhs_expr, self).into_expr_err(loc)?; + Ok(()) + } + ExprRet::SingleLiteral(lhs) => { + // TODO: try to pop from the stack and if there is a single element there + // use it as a type hint, then place it back on the stack + ContextVarNode::from(lhs) + .try_increase_size(self) + .into_expr_err(loc)?; + self.bit_not_inner(ctx, loc, ExprRet::Single(lhs))?; + Ok(()) + } + ExprRet::Single(lhs) => { + let lhs_cvar = ContextVarNode::from(lhs); + tracing::trace!( + "bitwise not: {}", + lhs_cvar.display_name(self).into_expr_err(loc)? + ); + let out_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}(~{})", + ctx.new_tmp(self).into_expr_err(loc)?, + lhs_cvar.name(self).into_expr_err(loc)?, + ), + display_name: format!("~{}", lhs_cvar.display_name(self).into_expr_err(loc)?,), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::BitNot, None)), + is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, + is_return: false, + ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), + }; + + let expr = Elem::Expr(RangeExpr::::new( + Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), + RangeOp::BitNot, + Elem::Null, + )); + + let out_var = ContextVarNode::from(self.add_node(Node::ContextVar(out_var))); + + out_var + .set_range_min(self, expr.clone()) + .into_expr_err(loc)?; + out_var.set_range_max(self, expr).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(out_var.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(f) => Err(ExprErr::MultiNot( + loc, + format!("Multiple elements in bitwise not expression: {f:?}"), + )), + ExprRet::Null => Err(ExprErr::NoRhs( + loc, + "No right hand side in `not` expression".to_string(), + )), + } + } +} diff --git a/crates/solc_expressions/cmp.rs b/crates/solc_expressions/cmp.rs new file mode 100644 index 00000000..f7fe03a1 --- /dev/null +++ b/crates/solc_expressions/cmp.rs @@ -0,0 +1,469 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::ContextBuilder; +use shared::analyzer::GraphError; + +use shared::{ + analyzer::AnalyzerLike, + context::*, + nodes::*, + range::{ + elem::{RangeElem, RangeOp}, + elem_ty::{Elem, RangeConcrete, RangeExpr}, + Range, SolcRange, + }, + Node, +}; + +use solang_parser::pt::{Expression, Loc}; +use std::cmp::Ordering; + +impl Cmp for T where T: AnalyzerLike + Sized {} +pub trait Cmp: AnalyzerLike + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn not(&mut self, loc: Loc, lhs_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(lhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + }; + + if matches!(lhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.not_inner(ctx, loc, lhs.flatten()) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn not_inner(&mut self, ctx: ContextNode, loc: Loc, lhs_expr: ExprRet) -> Result<(), ExprErr> { + match lhs_expr { + ExprRet::CtxKilled(kind) => { + ctx.kill(self, loc, kind).into_expr_err(loc)?; + ctx.push_expr(lhs_expr, self).into_expr_err(loc)?; + Ok(()) + } + ExprRet::Single(lhs) | ExprRet::SingleLiteral(lhs) => { + let lhs_cvar = ContextVarNode::from(lhs); + tracing::trace!("not: {}", lhs_cvar.display_name(self).into_expr_err(loc)?); + let range = self.not_eval(ctx, loc, lhs_cvar)?; + let out_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}(!{})", + ctx.new_tmp(self).into_expr_err(loc)?, + lhs_cvar.name(self).into_expr_err(loc)?, + ), + display_name: format!("!{}", lhs_cvar.display_name(self).into_expr_err(loc)?,), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Not, None)), + is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + Some(range), + ), + }; + + ctx.push_expr( + ExprRet::Single(self.add_node(Node::ContextVar(out_var))), + self, + ) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(f) => Err(ExprErr::MultiNot( + loc, + format!("Multiple elements in not expression: {f:?}"), + )), + ExprRet::Null => Err(ExprErr::NoRhs( + loc, + "No right hand side in `not` expression".to_string(), + )), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn cmp( + &mut self, + loc: Loc, + lhs_expr: &Expression, + op: RangeOp, + rhs_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(rhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Cmp operation had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Cmp operation had no left hand side".to_string())) + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.cmp_inner(ctx, loc, &lhs_paths.flatten(), op, &rhs_paths) + }) + }) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn cmp_inner( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_paths: &ExprRet, + op: RangeOp, + rhs_paths: &ExprRet, + ) -> Result<(), ExprErr> { + match (lhs_paths, rhs_paths) { + (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), + (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { + ContextVarNode::from(*lhs) + .literal_cast_from(&ContextVarNode::from(*rhs), self) + .into_expr_err(loc)?; + self.cmp_inner(ctx, loc, &ExprRet::Single(*rhs), op, rhs_paths) + } + (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + lhs_cvar.try_increase_size(self).into_expr_err(loc)?; + rhs_cvar.try_increase_size(self).into_expr_err(loc)?; + self.cmp_inner( + ctx, + loc, + &ExprRet::Single(lhs_cvar.into()), + op, + &ExprRet::Single(rhs_cvar.into()), + ) + } + (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { + ContextVarNode::from(*rhs) + .literal_cast_from(&ContextVarNode::from(*lhs), self) + .into_expr_err(loc)?; + self.cmp_inner(ctx, loc, lhs_paths, op, &ExprRet::Single(*rhs)) + } + (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs); + let rhs_cvar = ContextVarNode::from(*rhs); + tracing::trace!( + "cmp: {} {} {}", + lhs_cvar.display_name(self).unwrap(), + op.to_string(), + rhs_cvar.display_name(self).unwrap() + ); + let range = { + let elem = Elem::Expr(RangeExpr { + minimized: None, + maximized: None, + lhs: Box::new(Elem::from(lhs_cvar)), + op, + rhs: Box::new(Elem::from(rhs_cvar)), + }); + + let exclusions = lhs_cvar + .ref_range(self) + .into_expr_err(loc)? + .expect("No lhs range") + .range_exclusions(); + SolcRange::new(elem.clone(), elem, exclusions) + }; + // println!("{:?}", range.evaled_range_max(self)); + // println!("{:?}", range.evaled_range_min(self)); + + // println!( + // "cmp: {} {} {}, [{}, {}], [{}, {}] ", + // lhs_cvar.name(self).into_expr_err(loc)?, + // op.to_string(), + // rhs_cvar.name(self).into_expr_err(loc)?, + // lhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, + // lhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s, + // rhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, + // rhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s + // ); + + let out_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} {} {})", + ctx.new_tmp(self).into_expr_err(loc)?, + lhs_cvar.name(self).into_expr_err(loc)?, + op.to_string(), + rhs_cvar.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "{} {} {}", + lhs_cvar.display_name(self).into_expr_err(loc)?, + op.to_string(), + rhs_cvar.display_name(self).into_expr_err(loc)?, + ), + storage: None, + is_tmp: true, + is_symbolic: ContextVarNode::from(*lhs) + .is_symbolic(self) + .into_expr_err(loc)? + || ContextVarNode::from(*rhs) + .is_symbolic(self) + .into_expr_err(loc)?, + is_return: false, + tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + Some(range), + ), + }; + + ctx.push_expr( + ExprRet::Single(self.add_node(Node::ContextVar(out_var))), + self, + ) + .into_expr_err(loc) + } + (l @ ExprRet::Single(_lhs), ExprRet::Multi(rhs_sides)) => { + rhs_sides + .iter() + .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, l, op, expr_ret))?; + Ok(()) + } + (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_)) => { + lhs_sides + .iter() + .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, expr_ret, op, r))?; + Ok(()) + } + (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( + |(lhs_expr_ret, rhs_expr_ret)| { + self.cmp_inner(ctx, loc, lhs_expr_ret, op, rhs_expr_ret) + }, + )?; + Ok(()) + } else { + rhs_sides.iter().try_for_each(|rhs_expr_ret| { + self.cmp_inner(ctx, loc, lhs_paths, op, rhs_expr_ret) + })?; + Ok(()) + } + } + (e, f) => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled combination in `cmp`: {e:?} {f:?}"), + )), + } + } + + fn not_eval( + &self, + _ctx: ContextNode, + loc: Loc, + lhs_cvar: ContextVarNode, + ) -> Result { + if let Some(lhs_range) = lhs_cvar.range(self).into_expr_err(loc)? { + let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + + // invert + if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?) { + let val = Elem::Expr(RangeExpr { + minimized: None, + maximized: None, + lhs: Box::new(lhs_range.range_min().into_owned()), + op: RangeOp::Not, + rhs: Box::new(Elem::Null), + }); + + return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions)); + } + } + + let min = RangeConcrete { + val: Concrete::Bool(false), + loc, + }; + + let max = RangeConcrete { + val: Concrete::Bool(true), + loc, + }; + Ok(SolcRange::new( + Elem::Concrete(min), + Elem::Concrete(max), + vec![], + )) + } + + fn range_eval( + &self, + _ctx: ContextNode, + lhs_cvar: ContextVarNode, + rhs_cvar: ContextVarNode, + op: RangeOp, + ) -> Result { + if let Some(lhs_range) = lhs_cvar.ref_range(self)? { + if let Some(rhs_range) = rhs_cvar.ref_range(self)? { + match op { + RangeOp::Lt => { + // if lhs_max < rhs_min, we know this cmp will evaluate to + // true + + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { + return Ok(true.into()); + } + + // Similarly if lhs_min >= rhs_max, we know this cmp will evaluate to + // false + let lhs_min = lhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + match lhs_min.range_ord(&rhs_max) { + Some(Ordering::Greater) => { + return Ok(false.into()); + } + Some(Ordering::Equal) => { + return Ok(false.into()); + } + _ => {} + } + } + RangeOp::Gt => { + // if lhs_min > rhs_max, we know this cmp will evaluate to + // true + let lhs_min = lhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { + return Ok(true.into()); + } + + // if lhs_max <= rhs_min, we know this cmp will evaluate to + // false + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + match lhs_max.range_ord(&rhs_min) { + Some(Ordering::Less) => { + return Ok(false.into()); + } + Some(Ordering::Equal) => { + return Ok(false.into()); + } + _ => {} + } + } + RangeOp::Lte => { + // if lhs_max <= rhs_min, we know this cmp will evaluate to + // true + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + match lhs_max.range_ord(&rhs_min) { + Some(Ordering::Less) => { + return Ok(true.into()); + } + Some(Ordering::Equal) => { + return Ok(true.into()); + } + _ => {} + } + + // Similarly if lhs_min > rhs_max, we know this cmp will evaluate to + // false + let lhs_min = lhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { + return Ok(false.into()); + } + } + RangeOp::Gte => { + // if lhs_min >= rhs_max, we know this cmp will evaluate to + // true + let lhs_min = lhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + match lhs_min.range_ord(&rhs_max) { + Some(Ordering::Greater) => { + return Ok(true.into()); + } + Some(Ordering::Equal) => { + return Ok(true.into()); + } + _ => {} + } + + // if lhs_max < rhs_min, we know this cmp will evaluate to + // false + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { + return Ok(false.into()); + } + } + RangeOp::Eq => { + // if all elems are equal we know its true + // we dont know anything else + let lhs_min = lhs_range.evaled_range_min(self)?; + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + if let ( + Some(Ordering::Equal), + Some(Ordering::Equal), + Some(Ordering::Equal), + ) = ( + // check lhs_min == lhs_max, ensures lhs is const + lhs_min.range_ord(&lhs_max), + // check lhs_min == rhs_min, checks if lhs == rhs + lhs_min.range_ord(&rhs_min), + // check rhs_min == rhs_max, ensures rhs is const + rhs_min.range_ord(&rhs_max), + ) { + return Ok(true.into()); + } + } + RangeOp::Neq => { + // if all elems are equal we know its true + // we dont know anything else + let lhs_min = lhs_range.evaled_range_min(self)?; + let lhs_max = lhs_range.evaled_range_max(self)?; + let rhs_min = rhs_range.evaled_range_min(self)?; + let rhs_max = rhs_range.evaled_range_max(self)?; + if let ( + Some(Ordering::Equal), + Some(Ordering::Equal), + Some(Ordering::Equal), + ) = ( + // check lhs_min == lhs_max, ensures lhs is const + lhs_min.range_ord(&lhs_max), + // check lhs_min == rhs_min, checks if lhs == rhs + lhs_min.range_ord(&rhs_min), + // check rhs_min == rhs_max, ensures rhs is const + rhs_min.range_ord(&rhs_max), + ) { + return Ok(false.into()); + } + } + e => unreachable!("Cmp with strange op: {:?}", e), + } + Ok(SolcRange::default_bool()) + } else { + Ok(SolcRange::default_bool()) + } + } else { + Ok(SolcRange::default_bool()) + } + } +} diff --git a/crates/solc_expressions/cond_op.rs b/crates/solc_expressions/cond_op.rs new file mode 100644 index 00000000..3938a0d3 --- /dev/null +++ b/crates/solc_expressions/cond_op.rs @@ -0,0 +1,194 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::{exprs::Require, AnalyzerLike, ContextBuilder}; +use shared::{context::*, Edge, Node, NodeIdx}; + +use solang_parser::pt::CodeLocation; +use solang_parser::pt::{Expression, Loc, Statement}; + +impl CondOp for T where T: AnalyzerLike + Require + Sized {} +pub trait CondOp: AnalyzerLike + Require + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn cond_op_stmt( + &mut self, + loc: Loc, + if_expr: &Expression, + true_stmt: &Statement, + false_stmt: &Option>, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let tctx = + Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) + .into_expr_err(loc)?; + let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); + let fctx = + Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) + .into_expr_err(loc)?; + let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); + ctx.set_child_fork(true_subctx, false_subctx, analyzer) + .into_expr_err(loc)?; + let ctx_fork = analyzer.add_node(Node::ContextFork); + analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); + analyzer.add_edge( + NodeIdx::from(true_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + NodeIdx::from(false_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + + // we want to check if the true branch is possible to take + analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; + let mut true_killed = false; + if true_subctx.is_killed(analyzer).into_expr_err(loc)? { + // it was killed, therefore true branch is unreachable. + // since it is unreachable, we want to not create + // unnecessary subcontexts + true_killed = true; + } + + // we want to check if the false branch is possible to take + analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; + let mut false_killed = false; + if false_subctx.is_killed(analyzer).into_expr_err(loc)? { + // it was killed, therefore true branch is unreachable. + // since it is unreachable, we want to not create + // unnecessary subcontexts + false_killed = true; + } + + match (true_killed, false_killed) { + (true, true) => { + // both have been killed, delete the child and dont process the bodies + ctx.delete_child(analyzer).into_expr_err(loc)?; + } + (true, false) => { + // the true context has been killed, delete child, process the false fork expression + // in the parent context and parse the false body + ctx.delete_child(analyzer).into_expr_err(loc)?; + analyzer.false_fork_if_cvar(if_expr.clone(), ctx)?; + if let Some(false_stmt) = false_stmt { + return analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); + Ok(()) + }); + } + } + (false, true) => { + // the false context has been killed, delete child, process the true fork expression + // in the parent context and parse the true body + ctx.delete_child(analyzer).into_expr_err(loc)?; + analyzer.true_fork_if_cvar(if_expr.clone(), ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_statement( + true_stmt, + ctx.unchecked(analyzer).into_expr_err(loc)?, + Some(ctx), + ); + Ok(()) + })?; + } + (false, false) => { + // both branches are reachable. process each body + analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_statement( + true_stmt, + ctx.unchecked(analyzer).into_expr_err(loc)?, + Some(ctx), + ); + Ok(()) + })?; + if let Some(false_stmt) = false_stmt { + return analyzer.apply_to_edges( + false_subctx, + loc, + &|analyzer, ctx, _loc| { + analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); + Ok(()) + }, + ); + } + } + } + Ok(()) + }) + } + + /// When we have a conditional operator, we create a fork in the context. One side of the fork is + /// if the expression is true, the other is if it is false. + #[tracing::instrument(level = "trace", skip_all)] + fn cond_op_expr( + &mut self, + loc: Loc, + if_expr: &Expression, + true_expr: &Expression, + false_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!("conditional operator"); + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let tctx = + Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) + .into_expr_err(loc)?; + let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); + let fctx = + Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) + .into_expr_err(loc)?; + let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); + ctx.set_child_fork(true_subctx, false_subctx, analyzer) + .into_expr_err(loc)?; + let ctx_fork = analyzer.add_node(Node::ContextFork); + analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); + analyzer.add_edge( + NodeIdx::from(true_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + NodeIdx::from(false_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + + analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; + analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_expr(true_expr, ctx) + })?; + + analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; + analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_expr(false_expr, ctx) + }) + }) + } + + /// Creates the true_fork cvar (updates bounds assuming its true) + fn true_fork_if_cvar( + &mut self, + if_expr: Expression, + true_fork_ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.apply_to_edges(true_fork_ctx, if_expr.loc(), &|analyzer, ctx, _loc| { + analyzer.handle_require(&[if_expr.clone()], ctx)?; + Ok(()) + }) + } + + /// Creates the false_fork cvar (inverts the expression and sets the bounds assuming its false) + fn false_fork_if_cvar( + &mut self, + if_expr: Expression, + false_fork_ctx: ContextNode, + ) -> Result<(), ExprErr> { + let loc = if_expr.loc(); + let inv_if_expr = self.inverse_expr(if_expr); + self.apply_to_edges(false_fork_ctx, loc, &|analyzer, ctx, _loc| { + analyzer.handle_require(&[inv_if_expr.clone()], ctx)?; + Ok(()) + }) + } +} diff --git a/crates/solc_expressions/env.rs b/crates/solc_expressions/env.rs new file mode 100644 index 00000000..ba36b1c2 --- /dev/null +++ b/crates/solc_expressions/env.rs @@ -0,0 +1,449 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::func_call::FuncCaller; +use crate::context::ExprErr; +use crate::{context::ContextNode, AnalyzerLike}; +use shared::context::ExprRet; +use shared::context::{ContextEdge, ContextVar}; +use shared::nodes::Builtin; +use shared::nodes::Concrete; +use shared::Edge; +use shared::Node; +use solang_parser::pt::Expression; +use solang_parser::pt::Loc; + +use solang_parser::pt::Identifier; + +impl Env for T where T: AnalyzerLike + Sized {} +pub trait Env: AnalyzerLike + Sized { + fn env_variable( + &mut self, + ident: &Identifier, + ctx: ContextNode, + ) -> Result, ExprErr> { + match &*ident.name { + "msg" | "tx" => { + ctx.push_expr(ExprRet::Single(self.msg().into()), self) + .into_expr_err(ident.loc)?; + Ok(Some(())) + } + "block" => { + ctx.push_expr(ExprRet::Single(self.block().into()), self) + .into_expr_err(ident.loc)?; + Ok(Some(())) + } + "abi" => Ok(Some(())), + "_" => { + #[allow(clippy::manual_map)] + if let Some(mod_state) = &ctx + .underlying(self) + .into_expr_err(ident.loc)? + .modifier_state + .clone() + { + self.resume_from_modifier(ctx, mod_state.clone())?; + self.modifier_inherit_return(ctx, mod_state.parent_ctx); + Ok(Some(())) + } else { + Ok(None) + } + } + _e => Ok(None), + } + } + + fn block_access( + &mut self, + loc: Loc, + ctx: ContextNode, + ident_name: &str, + ) -> Result { + let name = format!("block.{}", ident_name); + tracing::trace!("Block Env member access: {}", name); + if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + Ok(ExprRet::Single(attr_var.latest_version(self).into())) + } else { + let (node, name) = match ident_name { + "hash" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.hash { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.blockhash".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Bytes(32)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.blockhash".to_string(); + var.display_name = "block.blockhash".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "basefee" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.basefee { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.basefee".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.basefee".to_string(); + var.display_name = "block.basefee".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "chainid" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.chainid { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.chainid".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.chainid".to_string(); + var.display_name = "block.chainid".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "coinbase" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.coinbase { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.coinbase".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Address); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.coinbase".to_string(); + var.display_name = "block.coinbase".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "difficulty" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.difficulty { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.difficulty".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.difficulty".to_string(); + var.display_name = "block.difficulty".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "gaslimit" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.gaslimit { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.gaslimit".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.gaslimit".to_string(); + var.display_name = "block.gaslimit".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "number" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.number { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.number".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.number".to_string(); + var.display_name = "block.number".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "prevrandao" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.prevrandao { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.prevrandao".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.prevrandao".to_string(); + var.display_name = "block.prevrandao".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "timestamp" => { + if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.timestamp { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "block.timestamp".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "block.timestamp".to_string(); + var.display_name = "block.timestamp".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + e => { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!("Unknown member access on block: {e:?}"), + )) + } + }; + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; + var.name = name.clone(); + var.display_name = name; + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + } + + fn msg_access( + &mut self, + loc: Loc, + ctx: ContextNode, + ident_name: &str, + ) -> Result { + let name = format!("msg.{}", ident_name); + tracing::trace!("Msg Env member access: {}", name); + + if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + Ok(ExprRet::Single(attr_var.latest_version(self).into())) + } else { + let (node, name) = match ident_name { + "data" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.data.clone() { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "msg.data".to_string(), + ) + } else { + let b = Builtin::DynamicBytes; + let node = self.builtin_or_add(b); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "msg.data".to_string(); + var.display_name = "msg.data".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "sender" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.sender { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "msg.sender".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Address); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "msg.sender".to_string(); + var.display_name = "msg.sender".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "sig" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.sig { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "msg.sig".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Bytes(4)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "msg.sig".to_string(); + var.display_name = "msg.sig".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "value" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.value { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "msg.value".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(256)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "msg.value".to_string(); + var.display_name = "msg.value".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "origin" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.origin { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "tx.origin".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Address); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "tx.origin".to_string(); + var.display_name = "tx.origin".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "gasprice" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.gasprice { + let c = Concrete::from(d); + ( + self.add_node(Node::Concrete(c)).into(), + "tx.gasprice".to_string(), + ) + } else { + let node = self.builtin_or_add(Builtin::Uint(64)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.name = "tx.gasprice".to_string(); + var.display_name = "tx.gasprice".to_string(); + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + "gaslimit" => { + if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.gaslimit { + let c = Concrete::from(d); + (self.add_node(Node::Concrete(c)).into(), "".to_string()) + } else { + let node = self.builtin_or_add(Builtin::Uint(64)); + let mut var = ContextVar::new_from_builtin(loc, node.into(), self) + .into_expr_err(loc)?; + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(cvar)); + } + } + e => { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!("Unknown member access on msg: {e:?}"), + )) + } + }; + + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; + var.name = name.clone(); + var.display_name = name; + var.is_tmp = false; + var.is_symbolic = true; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + } +} diff --git a/crates/solc_expressions/func_call/internal_call.rs b/crates/solc_expressions/func_call/internal_call.rs new file mode 100644 index 00000000..9f32b079 --- /dev/null +++ b/crates/solc_expressions/func_call/internal_call.rs @@ -0,0 +1,287 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::{func_call::FuncCaller, ContextBuilder}; +use shared::context::ExprRet; +use shared::nodes::{Builtin, Concrete, VarType}; +use shared::{ + analyzer::{AnalyzerLike, GraphLike}, + context::{ContextEdge, ContextNode, ContextVar, ContextVarNode}, + Edge, Node, +}; +use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; + +impl InternalFuncCaller for T where + T: AnalyzerLike + Sized + GraphLike +{ +} +pub trait InternalFuncCaller: + AnalyzerLike + Sized + GraphLike +{ + #[tracing::instrument(level = "trace", skip_all)] + fn call_internal_named_func( + &mut self, + ctx: ContextNode, + loc: &Loc, + ident: &Identifier, + // _func_expr: &Expression, + input_args: &[NamedArgument], + ) -> Result<(), ExprErr> { + // It is a function call, check if we have the ident in scope + let funcs = ctx.visible_funcs(self).into_expr_err(*loc)?; + // filter down all funcs to those that match + let possible_funcs = funcs + .iter() + .filter(|func| { + let named_correctly = func + .name(self) + .unwrap() + .starts_with(&format!("{}(", ident.name)); + if !named_correctly { + false + } else { + // filter by params + let params = func.params(self); + if params.len() != input_args.len() { + false + } else { + params.iter().all(|param| { + input_args + .iter() + .any(|input| input.name.name == param.name(self).unwrap()) + }) + } + } + }) + .copied() + .collect::>(); + + if possible_funcs.is_empty() { + // check structs + let structs = ctx.visible_structs(self); + let possible_structs = structs + .iter() + .filter(|strukt| { + let named_correctly = strukt + .name(self) + .unwrap() + .starts_with(&ident.name.to_string()); + if !named_correctly { + false + } else { + // filter by params + let fields = strukt.fields(self); + if fields.len() != input_args.len() { + false + } else { + fields.iter().all(|field| { + input_args + .iter() + .any(|input| input.name.name == field.name(self).unwrap()) + }) + } + } + }) + .copied() + .collect::>(); + if possible_structs.is_empty() { + Err(ExprErr::FunctionNotFound( + *loc, + format!( + "No functions or structs found for named function call: {:?}", + ident.name + ), + )) + } else if possible_structs.len() == 1 { + let strukt = possible_structs[0]; + let var = + ContextVar::new_from_struct(*loc, strukt, ctx, self).into_expr_err(*loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + strukt.fields(self).iter().try_for_each(|field| { + let field_cvar = ContextVar::maybe_new_from_field( + self, + *loc, + ContextVarNode::from(cvar) + .underlying(self) + .into_expr_err(*loc)?, + field.underlying(self).unwrap().clone(), + ) + .expect("Invalid struct field"); + + let fc_node = self.add_node(Node::ContextVar(field_cvar)); + self.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(fc_node.into(), self).into_expr_err(*loc)?; + let field_as_ret = ExprRet::Single(fc_node); + let input = input_args + .iter() + .find(|arg| arg.name.name == field.name(self).unwrap()) + .expect("No field in struct in struct construction"); + self.parse_ctx_expr(&input.expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(assignment) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + }; + + if matches!(assignment, ExprRet::CtxKilled(_)) { + ctx.push_expr(assignment, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_sides(ctx, loc, &field_as_ret, &assignment)?; + let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + Ok(()) + }) + })?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(*loc)?; + Ok(()) + })?; + Ok(()) + } else { + Err(ExprErr::Todo( + *loc, + "Disambiguation of struct construction not currently supported".to_string(), + )) + } + } else if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + let params = func.params(self); + let inputs: Vec<_> = params + .iter() + .map(|param| { + let input = input_args + .iter() + .find(|arg| arg.name.name == param.name(self).unwrap()) + .expect( + "No parameter with named provided in named parameter function call", + ); + input.expr.clone() + }) + .collect(); + self.parse_inputs(ctx, *loc, &inputs[..])?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + }) + } else { + todo!("Disambiguate named function call"); + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn call_internal_func( + &mut self, + ctx: ContextNode, + loc: &Loc, + ident: &Identifier, + func_expr: &Expression, + input_exprs: &[Expression], + ) -> Result<(), ExprErr> { + tracing::trace!("function call: {}(..)", ident.name); + // It is a function call, check if we have the ident in scope + let funcs = ctx.visible_funcs(self).into_expr_err(*loc)?; + // println!("visible funcs: {:#?}", funcs.iter().map(|f| f.name(self).unwrap()).collect::>()); + // filter down all funcs to those that match + let possible_funcs = funcs + .iter() + .filter(|func| { + func.name(self) + .unwrap() + .starts_with(&format!("{}(", ident.name)) + }) + .copied() + .collect::>(); + + if possible_funcs.is_empty() { + // this is a builtin, cast, or unknown function? + self.parse_ctx_expr(func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let ret = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let ret = ret.flatten(); + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + }) + } else if possible_funcs.len() == 1 { + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let inputs = inputs.flatten(); + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.setup_fn_call(&ident.loc, &inputs, (possible_funcs[0]).into(), ctx, None) + }) + } else { + // this is the annoying case due to function overloading & type inference on number literals + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let inputs = inputs.flatten(); + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let resizeables: Vec<_> = inputs.as_flat_vec() + .iter() + .map(|idx| { + match VarType::try_from_idx(analyzer, *idx) { + Some(VarType::BuiltIn(bn, _)) => { + matches!(analyzer.node(bn), Node::Builtin(Builtin::Uint(_)) | Node::Builtin(Builtin::Int(_)) | Node::Builtin(Builtin::Bytes(_))) + // match analyzer.node(bn) { + // Node::Builtin(Builtin::Uint(s)) if s < &256 => true, + // Node::Builtin(Builtin::Int(s)) if s < &256 => true, + // Node::Builtin(Builtin::Bytes(s)) if s < &32 => true, + // _ => false + // } + } + Some(VarType::Concrete(c)) => { + matches!(analyzer.node(c), Node::Concrete(Concrete::Uint(_, _)) | Node::Concrete(Concrete::Int(_, _)) | Node::Concrete(Concrete::Bytes(_, _))) + } + _ => false + } + }) + .collect(); + if let Some(func) = analyzer.disambiguate_fn_call( + &ident.name, + resizeables, + &inputs, + &possible_funcs, + ) { + analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + } else { + Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not disambiguate function, default input types: {}, possible functions: {:#?}", + inputs.try_as_func_input_str(analyzer), + possible_funcs + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect::>() + ), + )) + } + }) + } + } +} diff --git a/crates/solc_expressions/func_call/intrinsic_call.rs b/crates/solc_expressions/func_call/intrinsic_call.rs new file mode 100644 index 00000000..0804f6b5 --- /dev/null +++ b/crates/solc_expressions/func_call/intrinsic_call.rs @@ -0,0 +1,1060 @@ +use crate::context::func_call::FuncCaller; +use crate::context::{ + exprs::{Array, MemberAccess, Require}, + ContextBuilder, +}; +use crate::context::{ExprErr, IntoExprErr}; +use ethers_core::types::U256; +use shared::nodes::BuiltInNode; +use shared::nodes::StructNode; +use shared::nodes::TyNode; + +use shared::analyzer::Search; +use shared::analyzer::{AnalyzerLike, GraphLike}; +use shared::nodes::Concrete; + +use shared::{ + context::*, + nodes::{Builtin, VarType}, + range::{ + elem::RangeOp, + elem_ty::{Elem, RangeExpr}, + Range, SolcRange, + }, + Edge, Node, NodeIdx, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl IntrinsicFuncCaller for T where + T: AnalyzerLike + Sized + GraphLike + Search +{ +} +pub trait IntrinsicFuncCaller: + AnalyzerLike + Sized + GraphLike + Search +{ + /// Calls an intrinsic/builtin function call (casts, require, etc.) + #[tracing::instrument(level = "trace", skip_all)] + fn intrinsic_func_call( + &mut self, + loc: &Loc, + input_exprs: &[Expression], + func_idx: NodeIdx, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match self.node(func_idx) { + Node::Function(underlying) => { + if let Some(func_name) = &underlying.name { + match &*func_name.name { + "abi.decode" => { + // we skip the first because that is what is being decoded. + // TODO: check if we have a concrete bytes value + fn match_decode( + ctx: ContextNode, + loc: &Loc, + ret: ExprRet, + analyzer: &mut impl AnalyzerLike, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(expect_builtin) => { + match analyzer.node(expect_builtin) { + Node::Builtin(_) => { + let var = ContextVar::new_from_builtin( + *loc, + expect_builtin.into(), + analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + Node::ContextVar(cvar) => { + let bn = analyzer + .builtin_or_add( + cvar.ty + .as_builtin(analyzer) + .into_expr_err(*loc)?, + ) + .into(); + let var = ContextVar::new_from_builtin( + *loc, bn, analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + e => todo!("Unhandled type in abi.decode: {e:?}"), + } + } + ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { + match_decode(ctx, loc, i.clone(), analyzer) + }), + ExprRet::CtxKilled(kind) => { + ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) + } + e => panic!("This is invalid solidity: {:?}", e), + } + } + self.parse_ctx_expr(&input_exprs[1], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + match_decode(ctx, &loc, ret, analyzer) + }) + } + "abi.encode" + | "abi.encodePacked" + | "abi.encodeCall" + | "abi.encodeWithSignature" + | "abi.encodeWithSelector" => { + // currently we dont support concrete abi encoding, TODO + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(*loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "delegatecall" | "staticcall" | "call" => { + ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; + // TODO: try to be smarter based on the address input + let booln = self.builtin_or_add(Builtin::Bool); + let bool_cvar = ContextVar::new_from_builtin(*loc, booln.into(), self) + .into_expr_err(*loc)?; + let bool_node = self.add_node(Node::ContextVar(bool_cvar)); + ctx.add_var(bool_node.into(), self).into_expr_err(*loc)?; + self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); + + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(*loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr( + ExprRet::Multi(vec![ + ExprRet::Single(bool_node), + ExprRet::Single(node), + ]), + self, + ) + .into_expr_err(*loc)?; + Ok(()) + } + "code" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(*loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "balance" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Uint(256)); + let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(*loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "require" | "assert" => { + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { + analyzer.handle_require(input_exprs, ctx) + }) + } + "type" => self.parse_ctx_expr(&input_exprs[0], ctx), + "push" => { + assert!(input_exprs.len() == 2); + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "array[].push(..) was not an array to push to".to_string())) + }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(new_elem) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "array[].push(..) was not given an element to push".to_string())) + }; + + if matches!(new_elem, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let arr = array.expect_single().into_expr_err(loc)?; + let arr = ContextVarNode::from(arr).latest_version(analyzer); + // get length + let len = analyzer.tmp_length(arr, ctx, loc); + + let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + )?; + let index = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?.unwrap(); + if matches!(index, ExprRet::CtxKilled(_)) { + ctx.push_expr(index, analyzer).into_expr_err(loc)?; + return Ok(()); + } + // assign index to new_elem + analyzer.match_assign_sides(ctx, loc, &index, &new_elem) + }) + }) + } + "pop" => { + assert!(input_exprs.len() == 1); + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) + }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + // get the array + let arr = array.expect_single().into_expr_err(loc)?; + let arr = ContextVarNode::from(arr).latest_version(analyzer); + + // get length + analyzer.match_length(ctx, loc, array, false)?; + let Some(len) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) + }; + let len = len.expect_single().into_expr_err(loc)?; + let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; + next_len.set_range_min(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; + next_len.set_range_max(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; + + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single(next_len.latest_version(analyzer).into()), + ) + }) + } + "concat" => self.concat(loc, input_exprs, ctx), + "keccak256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(_input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + }; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + Ok(()) + }) + } + "sha256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + Ok(()) + }) + } + "ripemd160" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + Ok(()) + }) + } + "blockhash" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "blockhash function was not provided a block number".to_string())) + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + Ok(()) + }) + } + "gasleft" => { + let var = ContextVar::new_from_builtin( + *loc, + self.builtin_or_add(Builtin::Uint(64)).into(), + self, + ) + .into_expr_err(*loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), self) + .into_expr_err(*loc)?; + Ok(()) + } + "ecrecover" => { + self.parse_inputs(ctx, *loc, input_exprs)?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let cctx = Context::new_subctx( + ctx, + None, + loc, + None, + Some(func_idx.into()), + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let call_ctx = analyzer.add_node(Node::Context( + cctx + )); + ctx.set_child_call(call_ctx.into(), analyzer) + .into_expr_err(loc)?; + let call_node = analyzer.add_node(Node::FunctionCall); + analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); + analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); + analyzer.add_edge( + call_ctx, + call_node, + Edge::Context(ContextEdge::Subcontext), + ); + + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + }; + + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let mut inner_vals = vec![]; + match input { + ExprRet::Single(var) + | ExprRet::SingleLiteral(var) => { + inner_vals.push( + ContextVarNode::from(var).display_name(analyzer).unwrap(), + ); + } + _ => inner_vals.push("".to_string()), + } + let inner_name = inner_vals.into_iter().collect::>().join(", "); + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Address).into(), + analyzer, + ) + .into_expr_err(loc)?; + var.display_name = format!("ecrecover({})", inner_name); + var.is_symbolic = true; + var.is_return = true; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); + ContextNode::from(call_ctx) + .add_return_node(loc, cvar.into(), analyzer) + .into_expr_err(loc)?; + + let rctx = Context::new_subctx( + call_ctx.into(), + Some(ctx), + loc, + None, + None, + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let ret_ctx = analyzer.add_node(Node::Context( + rctx + )); + ContextNode::from(call_ctx) + .set_child_call(ret_ctx.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge(ret_ctx, call_ctx, Edge::Context(ContextEdge::Continue)); + + let tmp_ret = ContextVarNode::from(cvar) + .as_tmp( + ContextNode::from(call_ctx).underlying(analyzer).unwrap().loc, + ret_ctx.into(), + analyzer, + ) + .unwrap(); + tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; + tmp_ret.underlying_mut(analyzer).unwrap().display_name = + format!("ecrecover({}).return", inner_name); + ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; + analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); + + ContextNode::from(ret_ctx).push_expr(ExprRet::Single(tmp_ret.into()), analyzer).into_expr_err(loc)?; + Ok(()) + }) + } + "addmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, *loc, input_exprs)?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "mulmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "wrap" => { + if input_exprs.len() != 2 { + return Err(ExprErr::InvalidFunctionInput(*loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); + } + + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + }; + input.expect_length(2).into_expr_err(loc)?; + let ret = input.as_vec(); + let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; + let var = ContextVar::new_from_ty( + loc, + TyNode::from(wrapping_ty), + ctx, + analyzer, + ) + .into_expr_err(loc)?; + let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; + let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; + let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_wrapped), RangeOp::Cast, Elem::from(cvar))); + next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + next.set_range_max(analyzer, expr).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + "unwrap" => { + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + }; + input.expect_length(2).into_expr_err(loc)?; + let ret = input.as_vec(); + let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + BuiltInNode::from(TyNode::from(wrapping_ty).underlying(analyzer).into_expr_err(loc)?.ty), + analyzer, + ) + .into_expr_err(loc)?; + let to_be_unwrapped = ret[1].expect_single().into_expr_err(loc)?; + var.display_name = format!("{}.unwrap({})", + TyNode::from(wrapping_ty).name(analyzer).into_expr_err(loc)?, + ContextVarNode::from(to_be_unwrapped).display_name(analyzer).into_expr_err(loc)? + ); + + let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; + let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_unwrapped), RangeOp::Cast, Elem::from(cvar))); + next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + next.set_range_max(analyzer, expr).into_expr_err(loc)?; + + cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; + cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + e => Err(ExprErr::Todo( + *loc, + format!("builtin function: {e:?} doesn't exist or isn't implemented"), + )), + } + } else { + panic!("unnamed builtin?") + } + } + Node::Builtin(Builtin::Array(_)) => { + // create a new list + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + }; + + if matches!(len_var, ExprRet::CtxKilled(_)) { + ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let len_cvar = len_var.expect_single().into_expr_err(loc)?; + + let ty = VarType::try_from_idx(analyzer, func_idx); + + let new_arr = ContextVar { + loc: Some(loc), + name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), + display_name: "arr".to_string(), + storage: None, + is_tmp: true, + is_symbolic: false, + is_return: false, + tmp_of: None, + ty: ty.expect("No type for node"), + }; + + let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); + + let len_var = ContextVar { + loc: Some(loc), + name: arr.name(analyzer).into_expr_err(loc)? + ".length", + display_name: arr.display_name(analyzer).unwrap() + ".length", + storage: None, + is_tmp: true, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: ContextVarNode::from(len_cvar) + .underlying(analyzer) + .into_expr_err(loc)? + .ty + .clone(), + }; + + let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); + analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(arr, analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); + + // update the length + if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { + let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; + let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + + ctx.push_expr(ExprRet::Single(arr.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + Node::Builtin(ty) => { + // it is a cast + let ty = ty.clone(); + fn cast_match( + ctx: ContextNode, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ty: &Builtin, + ret: ExprRet, + func_idx: NodeIdx, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::CtxKilled(kind) => { + ctx.kill(analyzer, loc, kind).into_expr_err(loc) + } + ExprRet::Null => Ok(()), + ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { + let new_var = ContextVarNode::from(cvar) + .as_cast_tmp(loc, ctx, ty.clone(), analyzer) + .into_expr_err(loc)?; + + new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = + VarType::try_from_idx(analyzer, func_idx).expect(""); + // cast the ranges + if let Some(r) = ContextVarNode::from(cvar) + .range(analyzer) + .into_expr_err(loc)? + { + let curr_range = + SolcRange::try_from_builtin(ty).expect("No default range"); + let min = r + .range_min() + .into_owned() + .cast(curr_range.range_min().into_owned()); + let max = r + .range_max() + .into_owned() + .cast(curr_range.range_max().into_owned()); + new_var.set_range_min(analyzer, min).into_expr_err(loc)?; + new_var.set_range_max(analyzer, max).into_expr_err(loc)?; + // cast the range exclusions - TODO: verify this is correct + let mut exclusions = r.range_exclusions(); + exclusions.iter_mut().for_each(|range| { + *range = + range.clone().cast(curr_range.range_min().into_owned()); + }); + new_var + .set_range_exclusions(analyzer, exclusions) + .into_expr_err(loc)?; + } + + ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| cast_match(ctx, loc, analyzer, ty, i, func_idx)), + } + } + + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + cast_match(ctx, loc, analyzer, &ty, ret, func_idx) + }) + } + Node::ContextVar(_c) => { + // its a user type + // TODO: figure out if we actually need to do anything? + // input_exprs + // .iter() + // .try_for_each(|expr| self.parse_ctx_expr(expr, ctx))?; + + // self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + // }) + + ctx.push_expr(ExprRet::Single(func_idx), self) + .into_expr_err(*loc)?; + Ok(()) + } + Node::Contract(_) => { + if input_exprs.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + "Invalid number of inputs to a contract instantiation".to_string(), + )); + } + + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(func_idx) + ), + )) + } + }; + let idx = ret.expect_single().into_expr_err(loc)?; + let contract_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + contract_cvar + .set_range_min(analyzer, Elem::from(idx)) + .into_expr_err(loc)?; + contract_cvar + .set_range_max(analyzer, Elem::from(idx)) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + Node::Unresolved(_) => { + self.parse_inputs(ctx, *loc, input_exprs)?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Function call failed".to_string())) + }; + + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let visible_funcs = ctx.visible_funcs(analyzer).into_expr_err(loc)? + .iter() + .map(|func| func.name(analyzer).unwrap()) + .collect::>(); + + if let Node::Unresolved(ident) = analyzer.node(func_idx) { + Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find function: \"{}{}\", context: {}, visible functions: {:#?}", + ident.name, + inputs.try_as_func_input_str(analyzer), + ctx.path(analyzer), + visible_funcs + ) + )) + } else { + unreachable!() + } + }) + } + Node::Struct(_) => { + // struct construction + let strukt = StructNode::from(func_idx); + let var = + ContextVar::new_from_struct(*loc, strukt, ctx, self).into_expr_err(*loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Struct Function call failed".to_string())) + }; + + let inputs = inputs.as_vec(); + // set struct fields + strukt + .fields(analyzer) + .iter() + .zip(inputs) + .try_for_each(|(field, input)| { + let field_cvar = ContextVar::maybe_new_from_field( + analyzer, + loc, + ContextVarNode::from(cvar) + .underlying(analyzer) + .into_expr_err(loc)?, + field.underlying(analyzer).unwrap().clone(), + ) + .expect("Invalid struct field"); + + let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); + analyzer.add_edge( + fc_node, + cvar, + Edge::Context(ContextEdge::AttrAccess), + ); + analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; + let field_as_ret = ExprRet::Single(fc_node); + analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; + let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + Ok(()) + })?; + + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc) + }) + } + e => Err(ExprErr::FunctionNotFound(*loc, format!("{e:?}"))), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn concat( + &mut self, + loc: &Loc, + input_exprs: &[Expression], + ctx: ContextNode, + ) -> Result<(), ExprErr> { + input_exprs[1..].iter().try_for_each(|expr| { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let input = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or(ExprRet::Null); + ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) + }) + })?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())) + }; + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let inputs = inputs.as_vec(); + if inputs.is_empty() { + ctx.push_expr(ExprRet::Multi(vec![]), analyzer) + .into_expr_err(loc)?; + Ok(()) + } else { + let start = &inputs[0]; + if inputs.len() > 1 { + analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) + } else { + analyzer.match_concat(ctx, loc, start.clone(), &[], None) + } + } + }) + } + + fn match_concat( + &mut self, + ctx: ContextNode, + loc: Loc, + curr: ExprRet, + inputs: &[ExprRet], + accum_node: Option, + ) -> Result<(), ExprErr> { + if let Some(accum_node) = accum_node { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => { + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } else { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + let acc = ContextVarNode::from(var) + .as_tmp(loc, ctx, self) + .into_expr_err(loc)?; + inputs + .iter() + .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) + .collect::, ExprErr>>()?; + ctx.push_expr(ExprRet::Single(acc.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => Err(ExprErr::NoRhs( + loc, + "No input provided to concat function".to_string(), + )), + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } + } + + fn concat_inner( + &mut self, + loc: Loc, + accum: ContextVarNode, + right: ContextVarNode, + ) -> Result<(), ExprErr> { + match ( + accum.ty(self).into_expr_err(loc)?, + right.ty(self).into_expr_err(loc)?, + ) { + (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { + let new_ty = match ( + accum_cnode.underlying(self).into_expr_err(loc)?, + right_cnode.underlying(self).into_expr_err(loc)?, + ) { + (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (a, b) => { + // Invalid solidity + return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); + } + }; + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { + let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; + // let val = match underlying { + // Concrete::String(val) => { + // val + // .chars() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // v.encode_utf8(&mut bytes[..]); + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // Concrete::DynBytes(val) => { + // val + // .iter() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // bytes[0] = *v; + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) + // }; + // TODO: Extend with bn + + let range = SolcRange::from(underlying.clone()).unwrap(); + let min = range.min.clone().concat(r2.min.clone()); + let max = range.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; + + let new_ty = + VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { + // TODO: improve length calculation here + let min = r.min.clone().concat(r2.min.clone()); + let max = r.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; + Ok(()) + } + (_, _) => Ok(()), + } + } +} diff --git a/crates/solc_expressions/func_call/mod.rs b/crates/solc_expressions/func_call/mod.rs new file mode 100644 index 00000000..897feec9 --- /dev/null +++ b/crates/solc_expressions/func_call/mod.rs @@ -0,0 +1,1174 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::func_call::{ + internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, + namespaced_call::NameSpaceFuncCaller, +}; +use crate::context::ContextBuilder; +use crate::context::ExprErr; +use std::cell::RefCell; +use std::rc::Rc; + +use shared::analyzer::GraphLike; +use shared::context::ExprRet; +use shared::context::*; +use solang_parser::helpers::CodeLocation; +use std::collections::BTreeMap; + +use shared::range::Range; +use solang_parser::pt::{Expression, Loc, NamedArgument, StorageLocation}; + +use crate::VarType; + +use shared::{analyzer::AnalyzerLike, nodes::*, Edge, Node, NodeIdx}; + +pub mod internal_call; +pub mod intrinsic_call; +pub mod modifier; +pub mod namespaced_call; + +impl FuncCaller for T where + T: AnalyzerLike + Sized + GraphLike +{ +} +pub trait FuncCaller: + GraphLike + AnalyzerLike + Sized +{ + #[tracing::instrument(level = "trace", skip_all)] + fn named_fn_call_expr( + &mut self, + ctx: ContextNode, + loc: &Loc, + func_expr: &Expression, + input_exprs: &[NamedArgument], + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + match func_expr { + MemberAccess(loc, member_expr, ident) => { + self.call_name_spaced_named_func(ctx, loc, member_expr, ident, input_exprs) + } + Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), + e => Err(ExprErr::IntrinsicNamedArgs( + *loc, + format!("Cannot call intrinsic functions with named arguments. Call: {e:?}"), + )), + } + } + #[tracing::instrument(level = "trace", skip_all)] + fn fn_call_expr( + &mut self, + ctx: ContextNode, + loc: &Loc, + func_expr: &Expression, + input_exprs: &[Expression], + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + match func_expr { + MemberAccess(loc, member_expr, ident) => { + self.call_name_spaced_func(ctx, loc, member_expr, ident, input_exprs) + } + Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, input_exprs), + _ => { + self.parse_ctx_expr(func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Function call to nonexistent function".to_string())) + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + }) + } + } + } + + fn match_intrinsic_fallback( + &mut self, + ctx: ContextNode, + loc: &Loc, + input_exprs: &[Expression], + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(func_idx) | ExprRet::SingleLiteral(func_idx) => { + self.intrinsic_func_call(loc, input_exprs, func_idx, ctx) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|ret| self.match_intrinsic_fallback(ctx, loc, input_exprs, ret)), + ExprRet::CtxKilled(kind) => ctx.kill(self, *loc, kind).into_expr_err(*loc), + ExprRet::Null => Ok(()), + } + } + + /// Disambiguates a function call by their inputs (length & type) + fn disambiguate_fn_call( + &mut self, + fn_name: &str, + literals: Vec, + input_paths: &ExprRet, + funcs: &[FunctionNode], + ) -> Option { + let input_paths = input_paths.clone().flatten(); + // try to find the function based on naive signature + // This doesnt do type inference on NumberLiterals (i.e. 100 could be uintX or intX, and there could + // be a function that takes an int256 but we evaled as uint256) + let fn_sig = format!("{}{}", fn_name, input_paths.try_as_func_input_str(self)); + if let Some(func) = funcs.iter().find(|func| func.name(self).unwrap() == fn_sig) { + return Some(*func); + } + + // filter by input len + let inputs = input_paths.as_flat_vec(); + let funcs: Vec<&FunctionNode> = funcs + .iter() + .filter(|func| func.params(self).len() == inputs.len()) + .collect(); + + if funcs.len() == 1 { + return Some(*funcs[0]); + } + + if !literals.iter().any(|i| *i) { + None + } else { + let funcs = funcs + .iter() + .filter(|func| { + let params = func.params(self); + params + .iter() + .zip(&inputs) + .enumerate() + .all(|(i, (param, input))| { + let param_ty = VarType::try_from_idx(self, (*param).into()).unwrap(); + let input_ty = ContextVarNode::from(*input).ty(self).unwrap(); + if param_ty.ty_eq(input_ty, self).unwrap() { + true + } else if literals[i] { + let possibilities = ContextVarNode::from(*input) + .ty(self) + .unwrap() + .possible_builtins_from_ty_inf(self); + let param_ty = param.ty(self).unwrap(); + match self.node(param_ty) { + Node::Builtin(b) => possibilities.contains(b), + _ => false, + } + } else { + false + } + }) + }) + .collect::>(); + if funcs.len() == 1 { + Some(**funcs[0]) + } else { + // this would be invalid solidity, likely the user needs to perform a cast + None + } + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn parse_inputs( + &mut self, + ctx: ContextNode, + loc: Loc, + inputs: &[Expression], + ) -> Result<(), ExprErr> { + let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { + Rc::new(RefCell::new(true)) + } else { + Rc::new(RefCell::new(false)) + }; + + inputs + .iter() + .try_for_each(|input| { + self.parse_ctx_expr(input, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + })?; + if !inputs.is_empty() { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + } + + /// Setups up storage variables for a function call and calls it + fn setup_fn_call( + &mut self, + loc: &Loc, + inputs: &ExprRet, + func_idx: NodeIdx, + ctx: ContextNode, + func_call_str: Option<&str>, + ) -> Result<(), ExprErr> { + // if we have a single match thats our function + let var = match ContextVar::maybe_from_user_ty(self, *loc, func_idx) { + Some(v) => v, + None => panic!( + "Could not create context variable from user type: {:?}", + self.node(func_idx) + ), + }; + + let new_cvarnode = self.add_node(Node::ContextVar(var)); + ctx.add_var(new_cvarnode.into(), self).into_expr_err(*loc)?; + self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); + if let Some(func_node) = ContextVarNode::from(new_cvarnode) + .ty(self) + .into_expr_err(*loc)? + .func_node(self) + { + self.func_call(ctx, *loc, inputs, func_node, func_call_str, None) + } else { + unreachable!() + } + } + + /// Matches the input kinds and performs the call + fn func_call( + &mut self, + ctx: ContextNode, + loc: Loc, + input_paths: &ExprRet, + func: FunctionNode, + func_call_str: Option<&str>, + modifier_state: Option, + ) -> Result<(), ExprErr> { + let params = func.params(self); + let input_paths = input_paths.clone().flatten(); + if input_paths.has_killed() { + return ctx + .kill(self, loc, input_paths.killed_kind().unwrap()) + .into_expr_err(loc); + } + match input_paths { + ExprRet::Single(input_var) | ExprRet::SingleLiteral(input_var) => { + // if we get a single var, we expect the func to only take a single + // variable + self.func_call_inner( + false, + ctx, + func, + loc, + vec![ContextVarNode::from(input_var).latest_version(self)], + params, + func_call_str, + modifier_state, + ) + } + ExprRet::Multi(ref inputs) => { + if ExprRet::Multi(inputs.to_vec()).flatten().has_killed() { + return ctx + .kill( + self, + loc, + ExprRet::Multi(inputs.to_vec()).killed_kind().unwrap(), + ) + .into_expr_err(loc); + } + // check if the inputs length matchs func params length + // if they do, check that none are forks + if inputs.len() == params.len() { + let input_vars = inputs + .iter() + .map(|expr_ret| { + let var = expr_ret.expect_single().into_expr_err(loc)?; + Ok(ContextVarNode::from(var).latest_version(self)) + }) + .collect::, ExprErr>>()?; + self.func_call_inner( + false, + ctx, + func, + loc, + input_vars, + params, + func_call_str, + modifier_state, + ) + } else { + Err(ExprErr::InvalidFunctionInput( + loc, + format!( + "Length mismatch: {inputs:?} {params:?}, inputs as vars: {}, ctx: {}", + ExprRet::Multi(inputs.to_vec()).debug_str(self), + ctx.path(self) + ), + )) + } + } + e => todo!("here: {:?}", e), + } + } + + fn create_call_ctx( + &mut self, + curr_ctx: ContextNode, + loc: Loc, + func_node: FunctionNode, + modifier_state: Option, + ) -> Result { + let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; + let ctx = Context::new_subctx( + curr_ctx, + None, + loc, + None, + Some(func_node), + fn_ext, + self, + modifier_state, + ) + .into_expr_err(loc)?; + let callee_ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + curr_ctx + .set_child_call(callee_ctx, self) + .into_expr_err(loc)?; + let ctx_fork = self.add_node(Node::FunctionCall); + self.add_edge(ctx_fork, curr_ctx, Edge::Context(ContextEdge::Subcontext)); + self.add_edge(ctx_fork, func_node, Edge::Context(ContextEdge::Call)); + self.add_edge( + NodeIdx::from(callee_ctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + Ok(callee_ctx) + } + + /// Maps inputs to function parameters such that if there is a renaming i.e. `a(uint256 x)` is called via `a(y)`, + /// we map `y -> x` for future lookups + fn map_inputs_to_params( + &mut self, + loc: Loc, + entry_call: bool, + params: Vec, + inputs: Vec, + callee_ctx: ContextNode, + ) -> Result, ExprErr> { + Ok(params + .iter() + .zip(inputs.iter()) + .filter_map(|(param, input)| { + if !entry_call { + if let Some(name) = + self.add_if_err(param.maybe_name(self).into_expr_err(loc))? + { + let res = input + .latest_version(self) + .underlying(self) + .into_expr_err(loc) + .cloned(); + let mut new_cvar = self.add_if_err(res)?; + new_cvar.loc = Some(param.loc(self).unwrap()); + new_cvar.name = name.clone(); + new_cvar.display_name = name; + new_cvar.is_tmp = false; + new_cvar.storage = if let Some(StorageLocation::Storage(_)) = + param.underlying(self).unwrap().storage + { + new_cvar.storage + } else { + None + }; + + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) + { + let ty = new_cvar.ty.clone(); + if !ty.ty_eq(¶m_ty, self).unwrap() { + if let Some(new_ty) = ty.try_cast(¶m_ty, self).unwrap() { + new_cvar.ty = new_ty; + } + } + } + + let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + self.add_edge( + node, + input.latest_version(self), + Edge::Context(ContextEdge::InputVariable), + ); + + if let (Some(r), Some(r2)) = + (node.range(self).unwrap(), param.range(self).unwrap()) + { + let new_min = + r.range_min().into_owned().cast(r2.range_min().into_owned()); + let new_max = + r.range_max().into_owned().cast(r2.range_max().into_owned()); + let res = node.try_set_range_min(self, new_min).into_expr_err(loc); + self.add_if_err(res); + let res = node.try_set_range_max(self, new_max).into_expr_err(loc); + self.add_if_err(res); + let res = node + .try_set_range_exclusions(self, r.exclusions) + .into_expr_err(loc); + self.add_if_err(res); + } + callee_ctx.add_var(node, self).unwrap(); + self.add_edge(node, callee_ctx, Edge::Context(ContextEdge::Variable)); + Some((*input, node)) + } else { + None + } + } else { + None + } + }) + .collect::>()) + } + + /// Checks if there are any modifiers and executes them prior to executing the function + #[tracing::instrument(level = "trace", skip_all)] + fn func_call_inner( + &mut self, + entry_call: bool, + ctx: ContextNode, + func_node: FunctionNode, + loc: Loc, + inputs: Vec, + params: Vec, + func_call_str: Option<&str>, + modifier_state: Option, + ) -> Result<(), ExprErr> { + // pseudocode: + // 1. Create context for the call + // 2. Check for modifiers + // 3. Call modifier 0, then 1, then 2, ... then N. + // 4. Call this function + // 5. Finish modifier N.. then 2, then 1, then 0 + let callee_ctx = if entry_call { + ctx + } else { + self.create_call_ctx(ctx, loc, func_node, modifier_state)? + }; + + // TODO: implement joining + // if !entry_call { + // let mapping = params + // .iter() + // .zip(inputs.iter()) + // .map(|(param, input)| (*input, *param)) + // .collect::>(); + // ctx.join(func_node, &mapping, self); + // } + + // handle remapping of variable names and bringing variables into the new context + let renamed_inputs = + self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; + + // begin modifier handling by making sure modifiers were set + if !func_node.modifiers_set(self).into_expr_err(loc)? { + self.set_modifiers(func_node, ctx)?; + } + + // get modifiers + let mods = func_node.modifiers(self); + self.apply_to_edges(callee_ctx, loc, &|analyzer, callee_ctx, loc| { + if let Some(mod_state) = &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state { + // we are iterating through modifiers + if mod_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = mod_state.clone(); + mstate.num += 1; + analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, mstate) + } else { + // out of modifiers, execute the actual function call + analyzer.execute_call_inner( + loc, + ctx, + callee_ctx, + func_node, + &renamed_inputs, + func_call_str, + ) + } + } else if !mods.is_empty() { + // we have modifiers and havent executed them, start the process of executing them + let state = + ModifierState::new(0, loc, func_node, callee_ctx, ctx, renamed_inputs.clone()); + analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, state) + } else { + // no modifiers, just execute the function + analyzer.execute_call_inner( + loc, + ctx, + callee_ctx, + func_node, + &renamed_inputs, + func_call_str, + ) + } + }) + } + + /// Actually executes the function + #[tracing::instrument(level = "trace", skip_all)] + fn execute_call_inner( + &mut self, + loc: Loc, + caller_ctx: ContextNode, + callee_ctx: ContextNode, + func_node: FunctionNode, + _renamed_inputs: &BTreeMap, + func_call_str: Option<&str>, + ) -> Result<(), ExprErr> { + if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { + // add return nodes into the subctx + func_node + .returns(self) + .collect::>() + .into_iter() + .for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + callee_ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); + } + }); + + self.parse_ctx_statement(&body, false, Some(callee_ctx)); + self.ctx_rets(loc, caller_ctx, callee_ctx) + } else { + let ret_ctx = Context::new_subctx( + callee_ctx, + Some(caller_ctx), + loc, + None, + None, + false, + self, + caller_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone(), + ) + .unwrap(); + let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); + self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); + + let res = callee_ctx + .set_child_call(ret_subctx, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { + func_node + .returns(analyzer) + .collect::>() + .into_iter() + .try_for_each(|ret| { + let underlying = ret.underlying(analyzer).unwrap(); + let mut var = + ContextVar::new_from_func_ret(ctx, analyzer, underlying.clone()) + .unwrap() + .expect("No type for return variable?"); + if let Some(func_call) = &func_call_str { + var.name = + format!("{}_{}", func_call, callee_ctx.new_tmp(analyzer).unwrap()); + var.display_name = func_call.to_string(); + } + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + }) + } + } + + fn ctx_rets( + &mut self, + loc: Loc, + caller_ctx: ContextNode, + callee_ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!( + "Handling function call return for: {}, {}, depth: {:?}, {:?}", + caller_ctx.path(self), + callee_ctx.path(self), + caller_ctx.depth(self), + callee_ctx.depth(self), + ); + match callee_ctx.underlying(self).into_expr_err(loc)?.child { + Some(CallFork::Fork(w1, w2)) => { + self.ctx_rets(loc, caller_ctx, w1)?; + self.ctx_rets(loc, caller_ctx, w2)?; + Ok(()) + } + Some(CallFork::Call(c)) + if c.underlying(self).into_expr_err(loc)?.depth + >= caller_ctx.underlying(self).into_expr_err(loc)?.depth => + { + // follow rabbit hole + self.ctx_rets(loc, caller_ctx, c)?; + Ok(()) + } + _ => { + if callee_ctx.is_killed(self).into_expr_err(loc)? { + return Ok(()); + } + let callee_depth = callee_ctx.underlying(self).into_expr_err(loc)?.depth; + let caller_depth = caller_ctx.underlying(self).into_expr_err(loc)?.depth; + if callee_depth != caller_depth { + let ctx = Context::new_subctx( + callee_ctx, + Some(caller_ctx), + loc, + None, + None, + false, + self, + caller_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone(), + ) + .unwrap(); + let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); + self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); + + let res = callee_ctx + .set_child_call(ret_subctx, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + + if rets.is_empty() { + let func_rets: Vec = callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .collect(); + func_rets + .iter() + .filter_map(|ret| { + let n: String = ret.maybe_name(self).ok()??; + let ret_loc: Loc = ret.loc(self).ok()?; + Some((n, ret_loc)) + }) + .collect::>() + .into_iter() + .try_for_each(|(name, ret_loc)| { + if let Some(cvar) = callee_ctx + .var_by_name_or_recurse(self, &name) + .into_expr_err(loc)? + { + let cvar = cvar.latest_version(self); + // let ret_loc = ret.loc(self).into_expr_err(loc)?; + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Return), + ); + } + Ok(()) + })?; + + // add unnamed rets + func_rets + .into_iter() + .filter(|ret| ret.maybe_name(self).unwrap().is_none()) + .collect::>() + .iter() + .try_for_each(|ret| { + let ret_loc = ret.loc(self).into_expr_err(loc)?; + let cvar = ContextVar::new_from_func_ret( + callee_ctx, + self, + ret.underlying(self).into_expr_err(loc)?.clone(), + ) + .into_expr_err(loc)? + .unwrap(); + let cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); + callee_ctx.add_var(cvar, self).into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Variable), + ); + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); + Ok(()) + })?; + rets = callee_ctx.underlying(self).unwrap().ret.clone(); + } + let ret = rets + .into_iter() + .enumerate() + .map(|(i, (_, node))| { + let tmp_ret = node + .as_tmp(callee_ctx.underlying(self).unwrap().loc, ret_subctx, self) + .unwrap(); + tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; + tmp_ret + .underlying_mut(self) + .into_expr_err(loc)? + .display_name = + format!("{}.{}", callee_ctx.associated_fn_name(self).unwrap(), i); + ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; + self.add_edge( + tmp_ret, + ret_subctx, + Edge::Context(ContextEdge::Variable), + ); + Ok(ExprRet::Single(tmp_ret.into())) + }) + .collect::>()?; + ret_subctx + .push_expr(ExprRet::Multi(ret), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + + if rets.is_empty() { + callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .filter_map(|ret| { + let n: String = ret.maybe_name(self).ok()??; + let ret_loc: Loc = ret.loc(self).ok()?; + Some((n, ret_loc)) + }) + .collect::>() + .into_iter() + .try_for_each(|(name, ret_loc)| { + if let Some(cvar) = callee_ctx + .var_by_name_or_recurse(self, &name) + .into_expr_err(loc)? + { + let cvar = cvar.latest_version(self); + // let ret_loc = ret.loc(self).into_expr_err(loc)?; + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Return), + ); + } + Ok(()) + })?; + rets = callee_ctx.underlying(self).unwrap().ret.clone(); + } + callee_ctx + .push_expr( + ExprRet::Multi( + rets.iter() + .map(|(_, node)| ExprRet::Single((*node).into())) + .collect(), + ), + self, + ) + .into_expr_err(loc) + } + } + } + } + + /// Calls a modifier for a function + #[tracing::instrument(level = "trace", skip_all)] + fn call_modifier_for_fn( + &mut self, + loc: Loc, + func_ctx: ContextNode, + func_node: FunctionNode, + mod_state: ModifierState, + ) -> Result<(), ExprErr> { + let mod_node = func_node.modifiers(self)[mod_state.num]; + tracing::trace!( + "calling modifier {} for func {}", + mod_node.name(self).into_expr_err(loc)?, + func_node.name(self).into_expr_err(loc)? + ); + + let input_exprs = func_node + .modifier_input_vars(mod_state.num, self) + .into_expr_err(loc)?; + + input_exprs + .iter() + .try_for_each(|expr| self.parse_ctx_expr(expr, func_ctx))?; + self.apply_to_edges(func_ctx, loc, &|analyzer, ctx, loc| { + let input_paths = if input_exprs.is_empty() { + ExprRet::Multi(vec![]) + } else { + let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, format!("No inputs to modifier, expected: {}", input_exprs.len()))) + }; + + if matches!(input_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(input_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + input_paths + }; + + analyzer.func_call( + ctx, + loc, + &input_paths, + mod_node, + None, + Some(mod_state.clone()), + ) + }) + } + + /// Resumes the parent function of a modifier + #[tracing::instrument(level = "trace", skip_all)] + fn resume_from_modifier( + &mut self, + ctx: ContextNode, + modifier_state: ModifierState, + ) -> Result<(), ExprErr> { + tracing::trace!( + "resuming from modifier: {}", + ctx.associated_fn_name(self) + .into_expr_err(modifier_state.loc)? + ); + + let mods = modifier_state.parent_fn.modifiers(self); + self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { + if modifier_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = modifier_state.clone(); + mstate.num += 1; + + let loc = mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc; + + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + loc, + None, + None, + false, + analyzer, + Some(modifier_state.clone()), + ) + .unwrap(); + let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); + + analyzer.add_edge( + new_parent_subctx, + modifier_state.parent_ctx, + Edge::Context(ContextEdge::Continue), + ); + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; + + analyzer.call_modifier_for_fn( + mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc, + new_parent_subctx, + mstate.parent_fn, + mstate, + )?; + Ok(()) + } else { + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + modifier_state.loc, + None, + None, + false, + analyzer, + None, + ) + .unwrap(); + let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); + + analyzer.add_edge( + new_parent_subctx, + modifier_state.parent_ctx, + Edge::Context(ContextEdge::Continue), + ); + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; + + // actually execute the parent function + analyzer.execute_call_inner( + modifier_state.loc, + ctx, + new_parent_subctx, + modifier_state.parent_fn, + &modifier_state.renamed_inputs, + None, + )?; + + fn inherit_return_from_call( + analyzer: &mut (impl GraphLike + AnalyzerLike), + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + let mctx = + Context::new_subctx(ctx, Some(ctx), loc, None, None, false, analyzer, None) + .unwrap(); + let modifier_after_subctx = + ContextNode::from(analyzer.add_node(Node::Context(mctx))); + + ctx.set_child_call(modifier_after_subctx, analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + modifier_after_subctx, + ctx, + Edge::Context(ContextEdge::Continue), + ); + + let ret = ctx.underlying(analyzer).unwrap().ret.clone(); + modifier_after_subctx.underlying_mut(analyzer).unwrap().ret = ret; + Ok(()) + } + + analyzer.apply_to_edges(new_parent_subctx, loc, &|analyzer, ctx, _loc| { + inherit_return_from_call(analyzer, modifier_state.loc, ctx) + }) + + // if edges.is_empty() { + // inherit_return_from_call(analyzer, modifier_state.loc, new_parent_subctx)?; + // } else { + // edges.iter().try_for_each(|i| { + // inherit_return_from_call(analyzer, modifier_state.loc, *i)?; + // Ok(()) + // })?; + // } + // Ok(()) + } + }) + } + + /// Inherit the input changes from a function call + fn inherit_input_changes( + &mut self, + loc: Loc, + to_ctx: ContextNode, + from_ctx: ContextNode, + renamed_inputs: &BTreeMap, + ) -> Result<(), ExprErr> { + if to_ctx != from_ctx { + self.apply_to_edges(to_ctx, loc, &|analyzer, to_ctx, loc| { + renamed_inputs + .iter() + .try_for_each(|(input_var, updated_var)| { + let new_input = analyzer.advance_var_in_ctx( + input_var.latest_version(analyzer), + loc, + to_ctx, + )?; + let latest_updated = updated_var.latest_version(analyzer); + if let Some(updated_var_range) = + latest_updated.range(analyzer).into_expr_err(loc)? + { + let res = new_input + .set_range_min(analyzer, updated_var_range.range_min().into_owned()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_input + .set_range_max(analyzer, updated_var_range.range_max().into_owned()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_input + .set_range_exclusions( + analyzer, + updated_var_range.range_exclusions(), + ) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + Ok(()) + }) + })?; + } + Ok(()) + } + + /// Inherit the input changes from a function call + fn modifier_inherit_return(&mut self, mod_ctx: ContextNode, fn_ctx: ContextNode) { + let ret = fn_ctx.underlying(self).unwrap().ret.clone(); + mod_ctx.underlying_mut(self).unwrap().ret = ret; + } + + /// Inherit the storage changes from a function call + fn inherit_storage_changes( + &mut self, + loc: Loc, + inheritor_ctx: ContextNode, + grantor_ctx: ContextNode, + ) -> Result<(), ExprErr> { + if inheritor_ctx != grantor_ctx { + return self.apply_to_edges(inheritor_ctx, loc, &|analyzer, inheritor_ctx, loc| { + let vars = grantor_ctx.local_vars(analyzer).clone(); + vars.iter().try_for_each(|(name, old_var)| { + let var = old_var.latest_version(analyzer); + let underlying = var.underlying(analyzer).into_expr_err(loc)?; + if var.is_storage(analyzer).into_expr_err(loc)? { + if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { + let new_inheritor_var = analyzer + .advance_var_in_ctx( + inheritor_var, + underlying.loc.expect("No loc for val change"), + inheritor_ctx, + ) + .unwrap(); + let _ = new_inheritor_var + .set_range_min(analyzer, r.range_min().into_owned()); + let _ = new_inheritor_var + .set_range_max(analyzer, r.range_max().into_owned()); + let _ = new_inheritor_var + .set_range_exclusions(analyzer, r.range_exclusions()); + } + } else { + let new_in_inheritor = + analyzer.add_node(Node::ContextVar(underlying.clone())); + inheritor_ctx + .add_var(new_in_inheritor.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + new_in_inheritor, + inheritor_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + new_in_inheritor, + var, + Edge::Context(ContextEdge::InheritedVariable), + ); + } + } + Ok(()) + }) + }); + } + Ok(()) + } + + fn modifiers( + &mut self, + ctx: ContextNode, + func: FunctionNode, + ) -> Result, ExprErr> { + use std::fmt::Write; + let binding = func.underlying(self).unwrap().clone(); + let modifiers = binding.modifiers_as_base(); + if modifiers.is_empty() { + Ok(vec![]) + } else { + let res = modifiers + .iter() + .map(|modifier| { + assert_eq!(modifier.name.identifiers.len(), 1); + // construct arg string for function selector + let mut mod_name = format!("{}", modifier.name.identifiers[0]); + if let Some(args) = &modifier.args { + let args_str = args + .iter() + .map(|expr| { + let mctx = Context::new_subctx( + ctx, + None, + Loc::Implicit, + None, + None, + false, + self, + None, + ) + .into_expr_err(Loc::Implicit)?; + let callee_ctx = + ContextNode::from(self.add_node(Node::Context(mctx))); + let _res = ctx.set_child_call(callee_ctx, self); + self.parse_ctx_expr(expr, callee_ctx)?; + let f: Vec = + self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { + let ret = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap(); + Ok(ret.try_as_func_input_str(analyzer)) + })?; + + ctx.delete_child(self).into_expr_err(expr.loc())?; + Ok(f.first().unwrap().clone()) + }) + .collect::, ExprErr>>()? + .join(", "); + let _ = write!(mod_name, "{args_str}"); + } else { + let _ = write!(mod_name, "()"); + } + let _ = write!(mod_name, ""); + let found: Option = ctx + .visible_modifiers(self) + .unwrap() + .iter() + .find(|modifier| modifier.name(self).unwrap() == mod_name) + .copied(); + Ok(found) + }) + .collect::>, ExprErr>>()? + .into_iter() + .flatten() + .collect::>(); + Ok(res) + } + } + + fn set_modifiers(&mut self, func: FunctionNode, ctx: ContextNode) -> Result<(), ExprErr> { + let modifiers = self.modifiers(ctx, func)?; + modifiers + .iter() + .enumerate() + .for_each(|(i, modifier)| self.add_edge(*modifier, func, Edge::FuncModifier(i))); + func.underlying_mut(self).unwrap().modifiers_set = true; + Ok(()) + } +} diff --git a/crates/solc_expressions/func_call/modifier.rs b/crates/solc_expressions/func_call/modifier.rs new file mode 100644 index 00000000..a62adda5 --- /dev/null +++ b/crates/solc_expressions/func_call/modifier.rs @@ -0,0 +1,34 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::func_call::FuncCaller; + +use crate::context::ExprErr; + +use shared::analyzer::GraphLike; +use shared::context::*; + +use solang_parser::pt::{Expression, Loc}; + +use shared::{analyzer::AnalyzerLike, nodes::*}; + +impl ModifierCaller for T where + T: AnalyzerLike + Sized + GraphLike +{ +} +pub trait ModifierCaller: + GraphLike + AnalyzerLike + Sized +{ + fn handle_modifiers( + &mut self, + ctx: ContextNode, + loc: Loc, + _input_paths: &ExprRet, + func: FunctionNode, + _func_call_str: Option, + ) -> Result { + if !func.modifiers_set(self).into_expr_err(loc)? { + self.set_modifiers(func, ctx)?; + } + + todo!() + } +} diff --git a/crates/solc_expressions/func_call/namespaced_call.rs b/crates/solc_expressions/func_call/namespaced_call.rs new file mode 100644 index 00000000..9a4118d2 --- /dev/null +++ b/crates/solc_expressions/func_call/namespaced_call.rs @@ -0,0 +1,372 @@ +use crate::context::{ + exprs::{IntoExprErr, MemberAccess}, + func_call::intrinsic_call::IntrinsicFuncCaller, + func_call::FuncCaller, + ContextBuilder, ExprErr, +}; +use shared::nodes::BuiltInNode; +use shared::{ + analyzer::{AnalyzerLike, GraphLike}, + context::{ContextNode, ContextVarNode, ExprRet}, + nodes::FunctionNode, + Node, NodeIdx, +}; +use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; + +impl NameSpaceFuncCaller for T where + T: AnalyzerLike + Sized + GraphLike +{ +} +pub trait NameSpaceFuncCaller: + AnalyzerLike + Sized + GraphLike +{ + #[tracing::instrument(level = "trace", skip_all)] + fn call_name_spaced_named_func( + &mut self, + ctx: ContextNode, + _loc: &Loc, + member_expr: &Expression, + _ident: &Identifier, + _input_args: &[NamedArgument], + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(member_expr, ctx)?; + todo!("here"); + } + + #[tracing::instrument(level = "trace", skip_all)] + fn call_name_spaced_func( + &mut self, + ctx: ContextNode, + loc: &Loc, + member_expr: &Expression, + ident: &Identifier, + input_exprs: &[Expression], + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + tracing::trace!("Calling name spaced function"); + if let Variable(Identifier { name, .. }) = member_expr { + if name == "abi" { + let func_name = format!("abi.{}", ident.name); + let fn_node = self + .builtin_fn_or_maybe_add(&func_name) + .unwrap_or_else(|| panic!("No builtin function with name {func_name}")); + return self.intrinsic_func_call(loc, input_exprs, fn_node, ctx); + } else if name == "super" { + if let Some(contract) = ctx.maybe_associated_contract(self).into_expr_err(*loc)? { + let supers = contract.super_contracts(self); + let possible_funcs: Vec<_> = supers + .iter() + .filter_map(|con_node| { + con_node + .linearized_functions(self) + .into_iter() + .find(|(func_name, _func_node)| func_name.starts_with(&ident.name)) + .map(|(_, node)| node) + }) + .collect(); + + if possible_funcs.is_empty() { + return Err(ExprErr::FunctionNotFound( + *loc, + "Could not find function in super".to_string(), + )); + } + self.parse_inputs(ctx, *loc, input_exprs)?; + return self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = if let Some(inputs) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + { + inputs + } else { + ExprRet::Multi(vec![]) + }; + if possible_funcs.len() == 1 { + let mut inputs = inputs.as_vec(); + let func = possible_funcs[0]; + if func.params(analyzer).len() < inputs.len() { + inputs = inputs[1..].to_vec(); + } + let inputs = ExprRet::Multi(inputs); + if inputs.has_killed() { + return ctx + .kill(analyzer, loc, inputs.killed_kind().unwrap()) + .into_expr_err(loc); + } + analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + } else { + // this is the annoying case due to function overloading & type inference on number literals + let mut lits = vec![false]; + lits.extend( + input_exprs + .iter() + .map(|expr| { + match expr { + Negate(_, expr) => { + // negative number potentially + matches!(**expr, NumberLiteral(..) | HexLiteral(..)) + } + NumberLiteral(..) | HexLiteral(..) => true, + _ => false, + } + }) + .collect::>(), + ); + + if inputs.has_killed() { + return ctx + .kill(analyzer, loc, inputs.killed_kind().unwrap()) + .into_expr_err(loc); + } + if let Some(func) = analyzer.disambiguate_fn_call( + &ident.name, + lits, + &inputs, + &possible_funcs, + ) { + analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + } else { + Err(ExprErr::FunctionNotFound( + loc, + "Could not find function in super".to_string(), + )) + } + } + }); + } + } + } + + self.parse_ctx_expr(member_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Namespace function call had no namespace".to_string())) + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) + }) + } + + fn match_namespaced_member( + &mut self, + ctx: ContextNode, + loc: Loc, + member_expr: &Expression, + ident: &Identifier, + input_exprs: &[Expression], + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { + self.call_name_spaced_func_inner(ctx, loc, member_expr, ident, input_exprs, inner) + } + ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { + self.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) + }), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Null => Err(ExprErr::NoLhs( + loc, + "No function found due to null".to_string(), + )), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn call_name_spaced_func_inner( + &mut self, + ctx: ContextNode, + loc: Loc, + member_expr: &Expression, + ident: &Identifier, + input_exprs: &[Expression], + member: NodeIdx, + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + tracing::trace!( + "namespaced function call: {:?}.{:?}(..)", + ContextVarNode::from(member).display_name(self), + ident.name + ); + + let funcs = self.visible_member_funcs(ctx, loc, member)?; + // filter down all funcs to those that match + let possible_funcs = funcs + .iter() + .filter(|func| { + func.name(self) + .unwrap() + .starts_with(&format!("{}(", ident.name)) + }) + .copied() + .collect::>(); + + ctx.push_expr(ExprRet::Single(member), self) + .into_expr_err(loc)?; + + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Namespace function call had no inputs".to_string())) + }; + + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if possible_funcs.is_empty() { + // TODO: this is extremely ugly. + if inputs.has_killed() { + return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + } + let mut inputs = inputs.as_vec(); + if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + let inputs = ExprRet::Multi(inputs); + + let as_input_str = inputs.try_as_func_input_str(analyzer); + + let lits = inputs.literals_list().into_expr_err(loc)?; + if lits.iter().any(|i| *i) { + // try to disambiguate + if lits[0] { + Err(ExprErr::Todo(loc, "First element in function call was literal".to_string())) + } else { + let ty = if let Node::ContextVar(cvar) = analyzer.node(member) { + cvar.ty.ty_idx() + } else { + member + }; + + let possible_builtins: Vec<_> = analyzer.builtin_fn_inputs().iter().filter_map(|(func_name, (inputs, _))| { + if func_name.starts_with(&ident.name) { + if let Some(input) = inputs.first() { + let Ok(implicitly_castable) = BuiltInNode::from(ty).implicitly_castable_to(&BuiltInNode::from(input.ty), analyzer) else { + return None + }; + if implicitly_castable { + Some(func_name.clone()) + } else { + None + } + } else { + None + } + } else { + None + } + }).collect::>(); + let possible_builtins: Vec<_> = possible_builtins.into_iter().filter_map(|name| { + analyzer.builtin_fn_or_maybe_add(&name).map(FunctionNode::from) + }).collect(); + if let Some(func) = + analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_builtins) + { + let expr = &MemberAccess( + loc, + Box::new(member_expr.clone()), + Identifier { + loc: ident.loc, + name: func.name(analyzer).into_expr_err(loc)?.split('(').collect::>()[0].to_string(), + }, + ); + analyzer.parse_ctx_expr(expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let mut modifier_input_exprs = vec![member_expr.clone()]; + modifier_input_exprs.extend(input_exprs.to_vec()); + analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + }) + } else { + // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + Err(ExprErr::FunctionNotFound( + loc, + format!("Could not disambiguate function, possible functions: {:#?}", possible_builtins.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) + )) + } + } + } else { + let expr = &MemberAccess( + loc, + Box::new(member_expr.clone()), + Identifier { + loc: ident.loc, + name: format!("{}{}", ident.name, as_input_str), + }, + ); + analyzer.parse_ctx_expr(expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let mut modifier_input_exprs = vec![member_expr.clone()]; + modifier_input_exprs.extend(input_exprs.to_vec()); + analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + }) + } + } else if possible_funcs.len() == 1 { + let mut inputs = inputs.as_vec(); + let func = possible_funcs[0]; + if func.params(analyzer).len() > inputs.len() { + // Add the member back in if its a context variable + if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + } + let inputs = ExprRet::Multi(inputs); + if inputs.has_killed() { + return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + } + + + analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + } else { + // Add the member back in if its a context variable + let mut inputs = inputs.as_vec(); + if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + let inputs = ExprRet::Multi(inputs); + // this is the annoying case due to function overloading & type inference on number literals + let mut lits = vec![false]; + lits.extend( + input_exprs + .iter() + .map(|expr| { + match expr { + Negate(_, expr) => { + // negative number potentially + matches!(**expr, NumberLiteral(..) | HexLiteral(..)) + } + NumberLiteral(..) | HexLiteral(..) => true, + _ => false, + } + }) + .collect::>(), + ); + + if inputs.has_killed() { + return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + } + if let Some(func) = + analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_funcs) + { + analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + } else { + Err(ExprErr::FunctionNotFound( + loc, + format!("Could not disambiguate function, possible functions: {:#?}", possible_funcs.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) + )) + } + } + }) + } +} diff --git a/crates/solc_expressions/lib.rs b/crates/solc_expressions/lib.rs new file mode 100644 index 00000000..dbd5ebfa --- /dev/null +++ b/crates/solc_expressions/lib.rs @@ -0,0 +1,190 @@ +use shared::analyzer::GraphError; +use solang_parser::pt::Loc; + +mod array; +mod bin_op; +mod cmp; +mod cond_op; +mod env; +mod func_call; +mod list; +mod literal; +mod loops; +mod member_access; +mod require; +mod variable; +mod yul; + +pub use array::*; +pub use bin_op::*; +pub use cmp::*; +pub use cond_op::*; +pub use func_call::*; +pub use env::*; +pub use list::*; +pub use literal::*; +pub use loops::*; +pub use member_access::*; +pub use require::*; +pub use variable::*; +pub use yul::*; + +pub trait ExprParser: + BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env +{ +} +impl ExprParser for T where + T: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env +{ +} + +pub trait IntoExprErr { + fn into_expr_err(self, loc: Loc) -> Result; +} + +impl IntoExprErr for Result { + fn into_expr_err(self, loc: Loc) -> Result { + match self { + Ok(v) => Ok(v), + Err(e) => Err(ExprErr::from_graph_err(loc, e)), + } + } +} + +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub enum ExprErr { + ParseError(Loc, String), + NoLhs(Loc, String), + NoRhs(Loc, String), + NoReturn(Loc, String), + ArrayTy(Loc, String), + ArrayIndex(Loc, String), + UnhandledCombo(Loc, String), + UnhandledExprRet(Loc, String), + MultiNot(Loc, String), + VarBadType(Loc, String), + Todo(Loc, String), + BadRange(Loc, String), + ContractFunctionNotFound(Loc, String), + MemberAccessNotFound(Loc, String), + FunctionNotFound(Loc, String), + + FunctionCallBlockTodo(Loc, String), + + NonStoragePush(Loc, String), + IntrinsicNamedArgs(Loc, String), + InvalidFunctionInput(Loc, String), + TakeFromFork(Loc, String), + GraphError(Loc, GraphError), + Unresolved(Loc, String), +} + +impl ExprErr { + pub fn from_graph_err(loc: Loc, graph_err: GraphError) -> Self { + Self::GraphError(loc, graph_err) + } +} + +impl ExprErr { + pub fn loc(&self) -> Loc { + use ExprErr::*; + match self { + ParseError(loc, ..) => *loc, + NoLhs(loc, ..) => *loc, + NoRhs(loc, ..) => *loc, + NoReturn(loc, ..) => *loc, + ArrayTy(loc, ..) => *loc, + ArrayIndex(loc, ..) => *loc, + UnhandledCombo(loc, ..) => *loc, + UnhandledExprRet(loc, ..) => *loc, + MultiNot(loc, ..) => *loc, + VarBadType(loc, ..) => *loc, + Todo(loc, ..) => *loc, + FunctionCallBlockTodo(loc, ..) => *loc, + BadRange(loc, ..) => *loc, + ContractFunctionNotFound(loc, ..) => *loc, + MemberAccessNotFound(loc, ..) => *loc, + FunctionNotFound(loc, ..) => *loc, + NonStoragePush(loc, ..) => *loc, + IntrinsicNamedArgs(loc, ..) => *loc, + InvalidFunctionInput(loc, ..) => *loc, + TakeFromFork(loc, ..) => *loc, + GraphError(loc, ..) => *loc, + Unresolved(loc, ..) => *loc, + } + } + + pub fn msg(&self) -> &str { + use ExprErr::*; + match self { + ParseError(_, msg, ..) => msg, + NoLhs(_, msg, ..) => msg, + NoRhs(_, msg, ..) => msg, + NoReturn(_, msg, ..) => msg, + ArrayTy(_, msg, ..) => msg, + ArrayIndex(_, msg, ..) => msg, + UnhandledCombo(_, msg, ..) => msg, + UnhandledExprRet(_, msg, ..) => msg, + MultiNot(_, msg, ..) => msg, + VarBadType(_, msg, ..) => msg, + Todo(_, msg, ..) => msg, + FunctionCallBlockTodo(_, msg, ..) => msg, + BadRange(_, msg, ..) => msg, + ContractFunctionNotFound(_, msg, ..) => msg, + MemberAccessNotFound(_, msg, ..) => msg, + FunctionNotFound(_, msg, ..) => msg, + NonStoragePush(_, msg, ..) => msg, + IntrinsicNamedArgs(_, msg, ..) => msg, + InvalidFunctionInput(_, msg, ..) => msg, + TakeFromFork(_, msg, ..) => msg, + Unresolved(_, msg, ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(msg), ..) => { + msg + } + GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(msg), ..) => msg, + GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(msg), ..) => msg, + } + } + + pub fn report_msg(&self) -> &str { + use ExprErr::*; + match self { + ParseError(..) => "Could not parse this", + NoLhs(..) => "No left-hand side passed to expression", + NoRhs(..) => "No right-hand side passed to expression", + NoReturn(..) => "No returned element from expression", + ArrayTy(..) => "Unexpected type as array element", + ArrayIndex(..) => "Unexpected type as array index", + UnhandledCombo(..) => "Unhandled ExprRet variant combination", + UnhandledExprRet(..) => "Unhandled ExprRet variant", + MultiNot(..) => "Expected a single ExprRet in Not statement, got ExprRet::Multi", + VarBadType(..) => "This type cannot be made into a variable", + Todo(..) => "TODO", + FunctionCallBlockTodo(..) => "TODO", + Unresolved(..) => "Unresolved type: This is likely a bug. Please report it at https://github.com/nascentxyz/pyrometer", + BadRange(..) => "Expected a range for a variable but there was none", + ContractFunctionNotFound(..) => "Contract function could not be Found", + MemberAccessNotFound(..) => "Member element could not be found", + FunctionNotFound(..) => "Function could not be found", + NonStoragePush(..) => "Pushing on non-storage based array is unsupported", + IntrinsicNamedArgs(..) => "Arguments in calls to intrinsic functions cannot be named", + InvalidFunctionInput(..) => "Arguments to this function call do not match required types", + TakeFromFork(..) => "IR Error: Tried to take from an child context that ended up forking", + GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(_), ..) => "Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(_), ..) => "Max call depth reached - either recursion or loop", + GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(_), ..) => "TODO: Max fork width reached - Need to widen variables and remove contexts", + GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(_), ..) => "Graph IR Error: Child redefintion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(_), ..) => "Graph IR Error: Detached Variable. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(_), ..) => "Graph IR Error: Variable update in an old context. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(_), ..) => "Graph IR Error: Expecting single expression return, got multiple. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(_), ..) => "Graph IR Error: Expected a particular number of elements on the context stack but found a different amount. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(_), ..) => "Graph IR Error: Unbreakable recursion in variable range. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + } + } +} diff --git a/crates/solc_expressions/list.rs b/crates/solc_expressions/list.rs new file mode 100644 index 00000000..a5fae6e1 --- /dev/null +++ b/crates/solc_expressions/list.rs @@ -0,0 +1,111 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ContextBuilder; +use crate::context::ExprErr; +use shared::{analyzer::AnalyzerLike, context::*, nodes::*, Edge, Node}; +use solang_parser::pt::Expression; + +use solang_parser::pt::{Parameter, ParameterList}; + +use solang_parser::pt::Loc; + +impl List for T where T: AnalyzerLike + Sized {} + +pub trait List: AnalyzerLike + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { + params + .iter() + .try_for_each(|(loc, input)| { + if let Some(input) = input { + self.parse_ctx_expr(&input.ty, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + ctx.append_tmp_expr(analyzer.match_ty(ctx, &loc, &ret, input)?, analyzer).into_expr_err(loc) + }) + } else { + // create a dummy var + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + ctx.append_tmp_expr(ExprRet::Null, analyzer).into_expr_err(loc) + }) + } + })?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } + + fn match_ty( + &mut self, + ctx: ContextNode, + loc: &Loc, + ty_ret: &ExprRet, + input: &Parameter, + ) -> Result { + match ty_ret { + ExprRet::Null => Ok(ExprRet::Null), + ExprRet::Single(ty) | ExprRet::SingleLiteral(ty) => { + if let Some(input_name) = &input.name { + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let var = ContextVar { + loc: Some(*loc), + name: input_name.to_string(), + display_name: input_name.to_string(), + storage: input.storage.clone(), + is_tmp: false, + is_symbolic: false, + tmp_of: None, + is_return: false, + ty, + }; + let input_node = self.add_node(Node::ContextVar(var)); + ctx.add_var(input_node.into(), self).into_expr_err(*loc)?; + self.add_edge(input_node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(input_node)) + } else { + match self.node(*ty) { + Node::ContextVar(_var) => { + // reference the variable directly, don't create a temporary variable + Ok(ExprRet::Single(*ty)) + } + _ => { + // create a tmp + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let tmp_num = ctx.new_tmp(self).into_expr_err(*loc)?; + let new_lhs_underlying = ContextVar { + loc: Some(*loc), + name: format!("tmp{tmp_num}"), + display_name: format!("tmp{tmp_num}"), + storage: input.storage.clone(), + is_tmp: true, + is_symbolic: false, + tmp_of: None, + is_return: false, + ty, + }; + let input_node = self.add_node(Node::ContextVar(new_lhs_underlying)); + ctx.add_var(input_node.into(), self).into_expr_err(*loc)?; + self.add_edge(input_node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(input_node)) + } + } + } + } + ExprRet::Multi(inner) => Ok(ExprRet::Multi( + inner + .iter() + .map(|i| self.match_ty(ctx, loc, i, input)) + .collect::>()?, + )), + ExprRet::CtxKilled(kind) => Ok(ExprRet::CtxKilled(*kind)), + } + } +} diff --git a/crates/solc_expressions/literal.rs b/crates/solc_expressions/literal.rs new file mode 100644 index 00000000..ec8c4b8f --- /dev/null +++ b/crates/solc_expressions/literal.rs @@ -0,0 +1,226 @@ +use crate::context::exprs::IntoExprErr; +use crate::ExprErr; +use ethers_core::types::H256; +use ethers_core::types::I256; +use shared::context::ExprRet; +use shared::nodes::Builtin; +use shared::range::elem_ty::Elem; +use shared::{ + analyzer::AnalyzerLike, + context::*, + nodes::{Concrete, ConcreteNode}, + Edge, Node, +}; +use solang_parser::pt::HexLiteral; +use solang_parser::pt::Identifier; + +use ethers_core::types::{Address, U256}; +use solang_parser::pt::Loc; +use std::str::FromStr; + +impl Literal for T where T: AnalyzerLike + Sized {} + +pub trait Literal: AnalyzerLike + Sized { + fn number_literal( + &mut self, + ctx: ContextNode, + loc: Loc, + integer: &str, + exponent: &str, + negative: bool, + ) -> Result<(), ExprErr> { + let int = U256::from_dec_str(integer).unwrap(); + let val = if !exponent.is_empty() { + let exp = U256::from_dec_str(exponent).unwrap(); + int * U256::from(10).pow(exp) + } else { + int + }; + + let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; + let concrete_node = if negative { + let val = if val == U256::from(2).pow(255.into()) { + // no need to set upper bit + I256::from_raw(val) + } else { + I256::from(-1i32) * I256::from_raw(val) + }; + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Int(size, val)))) + } else { + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Uint(size, val)))) + }; + + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } + + fn rational_number_literal( + &mut self, + ctx: ContextNode, + loc: Loc, + integer: &str, + fraction: &str, + exponent: &str, + _unit: &Option, + ) -> Result<(), ExprErr> { + let int = U256::from_dec_str(integer).unwrap(); + let exp = if !exponent.is_empty() { + U256::from_dec_str(exponent).unwrap() + } else { + U256::from(0) + }; + let fraction_len = fraction.len(); + let fraction_denom = U256::from(10).pow(fraction_len.into()); + let fraction = U256::from_dec_str(fraction).unwrap(); + + let int_elem = Elem::min( + Elem::from(Concrete::from(int)), + Elem::from(Concrete::from(U256::from(1))), + ); + let exp_elem = Elem::from(Concrete::from(exp)); + let rational_range = (Elem::from(Concrete::from(fraction)) + + int_elem * Elem::from(Concrete::from(fraction_denom))) + * Elem::from(Concrete::from(U256::from(10))).pow(exp_elem); + let cvar = + ContextVar::new_from_builtin(loc, self.builtin_or_add(Builtin::Uint(256)).into(), self) + .into_expr_err(loc)?; + let node = ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); + node.set_range_max(self, rational_range.clone()) + .into_expr_err(loc)?; + node.set_range_min(self, rational_range) + .into_expr_err(loc)?; + + ctx.add_var(node, self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + + fn hex_num_literal( + &mut self, + ctx: ContextNode, + loc: Loc, + integer: &str, + negative: bool, + ) -> Result<(), ExprErr> { + let integer: String = integer.chars().filter(|c| *c != '_').collect(); + let val = U256::from_str_radix(&integer, 16).unwrap(); + let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; + let concrete_node = if negative { + let val = I256::from(-1i32) * I256::from_raw(val); + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Int(size, val)))) + } else { + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Uint(size, val)))) + }; + + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } + + fn hex_literals(&mut self, ctx: ContextNode, hexes: &[HexLiteral]) -> Result<(), ExprErr> { + if hexes.len() == 1 { + let mut h = H256::default(); + let mut max = 0; + if let Ok(hex_val) = hex::decode(&hexes[0].hex) { + hex_val.iter().enumerate().for_each(|(i, hex_byte)| { + if *hex_byte != 0x00u8 { + max = i as u8; + } + h.0[i] = *hex_byte; + }); + } + + let concrete_node = + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Bytes(max + 1, h)))); + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(hexes[0].loc, ctx, concrete_node, self) + .into_expr_err(hexes[0].loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(hexes[0].loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(hexes[0].loc)?; + Ok(()) + } else { + let mut h = vec![]; + hexes.iter().for_each(|sub_hex| { + if let Ok(hex_val) = hex::decode(&sub_hex.hex) { + h.extend(hex_val) + } + }); + + let mut loc = hexes[0].loc; + loc.use_end_from(&hexes[hexes.len() - 1].loc); + let concrete_node = + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::DynBytes(h)))); + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } + } + + fn address_literal(&mut self, ctx: ContextNode, loc: Loc, addr: &str) -> Result<(), ExprErr> { + let addr = Address::from_str(addr).unwrap(); + + let concrete_node = + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Address(addr)))); + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } + + fn string_literal(&mut self, ctx: ContextNode, loc: Loc, s: &str) -> Result<(), ExprErr> { + let concrete_node = + ConcreteNode::from(self.add_node(Node::Concrete(Concrete::String(s.to_string())))); + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } + + fn bool_literal(&mut self, ctx: ContextNode, loc: Loc, b: bool) -> Result<(), ExprErr> { + let concrete_node = ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Bool(b)))); + let ccvar = Node::ContextVar( + ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, + ); + let node = self.add_node(ccvar); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::SingleLiteral(node), self) + .into_expr_err(loc)?; + Ok(()) + } +} diff --git a/crates/solc_expressions/loops.rs b/crates/solc_expressions/loops.rs new file mode 100644 index 00000000..449b4d6e --- /dev/null +++ b/crates/solc_expressions/loops.rs @@ -0,0 +1,93 @@ +use crate::context::exprs::IntoExprErr; +use crate::ExprErr; +use solang_parser::pt::Loc; +use solang_parser::pt::Statement; + +use crate::context::ContextBuilder; +use shared::analyzer::GraphLike; +use shared::context::*; +use shared::{analyzer::AnalyzerLike, Node}; +use solang_parser::pt::Expression; + +impl Looper for T where T: AnalyzerLike + Sized + GraphLike {} +pub trait Looper: GraphLike + AnalyzerLike + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn for_loop( + &mut self, + loc: Loc, + ctx: ContextNode, + maybe_init: &Option>, + _maybe_limiter: &Option>, + _maybe_post: &Option>, + maybe_body: &Option>, + ) -> Result<(), ExprErr> { + // TODO: improve this + if let Some(initer) = maybe_init { + self.parse_ctx_statement(initer, false, Some(ctx)); + } + + if let Some(body) = maybe_body { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.reset_vars(loc, ctx, body) + }) + } else { + Ok(()) + } + } + + fn reset_vars(&mut self, loc: Loc, ctx: ContextNode, body: &Statement) -> Result<(), ExprErr> { + let og_ctx = ctx; + let sctx = Context::new_subctx(ctx, None, loc, None, None, false, self, None) + .into_expr_err(loc)?; + let subctx = ContextNode::from(self.add_node(Node::Context(sctx))); + ctx.set_child_call(subctx, self).into_expr_err(loc)?; + self.parse_ctx_statement(body, false, Some(subctx)); + self.apply_to_edges(subctx, loc, &|analyzer, ctx, loc| { + let vars = subctx.local_vars(analyzer).clone(); + vars.iter().for_each(|(name, var)| { + // widen to max range + if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = var + .underlying(analyzer) + .unwrap() + .ty + .default_range(analyzer) + .unwrap() + { + let new_inheritor_var = analyzer + .advance_var_in_ctx(inheritor_var, loc, ctx) + .unwrap(); + let res = new_inheritor_var + .set_range_min(analyzer, r.min) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_inheritor_var + .set_range_max(analyzer, r.max) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + } + }); + + let sctx = + Context::new_subctx(ctx, Some(og_ctx), loc, None, None, false, analyzer, None) + .into_expr_err(loc)?; + let sctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); + ctx.set_child_call(sctx, analyzer).into_expr_err(loc) + }) + } + + fn while_loop( + &mut self, + loc: Loc, + ctx: ContextNode, + _limiter: &Expression, + body: &Statement, + ) -> Result<(), ExprErr> { + // TODO: improve this + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.reset_vars(loc, ctx, body) + }) + } +} diff --git a/crates/solc_expressions/member_access.rs b/crates/solc_expressions/member_access.rs new file mode 100644 index 00000000..b3b68111 --- /dev/null +++ b/crates/solc_expressions/member_access.rs @@ -0,0 +1,1092 @@ +use crate::context::exprs::env::Env; +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::{context::exprs::variable::Variable, ContextBuilder, NodeIdx}; +use petgraph::{visit::EdgeRef, Direction}; +use shared::range::elem_ty::Elem; +use shared::range::Range; +use shared::{ + analyzer::AnalyzerLike, + context::*, + nodes::*, + range::SolcRange, + {Edge, Node}, +}; +use std::collections::BTreeSet; + +use ethers_core::types::{I256, U256}; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl MemberAccess for T where T: AnalyzerLike + Sized {} +pub trait MemberAccess: AnalyzerLike + Sized { + fn visible_member_funcs( + &mut self, + ctx: ContextNode, + loc: Loc, + member_idx: NodeIdx, + ) -> Result, ExprErr> { + let res = match self.node(member_idx) { + Node::ContextVar(cvar) => match &cvar.ty { + VarType::User(TypeNode::Contract(con_node), _) => { + let mut funcs = con_node.linearized_functions(self); + self + .possible_library_funcs(ctx, con_node.0.into()) + .into_iter() + .for_each(|func| { + let name = func.name(self).unwrap(); + funcs.entry(name).or_insert(func); + }); + funcs.values().copied().collect() + }, + VarType::BuiltIn(bn, _) => self + .possible_library_funcs(ctx, bn.0.into()) + .into_iter() + .collect::>(), + VarType::Concrete(cnode) => { + let b = cnode.underlying(self).unwrap().as_builtin(); + let bn = self.builtin_or_add(b); + self.possible_library_funcs(ctx, bn) + .into_iter() + .collect::>() + } + VarType::User(TypeNode::Struct(sn), _) => self + .possible_library_funcs(ctx, sn.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Enum(en), _) => self + .possible_library_funcs(ctx, en.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Ty(ty), _) => self + .possible_library_funcs(ctx, ty.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Func(func_node), _) => self + .possible_library_funcs(ctx, func_node.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Unresolved(n), _) => { + match self.node(*n) { + Node::Unresolved(ident) => { + return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) + } + _ => unreachable!() + } + } + }, + Node::Contract(_) => ContractNode::from(member_idx).funcs(self), + Node::Concrete(_) + | Node::Ty(_) + | Node::Struct(_) + | Node::Function(_) + | Node::Enum(_) + | Node::Builtin(_) => self + .possible_library_funcs(ctx, member_idx) + .into_iter() + .collect::>(), + e => { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!("This type cannot have member functions: {:?}", e), + )) + } + }; + Ok(res) + } + + /// Gets the array type + #[tracing::instrument(level = "trace", skip_all)] + fn member_access( + &mut self, + loc: Loc, + member_expr: &Expression, + ident: &Identifier, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // TODO: this is wrong as it overwrites a function call of the form elem.length(...) i believe + if ident.name == "length" { + return self.length(loc, member_expr, ctx); + } + + self.parse_ctx_expr(member_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_member(ctx, loc, ident, ret) + }) + } + + fn match_member( + &mut self, + ctx: ContextNode, + loc: Loc, + ident: &Identifier, + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { + ctx.push_expr(self.member_access_inner(loc, idx, ident, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|ret| self.match_member(ctx, loc, ident, ret)), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Null => Ok(()), + } + } + + fn member_access_var_ty( + &mut self, + cvar: ContextVar, + loc: Loc, + member_idx: NodeIdx, + ident: &Identifier, + ctx: ContextNode, + ) -> Result { + match &cvar.ty { + VarType::User(TypeNode::Struct(struct_node), _) => { + self.struct_member_access(member_idx, *struct_node, ident, ctx, loc, Some(cvar)) + } + VarType::User(TypeNode::Enum(enum_node), _) => { + self.enum_member_access(member_idx, *enum_node, ident, ctx, loc) + } + VarType::User(TypeNode::Ty(ty_node), _) => { + self.ty_member_access(member_idx, *ty_node, ident, ctx, loc, Some(cvar)) + } + VarType::User(TypeNode::Contract(con_node), _) => { + self.contract_member_access(member_idx, *con_node, ident, ctx, loc, Some(cvar)) + } + VarType::BuiltIn(bn, _) => self.builtin_member_access( + loc, + ctx, + *bn, + ContextVarNode::from(member_idx) + .is_storage(self) + .into_expr_err(loc)?, + ident, + ), + VarType::Concrete(cn) => { + let builtin = cn.underlying(self).into_expr_err(loc)?.as_builtin(); + let bn = self.builtin_or_add(builtin).into(); + self.builtin_member_access( + loc, + ctx, + bn, + ContextVarNode::from(member_idx) + .is_storage(self) + .into_expr_err(loc)?, + ident, + ) + } + e => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled member access: {:?}, {:?}", e, ident), + )), + } + } + + fn struct_member_access( + &mut self, + member_idx: NodeIdx, + struct_node: StructNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + maybe_parent: Option, + ) -> Result { + let name = format!( + "{}.{}", + struct_node.name(self).into_expr_err(loc)?, + ident.name + ); + tracing::trace!("Struct member access: {}", name); + if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + Ok(ExprRet::Single(attr_var.latest_version(self).into())) + } else if let Some(field) = struct_node.find_field(self, ident) { + let cvar = if let Some(parent) = maybe_parent { + parent + } else { + ContextVar::maybe_from_user_ty(self, loc, struct_node.into()).unwrap() + }; + if let Some(field_cvar) = ContextVar::maybe_new_from_field( + self, + loc, + &cvar, + field.underlying(self).unwrap().clone(), + ) { + let fc_node = self.add_node(Node::ContextVar(field_cvar)); + self.add_edge( + fc_node, + ContextVarNode::from(member_idx).first_version(self), + Edge::Context(ContextEdge::AttrAccess), + ); + ctx.add_var(fc_node.into(), self).into_expr_err(loc)?; + self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(fc_node)) + } else { + panic!("Couldn't create field variable"); + } + } else if let Some(func) = self.library_func_search(ctx, struct_node.0.into(), ident) { + Ok(func) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on struct \"{}\"", + ident.name, + struct_node.name(self).into_expr_err(loc)? + ), + )) + } + } + + fn enum_member_access( + &mut self, + _member_idx: NodeIdx, + enum_node: EnumNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + ) -> Result { + tracing::trace!("Enum member access: {}", ident.name); + + if let Some(variant) = enum_node + .variants(self) + .into_expr_err(loc)? + .iter() + .find(|variant| **variant == ident.name) + { + let var = + ContextVar::new_from_enum_variant(self, ctx, loc, enum_node, variant.to_string()) + .into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } else if let Some(ret) = self.library_func_search(ctx, enum_node.0.into(), ident) { + Ok(ret) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on enum \"{}\"", + ident.name, + enum_node.name(self).into_expr_err(loc)? + ), + )) + } + } + + fn contract_member_access( + &mut self, + member_idx: NodeIdx, + con_node: ContractNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + maybe_parent: Option, + ) -> Result { + tracing::trace!( + "Contract member access: {}.{}", + con_node + .maybe_name(self) + .into_expr_err(loc)? + .unwrap_or_else(|| "interface".to_string()), + ident.name + ); + + if let Some(func) = con_node + .funcs(self) + .into_iter() + .find(|func_node| func_node.name(self).unwrap() == ident.name) + { + if let Some(func_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { + let fn_node = self.add_node(Node::ContextVar(func_cvar)); + // this prevents attaching a dummy node to the parent which could cause a cycle in the graph + if maybe_parent.is_some() { + self.add_edge(fn_node, member_idx, Edge::Context(ContextEdge::FuncAccess)); + } + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unable to construct the function \"{}\" in contract \"{}\"", + ident.name, + con_node.name(self).into_expr_err(loc)? + ), + )) + } + } else if let Some(func) = con_node + .structs(self) + .into_iter() + .find(|struct_node| struct_node.name(self).unwrap() == ident.name) + { + if let Some(struct_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { + let struct_node = self.add_node(Node::ContextVar(struct_cvar)); + // this prevents attaching a dummy node to the parent which could cause a cycle in the graph + if maybe_parent.is_some() { + self.add_edge( + struct_node, + member_idx, + Edge::Context(ContextEdge::StructAccess), + ); + } + return Ok(ExprRet::Single(struct_node)); + } else { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unable to construct the struct \"{}\" in contract \"{}\"", + ident.name, + con_node.name(self).into_expr_err(loc)? + ), + )); + } + } else { + match &*ident.name { + "name" => { + let c = Concrete::from(con_node.name(self).unwrap()); + let cnode = self.add_node(Node::Concrete(c)); + let cvar = ContextVar::new_from_concrete(loc, ctx, cnode.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + "creationCode" | "runtimeCode" => { + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = + ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + "interfaceId" => { + // TODO: actually calculate this + let bn = self.builtin_or_add(Builtin::Bytes(4)); + let cvar = + ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + _ => { + return Err(ExprErr::ContractFunctionNotFound( + loc, + format!( + "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", + ident.name, + con_node.name(self).unwrap(), + con_node + .funcs(self) + .iter() + .map(|func| func.name(self).unwrap()) + .collect::>() + ), + )) + } + } + } + } + + fn ty_member_access( + &mut self, + _member_idx: NodeIdx, + ty_node: TyNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + _maybe_parent: Option, + ) -> Result { + let name = ident.name.split('(').collect::>()[0]; + if let Some(func) = self.library_func_search(ctx, ty_node.0.into(), ident) { + Ok(func) + } else if let Some(func) = self.builtin_fn_or_maybe_add(name) { + Ok(ExprRet::Single(func)) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on struct \"{}\"", + ident.name, + ty_node.name(self).into_expr_err(loc)? + ), + )) + } + } + + fn member_access_inner( + &mut self, + loc: Loc, + member_idx: NodeIdx, + ident: &Identifier, + ctx: ContextNode, + ) -> Result { + match self.node(member_idx) { + Node::ContextVar(cvar) => { + self.member_access_var_ty(cvar.clone(), loc, member_idx, ident, ctx) + } + Node::Contract(_c) => self.contract_member_access( + member_idx, + ContractNode::from(member_idx), + ident, + ctx, + loc, + None, + ), + Node::Struct(_c) => self.struct_member_access( + member_idx, + StructNode::from(member_idx), + ident, + ctx, + loc, + None, + ), + Node::Enum(_c) => { + self.enum_member_access(member_idx, EnumNode::from(member_idx), ident, ctx, loc) + } + Node::Ty(_ty) => { + self.ty_member_access(member_idx, TyNode::from(member_idx), ident, ctx, loc, None) + } + Node::Msg(_msg) => self.msg_access(loc, ctx, &ident.name), + Node::Block(_b) => self.block_access(loc, ctx, &ident.name), + Node::Builtin(ref _b) => { + self.builtin_member_access(loc, ctx, BuiltInNode::from(member_idx), false, ident) + } + e => Err(ExprErr::Todo( + loc, + format!("Member access on type: {e:?} is not yet supported"), + )), + } + } + + fn builtin_member_access( + &mut self, + loc: Loc, + ctx: ContextNode, + node: BuiltInNode, + is_storage: bool, + ident: &Identifier, + ) -> Result { + tracing::trace!("Looking for builtin member function"); + if let Some(ret) = self.library_func_search(ctx, node.0.into(), ident) { + Ok(ret) + } else { + match node.underlying(self).into_expr_err(loc)?.clone() { + Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { + match &*ident.name { + "delegatecall" + | "call" + | "staticcall" + | "delegatecall(address, bytes)" + | "call(address, bytes)" + | "staticcall(address, bytes)" => { + // TODO: check if the address is known to be a certain type and the function signature is known + // and call into the function + let builtin_name = ident.name.split('(').collect::>()[0]; + let func_node = self.builtin_fn_or_maybe_add(builtin_name).unwrap(); + Ok(ExprRet::Single(func_node)) + } + "code" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + "codehash" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Bytes(32)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + "balance" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Uint(256)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + _ if ident.name.starts_with("send") => { + let bn = self.builtin_or_add(Builtin::Bool); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + _ if ident.name.starts_with("transfer") => Ok(ExprRet::Multi(vec![])), + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on address: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + } + } + Builtin::Bool => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on bool: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::String => match ident.name.split('(').collect::>()[0] { + "concat" => { + let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); + Ok(ExprRet::Single(fn_node)) + } + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on string: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + }, + Builtin::Bytes(size) => Err(ExprErr::MemberAccessNotFound( + loc, + format!("Unknown member access on bytes{}: {:?}", size, ident.name), + )), + Builtin::Rational => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on rational: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::DynamicBytes => match ident.name.split('(').collect::>()[0] { + "concat" => { + let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); + Ok(ExprRet::Single(fn_node)) + } + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on bytes: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + }, + Builtin::Array(_) => { + if ident.name.starts_with("push") { + if is_storage { + let fn_node = self.builtin_fn_or_maybe_add("push").unwrap(); + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::NonStoragePush( + loc, + "Trying to push to nonstorage array is not supported".to_string(), + )) + } + } else if ident.name.starts_with("pop") { + if is_storage { + let fn_node = self.builtin_fn_or_maybe_add("pop").unwrap(); + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::NonStoragePush( + loc, + "Trying to pop from nonstorage array is not supported".to_string(), + )) + } + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on array[]: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )) + } + } + Builtin::SizedArray(s, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on array[{s}]: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Mapping(_, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on mapping: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Func(_, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on func: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Int(size) => { + let max = if size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1) + }; + match &*ident.name { + "max" => { + let c = Concrete::Int(size, max); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.max"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + "min" => { + let min = max * I256::from(-1i32) - I256::from(1i32); + let c = Concrete::Int(size, min); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.min"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + e => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown type attribute on int{size}: {e:?}, ctx: {}", + ctx.path(self) + ), + )), + } + } + Builtin::Uint(size) => match &*ident.name { + "max" => { + let size = size; + let max = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(size)) - 1 + }; + let c = Concrete::Uint(size, max); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("uint{size}.max"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + "min" => { + let min = U256::zero(); + let c = Concrete::from(min); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.min"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + e => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown type attribute on uint{size}: {e:?}, ctx: {}", + ctx.path(self) + ), + )), + }, + } + } + } + + fn library_func_search( + &mut self, + ctx: ContextNode, + ty: NodeIdx, + ident: &Identifier, + ) -> Option { + self.possible_library_funcs(ctx, ty) + .iter() + .filter_map(|func| { + if let Ok(name) = func.name(self) { + Some((name, func)) + } else { + None + } + }) + .find_map(|(name, func)| { + if name == ident.name { + Some(ExprRet::Single((*func).into())) + } else { + None + } + }) + } + + fn possible_library_funcs(&mut self, ctx: ContextNode, ty: NodeIdx) -> BTreeSet { + let mut funcs: BTreeSet = BTreeSet::new(); + if let Some(associated_contract) = ctx.maybe_associated_contract(self).unwrap() { + // search for contract scoped `using` statements + funcs.extend( + self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { + matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == associated_contract.into()) + }).map(|edge| edge.target().into()).collect::>() + ); + } + + // Search for global `using` funcs + if let Some(source) = ctx.maybe_associated_source(self) { + funcs.extend( + self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { + matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source) + }).map(|edge| edge.target().into()).collect::>() + ); + } + + funcs + } + + #[tracing::instrument(level = "trace", skip_all)] + fn index_access( + &mut self, + loc: Loc, + parent: NodeIdx, + dyn_builtin: BuiltInNode, + ident: &Identifier, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.variable(ident, ctx, None)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())) + }; + + if matches!(index_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(index_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_index_access(&index_paths, loc, parent.into(), dyn_builtin, ctx) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn match_index_access( + &mut self, + index_paths: &ExprRet, + loc: Loc, + parent: ContextVarNode, + dyn_builtin: BuiltInNode, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match index_paths { + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc), + ExprRet::Single(idx) => { + let parent = parent.first_version(self); + let parent_name = parent.name(self).into_expr_err(loc)?; + let parent_display_name = parent.display_name(self).unwrap(); + + tracing::trace!( + "Index access: {}[{}]", + parent_display_name, + ContextVarNode::from(*idx) + .display_name(self) + .into_expr_err(loc)? + ); + let parent_ty = dyn_builtin; + let parent_stor = parent + .storage(self) + .into_expr_err(loc)? + .as_ref() + .expect("parent didnt have a storage location?"); + let indexed_var = ContextVar::new_from_index( + self, + loc, + parent_name, + parent_display_name, + parent_stor.clone(), + &parent_ty, + ContextVarNode::from(*idx), + ) + .into_expr_err(loc)?; + + let idx_node = self.add_node(Node::ContextVar(indexed_var)); + self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); + self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; + self.add_edge(*idx, idx_node, Edge::Context(ContextEdge::Index)); + ctx.push_expr(ExprRet::Single(idx_node), self) + .into_expr_err(loc)?; + Ok(()) + } + e => Err(ExprErr::UnhandledExprRet( + loc, + format!("Unhandled expression return in index access: {e:?}"), + )), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn length( + &mut self, + loc: Loc, + input_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(input_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_length(ctx, loc, ret, true) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn tmp_length( + &mut self, + arr: ContextVarNode, + array_ctx: ContextNode, + loc: Loc, + ) -> ContextVarNode { + let arr = arr.first_version(self); + let name = format!("{}.length", arr.name(self).unwrap()); + tracing::trace!("Length access: {}", name); + if let Some(attr_var) = array_ctx.var_by_name_or_recurse(self, &name).unwrap() { + attr_var.latest_version(self) + } else { + let range = if let Ok(Some(size)) = arr.ty(self).unwrap().maybe_array_size(self) { + SolcRange::from(Concrete::from(size)) + } else { + SolcRange::try_from_builtin(&Builtin::Uint(256)) + }; + + let len_var = ContextVar { + loc: Some(loc), + name: arr.name(self).unwrap() + ".length", + display_name: arr.display_name(self).unwrap() + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + range, + ), + }; + let len_node = self.add_node(Node::ContextVar(len_var)); + + let next_arr = self + .advance_var_in_ctx(arr.latest_version(self), loc, array_ctx) + .unwrap(); + if next_arr + .underlying(self) + .unwrap() + .ty + .is_dyn_builtin(self) + .unwrap() + { + if let Some(r) = next_arr.ref_range(self).unwrap() { + let min = r.evaled_range_min(self).unwrap(); + let max = r.evaled_range_max(self).unwrap(); + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + + self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); + array_ctx.add_var(len_node.into(), self).unwrap(); + len_node.into() + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn match_length( + &mut self, + ctx: ContextNode, + loc: Loc, + elem_path: ExprRet, + update_len_bound: bool, + ) -> Result<(), ExprErr> { + match elem_path { + ExprRet::Null => { + ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; + Ok(()) + } + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Single(arr) => { + let next_arr = self.advance_var_in_ctx( + ContextVarNode::from(arr).latest_version(self), + loc, + ctx, + )?; + let arr = ContextVarNode::from(arr).first_version(self); + let name = format!("{}.length", arr.name(self).into_expr_err(loc)?); + tracing::trace!("Length access: {}", name); + if let Some(len_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + let len_var = len_var.latest_version(self); + let new_len = self.advance_var_in_ctx(len_var, loc, ctx)?; + if update_len_bound + && next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(new_len); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(new_len); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + ctx.push_expr(ExprRet::Single(new_len.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let range = if let Ok(Some(size)) = + arr.ty(self).into_expr_err(loc)?.maybe_array_size(self) + { + SolcRange::from(Concrete::from(size)) + } else { + SolcRange::try_from_builtin(&Builtin::Uint(256)) + }; + + let len_var = ContextVar { + loc: Some(loc), + name, + display_name: arr.display_name(self).into_expr_err(loc)? + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + range, + ), + }; + let len_node = self.add_node(Node::ContextVar(len_var)); + + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + + self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_node.into(), self).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(len_node), self) + .into_expr_err(loc)?; + Ok(()) + } + } + e => todo!("here: {e:?}"), + } + } +} diff --git a/crates/solc_expressions/require.rs b/crates/solc_expressions/require.rs new file mode 100644 index 00000000..0852ad30 --- /dev/null +++ b/crates/solc_expressions/require.rs @@ -0,0 +1,1503 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::{ + exprs::{BinOp, Variable}, + AnalyzerLike, Concrete, ConcreteNode, ContextBuilder, Node, +}; +use shared::range::elem_ty::RangeExpr; +use shared::range::range_string::ToRangeString; + +use shared::{ + context::*, + nodes::{BuiltInNode, Builtin, VarType}, + range::{ + elem::{RangeElem, RangeOp}, + elem_ty::{Elem, RangeConcrete}, + Range, RangeEval, SolcRange, + }, + Edge, +}; +use solang_parser::helpers::CodeLocation; + +use ethers_core::types::I256; +use solang_parser::pt::{Expression, Loc}; +use std::cmp::Ordering; + +impl Require for T where T: Variable + BinOp + Sized + AnalyzerLike {} +pub trait Require: AnalyzerLike + Variable + BinOp + Sized { + /// Inverts a comparator expression + fn inverse_expr(&self, expr: Expression) -> Expression { + match expr { + Expression::Equal(loc, lhs, rhs) => Expression::NotEqual(loc, lhs, rhs), + Expression::NotEqual(loc, lhs, rhs) => Expression::Equal(loc, lhs, rhs), + Expression::Less(loc, lhs, rhs) => Expression::MoreEqual(loc, lhs, rhs), + Expression::More(loc, lhs, rhs) => Expression::LessEqual(loc, lhs, rhs), + Expression::MoreEqual(loc, lhs, rhs) => Expression::Less(loc, lhs, rhs), + Expression::LessEqual(loc, lhs, rhs) => Expression::More(loc, lhs, rhs), + // Expression::And(loc, lhs, rhs) => { + // Expression::Or(loc, Box::new(self.inverse_expr(*lhs)), Box::new(self.inverse_expr(*rhs))) + // } + // Expression::Not(loc, lhs) => { + // Expression::Equal(loc, lhs, Box::new(Expression::BoolLiteral(loc, true))) + // } + e => Expression::Not(e.loc(), Box::new(e)), + } + } + + /// Handles a require expression + #[tracing::instrument(level = "trace", skip_all)] + fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { + match inputs.get(0).expect("No lhs input for require statement") { + Expression::Equal(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `==` had no right hand side".to_string())) + }; + + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `==` had no left hand side".to_string())) + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + ) + }) + }) + } + Expression::NotEqual(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `!=` had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `!=` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Neq, + RangeOp::Eq, + (RangeOp::Eq, RangeOp::Neq), + ) + }) + }) + } + Expression::Less(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `<` had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `<` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Lt, + RangeOp::Gt, + (RangeOp::Gt, RangeOp::Lt), + ) + }) + }) + } + Expression::More(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `>` had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `>` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Gt, + RangeOp::Lt, + (RangeOp::Lt, RangeOp::Gt), + ) + }) + }) + } + Expression::MoreEqual(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `>=` had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `>=` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + ) + }) + }) + } + Expression::LessEqual(loc, lhs, rhs) => { + self.parse_ctx_expr(rhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Require operation `<=` had no right hand side".to_string())) + }; + let rhs_paths = rhs_paths.flatten(); + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `<=` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths.flatten(), + &rhs_paths, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + ) + }) + }) + } + Expression::Not(loc, lhs) => { + self.parse_ctx_expr(lhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `NOT` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let cnode = + ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(false)))); + let tmp_false = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) + .into_expr_err(loc)?, + ); + let rhs_paths = + ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_false)).into()); + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths, + &rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + ) + }) + } + Expression::And(loc, lhs, rhs) => { + self.parse_ctx_expr(lhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(rhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) + .into_expr_err(loc)?, + ); + let node = analyzer.add_node(tmp_true); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + let tmp_rhs_paths = ExprRet::Single(node); + + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths, + &tmp_rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + )?; + + analyzer.handle_require_inner( + ctx, + loc, + &rhs_paths, + &tmp_rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + )?; + + + // update the part's bounds + let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + let underlying = lhs_cvar.underlying(analyzer).into_expr_err(loc)?; + if let Some(tmp) = underlying.tmp_of { + if let Some((op, inv_op, pair)) = tmp.op.require_parts() { + analyzer.handle_require_inner( + ctx, + loc, + &ExprRet::Single(tmp.lhs.into()), + &ExprRet::Single(tmp.rhs.unwrap().into()), + op, + inv_op, + pair, + )?; + } + } + + // update the part's bounds + let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); + let underlying = rhs_cvar.underlying(analyzer).into_expr_err(loc)?; + if let Some(tmp) = underlying.tmp_of { + if let Some((op, inv_op, pair)) = tmp.op.require_parts() { + analyzer.handle_require_inner( + ctx, + loc, + &ExprRet::Single(tmp.lhs.into()), + &ExprRet::Single(tmp.rhs.unwrap().into()), + op, + inv_op, + pair, + )?; + } + } + Ok(()) + }) + }) + } + Expression::Or(loc, lhs, rhs) => { + self.parse_ctx_expr(lhs, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(rhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); + + let elem = Elem::Expr(RangeExpr::new(lhs_cvar.into(), RangeOp::Or, rhs_cvar.into())); + let range = SolcRange::new(elem.clone(), elem, vec![]); + + let new_lhs_underlying = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} {} {})", + ctx.new_tmp(analyzer).into_expr_err(loc)?, + lhs_cvar.name(analyzer).into_expr_err(loc)?, + RangeOp::Or.to_string(), + rhs_cvar.name(analyzer).into_expr_err(loc)? + ), + display_name: format!( + "({} {} {})", + lhs_cvar.display_name(analyzer).into_expr_err(loc)?, + RangeOp::Or.to_string(), + rhs_cvar.display_name(analyzer).into_expr_err(loc)? + ), + storage: None, + is_tmp: true, + is_symbolic: lhs_cvar.is_symbolic(analyzer).into_expr_err(loc)? + || rhs_cvar.is_symbolic(analyzer).into_expr_err(loc)?, + is_return: false, + tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Or, Some(rhs_cvar))), + ty: VarType::BuiltIn(analyzer.builtin_or_add(Builtin::Bool).into(), Some(range)) + }; + let or_var = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_lhs_underlying))); + let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) + .into_expr_err(loc)?, + ); + let node = analyzer.add_node(tmp_true); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + let rhs_paths = ExprRet::Single(node); + analyzer.handle_require_inner( + ctx, + loc, + &ExprRet::Single(or_var.into()), + &rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + ) + }) + }) + } + other => { + self.parse_ctx_expr(other, ctx)?; + self.apply_to_edges(ctx, other.loc(), &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Require operation had no left hand side".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) + .into_expr_err(other.loc())?, + ); + let rhs_paths = + ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths, + &rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + ) + }) + } + } + } + + fn handle_require_inner( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: &ExprRet, + op: RangeOp, + rhs_op: RangeOp, + recursion_ops: (RangeOp, RangeOp), + ) -> Result<(), ExprErr> { + match (lhs_paths, rhs_paths) { + (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), + (_, ExprRet::CtxKilled(..)) | (ExprRet::CtxKilled(..), _) => Ok(()), + (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { + ContextVarNode::from(*lhs) + .cast_from(&ContextVarNode::from(*rhs), self) + .into_expr_err(loc)?; + self.handle_require_inner( + ctx, + loc, + &ExprRet::Single(*lhs), + rhs_paths, + op, + rhs_op, + recursion_ops, + ) + } + (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { + ContextVarNode::from(*rhs) + .cast_from(&ContextVarNode::from(*lhs), self) + .into_expr_err(loc)?; + self.handle_require_inner( + ctx, + loc, + lhs_paths, + &ExprRet::Single(*rhs), + op, + rhs_op, + recursion_ops, + ) + } + (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let new_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + let new_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; + + self.require(new_lhs, new_rhs, ctx, loc, op, rhs_op, recursion_ops)?; + Ok(()) + } + (l @ ExprRet::Single(_) | l @ ExprRet::SingleLiteral(_), ExprRet::Multi(rhs_sides)) => { + rhs_sides.iter().try_for_each(|expr_ret| { + self.handle_require_inner(ctx, loc, l, expr_ret, op, rhs_op, recursion_ops) + }) + } + (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { + lhs_sides.iter().try_for_each(|expr_ret| { + self.handle_require_inner(ctx, loc, expr_ret, r, op, rhs_op, recursion_ops) + }) + } + (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( + |(lhs_expr_ret, rhs_expr_ret)| { + self.handle_require_inner( + ctx, + loc, + lhs_expr_ret, + rhs_expr_ret, + op, + rhs_op, + recursion_ops, + ) + }, + ) + } else { + rhs_sides.iter().try_for_each(|rhs_expr_ret| { + self.handle_require_inner( + ctx, + loc, + lhs_paths, + rhs_expr_ret, + op, + rhs_op, + recursion_ops, + ) + }) + } + } + (e, f) => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled combination in require: {:?} {:?}", e, f), + )), + } + } + + /// Updates the range bounds for the variables passed into the require function. If the lefthand side is a temporary value, + /// it will recursively update the range bounds for the underlying variable + #[allow(clippy::too_many_arguments)] + #[tracing::instrument(level = "trace", skip_all)] + fn require( + &mut self, + mut new_lhs: ContextVarNode, + mut new_rhs: ContextVarNode, + ctx: ContextNode, + loc: Loc, + op: RangeOp, + rhs_op: RangeOp, + recursion_ops: (RangeOp, RangeOp), + ) -> Result, ExprErr> { + tracing::trace!( + "require: {} {} {}", + new_lhs.display_name(self).into_expr_err(loc)?, + op.to_string(), + new_rhs.display_name(self).into_expr_err(loc)? + ); + let mut any_unsat = false; + let mut tmp_cvar = None; + + if let Some(lhs_range) = new_lhs + .underlying(self) + .into_expr_err(loc)? + .ty + .range(self) + .into_expr_err(loc)? + { + let lhs_range_fn = SolcRange::dyn_fn_from_op(op); + // lhs_range.update_deps(new_lhs, ctx, self); + let mut new_var_range = lhs_range_fn(lhs_range.clone(), new_rhs); + + if let Some(rhs_range) = new_rhs.range(self).into_expr_err(loc)? { + let lhs_is_const = new_lhs.is_const(self).into_expr_err(loc)?; + // println!("is const: {lhs_is_const},[{}, {}]", new_lhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_lhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); + let rhs_is_const = new_rhs.is_const(self).into_expr_err(loc)?; + // println!("is const: {rhs_is_const}, [{}, {}]", new_rhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_rhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); + match (lhs_is_const, rhs_is_const) { + (true, true) => { + if self.const_killable(op, lhs_range, rhs_range) { + tracing::trace!("const killable"); + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(None); + } + } + (true, false) => { + // flip the new range around to be in terms of rhs + let rhs_range_fn = SolcRange::dyn_fn_from_op(rhs_op); + new_var_range = rhs_range_fn(rhs_range.clone(), new_lhs); + if self + .update_nonconst_from_const(loc, rhs_op, new_lhs, new_rhs, rhs_range)? + { + tracing::trace!("half-const killable"); + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(None); + } + } + (false, true) => { + if self.update_nonconst_from_const(loc, op, new_rhs, new_lhs, lhs_range)? { + tracing::trace!("half-const killable"); + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(None); + } + } + (false, false) => { + if self.update_nonconst_from_nonconst( + loc, op, new_lhs, new_rhs, lhs_range, rhs_range, + )? { + tracing::trace!("nonconst killable"); + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(None); + } + } + } + } else { + return Err(ExprErr::BadRange( + loc, + format!( + "Require: right hand side didnt have a range, likely invalid solidity - {:?}", + new_rhs.underlying(self).into_expr_err(loc)? + ) + )); + } + + if let Some(backing_arr) = new_lhs.len_var_to_array(self).into_expr_err(loc)? { + if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { + let min = r.range_min().into_owned(); + let max = r.range_max().into_owned(); + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(new_lhs); + backing_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(new_lhs); + backing_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + } else if let Some(arr) = new_lhs.index_to_array(self) { + if let Some(index) = new_lhs.index_access_to_index(self) { + let next_arr = self.advance_var_in_ctx(arr.latest_version(self), loc, ctx)?; + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(new_rhs)); + next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(new_rhs)); + next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + } + } + } + + if let Some(backing_arr) = new_rhs.len_var_to_array(self).into_expr_err(loc)? { + if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { + let min = r.range_min().into_owned(); + let max = r.range_max().into_owned(); + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(new_lhs); + backing_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(new_lhs); + backing_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + } + + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} {} {})", + ctx.new_tmp(self).into_expr_err(loc)?, + new_lhs.name(self).into_expr_err(loc)?, + op.to_string(), + new_rhs.name(self).into_expr_err(loc)?, + ), + display_name: format!( + "({} {} {})", + new_lhs.display_name(self).into_expr_err(loc)?, + op.to_string(), + new_rhs.display_name(self).into_expr_err(loc)?, + ), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new(new_lhs, op, Some(new_rhs))), + is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? + || new_rhs.is_symbolic(self).into_expr_err(loc)?, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + SolcRange::from(Concrete::Bool(true)), + ), + }; + + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + ctx.add_var(cvar, self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + tmp_cvar = Some(cvar); + + any_unsat |= new_var_range.unsat(self); + if any_unsat { + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(None); + } + + ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + } + + new_lhs.update_deps(ctx, self).into_expr_err(loc)?; + new_rhs.update_deps(ctx, self).into_expr_err(loc)?; + tracing::trace!( + "{} is tmp: {}", + new_lhs.display_name(self).unwrap(), + new_lhs.is_tmp(self).unwrap() + ); + if let Some(tmp) = new_lhs.tmp_of(self).into_expr_err(loc)? { + if tmp.op.inverse().is_some() && !matches!(op, RangeOp::Eq | RangeOp::Neq) { + self.range_recursion(tmp, recursion_ops, new_rhs, ctx, loc, &mut any_unsat)?; + } else { + match tmp.op { + RangeOp::Not => {} + _ => { + self.uninvertable_range_recursion(tmp, new_lhs, new_rhs, loc, ctx); + } + } + } + } + + Ok(tmp_cvar) + } + + /// Checks and returns whether the require statement is killable (i.e. impossible) + fn const_killable(&mut self, op: RangeOp, lhs_range: SolcRange, rhs_range: SolcRange) -> bool { + // check that the op is satisfied, return it as a bool + match op { + RangeOp::Eq => !lhs_range + .evaled_range_min(self) + .unwrap() + .range_eq(&rhs_range.evaled_range_min(self).unwrap()), + RangeOp::Neq => lhs_range + .evaled_range_min(self) + .unwrap() + .range_eq(&rhs_range.evaled_range_min(self).unwrap()), + RangeOp::Gt => { + matches!( + lhs_range + .evaled_range_min(self) + .unwrap() + .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + Some(Ordering::Equal) | Some(Ordering::Less) + ) + } + RangeOp::Gte => { + matches!( + lhs_range + .evaled_range_min(self) + .unwrap() + .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + Some(Ordering::Less) + ) + } + RangeOp::Lt => { + matches!( + lhs_range + .evaled_range_min(self) + .unwrap() + .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + Some(Ordering::Equal) | Some(Ordering::Greater) + ) + } + RangeOp::Lte => { + matches!( + lhs_range + .evaled_range_min(self) + .unwrap() + .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + Some(Ordering::Greater) + ) + } + e => todo!("Non-comparator in require, {e:?}"), + } + } + + /// Given a const var and a nonconst range, update the range based on the op + #[tracing::instrument(level = "trace", skip_all)] + fn update_nonconst_from_const( + &mut self, + loc: Loc, + op: RangeOp, + const_var: ContextVarNode, + nonconst_var: ContextVarNode, + mut nonconst_range: SolcRange, + ) -> Result { + tracing::trace!("Setting range for nonconst from const"); + match op { + RangeOp::Eq => { + // check that the constant is contained in the nonconst var range + let elem = Elem::from(const_var.latest_version(self)); + let evaled_min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + if evaled_min.maybe_concrete().is_none() { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", evaled_min.to_range_string(false, self).s))); + } + + if !nonconst_range.contains_elem(&elem, self) { + return Ok(true); + } + // if its contained, we can set the min & max to it + nonconst_var + .set_range_min(self, elem.clone()) + .into_expr_err(loc)?; + nonconst_var.set_range_max(self, elem).into_expr_err(loc)?; + Ok(false) + } + RangeOp::Neq => { + // check if contains + let elem = Elem::from(const_var.latest_version(self)); + + // potentially add the const var as a range exclusion + if let Some(Ordering::Equal) = nonconst_range + .evaled_range_min(self) + .into_expr_err(loc)? + .range_ord(&elem) + { + // mins are equivalent, add 1 instead of adding an exclusion + let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + let Some(min) = min + .maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); + }; + let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); + let min = nonconst_range.range_min().into_owned() + Elem::from(one); + nonconst_var.set_range_min(self, min).into_expr_err(loc)?; + } else if let Some(std::cmp::Ordering::Equal) = nonconst_range + .evaled_range_max(self) + .into_expr_err(loc)? + .range_ord(&elem) + { + // maxs are equivalent, subtract 1 instead of adding an exclusion + let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; + + let Some(max) = max.maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + }; + let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); + let max = nonconst_range.range_max().into_owned() - Elem::from(one); + nonconst_var.set_range_max(self, max).into_expr_err(loc)?; + } else { + // just add as an exclusion + nonconst_range.add_range_exclusion(elem); + nonconst_var + .set_range_exclusions(self, nonconst_range.exclusions) + .into_expr_err(loc)?; + } + + Ok(false) + } + RangeOp::Gt => { + let elem = Elem::from(const_var.latest_version(self)); + + // if nonconst max is <= const, we can't make this true + let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; + if matches!( + max.range_ord(&elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Less) | Some(Ordering::Equal) + ) { + return Ok(true); + } + + // we add one to the element because its strict > + let Some(max_conc) = max.maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + }; + let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); + nonconst_var + .set_range_min( + self, + (elem + one.into()).max(nonconst_range.range_min().into_owned()), + ) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Gte => { + let elem = Elem::from(const_var.latest_version(self)); + + // if nonconst max is < const, we can't make this true + if matches!( + nonconst_range + .evaled_range_max(self) + .into_expr_err(loc)? + .range_ord(&elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Less) + ) { + return Ok(true); + } + + nonconst_var + .set_range_min(self, elem.max(nonconst_range.range_min().into_owned())) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Lt => { + let elem = Elem::from(const_var.latest_version(self)); + + // if nonconst min is >= const, we can't make this true + let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + if matches!( + min.range_ord(&elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Greater) | Some(Ordering::Equal) + ) { + return Ok(true); + } + + // we add one to the element because its strict > + + let Some(min_conc) = min.maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(true, self).s))); + }; + let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); + + nonconst_var + .set_range_max( + self, + (elem - one.into()).min(nonconst_range.range_max().into_owned()), + ) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Lte => { + let elem = Elem::from(const_var.latest_version(self)); + + // if nonconst min is > const, we can't make this true + let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + if matches!( + min.range_ord(&elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Greater) + ) { + return Ok(true); + } + + nonconst_var + .set_range_max(self, elem.min(nonconst_range.range_max().into_owned())) + .into_expr_err(loc)?; + Ok(false) + } + e => todo!("Non-comparator in require, {e:?}"), + } + } + + /// Given a const var and a nonconst range, update the range based on the op. Returns whether its impossible + fn update_nonconst_from_nonconst( + &mut self, + loc: Loc, + op: RangeOp, + new_lhs: ContextVarNode, + new_rhs: ContextVarNode, + mut lhs_range: SolcRange, + mut rhs_range: SolcRange, + ) -> Result { + tracing::trace!("Setting range for nonconst from nonconst"); + match op { + RangeOp::Eq => { + // check that there is overlap in the ranges + if !lhs_range.overlaps(&rhs_range, self) { + return Ok(true); + } + + // take the tighest range + match lhs_range + .evaled_range_min(self) + .into_expr_err(loc)? + .range_ord(&rhs_range.evaled_range_min(self).into_expr_err(loc)?) + { + Some(Ordering::Greater) => { + // take lhs range min as its tigher + new_rhs + .set_range_min(self, Elem::from(new_rhs)) + .into_expr_err(loc)?; + } + Some(Ordering::Less) => { + // take rhs range min as its tigher + new_lhs + .set_range_min(self, rhs_range.range_min().into_owned()) + .into_expr_err(loc)?; + } + _ => { + // equal or not comparable - both keep their minimums + } + } + + // take the tighest range + match lhs_range + .evaled_range_max(self) + .into_expr_err(loc)? + .range_ord(&rhs_range.evaled_range_max(self).into_expr_err(loc)?) + { + Some(Ordering::Less) => { + // take lhs range min as its tigher + new_rhs + .set_range_max(self, lhs_range.range_max().into_owned()) + .into_expr_err(loc)?; + } + Some(Ordering::Greater) => { + // take rhs range min as its tigher + new_lhs + .set_range_max(self, rhs_range.range_max().into_owned()) + .into_expr_err(loc)?; + } + _ => { + // equal or not comparable - both keep their maximums + } + } + + Ok(false) + } + RangeOp::Neq => { + let rhs_elem = Elem::from(new_rhs.latest_version(self)); + // just add as an exclusion + lhs_range.add_range_exclusion(rhs_elem); + new_lhs + .set_range_exclusions(self, lhs_range.exclusions) + .into_expr_err(loc)?; + + let lhs_elem = Elem::from(new_lhs.latest_version(self)); + // just add as an exclusion + rhs_range.add_range_exclusion(lhs_elem); + new_rhs + .set_range_exclusions(self, rhs_range.exclusions) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Gt => { + let rhs_elem = Elem::from(new_rhs.latest_version(self)); + let lhs_elem = Elem::from(new_lhs.latest_version(self)); + + // if lhs.max is <= rhs.min, we can't make this true + let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; + if matches!( + max.range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Less) | Some(Ordering::Equal) + ) { + return Ok(true); + } + + let Some(max_conc) = max.maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + }; + + let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); + + // we add/sub one to the element because its strict > + new_lhs + .set_range_min( + self, + (rhs_elem + one.clone().into()).max(lhs_range.range_min().into_owned()), + ) + .into_expr_err(loc)?; + new_rhs + .set_range_max( + self, + (lhs_elem - one.into()).min(rhs_range.range_max().into_owned()), + ) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Gte => { + let rhs_elem = Elem::from(new_rhs.latest_version(self)); + let lhs_elem = Elem::from(new_lhs.latest_version(self)); + + // if lhs.max is < rhs.min, we can't make this true + if matches!( + lhs_range + .evaled_range_max(self) + .into_expr_err(loc)? + .range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), + Some(Ordering::Less) + ) { + return Ok(true); + } + + new_lhs + .set_range_min(self, rhs_elem.max(lhs_range.range_min().into_owned())) + .into_expr_err(loc)?; + new_rhs + .set_range_max(self, lhs_elem.min(rhs_range.range_max().into_owned())) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Lt => { + let rhs_elem = Elem::from(new_rhs.latest_version(self)); + let lhs_elem = Elem::from(new_lhs.latest_version(self)); + + // if lhs min is >= rhs.max, we can't make this true + let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + if matches!( + min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), + Some(Ordering::Greater) | Some(Ordering::Equal) + ) { + return Ok(true); + } + + // we add/sub one to the element because its strict > + let Some(min_conc) = min.maybe_concrete() else { + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); + }; + + let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); + + new_lhs + .set_range_max( + self, + (rhs_elem - one.clone().into()).min(lhs_range.range_max().into_owned()), + ) + .into_expr_err(loc)?; + new_rhs + .set_range_min( + self, + (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), + ) + .into_expr_err(loc)?; + Ok(false) + } + RangeOp::Lte => { + let rhs_elem = Elem::from(new_rhs.latest_version(self)); + let lhs_elem = Elem::from(new_lhs.latest_version(self)); + + // if nonconst min is > const, we can't make this true + let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + if matches!( + min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), + Some(Ordering::Greater) + ) { + return Ok(true); + } + + new_lhs + .set_range_max(self, rhs_elem.min(lhs_range.range_max().into_owned())) + .into_expr_err(loc)?; + new_rhs + .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) + .into_expr_err(loc)?; + Ok(false) + } + e => todo!("Non-comparator in require, {e:?}"), + } + } + + fn uninvertable_range_recursion( + &mut self, + tmp_construction: TmpConstruction, + _new_lhs_core: ContextVarNode, + _rhs_cvar: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) { + if !tmp_construction.lhs.is_const(self).unwrap() { + // widen to maximum range :( + let new_underlying_lhs = self + .advance_var_in_ctx(tmp_construction.lhs.latest_version(self), loc, ctx) + .unwrap(); + if let Some(lhs_range) = tmp_construction.lhs.ref_range(self).unwrap() { + if let Elem::Concrete(c) = lhs_range.evaled_range_min(self).unwrap() { + new_underlying_lhs + .set_range_min( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::min(&c.val).unwrap_or_else(|| c.val.clone()), + loc, + }), + ) + .unwrap(); + new_underlying_lhs + .set_range_max( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::max(&c.val).unwrap_or(c.val), + loc, + }), + ) + .unwrap(); + } + } + } + } + + /// Recursively updates the range for a + fn range_recursion( + &mut self, + tmp_construction: TmpConstruction, + (flip_op, no_flip_op): (RangeOp, RangeOp), + rhs_cvar: ContextVarNode, + ctx: ContextNode, + loc: Loc, + any_unsat: &mut bool, + ) -> Result<(), ExprErr> { + tracing::trace!("Recursing through range"); + // handle lhs + let Some(inverse) = tmp_construction + .op + .inverse() else { + return Ok(()); + }; + + if !tmp_construction.lhs.is_const(self).into_expr_err(loc)? { + tracing::trace!("handling lhs range recursion"); + let adjusted_gt_rhs = ContextVarNode::from({ + let tmp = self.op( + loc, + rhs_cvar, + tmp_construction.rhs.expect("No rhs in tmp_construction"), + ctx, + inverse, + false, + )?; + if matches!(tmp, ExprRet::CtxKilled(_)) { + ctx.push_expr(tmp, self).into_expr_err(loc)?; + return Ok(()); + } + tmp.expect_single().into_expr_err(loc)? + }); + let new_underlying_lhs = + self.advance_var_in_curr_ctx(tmp_construction.lhs.latest_version(self), loc)?; + if let Some(lhs_range) = new_underlying_lhs + .underlying(self) + .into_expr_err(loc)? + .ty + .range(self) + .into_expr_err(loc)? + { + if let Some(_rhs_range) = adjusted_gt_rhs + .underlying(self) + .into_expr_err(loc)? + .ty + .ref_range(self) + .into_expr_err(loc)? + { + let lhs_range_fn = SolcRange::dyn_fn_from_op(no_flip_op); + let new_lhs_range = lhs_range_fn(lhs_range, adjusted_gt_rhs); + + new_underlying_lhs + .set_range_min(self, new_lhs_range.range_min().into_owned()) + .into_expr_err(loc)?; + new_underlying_lhs + .set_range_max(self, new_lhs_range.range_max().into_owned()) + .into_expr_err(loc)?; + + if new_lhs_range.unsat(self) { + *any_unsat = true; + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(()); + } + if let Some(tmp) = new_underlying_lhs.tmp_of(self).into_expr_err(loc)? { + self.range_recursion( + tmp, + (flip_op, no_flip_op), + adjusted_gt_rhs, + ctx, + loc, + any_unsat, + )?; + } + } + } + } + + // handle rhs + if let Some(rhs) = tmp_construction.rhs { + if !rhs.is_const(self).into_expr_err(loc)? { + tracing::trace!("handling rhs range recursion"); + let (needs_inverse, adjusted_gt_rhs) = match tmp_construction.op { + RangeOp::Sub(..) => { + let concrete = ConcreteNode( + self.add_node(Node::Concrete(Concrete::Int(256, I256::from(-1i32)))) + .index(), + ); + let lhs_cvar = ContextVar::new_from_concrete(loc, ctx, concrete, self) + .into_expr_err(loc)?; + let tmp_lhs = + ContextVarNode::from(self.add_node(Node::ContextVar(lhs_cvar))); + + // tmp_rhs = rhs_cvar * -1 + let tmp_rhs = + self.op(loc, rhs_cvar, tmp_lhs, ctx, RangeOp::Mul(false), false)?; + if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(tmp_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let tmp_rhs = + ContextVarNode::from(tmp_rhs.expect_single().into_expr_err(loc)?); + + // new_rhs = (rhs_cvar * -1) + tmp_construction.lhs + let new_rhs = + self.op(loc, tmp_rhs, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (true, new_rhs) + } + RangeOp::Add(..) => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Mul(..) => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Div(..) => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Shl => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Shr => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Eq => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + RangeOp::Neq => { + let new_rhs = + self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + if matches!(new_rhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_rhs, self).into_expr_err(loc)?; + return Ok(()); + } + let new_rhs = + ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); + (false, new_rhs) + } + e => panic!("here {e:?}"), + }; + + let new_underlying_rhs = + self.advance_var_in_curr_ctx(rhs.latest_version(self), loc)?; + if let Some(lhs_range) = new_underlying_rhs + .underlying(self) + .into_expr_err(loc)? + .ty + .range(self) + .into_expr_err(loc)? + { + if let Some(_rhs_range) = adjusted_gt_rhs + .underlying(self) + .into_expr_err(loc)? + .ty + .ref_range(self) + .into_expr_err(loc)? + { + let new_lhs_range = if needs_inverse { + let lhs_range_fn = SolcRange::dyn_fn_from_op(flip_op); + lhs_range_fn(lhs_range, adjusted_gt_rhs) + } else { + let lhs_range_fn = SolcRange::dyn_fn_from_op(no_flip_op); + lhs_range_fn(lhs_range, adjusted_gt_rhs) + }; + + new_underlying_rhs + .set_range_min(self, new_lhs_range.range_min().into_owned()) + .into_expr_err(loc)?; + new_underlying_rhs + .set_range_max(self, new_lhs_range.range_max().into_owned()) + .into_expr_err(loc)?; + + if new_lhs_range.unsat(self) { + *any_unsat = true; + ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; + return Ok(()); + } + + if let Some(tmp) = new_underlying_rhs.tmp_of(self).into_expr_err(loc)? { + self.range_recursion( + tmp, + (flip_op, no_flip_op), + adjusted_gt_rhs, + ctx, + loc, + any_unsat, + )?; + } + } + } + } + } + + Ok(()) + } +} diff --git a/crates/solc_expressions/variable.rs b/crates/solc_expressions/variable.rs new file mode 100644 index 00000000..d77dc4a2 --- /dev/null +++ b/crates/solc_expressions/variable.rs @@ -0,0 +1,135 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ExprErr; +use crate::context::{exprs::env::Env, ContextBuilder}; +use shared::nodes::VarNode; +use shared::{analyzer::AnalyzerLike, context::*, Edge, Node}; +use solang_parser::pt::Expression; + +use solang_parser::pt::Identifier; + +impl Variable for T where T: AnalyzerLike + Sized {} + +pub trait Variable: AnalyzerLike + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn variable( + &mut self, + ident: &Identifier, + ctx: ContextNode, + recursion_target: Option, + ) -> Result<(), ExprErr> { + tracing::trace!( + "Getting variable: {}, loc: {:?}, ctx: {}", + &ident.name, + ident.loc, + ctx.path(self) + ); + let target_ctx = if let Some(recursion_target) = recursion_target { + recursion_target + } else { + ctx + }; + + // solang doesnt have `super` as a keyword + if let Some(cvar) = ctx.var_by_name(self, &ident.name) { + let cvar = cvar.latest_version(self); + self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { + let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; + edge_ctx + .push_expr(ExprRet::Single(var.into()), analyzer) + .into_expr_err(ident.loc) + }) + } else if ident.name == "_" { + self.env_variable(ident, target_ctx)?; + Ok(()) + } else if let Some(cvar) = ctx + .var_by_name_or_recurse(self, &ident.name) + .into_expr_err(ident.loc)? + { + // check if we can inherit it + let cvar = cvar.latest_version(self); + self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { + let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; + edge_ctx + .push_expr(ExprRet::Single(var.into()), analyzer) + .into_expr_err(ident.loc) + }) + // if let Some(recursion_target) = recursion_target { + // self.variable(ident, parent_ctx, Some(recursion_target)) + // } else { + // self.variable(ident, parent_ctx, Some(target_ctx)) + // } + } else if (self.env_variable(ident, target_ctx)?).is_some() { + Ok(()) + } else if let Some(idx) = self.user_types().get(&ident.name).cloned() { + let const_var = if let Node::Var(_v) = self.node(idx) { + VarNode::from(idx) + .const_value(ident.loc, self) + .into_expr_err(ident.loc)? + } else { + None + }; + + let var = if let Some(con) = const_var { + con + } else { + match self.node(idx) { + Node::Var(_) | Node::Enum(_) => { + match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + ident.loc, + format!( + "Could not create context variable from user type: {:?}", + self.node(idx) + ), + )) + } + } + } + _ => { + return target_ctx + .push_expr(ExprRet::Single(idx), self) + .into_expr_err(ident.loc) + } + } + }; + + let new_cvarnode = self.add_node(Node::ContextVar(var)); + + ctx.add_var(new_cvarnode.into(), self) + .into_expr_err(ident.loc)?; + self.add_edge( + new_cvarnode, + target_ctx, + Edge::Context(ContextEdge::Variable), + ); + target_ctx + .push_expr(ExprRet::Single(new_cvarnode), self) + .into_expr_err(ident.loc)?; + Ok(()) + } else if let Some(func_node) = self.builtin_fn_or_maybe_add(&ident.name) { + target_ctx + .push_expr(ExprRet::Single(func_node), self) + .into_expr_err(ident.loc)?; + Ok(()) + } else if let Some(_func) = target_ctx + .visible_funcs(self) + .into_expr_err(ident.loc)? + .iter() + .find(|func| func.name(self).unwrap() == ident.name) + { + Err(ExprErr::Todo( + ident.loc, + "Function as variables has limited support".to_string(), + )) + } else { + let node = self.add_node(Node::Unresolved(ident.clone())); + self.user_types_mut().insert(ident.name.clone(), node); + target_ctx + .push_expr(ExprRet::Single(node), self) + .into_expr_err(ident.loc)?; + Ok(()) + } + } +} diff --git a/crates/solc_expressions/yul/mod.rs b/crates/solc_expressions/yul/mod.rs new file mode 100644 index 00000000..223167de --- /dev/null +++ b/crates/solc_expressions/yul/mod.rs @@ -0,0 +1,343 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::ContextBuilder; +use crate::context::ExprParser; +use crate::AnalyzerLike; +use crate::ExprErr; +use shared::context::Context; +use shared::context::ContextVar; +use shared::context::ContextVarNode; +use shared::context::ExprRet; +use shared::nodes::Builtin; +use shared::nodes::VarType; +use shared::{ + context::{ContextEdge, ContextNode}, + Edge, Node, +}; +use solang_parser::helpers::CodeLocation; +use solang_parser::pt::Expression; +use solang_parser::pt::Loc; + +use solang_parser::pt::{YulExpression, YulFor, YulStatement, YulSwitch}; + +mod yul_cond_op; +pub use yul_cond_op::*; + +mod yul_funcs; +pub use yul_funcs::*; + +impl YulBuilder for T where + T: AnalyzerLike + Sized + ExprParser +{ +} +pub trait YulBuilder: + AnalyzerLike + Sized + ExprParser +{ + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) + where + Self: Sized, + { + if let Some(true) = self.add_if_err(ctx.is_ended(self).into_expr_err(stmt.loc())) { + return; + } + if let Some(live_edges) = self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { + if live_edges.is_empty() { + self.parse_ctx_yul_stmt_inner(stmt, ctx) + } else { + live_edges.iter().for_each(|fork_ctx| { + self.parse_ctx_yul_stmt_inner(stmt, *fork_ctx); + }); + } + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn parse_ctx_yul_stmt_inner(&mut self, stmt: &YulStatement, ctx: ContextNode) + where + Self: Sized, + { + use YulStatement::*; + // println!("ctx: {}, yul stmt: {:?}", ctx.path(self), stmt); + + let res = ctx + .pop_expr_latest(stmt.loc(), self) + .into_expr_err(stmt.loc()); + let _ = self.add_if_err(res); + + if ctx.is_killed(self).unwrap() { + return; + } + let ret = self.apply_to_edges(ctx, stmt.loc(), &|analyzer, ctx, _loc| { + match stmt { + Assign(loc, yul_exprs, yul_expr) => { + match yul_exprs + .iter() + .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) + { + Ok(()) => { + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "No left hand side assignments in yul block".to_string())) + }; + if matches!(lhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) + }; + + if matches!(rhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_sides( + ctx, + loc, + &lhs_side, + &rhs_side, + ) + }) + }) + } + Err(e) => Err(e), + } + } + VariableDeclaration(loc, yul_idents, maybe_yul_expr) => { + let nodes = yul_idents + .iter() + .map(|ident| { + let b_ty = analyzer.builtin_or_add(Builtin::Uint(256)); + let var = ContextVar { + loc: Some(ident.loc), + name: ident.id.name.clone(), + display_name: ident.id.name.clone(), + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), + }; + let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + ctx.add_var(cvar, analyzer).unwrap(); + analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + analyzer.advance_var_in_ctx(cvar, *loc, ctx).unwrap() + }) + .collect::>(); + + if let Some(yul_expr) = maybe_yul_expr { + analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_yul(ctx, loc, &nodes, ret) + + }) + } else { + Ok(()) + } + } + If(loc, yul_expr, yul_block) => { + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let ret = analyzer.yul_cond_op_stmt(loc, yul_expr, yul_block, ctx); + let _ = analyzer.add_if_err(ret); + Ok(()) + }) + } + For(YulFor { + loc, + init_block: _, + condition: _, + post_block: _, + execution_block: _, + }) => { + let sctx = Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) + .into_expr_err(*loc)?; + let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); + ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; + analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { + let vars = subctx.local_vars(analyzer).clone(); + vars.iter().for_each(|(name, var)| { + // widen to max range + if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = var + .underlying(analyzer) + .unwrap() + .ty + .default_range(analyzer) + .unwrap() + { + let new_inheritor_var = analyzer + .advance_var_in_ctx(inheritor_var, loc, ctx) + .unwrap(); + let res = new_inheritor_var + .set_range_min(analyzer, r.min) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_inheritor_var + .set_range_max(analyzer, r.max) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + } + }); + Ok(()) + }) + } + Switch(YulSwitch { + loc, + condition, + cases, + default, + }) => { + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.yul_switch_stmt(loc, condition.clone(), cases.to_vec(), default.clone(), ctx) + }) + } + Leave(loc) => { + Err(ExprErr::Todo(*loc, "Yul `leave` statements are not currently supported".to_string())) + } + Break(loc) => { + Err(ExprErr::Todo(*loc, "Yul `break` statements are not currently supported".to_string())) + } + Continue(loc) => { + Err(ExprErr::Todo(*loc, "Yul `continue` statements are not currently supported".to_string())) + } + Block(yul_block) => { + yul_block + .statements + .iter() + .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); + Ok(()) + } + FunctionDefinition(yul_func_def) => { + Err(ExprErr::Todo(yul_func_def.loc(), "Yul `function` defintions are not currently supported".to_string())) + } + FunctionCall(yul_func_call) => { + analyzer.yul_func_call(yul_func_call, ctx) + } + Error(loc) => { + Err(ExprErr::ParseError(*loc, "Could not parse this yul statement".to_string())) + } + } + }); + let _ = self.add_if_err(ret); + } + + #[tracing::instrument(level = "trace", skip_all)] + fn parse_ctx_yul_expr( + &mut self, + expr: &YulExpression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!("Parsing yul expression: {expr:?}"); + + let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; + if edges.is_empty() { + self.parse_ctx_yul_expr_inner(expr, ctx) + } else { + edges + .iter() + .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(expr, *fork_ctx))?; + Ok(()) + } + } + + fn parse_ctx_yul_expr_inner( + &mut self, + expr: &YulExpression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + use YulExpression::*; + match expr { + BoolLiteral(loc, b, _) => self.bool_literal(ctx, *loc, *b), + NumberLiteral(loc, int, expr, _unit) => { + self.number_literal(ctx, *loc, int, expr, false) + } + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), + HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), + StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), + Variable(ident) => self.variable(ident, ctx, None), + FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), + SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( + expr.loc(), + "Yul member access not yet supported".to_string(), + )), + } + } + + fn match_assign_yul( + &mut self, + _ctx: ContextNode, + loc: Loc, + nodes: &[ContextVarNode], + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => { + self.match_assign_yul_inner(loc, &nodes[0], s)?; + } + ExprRet::Multi(inner) => { + if inner.len() == nodes.len() { + inner + .into_iter() + .zip(nodes.iter()) + .map(|(ret, node)| self.match_assign_yul_inner(loc, node, ret)) + .collect::, ExprErr>>()?; + } else { + return Err(ExprErr::Todo( + loc, + format!("Differing number of assignees and assignors in yul expression, assignors: {}, assignees: {}", nodes.len(), inner.len()), + )); + }; + } + ExprRet::CtxKilled(_kind) => {} + ExprRet::Null => {} + } + + Ok(()) + } + + fn match_assign_yul_inner( + &mut self, + loc: Loc, + node: &ContextVarNode, + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret.flatten() { + ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { + let assign = ContextVarNode::from(idx); + let assign_ty = assign.underlying(self).into_expr_err(loc)?.ty.clone(); + if assign_ty.is_dyn(self).into_expr_err(loc)? { + let b_ty = self.builtin_or_add(Builtin::Bytes(32)); + node.underlying_mut(self).into_expr_err(loc)?.ty = + VarType::try_from_idx(self, b_ty).unwrap(); + } else { + node.underlying_mut(self).into_expr_err(loc)?.ty = assign_ty; + } + } + ExprRet::Multi(_inner) => { + return Err(ExprErr::Todo( + loc, + "Multi in single assignment yul expression is unhandled".to_string(), + )) + } + ExprRet::CtxKilled(..) => {} + ExprRet::Null => {} + } + Ok(()) + } +} diff --git a/crates/solc_expressions/yul/yul_cond_op.rs b/crates/solc_expressions/yul/yul_cond_op.rs new file mode 100644 index 00000000..59d35621 --- /dev/null +++ b/crates/solc_expressions/yul/yul_cond_op.rs @@ -0,0 +1,365 @@ +use crate::context::exprs::IntoExprErr; +use crate::context::yul::YulBuilder; +use crate::context::ContextBuilder; +use crate::context::ExprErr; +use crate::Concrete; +use crate::ConcreteNode; +use crate::{exprs::Require, AnalyzerLike}; +use ethers_core::types::U256; +use shared::context::ExprRet; +use shared::range::elem::RangeOp; +use shared::{context::*, Edge, Node, NodeIdx}; +use solang_parser::pt::Identifier; +use solang_parser::pt::YulBlock; +use solang_parser::pt::YulFunctionCall; +use solang_parser::pt::YulSwitchOptions; + +use solang_parser::pt::CodeLocation; +use solang_parser::pt::{Expression, Loc}; +use solang_parser::pt::{YulExpression, YulStatement}; + +impl YulCondOp for T where T: AnalyzerLike + Require + Sized +{} +pub trait YulCondOp: AnalyzerLike + Require + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn yul_cond_op_stmt( + &mut self, + loc: Loc, + if_expr: &YulExpression, + true_stmt: &YulBlock, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let tctx = + Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) + .into_expr_err(loc)?; + let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); + let fctx = + Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) + .into_expr_err(loc)?; + let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); + ctx.set_child_fork(true_subctx, false_subctx, analyzer) + .into_expr_err(loc)?; + let ctx_fork = analyzer.add_node(Node::ContextFork); + analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); + analyzer.add_edge( + NodeIdx::from(true_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + NodeIdx::from(false_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + + analyzer.parse_ctx_yul_expr(if_expr, true_subctx)?; + analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "True conditional had no lhs".to_string())); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_yul_true(ctx, if_expr.loc(), &ret) + })?; + + analyzer.parse_ctx_yul_statement(&YulStatement::Block(true_stmt.clone()), true_subctx); + // let false_expr = YulExpression::FunctionCall(Box::new(YulFunctionCall { + // loc, + // id: Identifier { + // loc, + // name: "iszero".to_string(), + // }, + // arguments: vec![if_expr.clone()], + // })); + analyzer.parse_ctx_yul_expr(if_expr, false_subctx)?; + analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "False conditional had no lhs".to_string())); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_yul_false(ctx, if_expr.loc(), &ret) + }) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn yul_if_else( + &mut self, + loc: Loc, + if_else_chain: &IfElseChain, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) + .into_expr_err(loc)?; + let true_subctx = ContextNode::from( + analyzer.add_node(Node::Context( + tctx + )), + ); + let fctx = Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) + .into_expr_err(loc)?; + let false_subctx = ContextNode::from( + analyzer.add_node(Node::Context( + fctx + )), + ); + ctx.set_child_fork(true_subctx, false_subctx, analyzer) + .into_expr_err(loc)?; + let ctx_fork = analyzer.add_node(Node::ContextFork); + analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); + analyzer.add_edge( + NodeIdx::from(true_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + NodeIdx::from(false_subctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + + + let if_expr_loc = if_else_chain.if_expr.loc(); + analyzer.apply_to_edges(true_subctx, if_expr_loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(&if_else_chain.if_expr, true_subctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + let Some(true_vars) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul switch statement was missing a case discriminator".to_string())) + }; + + if matches!(true_vars, ExprRet::CtxKilled(_)) { + ctx.push_expr(true_vars, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_yul_true(ctx, loc, &true_vars)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_yul_statement(&if_else_chain.true_stmt, ctx); + Ok(()) + }) + }) + })?; + + + if let Some(next) = &if_else_chain.next { + match next { + ElseOrDefault::Default(default) => { + analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_yul_statement(default, ctx); + Ok(()) + }) + } + ElseOrDefault::Else(iec) => { + analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { + analyzer.yul_if_else(loc, iec, ctx) + }) + } + } + } else { + Ok(()) + } + }) + } + + fn match_yul_true( + &mut self, + ctx: ContextNode, + loc: Loc, + true_cvars: &ExprRet, + ) -> Result<(), ExprErr> { + match true_cvars { + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc)?, + ExprRet::Single(_true_cvar) | ExprRet::SingleLiteral(_true_cvar) => { + let cnode = ConcreteNode::from( + self.add_node(Node::Concrete(Concrete::Uint(1, U256::from(0)))), + ); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, self) + .into_expr_err(loc)?, + ); + let rhs_paths = + ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); + + self.handle_require_inner( + ctx, + loc, + true_cvars, + &rhs_paths, + RangeOp::Gt, + RangeOp::Lt, + (RangeOp::Lt, RangeOp::Gt), + )?; + } + ExprRet::Multi(ref true_paths) => { + // TODO: validate this + // we only take one because we just need the context out of the return + true_paths + .iter() + .take(1) + .try_for_each(|expr_ret| self.match_yul_true(ctx, loc, expr_ret))?; + } + ExprRet::Null => {} + } + Ok(()) + } + + fn match_yul_false( + &mut self, + ctx: ContextNode, + loc: Loc, + false_cvars: &ExprRet, + ) -> Result<(), ExprErr> { + match false_cvars { + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc)?, + ExprRet::Single(_false_cvar) | ExprRet::SingleLiteral(_false_cvar) => { + let cnode = ConcreteNode::from( + self.add_node(Node::Concrete(Concrete::Uint(1, U256::from(0)))), + ); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, self) + .into_expr_err(loc)?, + ); + let rhs_paths = + ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); + + self.handle_require_inner( + ctx, + loc, + false_cvars, + &rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + )?; + } + ExprRet::Multi(ref false_paths) => { + // TODO: validate this + // we only take one because we just need the context out of the return + false_paths + .iter() + .take(1) + .try_for_each(|expr_ret| self.match_yul_false(ctx, loc, expr_ret))?; + } + ExprRet::Null => {} + } + + Ok(()) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn yul_switch_stmt( + &mut self, + loc: Loc, + condition: YulExpression, + cases: Vec, + default: Option, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + let iec = IfElseChain::from(loc, (condition, cases, default))?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.yul_if_else(loc, &iec, ctx) + }) + } +} + +#[derive(Clone, Debug)] +pub struct IfElseChain { + pub if_expr: YulExpression, + pub true_stmt: YulStatement, + pub next: Option, +} + +#[derive(Clone, Debug)] +pub enum ElseOrDefault { + Else(Box), + Default(YulStatement), +} + +impl From for ElseOrDefault { + fn from(iec: IfElseChain) -> Self { + Self::Else(Box::new(iec)) + } +} + +impl IfElseChain { + pub fn from_child(ed: ElseOrDefault) -> Option { + match ed { + ElseOrDefault::Else(iec) => Some(*iec), + _ => None, + } + } +} + +impl From for ElseOrDefault { + fn from(default: YulSwitchOptions) -> Self { + match default { + YulSwitchOptions::Default(_loc, block) => { + ElseOrDefault::Default(YulStatement::Block(block)) + } + _ => unreachable!("case as default"), + } + } +} + +pub type SwitchInfo = ( + YulExpression, + Vec, + Option, +); + +impl IfElseChain { + pub fn from(loc: Loc, (condition, cases, default): SwitchInfo) -> Result { + let mut child: Option = default.map(|default| default.into()); + + cases.into_iter().rev().for_each(|case| { + let mut chain_part: IfElseChain = From::from((condition.clone(), case)); + if let Some(c) = child.take() { + chain_part.next = c.into(); + } + child = Some(chain_part.into()); + }); + let Some(child) = child else { + return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) + }; + + let Some(iec) = IfElseChain::from_child(child) else { + return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) + }; + Ok(iec) + } +} + +impl From<(YulExpression, YulSwitchOptions)> for IfElseChain { + fn from((condition, case): (YulExpression, YulSwitchOptions)) -> Self { + match case { + YulSwitchOptions::Case(loc, expr, stmt) => { + let if_expr = YulExpression::FunctionCall(Box::new(YulFunctionCall { + loc, + id: Identifier { + loc, + name: "eq".to_string(), + }, + arguments: vec![condition, expr], + })); + IfElseChain { + if_expr, + true_stmt: YulStatement::Block(stmt), + next: None, + } + } + YulSwitchOptions::Default(_loc, _block) => { + unreachable!("We shouldn't have a `default` case in cases - only in the `default` input parameter") + } + } + } +} diff --git a/crates/solc_expressions/yul/yul_funcs.rs b/crates/solc_expressions/yul/yul_funcs.rs new file mode 100644 index 00000000..5f151e5f --- /dev/null +++ b/crates/solc_expressions/yul/yul_funcs.rs @@ -0,0 +1,656 @@ +use crate::context::exprs::BinOp; +use crate::context::exprs::Cmp; +use crate::context::exprs::Env; +use crate::context::exprs::IntoExprErr; +use crate::context::yul::YulBuilder; +use crate::context::ContextBuilder; +use crate::context::ExprErr; +use crate::Concrete; +use crate::ConcreteNode; +use crate::Node; +use ethers_core::types::U256; +use shared::analyzer::AnalyzerLike; +use shared::analyzer::GraphLike; +use shared::context::ExprRet; +use shared::nodes::VarType; +use shared::range::elem_ty::RangeExpr; + +use solang_parser::pt::YulExpression; +use std::cell::RefCell; +use std::rc::Rc; + +use shared::range::{elem_ty::Elem, SolcRange}; +use shared::{context::ContextEdge, nodes::Builtin, Edge}; +use shared::{context::*, range::elem::RangeOp}; +use solang_parser::pt::YulFunctionCall; +use solang_parser::pt::{Expression, Loc, StorageLocation}; + +impl YulFuncCaller for T where + T: AnalyzerLike + Sized + GraphLike +{ +} +pub trait YulFuncCaller: + GraphLike + AnalyzerLike + Sized +{ + fn yul_func_call( + &mut self, + func_call: &YulFunctionCall, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + let YulFunctionCall { loc, id, arguments } = func_call; + + match &*id.name { + "caller" => { + let t = self.msg_access(*loc, ctx, "sender")?; + ctx.push_expr(t, self).into_expr_err(*loc) + } + "origin" => { + let t = self.msg_access(*loc, ctx, "origin")?; + ctx.push_expr(t, self).into_expr_err(*loc) + } + "gasprice" => { + let t = self.msg_access(*loc, ctx, "gasprice")?; + ctx.push_expr(t, self).into_expr_err(*loc) + } + "callvalue" => { + let t = self.msg_access(*loc, ctx, "value")?; + ctx.push_expr(t, self).into_expr_err(*loc) + } + "pop" => { + let _ = ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; + Ok(()) + } + "hash" | "basefee" | "chainid" | "coinbase" | "difficulty" | "gaslimit" | "number" + | "prevrandao" | "timestamp" => { + let t = self.block_access(*loc, ctx, &id.name)?; + ctx.push_expr(t, self).into_expr_err(*loc) + } + "log0" | "log1" | "log2" | "log3" | "log4" => { + ctx.push_expr(ExprRet::Multi(vec![]), self) + .into_expr_err(*loc)?; + Ok(()) + } + "stop" | "revert" | "selfdestruct" | "invalid" => { + ctx.kill(self, *loc, KilledKind::Revert).into_expr_err(*loc) + } + "return" => { + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(offset) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul Return had no offset".to_string())) + }; + if matches!(offset, ExprRet::CtxKilled(_)) { + ctx.push_expr(offset, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(size) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Yul Return had no size".to_string())) + }; + if matches!(size, ExprRet::CtxKilled(_)) { + ctx.push_expr(size, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.return_yul(ctx, loc, size)?; + ctx.kill(analyzer, loc, KilledKind::Ended) + .into_expr_err(loc)?; + // ctx.push_expr(ExprRet::CtxKilled(KilledKind::Ended), analyzer) + // .into_expr_err(loc)?; + Ok(()) + }) + }) + } + "not" => { + if arguments.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `not` expected 1 argument found: {:?}", + arguments.len() + ), + )); + } + + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + }; + + if matches!(lhs, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.bit_not_inner(ctx, loc, lhs.flatten()) + }) + } + "add" | "sub" | "mul" | "div" | "sdiv" | "mod" | "smod" | "exp" | "and" | "or" + | "xor" | "shl" | "shr" | "sar" => { + let op = match &*id.name { + "add" => RangeOp::Add(true), + "sub" => RangeOp::Sub(true), + "mul" => RangeOp::Mul(true), + "div" | "sdiv" => RangeOp::Div(true), + "mod" | "smod" => RangeOp::Mod, + "exp" => RangeOp::Exp, + "and" => RangeOp::BitAnd, + "or" => RangeOp::BitOr, + "xor" => RangeOp::BitXor, + "shl" => RangeOp::Shl, + "shr" | "sar" => RangeOp::Shr, + _ => unreachable!(), + }; + + if arguments.len() != 2 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `{}` expects 2 arguments found: {:?}", + id.name, + arguments.len() + ), + )); + } + + let inputs: Vec = if matches!(&*id.name, "shl" | "shr" | "sar") { + // yul shifts are super dumb and are reversed. + vec![arguments[1].clone(), arguments[0].clone()] + } else { + vec![arguments[0].clone(), arguments[1].clone()] + }; + + self.parse_inputs(ctx, *loc, &inputs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no inputs".to_string())) + }; + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + inputs.expect_length(2).into_expr_err(loc)?; + let inputs = inputs.as_vec(); + + // we have to cast the inputs into an EVM word, which is effectively a u256. + let word_ty = analyzer.builtin_or_add(Builtin::Uint(256)); + let cast_ty = VarType::try_from_idx(analyzer, word_ty).unwrap(); + let lhs_paths = ContextVarNode::from(inputs[0].expect_single().into_expr_err(loc)?); + lhs_paths.cast_from_ty(cast_ty.clone(), analyzer).into_expr_err(loc)?; + let rhs_paths = ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); + rhs_paths.cast_from_ty(cast_ty, analyzer).into_expr_err(loc)?; + + analyzer.op_match(ctx, loc, &ExprRet::Single(lhs_paths.into()), &ExprRet::Single(rhs_paths.into()), op, false) + }) + } + "lt" | "gt" | "slt" | "sgt" | "eq" => { + let op = match &*id.name { + "lt" | "slt" => RangeOp::Lt, + "gt" | "sgt" => RangeOp::Gt, + "eq" => RangeOp::Eq, + _ => unreachable!(), + }; + + if arguments.len() != 2 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `{}` expects 2 arguments found: {:?}", + id.name, + arguments.len() + ), + )); + } + + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no right hand side".to_string())) + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no left hand side".to_string())) + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.cmp_inner(ctx, loc, &lhs_paths, op, &rhs_paths)?; + let Some(result) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no return".to_string())) + }; + + let res = ContextVarNode::from(result.expect_single().into_expr_err(loc)?); + let next = analyzer.advance_var_in_ctx(res, loc, ctx)?; + let expr = Elem::Expr(RangeExpr::new( + Elem::from(res), + RangeOp::Cast, + Elem::from(Concrete::Uint(1, U256::zero())) + )); + + next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + next.set_range_max(analyzer, expr).into_expr_err(loc)?; + ctx.push_expr( + ExprRet::Single(next.into()), + analyzer, + ) + .into_expr_err(loc) + }) + }) + } + "iszero" => { + if arguments.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `iszero` expects 1 arguments found: {:?}", + arguments.len() + ), + )); + } + + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `iszero` operation had no input".to_string())) + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let cnode = ConcreteNode::from( + analyzer.add_node(Node::Concrete(Concrete::from(U256::from(0)))), + ); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) + .into_expr_err(loc)?, + ); + let rhs_paths = + ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); + + analyzer.cmp_inner(ctx, loc, &lhs_paths, RangeOp::Eq, &rhs_paths) + }) + } + "addmod" | "mulmod" => { + let b = Builtin::Uint(256); + let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "msize" | "pc" | "mload" | "sload" | "gas" | "returndatasize" => { + // TODO: actually handle this. @MemoryModel + let b = Builtin::Uint(256); + let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "calldatacopy" => { + // TODO: actually handle this. @MemoryModel + Ok(()) + } + "calldataload" => { + if arguments.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `calldataload` expects 1 arguments found: {:?}", + arguments.len() + ), + )); + } + + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `calldataload` operation had no input".to_string())) + }; + // TODO: check const version + let b = Builtin::Uint(256); + let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) + .into_expr_err(loc)?; + let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + var.display_name = format!("calldata[{}:{}+32]", elem.display_name(analyzer).into_expr_err(loc)?, elem.display_name(analyzer).into_expr_err(loc)?); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) + }) + } + "keccak256" => { + let b = Builtin::Bytes(32); + let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "call" | "delegatecall" | "callcode" | "staticcall" => { + let b = Builtin::Uint(256); + let mut var = + ContextVar::new_from_builtin(*loc, self.builtin_or_add(b.clone()).into(), self) + .into_expr_err(*loc)?; + var.display_name = format!("{id}_success"); + let mut range = SolcRange::try_from_builtin(&b).unwrap(); + range.min = Elem::from(Concrete::from(U256::from(0))); + range.max = Elem::from(Concrete::from(U256::from(1))); + var.ty.set_range(range).into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "create" | "create2" => { + let b = Builtin::Address; + let mut var = + ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + var.display_name = format!("{id}_success"); + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "returndatacopy" => { + ctx.push_expr(ExprRet::Multi(vec![]), self) + .into_expr_err(*loc)?; + Ok(()) + } + "byte" => { + let b = Builtin::Uint(8); + let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } + "mstore" | "mstore8" => { + // TODO: improve this. Right now we are extremely pessimistic and just say we know nothing about memory variables anymore. + // We should check if the location is a reference to an existing var and update based on that + // @MemoryModel + let vars = ctx.local_vars(self).clone(); + vars.into_iter().try_for_each(|(_name, var)| { + // widen to any max range + let latest_var = var.latest_version(self); + if matches!( + latest_var.underlying(self).into_expr_err(*loc)?.storage, + Some(StorageLocation::Memory(_)) + ) { + let res = latest_var.ty(self).into_expr_err(*loc)?; + if let Some(r) = res.default_range(self).unwrap() { + let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); + let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); + let _ = self.add_if_err(res); + let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); + let _ = self.add_if_err(res); + } + } + Ok(()) + })?; + ctx.push_expr(ExprRet::Multi(vec![]), self) + .into_expr_err(*loc)?; + Ok(()) + } + "sstore" => { + // TODO: improve this. Right now we are extremely pessimistic and just say we know nothing about storage variables anymore. + // We should check if the location is a reference to an existing var and update based on that + let vars = ctx.local_vars(self).clone(); + vars.iter().try_for_each(|(_name, var)| { + // widen to any max range + let latest_var = var.latest_version(self); + if matches!( + latest_var.underlying(self).into_expr_err(*loc)?.storage, + Some(StorageLocation::Storage(_)) + ) { + let res = latest_var.ty(self).into_expr_err(*loc)?; + if let Some(r) = res.default_range(self).unwrap() { + let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); + let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); + let _ = self.add_if_err(res); + let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); + let _ = self.add_if_err(res); + } + } + Ok(()) + })?; + ctx.push_expr(ExprRet::Multi(vec![]), self) + .into_expr_err(*loc)?; + Ok(()) + } + "balance" => { + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `balance` operation had no input".to_string())) + }; + + let b = Builtin::Uint(256); + let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) + .into_expr_err(loc)?; + let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + var.display_name = format!("balance({})", elem.display_name(analyzer).into_expr_err(loc)?); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) + }) + } + "selfbalance" => { + let b = Builtin::Uint(256); + let mut var = + ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + var.display_name = "selfbalance()".to_string(); + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc) + } + "address" => { + let b = Builtin::Address; + let mut var = + ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + var.display_name = "address()".to_string(); + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc) + } + "extcodesize" => { + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) + }; + + let b = Builtin::Uint(256); + let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) + .into_expr_err(loc)?; + let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + var.display_name = format!("extcodesize({})", elem.display_name(analyzer).into_expr_err(loc)?); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) + }) + } + "codesize" => { + let b = Builtin::Uint(256); + let mut var = + ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + var.display_name = "codesize()".to_string(); + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc) + } + "codecopy" => { + if arguments.len() != 3 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `{}` expects 3 arguments found: {:?}", + id.name, + arguments.len() + ), + )); + } + + self.parse_inputs(ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `codecopy` operation had no input".to_string())) + }; + ctx.push_expr(ExprRet::Multi(vec![]), analyzer) + .into_expr_err(loc) + }) + } + "extcodecopy" => { + if arguments.len() != 4 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `{}` expects 4 arguments found: {:?}", + id.name, + arguments.len() + ), + )); + } + + self.parse_inputs(ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `extcodecopy` operation had no input".to_string())) + }; + ctx.push_expr(ExprRet::Multi(vec![]), analyzer) + .into_expr_err(loc) + }) + } + "extcodehash" => { + self.parse_ctx_yul_expr(&arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) + }; + + let b = Builtin::Bytes(32); + let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) + .into_expr_err(loc)?; + let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + var.display_name = format!("extcodehash({})", elem.display_name(analyzer).into_expr_err(loc)?); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) + }) + } + _ => Err(ExprErr::Todo( + *loc, + format!("Unhandled builtin yul function: {id:?}"), + )), + } + } + + fn return_yul(&mut self, ctx: ContextNode, loc: Loc, size: ExprRet) -> Result<(), ExprErr> { + match size { + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Single(size) | ExprRet::SingleLiteral(size) => { + let b = Builtin::DynamicBytes; + let mut var = + ContextVar::new_from_builtin(loc, self.builtin_or_add(b.clone()).into(), self) + .into_expr_err(loc)?; + let mut range = SolcRange::try_from_builtin(&b).unwrap(); + match &mut range.min { + Elem::ConcreteDyn(ref mut r) => r.set_len(Elem::from(size)), + _ => unreachable!(), + } + match range.max { + Elem::ConcreteDyn(ref mut r) => r.set_len(Elem::from(size)), + _ => unreachable!(), + } + var.is_return = true; + var.ty.set_range(range).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(var)); + self.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); + ctx.add_return_node(loc, ContextVarNode::from(node).latest_version(self), self) + .into_expr_err(loc) + } + ExprRet::Multi(sizes) => { + sizes + .into_iter() + .try_for_each(|size| self.return_yul(ctx, loc, size))?; + Ok(()) + } + ExprRet::Null => Ok(()), + } + } + + // fn byte_index(&mut self, var: ExprRet, index: ExprRet) -> Result { + // match (var, index) { + // (ExprRet::Single(var_idx) + // | ExprRet::Single(var_idx), + // ExprRet::Single(index_idx) + // | ExprRet::Single(index_idx), + // ) => { + + // } + // } + // } + + #[tracing::instrument(level = "trace", skip_all)] + fn parse_inputs( + &mut self, + ctx: ContextNode, + loc: Loc, + inputs: &[YulExpression], + ) -> Result<(), ExprErr> { + let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { + Rc::new(RefCell::new(true)) + } else { + Rc::new(RefCell::new(false)) + }; + + inputs + .iter() + .try_for_each(|input| { + self.parse_ctx_yul_expr(input, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + })?; + if !inputs.is_empty() { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + } +} diff --git a/shared/src/context/mod.rs b/shared/src/context/mod.rs index 6e0eac7c..7df2b145 100644 --- a/shared/src/context/mod.rs +++ b/shared/src/context/mod.rs @@ -116,1537 +116,8 @@ pub struct ContextCache { pub associated_contract: Option, } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Context { - /// The function associated with this context - pub parent_fn: FunctionNode, - /// Whether this function call is actually a modifier call - pub modifier_state: Option, - /// An optional parent context (i.e. this context is a fork or subcontext of another previous context) - pub parent_ctx: Option, - pub returning_ctx: Option, - /// Variables whose bounds are required to be met for this context fork to exist. i.e. a conditional operator - /// like an if statement - pub ctx_deps: BTreeMap, - /// A string that represents the path taken from the root context (i.e. `fn_entry.fork.1`) - pub path: String, - /// Denotes whether this context was killed by an unsatisfiable require, assert, etc. statement - pub killed: Option<(Loc, KilledKind)>, - /// Denotes whether this context is a fork of another context - pub is_fork: bool, - /// Denotes whether this context is the result of a internal function call, and points to the FunctionNode - pub fn_call: Option, - /// Denotes whether this context is the result of a internal function call, and points to the FunctionNode - pub ext_fn_call: Option, - /// The child context. This is either of the form `Call(child_context)` or `Fork(world1, world2)`. Once - /// a child is defined we should *never* evaluate an expression in this context. - pub child: Option, - /// A counter for temporary variables - this lets a context create unique temporary variables - pub tmp_var_ctr: usize, - /// The location in source of the context - pub loc: Loc, - /// The return node and the return location - pub ret: Vec<(Loc, ContextVarNode)>, - /// Depth tracker - pub depth: usize, - /// Width tracker - pub width: usize, - pub tmp_expr: Vec>, - pub expr_ret_stack: Vec, - pub unchecked: bool, - pub number_of_live_edges: usize, - - // caching related things - pub cache: ContextCache, -} - -impl Context { - /// Creates a new context from a function - pub fn new(parent_fn: FunctionNode, fn_name: String, loc: Loc) -> Self { - Context { - parent_fn, - parent_ctx: None, - returning_ctx: None, - path: fn_name, - tmp_var_ctr: 0, - killed: None, - ctx_deps: Default::default(), - is_fork: false, - fn_call: None, - ext_fn_call: None, - child: None, - ret: vec![], - loc, - modifier_state: None, - depth: 0, - width: 0, - expr_ret_stack: Vec::with_capacity(5), - tmp_expr: vec![], - unchecked: false, - number_of_live_edges: 0, - cache: Default::default(), - } - } - - /// Creates a new subcontext from an existing context - pub fn new_subctx( - parent_ctx: ContextNode, - returning_ctx: Option, - loc: Loc, - fork_expr: Option<&str>, - fn_call: Option, - fn_ext: bool, - analyzer: &mut impl AnalyzerLike, - modifier_state: Option, - ) -> Result { - let mut depth = - parent_ctx.underlying(analyzer)?.depth + if fork_expr.is_some() { 0 } else { 1 }; - - let width = - parent_ctx.underlying(analyzer)?.width + if fork_expr.is_some() { 1 } else { 0 }; - - if analyzer.max_depth() < depth { - return Err(GraphError::MaxStackDepthReached(format!( - "Stack depth limit reached: {}", - depth - 1 - ))); - } - - let tw = parent_ctx.total_width(analyzer)?; - if analyzer.max_width() < tw { - return Err(GraphError::MaxStackWidthReached(format!( - "Stack width limit reached: {}", - width - 1 - ))); - } - - let (fn_name, ext_fn_call, fn_call) = if let Some(fn_call) = fn_call { - if fn_ext { - (fn_call.name(analyzer)?, Some(fn_call), None) - } else { - (fn_call.name(analyzer)?, None, Some(fn_call)) - } - } else if let Some(returning_ctx) = returning_ctx { - let fn_node = returning_ctx.associated_fn(analyzer)?; - (fn_node.name(analyzer)?, None, Some(fn_node)) - } else { - ("anonymous_fn_call".to_string(), None, None) - }; - - let path = format!( - "{}.{}", - parent_ctx.underlying(analyzer)?.path, - if let Some(ref fork_expr) = fork_expr { - format!("fork{{ {} }}", fork_expr) - } else if let Some(returning_ctx) = returning_ctx { - depth = depth.saturating_sub(2); - format!( - "resume{{ {} }}", - returning_ctx.associated_fn_name(analyzer)? - ) - } else { - fn_name - } - ); - - let parent_fn = parent_ctx.associated_fn(analyzer)?; - - parent_ctx.underlying_mut(analyzer)?.number_of_live_edges += 1; - - tracing::trace!("new subcontext path: {path}, depth: {depth}"); - Ok(Context { - parent_fn, - parent_ctx: Some(parent_ctx), - returning_ctx, - path, - is_fork: fork_expr.is_some(), - fn_call, - ext_fn_call, - ctx_deps: parent_ctx.underlying(analyzer)?.ctx_deps.clone(), - killed: None, - child: None, - tmp_var_ctr: parent_ctx.underlying(analyzer)?.tmp_var_ctr, - ret: vec![], - loc, - modifier_state, - depth, - width, - expr_ret_stack: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.expr_ret_stack.clone() - } else if let Some(ret_ctx) = returning_ctx { - ret_ctx.underlying(analyzer)?.expr_ret_stack.clone() - } else { - vec![] - }, - tmp_expr: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.tmp_expr.clone() - } else if let Some(ret_ctx) = returning_ctx { - ret_ctx.underlying(analyzer)?.tmp_expr.clone() - } else { - vec![] - }, - unchecked: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.unchecked - } else if let Some(ret_ctx) = returning_ctx { - ret_ctx.underlying(analyzer)?.unchecked - } else { - false - }, - number_of_live_edges: 0, - cache: ContextCache { - vars: Default::default(), - visible_funcs: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone() - } else if let Some(ret_ctx) = returning_ctx { - ret_ctx.underlying(analyzer)?.cache.visible_funcs.clone() - } else { - None - }, - first_ancestor: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.cache.first_ancestor - } else if let Some(ret_ctx) = returning_ctx { - ret_ctx.underlying(analyzer)?.cache.first_ancestor - } else { - None - }, - associated_source: None, - associated_contract: None, - }, - }) - } - - /// Set the child context to a fork - pub fn set_child_fork(&mut self, world1: ContextNode, world2: ContextNode) -> bool { - if self.child.is_some() { - false - } else { - self.child = Some(CallFork::Fork(world1, world2)); - true - } - } - - /// Set the child context to a call - pub fn set_child_call(&mut self, call_ctx: ContextNode) -> bool { - if self.child.is_some() { - false - } else { - self.child = Some(CallFork::Call(call_ctx)); - true - } - } - - pub fn delete_child(&mut self) { - self.child = None; - } - - pub fn as_string(&mut self) -> String { - "Context".to_string() - } -} - -#[derive(Debug, Clone)] -pub struct CtxTree { - pub node: ContextNode, - pub lhs: Option>, - pub rhs: Option>, -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -/// A wrapper of a node index that corresponds to a [`Context`] -pub struct ContextNode(pub usize); - -impl AsDotStr for ContextNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - format!("Context {{ {} }}", self.path(analyzer)) - } -} - -impl ContextNode { - // pub fn called_functions(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // self.underlying(analyzer)?.children.iter().filter_map(|child| { - // match child.maybe_call()?.underlying(analyzer) { - // Ok(underlying) => { - // match (underlying.fn_call, underlying.ext_fn_call) { - // (Some(fn_call), _) => Some(Ok(fn_call)), - // (_, Some(ext_fn_call)) => Some(Ok(ext_fn_call)), - // (None, None) => None - // } - // } - // Err(_) => None - // } - // }).collect() - // } - - pub fn join( - &self, - _func: FunctionNode, - _mapping: &BTreeMap, - _analyzer: &mut (impl GraphLike + AnalyzerLike), - ) { - todo!("Joining not supported yet"); - // println!("joining"); - // if let Some(body_ctx) = func.maybe_body_ctx(analyzer) { - // let vars: Vec<_> = body_ctx.vars(analyzer).values().map(|var| var.latest_version(analyzer)).collect(); - // println!("vars: {vars:#?}"); - // let replacements: Vec<(ContextVarNode, ContextVarNode)> = mapping.iter().filter_map(|(input_var, param)| { - // vars.iter().find(|var| var.name(analyzer).unwrap() == param.name(analyzer).unwrap()).map(|var| { - // (*var, *input_var) - // }) - // }).collect(); - - // let mut mapping = BTreeMap::default(); - // replacements.into_iter().for_each(|(var, replacement)| { - // mapping.insert(var, replacement); - // let mut latest = var; - // while let Some(next) = latest.next_version(analyzer) { - // latest = next; - // mapping.insert(latest, replacement); - // } - // }); - - // println!("mapping: {mapping:#?}"); - - // vars.iter().for_each(|var| { - // let mut latest = *var; - // let mut range = latest.range(analyzer).unwrap().unwrap(); - // println!("var: {var:?}, depends on: {:#?}, {range:#?}", var.range_deps(analyzer)); - // range.uncache_range_min(); - // range.uncache_range_max(); - // mapping.iter().for_each(|(to_replace, replacement)| { - // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); - // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); - // }); - // latest.set_range(analyzer, range).unwrap(); - // while let Some(next) = latest.next_version(analyzer) { - // latest = next; - // let mut range = latest.range(analyzer).unwrap().unwrap(); - // range.uncache_range_min(); - // range.uncache_range_max(); - // mapping.iter().for_each(|(to_replace, replacement)| { - // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); - // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); - // }); - // latest.set_range(analyzer, range).unwrap(); - // } - // }); - - // } else { - // // need to process the function - // } - } - - pub fn is_ext_fn(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) - } - - pub fn add_var( - &self, - var: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let name = var.name(analyzer)?; - let vars = &mut self.underlying_mut(analyzer)?.cache.vars; - vars.insert(name, var); - Ok(()) - } - - pub fn first_ancestor( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { - Ok(first_ancestor) - } else if let Some(parent) = self.underlying(analyzer)?.parent_ctx { - let first = parent.first_ancestor(analyzer)?; - self.underlying_mut(analyzer)?.cache.first_ancestor = Some(first); - Ok(first) - } else { - Ok(*self) - } - } - - pub fn total_width( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - self.first_ancestor(analyzer)? - .number_of_live_edges(analyzer) - } - - pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.unchecked) - } - - pub fn set_unchecked( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.unchecked = true; - Ok(()) - } - - pub fn unset_unchecked( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.unchecked = false; - Ok(()) - } - - pub fn push_tmp_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - underlying_mut.tmp_expr.push(Some(expr_ret)); - Ok(()) - } - - pub fn append_tmp_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - match underlying_mut.tmp_expr.pop() { - Some(Some(s @ ExprRet::Single(_))) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(s @ ExprRet::SingleLiteral(_))) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(ExprRet::Multi(ref mut inner))) => { - inner.push(expr_ret); - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(inner.to_vec()))); - } - Some(Some(s @ ExprRet::Null)) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(ExprRet::CtxKilled(kind))) => { - underlying_mut.tmp_expr = vec![Some(ExprRet::CtxKilled(kind))]; - underlying_mut.expr_ret_stack = vec![ExprRet::CtxKilled(kind)]; - } - _ => { - underlying_mut.tmp_expr.push(Some(expr_ret)); - } - } - Ok(()) - } - - pub fn pop_tmp_expr( - &self, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { - Ok(Some(self.maybe_move_expr(expr, loc, analyzer)?)) - } else { - Ok(None) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn push_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - tracing::trace!( - "pushing: {}, existing: {:?}, path: {}", - expr_ret.debug_str(analyzer), - self.underlying(analyzer)? - .expr_ret_stack - .iter() - .map(|i| i.debug_str(analyzer)) - .collect::>(), - self.path(analyzer) - ); - let underlying_mut = self.underlying_mut(analyzer)?; - underlying_mut.expr_ret_stack.push(expr_ret); - Ok(()) - } - - pub fn maybe_move_expr( - &self, - expr: ExprRet, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match expr { - ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( - self.maybe_move_var(var.into(), loc, analyzer)?.into(), - )), - ExprRet::Single(var) => Ok(ExprRet::Single( - self.maybe_move_var(var.into(), loc, analyzer)?.into(), - )), - ExprRet::Multi(inner) => Ok(ExprRet::Multi( - inner - .iter() - .map(|i| self.maybe_move_expr(i.clone(), loc, analyzer)) - .collect::>()?, - )), - e => Ok(e), - } - } - - pub fn maybe_move_var( - &self, - var: ContextVarNode, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(ctx) = var.maybe_ctx(analyzer) { - if ctx != *self { - let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); - new_cvar.loc = Some(loc); - - let new_cvarnode = analyzer.add_node(Node::ContextVar(new_cvar)); - analyzer.add_edge(new_cvarnode, *self, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge( - new_cvarnode, - var.0, - Edge::Context(ContextEdge::InheritedVariable), - ); - Ok(new_cvarnode.into()) - } else { - Ok(var) - } - } else { - Ok(var) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn pop_expr( - &self, - _loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - tracing::trace!("popping var from: {}", self.path(analyzer)); - let underlying_mut = self.underlying_mut(analyzer)?; - - let new: Vec = Vec::with_capacity(5); - - let old = std::mem::replace(&mut underlying_mut.expr_ret_stack, new); - if old.is_empty() { - Ok(None) - } else { - Ok(Some(ExprRet::Multi(old))) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn pop_expr_latest( - &self, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - if let Some(elem) = underlying_mut.expr_ret_stack.pop() { - tracing::trace!( - "popping var {} from: {}", - elem.debug_str(analyzer), - self.path(analyzer) - ); - Ok(Some(self.maybe_move_expr(elem, loc, analyzer)?)) - } else { - Ok(None) - } - } - - pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { - self.local_vars(analyzer) - .iter() - .flat_map(|(_name, var)| var.return_assignments(analyzer)) - .collect() - } - - pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { - self.local_vars(analyzer) - .iter() - .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) - .collect() - } - - pub fn depth(&self, analyzer: &impl GraphLike) -> usize { - self.underlying(analyzer).unwrap().depth - } - - /// The path of the underlying context - pub fn path(&self, analyzer: &impl GraphLike) -> String { - self.underlying(analyzer).unwrap().path.clone() - } - - /// *All* subcontexts (including subcontexts of subcontexts, recursively) - pub fn subcontexts(&self, analyzer: &impl GraphLike) -> Vec { - let underlying = self.underlying(analyzer).unwrap(); - match underlying.child { - Some(CallFork::Call(c)) => vec![c], - Some(CallFork::Fork(w1, w2)) => vec![w1, w2], - None => vec![], - } - } - - /// Gets the associated contract for the function for the context - pub fn associated_contract( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - Ok(self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer) - .expect("No associated contract for context")) - } - - /// Tries to get the associated function for the context - pub fn maybe_associated_contract( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - Ok(self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer)) - } - - pub fn maybe_associated_source( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - let context = self.underlying(analyzer).unwrap(); - if let Some(src) = context.cache.associated_source { - Some(src) - } else if let Some(parent_ctx) = context.parent_ctx { - let src = parent_ctx.maybe_associated_source(analyzer)?; - self.underlying_mut(analyzer) - .unwrap() - .cache - .associated_source = Some(src); - Some(src) - } else { - let func = self.associated_fn(analyzer).unwrap(); - func.maybe_associated_source(analyzer) - } - } - - pub fn associated_source_unit_part( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(sup) = self - .associated_fn(analyzer)? - .maybe_associated_source_unit_part(analyzer) - { - Ok(sup) - } else { - Err(GraphError::NodeConfusion( - "Expected context to have an associated source but didnt".to_string(), - )) - } - } - - /// Gets visible functions - pub fn visible_modifiers( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())) - }; - if let Some(contract) = self.maybe_associated_contract(analyzer)? { - let mut modifiers = contract.modifiers(analyzer); - // extend with free floating functions - modifiers.extend( - analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>(), - ); - - // extend with inherited functions - let inherited_contracts = analyzer.search_children_exclude_via( - contract.0.into(), - &Edge::InheritedContract, - &[Edge::Func], - ); - modifiers.extend( - inherited_contracts - .into_iter() - .flat_map(|inherited_contract| { - ContractNode::from(inherited_contract).modifiers(analyzer) - }) - .collect::>(), - ); - - let mut mapping: BTreeMap> = BTreeMap::new(); - for modifier in modifiers.iter() { - let entry = mapping.entry(modifier.name(analyzer)?).or_default(); - entry.insert(*modifier); - } - mapping - .into_values() - .map(|modifier_set| { - let as_vec = modifier_set.iter().collect::>(); - - if as_vec.len() > 2 { - println!("{}", as_vec.iter().map(|i| i.name(analyzer).unwrap()).collect::>().join(", ")); - panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") - } else if as_vec.len() == 2 { - as_vec[0].get_overriding(as_vec[1], analyzer) - } else { - Ok(*as_vec[0]) - } - }) - .collect() - } else { - // we are in a free floating function, only look at free floating functions - let Some(source) = self.maybe_associated_source(analyzer) else { - return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())); - }; - Ok(analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>()) - } - } - - /// Gets visible functions - pub fn visible_funcs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - // TODO: filter privates - if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { - return Ok(vis.clone()); - } - if let Some(contract) = self.maybe_associated_contract(analyzer)? { - let mut mapping = contract.linearized_functions(analyzer); - // extend with free floating functions - mapping.extend( - analyzer - .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) - .into_iter() - .filter_map(|i| { - let fn_node = FunctionNode::from(i); - if let Ok(name) = fn_node.name(analyzer) { - if !mapping.contains_key(&name) { - Some((name, fn_node)) - } else { - None - } - } else { - None - } - }) - .collect::>(), - ); - let funcs: Vec<_> = mapping.values().copied().collect(); - self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); - Ok(funcs) - } else { - // we are in a free floating function, only look at free floating functions - let funcs = analyzer - .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>(); - - self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); - Ok(funcs) - } - } - - /// Gets all visible functions - pub fn source_funcs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Vec { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return vec![] - }; - analyzer - .search_children_exclude_via( - source, - &Edge::Func, - &[ - Edge::Context(ContextEdge::Context), - Edge::Context(ContextEdge::Variable), - ], - ) - .into_iter() - .map(FunctionNode::from) - .collect::>() - } - - /// Gets all visible structs - pub fn visible_structs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Vec { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return vec![] - }; - - analyzer - .search_children_exclude_via(source, &Edge::Struct, &[Edge::Func]) - .into_iter() - .map(StructNode::from) - .collect::>() - } - - /// Gets the associated function for the context - pub fn associated_fn(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - if let Some(fn_call) = underlying.fn_call { - Ok(fn_call) - } else if let Some(ext_fn_call) = underlying.ext_fn_call { - Ok(ext_fn_call) - } else { - Ok(underlying.parent_fn) - } - } - - /// Checks whether a function is external to the current context - pub fn is_fn_ext( - &self, - fn_node: FunctionNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match fn_node.maybe_associated_contract(analyzer) { - None => Ok(false), - Some(fn_ctrt) => { - if let Some(self_ctrt) = self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer) - { - Ok(Some(self_ctrt) != Some(fn_ctrt) - && !self_ctrt - .underlying(analyzer)? - .inherits - .iter() - .any(|inherited| *inherited == fn_ctrt)) - } else { - Ok(false) - } - } - } - } - - /// Gets the associated function name for the context - pub fn associated_fn_name(&self, analyzer: &impl GraphLike) -> Result { - self.associated_fn(analyzer)?.name(analyzer) - } - - /// Gets a mutable reference to the underlying context in the graph - pub fn underlying_mut<'a>( - &self, - analyzer: &'a mut (impl GraphLike + AnalyzerLike), - ) -> Result<&'a mut Context, GraphError> { - match analyzer.node_mut(*self) { - Node::Context(c) => Ok(c), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Context but it was: {e:?}" - ))), - } - } - - /// Gets an immutable reference to the underlying context in the graph - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Context, GraphError> { - match analyzer.node(*self) { - Node::Context(c) => Ok(c), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Context but it was: {e:?}" - ))), - } - } - - /// Gets a variable by name in the context - pub fn var_by_name(&self, analyzer: &impl GraphLike, name: &str) -> Option { - self.underlying(analyzer) - .unwrap() - .cache - .vars - .get(name) - .copied() - } - - pub fn var_by_name_or_recurse( - &self, - analyzer: &impl GraphLike, - name: &str, - ) -> Result, GraphError> { - if let Some(var) = self.var_by_name(analyzer, name) { - Ok(Some(var)) - } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { - parent.var_by_name_or_recurse(analyzer, name) - } else { - Ok(None) - } - } - - pub fn ancestor_in_fn( - &self, - analyzer: &impl GraphLike, - associated_fn: FunctionNode, - ) -> Result, GraphError> { - if let Some(ret) = self.underlying(analyzer)?.returning_ctx { - if ret.associated_fn(analyzer)? == associated_fn { - return Ok(Some(ret)); - } - } - - if let Some(parent) = self.underlying(analyzer)?.parent_ctx { - if parent.associated_fn(analyzer)? == associated_fn { - Ok(Some(parent)) - } else if let Some(mod_state) = &parent.underlying(analyzer)?.modifier_state { - if mod_state.parent_fn == associated_fn { - Ok(Some(parent)) - } else { - parent.ancestor_in_fn(analyzer, associated_fn) - } - } else { - parent.ancestor_in_fn(analyzer, associated_fn) - } - } else { - Ok(None) - } - } - - /// Gets all variables associated with a context - pub fn vars<'a>(&self, analyzer: &'a impl GraphLike) -> &'a BTreeMap { - &self.underlying(analyzer).unwrap().cache.vars - } - - /// Gets all variables associated with a context - pub fn local_vars<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> &'a BTreeMap { - self.vars(analyzer) - } - /// Gets the latest version of a variable associated with a context - pub fn latest_var_by_name( - &self, - analyzer: &impl GraphLike, - name: &str, - ) -> Option { - self.var_by_name(analyzer, name) - .map(|var| var.latest_version(analyzer)) - } - - /// Reads the current temporary counter and increments the counter - pub fn new_tmp( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let context = self.underlying_mut(analyzer)?; - let ret = context.tmp_var_ctr; - context.tmp_var_ctr += 1; - Ok(ret) - } - - /// Returns all forks associated with the context - pub fn calls(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let descendents = self.descendents(analyzer)?; - Ok(descendents - .into_iter() - .filter_map(|c| c.maybe_call()) - .collect()) - } - - /// Returns all forks associated with the context - // pub fn forks(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // todo!() - // let descendents = self.descendents(analyzer)?; - // Ok(descendents.into_iter().filter_map(|c| c.maybe_fork()).collect()) - // } - - // /// Returns all *live* forks associated with the context - // pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // let forks = self.forks(analyzer)?; - // let mut live = vec![]; - // for fork in forks { - // if !fork.is_ended(analyzer)? { - // live.push(fork); - // } - // } - // Ok(live) - // } - - /// Returns tail contexts associated with the context - pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.live_edges(analyzer)?; - if call_edges.is_empty() && !call.is_ended(analyzer)? { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.live_edges(analyzer)?; - if fork_edges.is_empty() && !w1.is_ended(analyzer)? { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.live_edges(analyzer)?; - if fork_edges.is_empty() && !w2.is_ended(analyzer)? { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.reverted_edges(analyzer)?; - if call_edges.is_empty() && call.is_killed(analyzer)? { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.reverted_edges(analyzer)?; - if fork_edges.is_empty() && w1.is_killed(analyzer)? { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.reverted_edges(analyzer)?; - if fork_edges.is_empty() && w2.is_killed(analyzer)? { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.number_of_live_edges) - // if let Some(child) = self.underlying(analyzer)?.child { - // let mut edges = 0; - // match child { - // CallFork::Call(call) => { - // let call_edges = call.number_of_live_edges(analyzer)?; - // if call_edges == 0 && !call.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += call_edges; - // } - // } - // CallFork::Fork(w1, w2) => { - // let fork_edges = w1.number_of_live_edges(analyzer)?; - // if fork_edges == 0 && !w1.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += fork_edges; - // } - // let fork_edges = w2.number_of_live_edges(analyzer)?; - // if fork_edges == 0 && !w2.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += fork_edges; - // } - // } - // } - // Ok(edges) - // } else { - // Ok(0) - // } - } - - /// Returns tail contexts associated with the context - pub fn all_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.all_edges(analyzer)?; - if call_edges.is_empty() { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.all_edges(analyzer)?; - if fork_edges.is_empty() { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.all_edges(analyzer)?; - if fork_edges.is_empty() { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut descendents = vec![child]; - match child { - CallFork::Call(c) => descendents.extend(c.descendents(analyzer)?), - CallFork::Fork(w1, w2) => { - descendents.extend(w1.descendents(analyzer)?); - descendents.extend(w2.descendents(analyzer)?); - } - } - Ok(descendents) - } else { - Ok(vec![]) - } - } - - /// Adds a fork to the context - pub fn set_child_fork( - &self, - w1: ContextNode, - w2: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - assert!(matches!(analyzer.node(w1), Node::Context(_))); - assert!(matches!(analyzer.node(w2), Node::Context(_))); - assert!(*self != w1 && *self != w2, "Tried to set child to self"); - let context = self.underlying_mut(analyzer)?; - if !context.set_child_fork(w1, w2) { - let child_str = match context.child { - Some(CallFork::Fork(w1, w2)) => { - format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) - } - Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), - None => unreachable!(), - }; - Err(GraphError::ChildRedefinition(format!( - "This is a bug. Tried to redefine a child context, parent:\n{}, current child:\n{},\nnew child: Fork({}, {})", - self.path(analyzer), - child_str, - w1.path(analyzer), - w2.path(analyzer), - ))) - } else { - Ok(()) - } - } - - /// Adds a child to the context - pub fn set_child_call( - &self, - call: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - assert!(matches!(analyzer.node(call), Node::Context(_))); - assert!(*self != call, "Tried to set child to self"); - let context = self.underlying_mut(analyzer)?; - if !context.set_child_call(call) { - let child_str = match context.child { - Some(CallFork::Fork(w1, w2)) => { - format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) - } - Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), - None => unreachable!(), - }; - tracing::trace!("Error setting child as a call"); - Err(GraphError::ChildRedefinition(format!( - "This is a bug. Tried to redefine a child context, parent: {}, current child: {}, new child: {}", - self.path(analyzer), - child_str, - call.path(analyzer) - ) - )) - } else { - Ok(()) - } - } - - pub fn delete_child( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - match child { - CallFork::Fork(w1, w2) => { - w1.propogate_end(analyzer)?; - w2.propogate_end(analyzer)?; - } - CallFork::Call(c) => { - c.propogate_end(analyzer)?; - } - } - } - let context = self.underlying_mut(analyzer)?; - context.delete_child(); - Ok(()) - } - - /// Kills the context by denoting it as killed. Recurses up the contexts and kills - /// parent contexts if all subcontexts of that context are killed - pub fn kill( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - kill_loc: Loc, - kill_kind: KilledKind, - ) -> Result<(), GraphError> { - tracing::trace!("killing: {}", self.path(analyzer)); - if let Some(child) = self.underlying(analyzer)?.child { - match child { - CallFork::Call(call) => { - if !call.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - call.kill(analyzer, kill_loc, kill_kind)?; - } - CallFork::Fork(w1, w2) => { - if !w1.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - - if !w2.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - - w1.kill(analyzer, kill_loc, kill_kind)?; - w2.kill(analyzer, kill_loc, kill_kind)?; - } - } - } - - let context = self.underlying_mut(analyzer)?; - let parent = context.parent_ctx; - if context.killed.is_none() { - context.killed = Some((kill_loc, kill_kind)); - } - - if let Some(parent_ctx) = parent { - parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; - } - - self.propogate_end(analyzer)?; - - Ok(()) - } - - /// Kills if and only if all subcontexts are killed - pub fn end_if_all_forks_ended( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - kill_loc: Loc, - kill_kind: KilledKind, - ) -> Result<(), GraphError> { - let all_edges = self.all_edges(analyzer)?; - let reverted_edges = self.reverted_edges(analyzer)?; - if reverted_edges.len() == all_edges.len() { - tracing::trace!("killing recursively: {}", self.path(analyzer)); - let context = self.underlying_mut(analyzer)?; - if context.ret.is_empty() { - if context.killed.is_none() { - context.killed = Some((kill_loc, kill_kind)); - } - if let Some(parent_ctx) = context.parent_ctx { - parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; - } - } - } - Ok(()) - } - - /// Gets parent list - pub fn parent_list(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let context = self.underlying(analyzer)?; - let mut parents = vec![]; - if let Some(parent_ctx) = context.parent_ctx { - parents.push(parent_ctx); - parents.extend(parent_ctx.parent_list(analyzer)?); - } - Ok(parents) - } - - pub fn recursive_calls( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - // Ok( - let calls = self.calls(analyzer)?; - Ok(calls - .iter() - .flat_map(|call| { - let mut inner_calls = call.recursive_calls(analyzer).unwrap(); - inner_calls.insert(0, *call); - inner_calls - }) - .collect::>()) - } - - /// Gets the lineage for a context - /// A lineage is of the form `[ancestor N, .. , ancestor0, SELF, call0, .., call N]`. It - /// gives the user a full picture of control flow - pub fn lineage( - &self, - _analyzer: &impl GraphLike, - _entry: bool, - ) -> Result, GraphError> { - todo!() - } - - pub fn terminal_child_list( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let calls = self.calls(analyzer)?; - if calls.is_empty() { - Ok(vec![*self]) - } else { - let mut children = vec![]; - - for child in calls.into_iter() { - children.extend(child.terminal_child_list(analyzer)?) - } - Ok(children) - } - } - - /// Returns whether the context is killed - pub fn is_killed(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.killed.is_some()) - } - - /// Returns whether the context is killed - pub fn is_ended(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) - } - - pub fn killed_or_ret(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - Ok(underlying.killed.is_some() - || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) - } - - /// Returns an option to where the context was killed - pub fn killed_loc( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.killed) - } - - /// Returns a map of variable dependencies for this context - pub fn ctx_deps( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.ctx_deps.clone()) - } - - /// Returns a vector of variable dependencies for this context - pub fn add_ctx_dep( - &self, - dep: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); - if dep.is_symbolic(analyzer)? { - let dep_name = dep.name(analyzer)?; - let underlying = self.underlying_mut(analyzer)?; - underlying.ctx_deps.insert(dep_name, dep); - } - Ok(()) - } - - pub fn add_return_node( - &self, - ret_stmt_loc: Loc, - ret: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.ret.push((ret_stmt_loc, ret)); - self.propogate_end(analyzer)?; - Ok(()) - } - - pub fn propogate_end( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying = &mut self.underlying_mut(analyzer)?; - let curr_live = underlying.number_of_live_edges; - underlying.number_of_live_edges = 0; - if let Some(parent) = self.underlying(analyzer)?.parent_ctx { - let live_edges = &mut parent.underlying_mut(analyzer)?.number_of_live_edges; - *live_edges = live_edges.saturating_sub(1 + curr_live); - parent.propogate_end(analyzer)?; - } - Ok(()) - } - - pub fn return_nodes( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.ret.clone()) - } - - pub fn as_string(&mut self) -> String { - "Context".to_string() - } - - pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { - let deps = self.ctx_deps(g)?; - #[derive(Debug, Copy, Clone)] - pub enum DepEdge { - Lhs, - Rhs, - } - - let mut gr: petgraph::Graph = - petgraph::Graph::default(); - deps.iter().try_for_each(|(_, dep)| { - let mapping = dep.graph_dependent_on(g)?; - mapping.into_iter().for_each(|(k, tmp)| { - let top = gr.add_node(k.into()); - let lhs = gr.add_node(tmp.lhs.into()); - gr.add_edge(top, lhs, DepEdge::Lhs); - if let Some(rhs) = tmp.rhs { - let rhs = gr.add_node(rhs.into()); - gr.add_edge(top, rhs, DepEdge::Rhs); - } - }); - Ok(()) - })?; - - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &gr, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - let e = edge_ref.weight(); - format!("label = \"{e:?}\"") - }, - &|_graph, (idx, node_ref)| { - let inner = match g.node(*node_ref) { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(g).unwrap() { - r.as_dot_str(g) - // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - } else { - "".to_string() - }; - - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(g).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, g), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - g.node(*node_ref).dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - let dot_str = dot_str.join("\n"); - - println!("{dot_str}"); - use std::env::temp_dir; - use std::fs; - use std::io::Write; - use std::process::Command; - let mut dir = temp_dir(); - let file_name = "dot.dot"; - dir.push(file_name); - - let mut file = fs::File::create(dir.clone()).unwrap(); - file.write_all(dot_str.as_bytes()).unwrap(); - Command::new("dot") - .arg("-Tsvg") - .arg(dir) - .arg("-o") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Command::new("open") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Ok(()) - } -} - -impl From for NodeIdx { - fn from(val: ContextNode) -> Self { - val.0.into() - } -} - -impl From for ContextNode { - fn from(idx: NodeIdx) -> Self { - ContextNode(idx.index()) - } -} // 2023-05-13T04:28:34.318383Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_expr_inner{ctx=getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }}:fn_call_expr:call_internal_func:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner: pyrometer::context: Applying to live edges of: getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256).anonymous_fn_call. edges: [ // "getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256).anonymous_fn_call.average(uint256, uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }.fork{ true }._unsafeAccess(Checkpoint[], uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }", From 93b344d50fd6846acf15d098bbf4ef955260d4f1 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 13:22:43 -0800 Subject: [PATCH 03/71] range improvements --- crates/graph/var_type.rs | 2 +- crates/range/elem/concrete.rs | 32 +- crates/range/elem/elem_enum.rs | 194 ++++++--- crates/range/elem/expr.rs | 482 +++++++++++++++++++++- crates/range/elem/map_or_array.rs | 52 ++- crates/range/elem/mod.rs | 43 +- crates/range/elem/reference.rs | 143 ++++--- crates/range/exec/add.rs | 4 +- crates/range/exec/bitwise.rs | 2 +- crates/range/exec/cast.rs | 4 +- crates/range/exec/concat.rs | 4 +- crates/range/exec/div.rs | 2 +- crates/range/exec/max.rs | 1 - crates/range/exec/mod.rs | 647 ++++++++++++++++-------------- crates/range/exec/modulo.rs | 2 +- crates/range/exec/mul.rs | 4 + crates/range/exec/shift.rs | 2 +- crates/range/exec/sub.rs | 4 +- crates/range/range_string.rs | 8 +- crates/range/solc_range.rs | 67 +++- shared/src/nodes/mod.rs | 2 +- shared/src/range/elem_ty.rs | 42 +- shared/src/range/range_ops.rs | 8 +- shared/src/range/range_string.rs | 4 +- 24 files changed, 1281 insertions(+), 474 deletions(-) diff --git a/crates/graph/var_type.rs b/crates/graph/var_type.rs index 4c1fb701..a2678ce1 100644 --- a/crates/graph/var_type.rs +++ b/crates/graph/var_type.rs @@ -507,7 +507,7 @@ impl VarType { let name = index.name(analyzer)?; let is_const = index.is_const(analyzer)?; if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { - Elem::Dynamic(Dynamic { idx, .. }) => match analyzer.node(*idx) { + Elem::Reference(Reference { idx, .. }) => match analyzer.node(*idx) { Node::ContextVar(_) => { let cvar = ContextVarNode::from(*idx); cvar.name(analyzer).unwrap() == name diff --git a/crates/range/elem/concrete.rs b/crates/range/elem/concrete.rs index 38c31542..fb088871 100644 --- a/crates/range/elem/concrete.rs +++ b/crates/range/elem/concrete.rs @@ -1,4 +1,3 @@ - /// A concrete value for a range element #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeConcrete { @@ -17,9 +16,17 @@ impl From for RangeConcrete { impl RangeElem for RangeConcrete { // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { - // Elem::Concrete(self.clone()) + // Elem::Concrete(self.clone()) // } + fn flatten( + &self, + _maximize: bool, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + fn range_eq(&self, other: &Self) -> bool { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => self_val == other_val, @@ -101,10 +108,18 @@ impl RangeElem for RangeConcrete { Ok(Elem::Concrete(self.clone())) } - fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_maximize( + &self, + _exclude: &mut Vec, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_minimize( + &self, + _exclude: &mut Vec, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } @@ -116,4 +131,13 @@ impl RangeElem for RangeConcrete { Ok(()) } fn uncache(&mut self) {} + + fn contains_op_set( + &self, + _: bool, + _op_set: &[RangeOp], + _analyzer: &impl GraphLike, + ) -> Result { + Ok(false) + } } \ No newline at end of file diff --git a/crates/range/elem/elem_enum.rs b/crates/range/elem/elem_enum.rs index 0b4428c3..975e1d7b 100644 --- a/crates/range/elem/elem_enum.rs +++ b/crates/range/elem/elem_enum.rs @@ -1,9 +1,8 @@ - /// A core range element. #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Elem { /// A range element that is a reference to another node - Reference(Reference), + Dynamic(Dynamic), /// A concrete range element of type `T`. e.g.: some number like `10` ConcreteDyn(Box>), /// A concrete range element of type `T`. e.g.: some number like `10` @@ -17,14 +16,32 @@ pub enum Elem { impl std::fmt::Display for Elem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::Dynamic(Dynamic { idx, .. }) => write!(f, "idx_{}", idx.index()), Elem::ConcreteDyn(..) => write!(f, "range_elem"), Elem::Concrete(RangeConcrete { val, .. }) => { write!(f, "{}", val.as_string()) } - Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => { - write!(f, "({} {} {})", op.to_string(), lhs, rhs) - } + Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { + RangeOp::Min | RangeOp::Max => { + write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) + } + RangeOp::Cast => match &**rhs { + Elem::Concrete(RangeConcrete { val, .. }) => { + write!( + f, + "{}({}, {})", + op.to_string(), + lhs, + val.as_builtin().basic_as_string() + ) + } + _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), + }, + RangeOp::BitNot => { + write!(f, "~{}", lhs) + } + _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), + }, _ => write!(f, ""), } } @@ -41,20 +58,20 @@ impl From for Elem { impl From for Elem { fn from(c: ContextVarNode) -> Self { - Elem::Reference(Reference::new(c.into())) + Elem::Dynamic(Dynamic::new(c.into())) } } impl From for Elem { fn from(idx: NodeIdx) -> Self { - Elem::Reference(Reference::new(idx)) + Elem::Dynamic(Dynamic::new(idx)) } } impl Elem { pub fn contains_node(&self, node_idx: NodeIdx) -> bool { match self { - Self::Reference(d) => d.idx == node_idx, + Self::Dynamic(d) => d.idx == node_idx, Self::Concrete(_) => false, Self::Expr(expr) => expr.contains_node(node_idx), Self::ConcreteDyn(d) => d.contains_node(node_idx), @@ -62,6 +79,13 @@ impl Elem { } } + pub fn expect_into_expr(self) -> RangeExpr { + match self { + Self::Expr(expr) => expr, + _ => panic!("Not expression"), + } + } + pub fn dyn_map(&self) -> Option<&BTreeMap> { match self { Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), @@ -118,9 +142,9 @@ impl Elem { } } -impl From for Elem { - fn from(dy: Reference) -> Self { - Elem::Reference(dy) +impl From for Elem { + fn from(dy: Dynamic) -> Self { + Elem::Dynamic(dy) } } @@ -131,9 +155,46 @@ impl From> for Elem { } impl Elem { + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { + match self { + Self::Dynamic(Dynamic { idx, .. }) => { + if *idx == to_replace { + *self = replacement; + } + } + Self::Concrete(_) => {} + Self::Expr(expr) => { + expr.lhs.replace_dep(to_replace, replacement.clone()); + expr.rhs.replace_dep(to_replace, replacement); + expr.maximized = None; + expr.minimized = None; + } + Self::ConcreteDyn(_d) => todo!(), + Self::Null => {} + } + } + + pub fn inverse_if_boolean(&self) -> Option { + match self { + Self::Dynamic(Dynamic { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), + Self::ConcreteDyn(_d) => None, + Self::Null => None, + } + } + pub fn node_idx(&self) -> Option { match self { - Self::Reference(Reference { idx, .. }) => Some(*idx), + Self::Dynamic(Dynamic { idx, .. }) => Some(*idx), _ => None, } } @@ -155,7 +216,7 @@ impl Elem { val: Concrete::Int(_, val), .. }) if val < &I256::zero() => true, - Elem::Reference(dy) => { + Elem::Dynamic(dy) => { if maximize { dy.maximize(analyzer)?.is_negative(maximize, analyzer)? } else { @@ -185,6 +246,13 @@ impl Elem { } } + pub fn maybe_concrete_value(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + pub fn maybe_range_dyn(&self) -> Option> { match self { Elem::ConcreteDyn(a) => Some(*a.clone()), @@ -203,21 +271,29 @@ impl RangeElem for Elem { fn range_ord(&self, other: &Self) -> Option { match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => { - let ord = a.range_ord(b); - if ord.is_none() { - println!("couldnt compare: {a:?} {b:?}"); - } - - ord - } + (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), + (Self::Dynamic(a), Self::Dynamic(b)) => a.range_ord(b), _ => None, } } + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + match self { + Self::Dynamic(d) => d.flatten(maximize, analyzer), + Self::Concrete(c) => c.flatten(maximize, analyzer), + Self::Expr(expr) => expr.flatten(maximize, analyzer), + Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), + Self::Null => Ok(Elem::Null), + } + } + fn dependent_on(&self) -> Vec { match self { - Self::Reference(d) => d.dependent_on(), + Self::Dynamic(d) => d.dependent_on(), Self::Concrete(_) => vec![], Self::Expr(expr) => expr.dependent_on(), Self::ConcreteDyn(d) => d.dependent_on(), @@ -227,7 +303,7 @@ impl RangeElem for Elem { fn update_deps(&mut self, mapping: &BTreeMap) { match self { - Self::Reference(d) => d.update_deps(mapping), + Self::Dynamic(d) => d.update_deps(mapping), Self::Concrete(_) => {} Self::Expr(expr) => expr.update_deps(mapping), Self::ConcreteDyn(d) => d.update_deps(mapping), @@ -237,7 +313,7 @@ impl RangeElem for Elem { fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { match self { - Self::Reference(ref mut d) => { + Self::Dynamic(ref mut d) => { if d.idx == node_idx { d.idx = new_idx } @@ -252,7 +328,7 @@ impl RangeElem for Elem { fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { use Elem::*; let res = match self { - Reference(dy) => dy.maximize(analyzer)?, + Dynamic(dy) => dy.maximize(analyzer)?, Concrete(inner) => inner.maximize(analyzer)?, ConcreteDyn(inner) => inner.maximize(analyzer)?, Expr(expr) => expr.maximize(analyzer)?, @@ -264,7 +340,7 @@ impl RangeElem for Elem { fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { use Elem::*; let res = match self { - Reference(dy) => dy.minimize(analyzer)?, + Dynamic(dy) => dy.minimize(analyzer)?, Concrete(inner) => inner.minimize(analyzer)?, ConcreteDyn(inner) => inner.minimize(analyzer)?, Expr(expr) => expr.minimize(analyzer)?, @@ -273,34 +349,40 @@ impl RangeElem for Elem { Ok(res) } - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { use Elem::*; - let res = match self { - Reference(dy) => dy.simplify_maximize(analyzer)?, - Concrete(inner) => inner.simplify_maximize(analyzer)?, - ConcreteDyn(inner) => inner.simplify_maximize(analyzer)?, - Expr(expr) => expr.simplify_maximize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) + match self { + Dynamic(dy) => dy.simplify_maximize(exclude, analyzer), + Concrete(inner) => inner.simplify_maximize(exclude, analyzer), + ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), + Expr(expr) => expr.simplify_maximize(exclude, analyzer), + Null => Ok(Elem::Null), + } } - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { use Elem::*; - let res = match self { - Reference(dy) => dy.simplify_minimize(analyzer)?, - Concrete(inner) => inner.simplify_minimize(analyzer)?, - ConcreteDyn(inner) => inner.simplify_minimize(analyzer)?, - Expr(expr) => expr.simplify_minimize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) + match self { + Dynamic(dy) => dy.simplify_minimize(exclude, analyzer), + Concrete(inner) => inner.simplify_minimize(exclude, analyzer), + ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), + Expr(expr) => expr.simplify_minimize(exclude, analyzer), + Null => Ok(Elem::Null), + } } fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { use Elem::*; match self { - Reference(dy) => dy.cache_maximize(analyzer), + Dynamic(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), Expr(expr) => expr.cache_maximize(analyzer), @@ -311,7 +393,7 @@ impl RangeElem for Elem { fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { use Elem::*; match self { - Reference(dy) => dy.cache_minimize(analyzer), + Dynamic(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), Expr(expr) => expr.cache_minimize(analyzer), @@ -321,13 +403,29 @@ impl RangeElem for Elem { fn uncache(&mut self) { use Elem::*; match self { - Reference(dy) => dy.uncache(), + Dynamic(dy) => dy.uncache(), Concrete(inner) => inner.uncache(), ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), Null => {} } } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + use Elem::*; + match self { + Dynamic(dy) => dy.contains_op_set(max, op_set, analyzer), + Concrete(inner) => inner.contains_op_set(max, op_set, analyzer), + ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), + Expr(expr) => expr.contains_op_set(max, op_set, analyzer), + Null => Ok(false), + } + } } impl Add for Elem { diff --git a/crates/range/elem/expr.rs b/crates/range/elem/expr.rs index 0d2644b0..e0870e86 100644 --- a/crates/range/elem/expr.rs +++ b/crates/range/elem/expr.rs @@ -1,3 +1,28 @@ + + +static SINGLETON_EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, +]; + +static EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::And, + RangeOp::Or, +]; + +static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; + + /// A range expression composed of other range [`Elem`] #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeExpr { @@ -8,6 +33,33 @@ pub struct RangeExpr { pub rhs: Box>, } +impl RangeExpr { + pub fn inverse_if_boolean(&self) -> Option { + if EQ_OPS.contains(&self.op) { + if SINGLETON_EQ_OPS.contains(&self.op) { + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.logical_inverse().unwrap(); + Some(new_self) + } else { + // non-singleton, i.e. AND or OR + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.inverse().unwrap(); + if let Some(new_lhs) = new_self.inverse_if_boolean() { + *new_self.lhs = Elem::Expr(new_lhs); + } + if let Some(new_rhs) = new_self.inverse_if_boolean() { + *new_self.rhs = Elem::Expr(new_rhs); + } + Some(new_self) + } + } else { + None + } + } +} + impl RangeExpr { /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { @@ -30,6 +82,18 @@ impl RangeElem for RangeExpr { false } + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Expr(RangeExpr::new( + self.lhs.flatten(maximize, analyzer)?, + self.op, + self.rhs.flatten(maximize, analyzer)?, + ))) + } + fn range_ord(&self, _other: &Self) -> Option { todo!() } @@ -65,11 +129,35 @@ impl RangeElem for RangeExpr { } } - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - self.simplify_exec_op(true, analyzer) + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let l = self.lhs.simplify_maximize(exclude, analyzer)?; + let r = self.rhs.simplify_maximize(exclude, analyzer)?; + match collapse(l, self.op, r) { + MaybeCollapsed::Collapsed(collapsed) => collapsed + .expect_into_expr() + .simplify_exec_op(true, exclude, analyzer), + MaybeCollapsed::Not(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(true, exclude, analyzer) + } + } } - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - self.simplify_exec_op(false, analyzer) + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let l = self.lhs.simplify_minimize(exclude, analyzer)?; + let r = self.rhs.simplify_minimize(exclude, analyzer)?; + match collapse(l, self.op, r) { + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) + } + } } fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { @@ -89,4 +177,390 @@ impl RangeElem for RangeExpr { fn uncache(&mut self) { self.uncache_exec(); } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + if op_set.contains(&self.op) { + Ok(true) + } else { + self.lhs.contains_op_set(max, op_set, analyzer)?; + self.rhs.contains_op_set(max, op_set, analyzer) + } + } +} + +enum MaybeCollapsed { + Collapsed(Elem), + Not(Elem, Elem), +} + +fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { + let zero = Elem::from(Concrete::from(U256::zero())); + match (l.clone(), r.clone()) { + // if we have an expression, it fundamentally must have a dynamic in it + (Elem::Expr(expr), c @ Elem::Concrete(_)) => { + // potentially collapsible + let x = expr.lhs; + let y = expr.rhs; + let z = c; + match (expr.op, op) { + (RangeOp::Eq, RangeOp::Eq) => { + // ((x == y) == z) + // can skip if x and z eq + if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z) { + MaybeCollapsed::Collapsed(l) + } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z) { + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(true))) { + MaybeCollapsed::Collapsed(l) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(l_op), RangeOp::Add(r_op)) => { + // ((x + y) + z) + let op_fn = if l_op && r_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { + // ((x + y) - z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && y >= z ==> x + (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + let new_expr = Elem::Expr(RangeExpr::new(*x, expr.op, new)); + MaybeCollapsed::Collapsed(new_expr) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x - (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => { + // x and z are concrete, if x >= z, just do (x - z) + y + // else do (y - (z - x)) + match x.range_ord(&z) { + Some(std::cmp::Ordering::Equal) + | Some(std::cmp::Ordering::Greater) => { + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, expr.op, new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // (y - (z - x)) because z > x, therefore its (-k + y) ==> (y - k) where k = (x - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *y, + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => MaybeCollapsed::Not(l, r), + } + } + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { + // ((x - y) + z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && z <= y ==> x - (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, expr.op, new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x + (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, + RangeOp::Add(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => { + // x and z are concrete, just add them ==> (x + z) - y + let op_fn = if l_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + new, expr.op, *y, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Mul(l_op), RangeOp::Mul(r_op)) => { + // ((x * y) * z) + if l_op == r_op { + let op_fn = if l_op { + // unchecked + RangeMul::range_wrapping_mul + } else { + // checked + as RangeMul>::range_mul + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(wrapping), op) if EQ_OPS.contains(&op) => { + let const_op = if wrapping { + RangeSub::range_wrapping_sub + } else { + RangeSub::range_sub + }; + // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) + // .. + // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) + if let Some(new) = const_op(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = const_op(&z, &x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Sub(wrapping), op) if EQ_OPS.contains(&op) => { + let op_y = if wrapping { + as RangeAdd>::range_wrapping_add + } else { + as RangeAdd>::range_add + }; + let op_x = if wrapping { + as RangeSub>::range_wrapping_sub + } else { + as RangeSub>::range_sub + }; + // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) + // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) + if let Some(new) = op_x(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_y(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Mul(wrapping), op) if EQ_OPS.contains(&op) => { + let div_op = if wrapping { + RangeDiv::range_wrapping_div + } else { + RangeDiv::range_div + }; + // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) + // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) + if let Some(new) = div_op(&z, &x) { + let new_op = if matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, new_op, new))) + } else if let Some(new) = div_op(&z, &y) { + let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Div(wrapping), op) if EQ_OPS.contains(&op) => { + let mul_op = if wrapping { + as RangeMul>::range_wrapping_mul + } else { + as RangeMul>::range_mul + }; + let div_op = if wrapping { + as RangeDiv>::range_wrapping_div + } else { + as RangeDiv>::range_div + }; + + // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) + // .. + // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) + if let Some(new) = mul_op(&z, &y) { + let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + } else if !FLIP_INEQ_OPS.contains(&op) { + if let Some(new) = div_op(&x, &z) { + // y is the dynamic element + // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially + // but we dont know if y was negative. so we limit to just eq & neq + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (_, RangeOp::Eq) => { + // (x _ y) == z ==> (x _ y if z == true) + if z.range_eq(&Elem::from(Concrete::from(true))) { + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(false))) { + // (!x && !y) + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(l, r), + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (_, RangeOp::Neq) => { + // (x _ y) != z ==> (x _ y if z != false) + if z.range_eq(&Elem::from(Concrete::from(false))) { + // != false is == true + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(true))) { + // != true is == false, to make it == true, inverse everything + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(l, r), + } + } else { + MaybeCollapsed::Not(l, r) + } + } + _ => MaybeCollapsed::Not(l, r), + } + } + (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone()) { + collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, + MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), + }, + _ => MaybeCollapsed::Not(l, r), + } } \ No newline at end of file diff --git a/crates/range/elem/map_or_array.rs b/crates/range/elem/map_or_array.rs index f9a5ff6d..57814a3a 100644 --- a/crates/range/elem/map_or_array.rs +++ b/crates/range/elem/map_or_array.rs @@ -24,7 +24,7 @@ impl RangeElem for RangeDyn { } fn range_ord(&self, _other: &Self) -> Option { - todo!() + None } fn dependent_on(&self) -> Vec { @@ -38,6 +38,26 @@ impl RangeElem for RangeDyn { deps } + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.flatten(maximize, analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.flatten(maximize, analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + fn update_deps(&mut self, mapping: &BTreeMap) { self.len.update_deps(mapping); self.val @@ -99,30 +119,38 @@ impl RangeElem for RangeDyn { }))) } - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, maximized: None, - len: self.len.simplify_maximize(analyzer)?, + len: self.len.simplify_maximize(exclude, analyzer)?, val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_maximize(analyzer)?); + map.insert(idx, val.simplify_maximize(exclude, analyzer)?); } map }, loc: self.loc, }))) } - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, maximized: None, - len: self.len.simplify_minimize(analyzer)?, + len: self.len.simplify_minimize(exclude, analyzer)?, val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_minimize(analyzer)?); + map.insert(idx, val.simplify_minimize(exclude, analyzer)?); } map }, @@ -148,4 +176,14 @@ impl RangeElem for RangeDyn { self.minimized = None; self.maximized = None; } + + fn contains_op_set( + &self, + _max: bool, + _op_set: &[RangeOp], + _: &impl GraphLike, + ) -> Result { + // TODO: reevaluate this + Ok(false) + } } \ No newline at end of file diff --git a/crates/range/elem/mod.rs b/crates/range/elem/mod.rs index 826c8f0f..d6a81eda 100644 --- a/crates/range/elem/mod.rs +++ b/crates/range/elem/mod.rs @@ -90,6 +90,25 @@ impl RangeOp { Shr => Some(Shl), Eq => Some(Neq), Neq => Some(Eq), + Lt => Some(Gt), + Lte => Some(Gte), + Gt => Some(Lt), + Gte => Some(Lte), + _ => None, // e => panic!("tried to inverse unreversable op: {:?}", e), + } + } + + pub fn logical_inverse(self) -> Option { + use RangeOp::*; + match self { + Eq => Some(Neq), + Neq => Some(Eq), + Lt => Some(Gte), + Lte => Some(Gt), + Gt => Some(Lte), + Gte => Some(Lt), + Or => Some(And), + And => Some(Or), _ => None, // e => panic!("tried to inverse unreversable op: {:?}", e), } } @@ -144,17 +163,30 @@ impl ToString for RangeOp { } pub trait RangeElem { + /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables + fn flatten(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + /// Maximizes the element and caches the result for quicker use later fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + /// Minimizes the element and caches the result for quicker use later fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + /// Uncaches the minimum and maximum fn uncache(&mut self); /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError>; /// Checks if two range elements are equal fn range_eq(&self, other: &Self) -> bool; /// Tries to compare the ordering of two range elements @@ -185,4 +217,11 @@ pub trait RangeElem { /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a /// cyclic dependency. fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result; } diff --git a/crates/range/elem/reference.rs b/crates/range/elem/reference.rs index 8fd6d5dc..7269770a 100644 --- a/crates/range/elem/reference.rs +++ b/crates/range/elem/reference.rs @@ -22,8 +22,12 @@ impl RangeElem for Reference { false } - fn range_ord(&self, _other: &Self) -> Option { - todo!() + fn range_ord(&self, other: &Self) -> Option { + if self.idx == other.idx { + Some(std::cmp::Ordering::Equal) + } else { + None + } } fn dependent_on(&self) -> Vec { @@ -36,6 +40,30 @@ impl RangeElem for Reference { } } + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + if cvar.is_independent_and_storage_or_calldata(analyzer)? { + return Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))); + } + if maximize { + cvar.range_max(analyzer)? + .unwrap() + .flatten(maximize, analyzer) + } else { + let flattened = cvar + .range_min(analyzer)? + .unwrap() + .flatten(maximize, analyzer)?; + Ok(flattened) + } + } + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { @@ -88,60 +116,38 @@ impl RangeElem for Reference { } } - fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - // let cvar = ContextVarNode::from(self.idx); - // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Reference(self.clone())) - // } - // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Reference(self.clone())) - // } - // let cvar = cvar.underlying(analyzer)?; - // match &cvar.ty { - // VarType::User(TypeNode::Contract(_), maybe_range) - // | VarType::User(TypeNode::Enum(_), maybe_range) - // | VarType::User(TypeNode::Ty(_), maybe_range) - // | VarType::BuiltIn(_, maybe_range) => { - // if let Some(range) = maybe_range { - // range.simplified_range_max(analyzer) - // } else { - // Ok(Elem::Reference(self.clone())) - // } - // } - // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - // val: concrete_node.underlying(analyzer)?.clone(), - // loc: cvar.loc.unwrap_or(Loc::Implicit), - // })), - // _e => Ok(Elem::Reference(self.clone())), - // } + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + + let independent = cvar.is_independent_and_storage_or_calldata(analyzer)?; + if independent { + Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))) + } else { + self.flatten(true, analyzer)? + .simplify_maximize(exclude, analyzer) + } } - fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - // let cvar = ContextVarNode::from(self.idx); - // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Reference(self.clone())) - // } - // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Reference(self.clone())) - // } - // let cvar = cvar.underlying(analyzer)?; - - // match &cvar.ty { - // VarType::User(TypeNode::Contract(_), maybe_range) - // | VarType::User(TypeNode::Enum(_), maybe_range) - // | VarType::User(TypeNode::Ty(_), maybe_range) - // | VarType::BuiltIn(_, maybe_range) => { - // if let Some(range) = maybe_range { - // range.simplified_range_min(analyzer) - // } else { - // Ok(Elem::Reference(self.clone())) - // } - // } - // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - // val: concrete_node.underlying(analyzer)?.clone(), - // loc: cvar.loc.unwrap_or(Loc::Implicit), - // })), - // _e => Ok(Elem::Reference(self.clone())), - // } + + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + if cvar.is_independent_and_storage_or_calldata(analyzer)? { + Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))) + } else { + self.flatten(false, analyzer)? + .simplify_minimize(exclude, analyzer) + } } fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { @@ -162,4 +168,31 @@ impl RangeElem for Reference { self.minimized = None; self.maximized = None; } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + if max { + range.max.contains_op_set(max, op_set, analyzer) + } else { + range.min.contains_op_set(max, op_set, analyzer) + } + } else { + Ok(false) + } + } + VarType::Concrete(_concrete_node) => Ok(false), + _e => Ok(false), + } + } } \ No newline at end of file diff --git a/crates/range/exec/add.rs b/crates/range/exec/add.rs index 01c1b73c..a9bf7a18 100644 --- a/crates/range/exec/add.rs +++ b/crates/range/exec/add.rs @@ -91,21 +91,21 @@ impl RangeAdd for RangeConcrete { impl RangeAdd for Elem { fn range_add(&self, other: &Self) -> Option> { match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { Some(other.clone()) } (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), _ => None, } } fn range_wrapping_add(&self, other: &Self) -> Option> { match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { Some(other.clone()) } (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), _ => None, } } diff --git a/crates/range/exec/bitwise.rs b/crates/range/exec/bitwise.rs index 4ac5a776..d8984ae9 100644 --- a/crates/range/exec/bitwise.rs +++ b/crates/range/exec/bitwise.rs @@ -170,4 +170,4 @@ impl RangeBitwise for Elem { _ => None, } } -} +} \ No newline at end of file diff --git a/crates/range/exec/cast.rs b/crates/range/exec/cast.rs index ec122be9..ce78c84d 100644 --- a/crates/range/exec/cast.rs +++ b/crates/range/exec/cast.rs @@ -200,8 +200,8 @@ impl RangeCast> for RangeDyn { )), None, ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } diff --git a/crates/range/exec/concat.rs b/crates/range/exec/concat.rs index 194506e2..c7fa9481 100644 --- a/crates/range/exec/concat.rs +++ b/crates/range/exec/concat.rs @@ -127,8 +127,8 @@ impl RangeConcat> for RangeDyn { loc: other.loc, }))) } - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } diff --git a/crates/range/exec/div.rs b/crates/range/exec/div.rs index f1eb12c7..f64a4205 100644 --- a/crates/range/exec/div.rs +++ b/crates/range/exec/div.rs @@ -145,4 +145,4 @@ impl RangeDiv for Elem { _ => None, } } -} +} \ No newline at end of file diff --git a/crates/range/exec/max.rs b/crates/range/exec/max.rs index 2d6aa7a9..0a5da292 100644 --- a/crates/range/exec/max.rs +++ b/crates/range/exec/max.rs @@ -1,4 +1,3 @@ - pub trait RangeMax { /// Take the maximum of two range elements fn range_max(&self, other: &Rhs) -> Option>; diff --git a/crates/range/exec/mod.rs b/crates/range/exec/mod.rs index e2ea46a6..71a14f4d 100644 --- a/crates/range/exec/mod.rs +++ b/crates/range/exec/mod.rs @@ -1,5 +1,3 @@ - - /// For execution of operations to be performed on range expressions pub trait ExecOp { /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side @@ -27,14 +25,16 @@ pub trait ExecOp { fn simplify_spread( &self, + exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; + ) -> Result<((Elem, Elem, Elem, Elem), bool), GraphError>; fn uncache_exec(&mut self); fn simplify_exec_op( &self, maximize: bool, + exclude: &mut Vec, analyzer: &impl GraphLike, ) -> Result, GraphError>; @@ -75,9 +75,25 @@ impl ExecOp for RangeExpr { fn simplify_exec_op( &self, maximize: bool, + exclude: &mut Vec, analyzer: &impl GraphLike, ) -> Result, GraphError> { - let parts = self.simplify_spread(analyzer)?; + let (parts, lhs_is_conc) = self.simplify_spread(exclude, analyzer)?; + if self.op == RangeOp::Cast { + // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete + if lhs_is_conc { + return self.exec_op(maximize, analyzer); + } else { + // we can drop the cast if the max of the dynamic lhs is less than the cast + let concretized_lhs = self.lhs.maximize(analyzer)?; + if matches!( + concretized_lhs.range_ord(&self.rhs), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ) { + return Ok(*self.lhs.clone()); + } + } + } self.exec(parts, maximize) } @@ -102,21 +118,26 @@ impl ExecOp for RangeExpr { fn simplify_spread( &self, + exclude: &mut Vec, analyzer: &impl GraphLike, ) -> Result< ( - Elem, - Elem, - Elem, - Elem, + ( + Elem, + Elem, + Elem, + Elem, + ), + bool, ), GraphError, > { - let lhs_min = self.lhs.simplify_minimize(analyzer)?; - let lhs_max = self.lhs.simplify_maximize(analyzer)?; - let rhs_min = self.rhs.simplify_minimize(analyzer)?; - let rhs_max = self.rhs.simplify_maximize(analyzer)?; - Ok((lhs_min, lhs_max, rhs_min, rhs_max)) + let lhs_min = self.lhs.simplify_minimize(exclude, analyzer)?; + let lhs_max = self.lhs.simplify_maximize(exclude, analyzer)?; + let rhs_min = self.rhs.simplify_minimize(exclude, analyzer)?; + let rhs_max = self.rhs.simplify_maximize(exclude, analyzer)?; + let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); + Ok(((lhs_min, lhs_max, rhs_min, rhs_max), lhs_is_conc)) } fn exec( @@ -145,17 +166,54 @@ impl ExecOp for RangeExpr { let rhs_min_neg = rhs_min.pre_evaled_is_negative(); let rhs_max_neg = rhs_max.pre_evaled_is_negative(); + let consts = ( + matches!(lhs_min.range_ord(&lhs_max), Some(std::cmp::Ordering::Equal)), + matches!(rhs_min.range_ord(&rhs_max), Some(std::cmp::Ordering::Equal)), + ); + + fn fallback( + this: &RangeExpr, + lhs: Elem, + rhs: Elem, + consts: (bool, bool), + ) -> Elem { + // println!("fallback exec: {} {} {}", this.lhs, this.op.to_string(), this.rhs); + match consts { + (true, true) => { + // println!("true true: {} {} {}", lhs, this.op.to_string(), rhs); + Elem::Expr(RangeExpr::new(lhs, this.op, rhs)) + } + (false, true) => { + // println!("false true: {} {} {}", this.lhs, this.op.to_string(), rhs); + Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)) + } + (true, false) => { + // println!("true false: {} {} {}", lhs, this.op.to_string(), this.rhs); + Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())) + } + (false, false) => { + // println!("false false: {} {} {}", this.lhs, this.op.to_string(), this.rhs); + Elem::Expr(this.clone()) + } + } + } + let res = match self.op { RangeOp::Add(unchecked) => { if unchecked { - let candidates = vec![ + let mut candidates = vec![ lhs_min.range_wrapping_add(&rhs_min), lhs_min.range_wrapping_add(&rhs_max), lhs_max.range_wrapping_add(&rhs_min), lhs_max.range_wrapping_add(&rhs_max), - lhs_max.range_add(&rhs_max), - lhs_min.range_add(&rhs_min), ]; + + // if they arent constants, we can test a normal add + if !matches!(consts, (true, true)) { + candidates.push(lhs_max.range_add(&rhs_max)); + candidates.push(lhs_min.range_add(&rhs_min)); + } + let mut candidates = candidates.into_iter().flatten().collect::>(); candidates.sort_by(|a, b| match a.range_ord(b) { Some(r) => r, @@ -163,7 +221,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -175,11 +233,11 @@ impl ExecOp for RangeExpr { // if we are maximizing, the largest value will always just be the the largest value + the largest value lhs_max .range_add(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { lhs_min .range_add(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Sub(unchecked) => { @@ -197,7 +255,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -209,12 +267,12 @@ impl ExecOp for RangeExpr { // if we are maximizing, the largest value will always just be the the largest value - the smallest value lhs_max .range_sub(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { // if we are minimizing, the smallest value will always be smallest value - largest value lhs_min .range_sub(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Mul(unchecked) => { @@ -232,7 +290,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -249,7 +307,7 @@ impl ExecOp for RangeExpr { // largest positive value lhs_min .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (true, false, true, false) => { // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller @@ -263,30 +321,30 @@ impl ExecOp for RangeExpr { } (None, Some(max_expr)) => max_expr, (Some(min_expr), None) => min_expr, - (None, None) => Elem::Expr(self.clone()), + (None, None) => fallback(self, lhs_min, rhs_min, consts), } } (_, false, _, false) => { // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value lhs_max .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (false, false, true, true) => { // since we are forced to go negative here, values closest to 0 will ensure we get the maximum lhs_min .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (true, true, false, false) => { // since we are forced to go negative here, values closest to 0 will ensure we get the maximum lhs_max .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (true, _, true, _) => lhs_min .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())), + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), (false, true, _, _) | (_, _, false, true) => { panic!("unsatisfiable range") } @@ -297,14 +355,14 @@ impl ExecOp for RangeExpr { // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value lhs_min .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (true, true, true, true) => { // all negative, will be max * max because those are closest to 0 resulting in the // smallest positive value lhs_max .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (true, false, true, false) => { // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller @@ -318,24 +376,24 @@ impl ExecOp for RangeExpr { } (None, Some(max_expr)) => max_expr, (Some(min_expr), None) => min_expr, - (None, None) => Elem::Expr(self.clone()), + (None, None) => fallback(self, lhs_min, rhs_min, consts), } } (true, _, _, false) => { // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value lhs_min .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (_, false, _, true) => { // just lhs has a positive value, most negative will be lhs_max, rhs_max lhs_max .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } (false, false, true, false) => lhs_max .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())), + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), (false, true, _, _) | (_, _, false, true) => { panic!("unsatisfiable range") } @@ -390,7 +448,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -399,109 +457,109 @@ impl ExecOp for RangeExpr { candidates[0].clone() } // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger - // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // max_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // min_expr - // } - // _ => { - // max_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (false, false, true, true) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, false, false) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, false, _) => { - // // lhs is positive, rhs min is positive, guaranteed to give largest - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, false) => { - // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, true, _) => { - // // at this point, its either all trues, or a single false - // // given that, to maximize, the only way to get a positive value is to use the most negative values - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger + // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // max_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // min_expr + // } + // _ => { + // max_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (false, false, true, true) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, false, false) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, false, _) => { + // // lhs is positive, rhs min is positive, guaranteed to give largest + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, false) => { + // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, true, _) => { + // // at this point, its either all trues, or a single false + // // given that, to maximize, the only way to get a positive value is to use the most negative values + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (false, false, false, false) => { - // // smallest number will be lhs_min / rhs_min since both are positive - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, true) => { - // // smallest number will be lhs_max / rhs_min since both are negative - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, false) => { - // // The way to maintain most negative value is lhs_min / rhs_max, all others would go - // // positive or guaranteed to be closer to 0 - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger - // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // min_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // max_expr - // } - // _ => { - // min_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (_, false, true, _) => { - // // We are going negative here, so it will be most positive / least negative - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, _) => { - // // We are going negative here, so it will be most negative / least positive - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (false, false, false, false) => { + // // smallest number will be lhs_min / rhs_min since both are positive + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, true) => { + // // smallest number will be lhs_max / rhs_min since both are negative + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, false) => { + // // The way to maintain most negative value is lhs_min / rhs_max, all others would go + // // positive or guaranteed to be closer to 0 + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger + // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // min_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // max_expr + // } + // _ => { + // min_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (_, false, true, _) => { + // // We are going negative here, so it will be most positive / least negative + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, _) => { + // // We are going negative here, so it will be most negative / least positive + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } } // RangeOp::Mod => { @@ -521,7 +579,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -530,38 +588,38 @@ impl ExecOp for RangeExpr { candidates[0].clone() } // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // // counter-intuitively, we want the maximum value from a call to minimum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the minimum values but getting the larger of the minimum - // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // // counter-intuitively, we want the maximum value from a call to minimum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the minimum values but getting the larger of the minimum + // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } } RangeOp::Max => { @@ -578,7 +636,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -587,85 +645,94 @@ impl ExecOp for RangeExpr { candidates[0].clone() } // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (_, true, _, true) | (_, false, _, false) => { - // // counter-intuitively, we want the minimum value from a call to maximum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the maximum values but getting the smaller of the maximum - // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, true) => { - // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, _, false) => { - // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (_, true, _, true) | (_, false, _, false) => { + // // counter-intuitively, we want the minimum value from a call to maximum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the maximum values but getting the smaller of the maximum + // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, true) => { + // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, _, false) => { + // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } // } } RangeOp::Gt => { if maximize { lhs_max .range_gt(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { lhs_min .range_gt(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Lt => { if maximize { lhs_min .range_lt(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { lhs_max .range_lt(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Gte => { if maximize { lhs_max .range_gte(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { lhs_min .range_gte(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Lte => { if maximize { lhs_min .range_lte(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { lhs_max .range_lte(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::Eq => { + // prevent trying to eval when we have dependents + if !lhs_min.dependent_on().is_empty() + || !lhs_max.dependent_on().is_empty() + || !rhs_min.dependent_on().is_empty() + || !rhs_max.dependent_on().is_empty() + { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + let loc = if let Some(c) = lhs_min.maybe_concrete() { c.loc } else if let Some(c) = lhs_max.maybe_concrete() { @@ -708,7 +775,7 @@ impl ExecOp for RangeExpr { loc, }) } else { - Elem::Expr(self.clone()) + fallback(self, lhs_min, rhs_min, consts) } } else { // check if either lhs element is *not* contained by rhs @@ -738,6 +805,14 @@ impl ExecOp for RangeExpr { } } RangeOp::Neq => { + // prevent trying to eval when we have dependents + if !lhs_min.dependent_on().is_empty() + || !lhs_max.dependent_on().is_empty() + || !rhs_min.dependent_on().is_empty() + || !rhs_max.dependent_on().is_empty() + { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } let loc = if let Some(c) = lhs_min.maybe_concrete() { c.loc } else if let Some(c) = lhs_max.maybe_concrete() { @@ -749,91 +824,65 @@ impl ExecOp for RangeExpr { } else { Loc::Implicit }; - if maximize { - // check if either lhs element is *not* contained by rhs - match ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }), - // if any of those are not equal, we can construct - // an element that is true - _ => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }), - } - } else { - // if they are constants and equal, we can stop here - // (rhs min == rhs max) == (lhs min == lhs max ) - if let ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) = ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - // they aren't constants, check if there is any overlap - match ( - // check if lhs minimum is contained within the right hand side - // this means the values could be equal - // effectively: - // rhs min <= lhs min <= rhs max - lhs_min.range_ord(&rhs_min), - lhs_min.range_ord(&rhs_max), - ) { - (_, Some(std::cmp::Ordering::Equal)) - | (Some(std::cmp::Ordering::Equal), _) - | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { + if maximize { + // the only case here in which we can't assert that + // true is the maximum is when they are both consts and equal + if matches!(consts, (true, true)) { + // both are consts, check if they are equal + if matches!(lhs_min.range_ord(&rhs_min), Some(std::cmp::Ordering::Equal)) { return Ok(Elem::Concrete(RangeConcrete { val: Concrete::Bool(false), loc, - })) + })); } - _ => {} } - match ( - // check if the lhs maximum is contained within the right hand side - // effectively: - // rhs min <= lhs max <= rhs max - lhs_max.range_ord(&rhs_min), - lhs_max.range_ord(&rhs_max), - ) { - (_, Some(std::cmp::Ordering::Equal)) - | (Some(std::cmp::Ordering::Equal), _) - | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }) + } else { + // we *want* to produce false + if matches!(consts, (true, true)) { + // both are consts, check if we are forced to return true + if matches!( + lhs_min.range_ord(&rhs_min), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Less) + ) { return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), + val: Concrete::Bool(true), loc, - })) + })); } - _ => {} } - Elem::Expr(self.clone()) + // check for any overlap + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + + // if lhs max is less than the rhs min, it has to be != (true) + if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + })); + } + + // if lhs min is greater than the rhs max, it has to be != (true) + if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + })); + } + + // we can force an equal value if needed + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + }) + // fallback(self, lhs_min, rhs_min, consts) } } RangeOp::Shl => { @@ -850,7 +899,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -873,7 +922,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -896,7 +945,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -919,7 +968,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -938,7 +987,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -963,7 +1012,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -987,7 +1036,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1044,7 +1093,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1101,7 +1150,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1158,7 +1207,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1185,13 +1234,13 @@ impl ExecOp for RangeExpr { if min_contains && max_contains { match lhs_min { Elem::Concrete( - r @ RangeConcrete { + ref r @ RangeConcrete { val: Concrete::Uint(..), .. }, ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), Elem::Concrete( - r @ RangeConcrete { + ref r @ RangeConcrete { val: Concrete::Int(..), .. }, @@ -1207,7 +1256,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1231,7 +1280,7 @@ impl ExecOp for RangeExpr { }); if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); + return Ok(fallback(self, lhs_min, rhs_min, consts)); } if maximize { @@ -1240,7 +1289,7 @@ impl ExecOp for RangeExpr { candidates[0].clone() } } - _ => Elem::Expr(self.clone()), + _ => fallback(self, lhs_min, rhs_min, consts), }; Ok(res) } diff --git a/crates/range/exec/modulo.rs b/crates/range/exec/modulo.rs index 5e1278ef..fa643b8e 100644 --- a/crates/range/exec/modulo.rs +++ b/crates/range/exec/modulo.rs @@ -42,4 +42,4 @@ impl RangeMod for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/range/exec/mul.rs b/crates/range/exec/mul.rs index 6a9da09b..409af3cc 100644 --- a/crates/range/exec/mul.rs +++ b/crates/range/exec/mul.rs @@ -91,6 +91,8 @@ impl RangeMul for Elem { (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { Some(other.clone()) } + (Elem::Concrete(a), b) if a.val.into_u256() == Some(U256::from(1)) => Some(b.clone()), + (a, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::from(1)) => Some(a.clone()), _ => None, } } @@ -102,6 +104,8 @@ impl RangeMul for Elem { (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { Some(other.clone()) } + (Elem::Concrete(a), b) if a.val.into_u256() == Some(U256::from(1)) => Some(b.clone()), + (a, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::from(1)) => Some(a.clone()), _ => None, } } diff --git a/crates/range/exec/shift.rs b/crates/range/exec/shift.rs index c54cd8af..2af111a7 100644 --- a/crates/range/exec/shift.rs +++ b/crates/range/exec/shift.rs @@ -162,4 +162,4 @@ impl RangeShift for Elem { _ => None, } } -} +} \ No newline at end of file diff --git a/crates/range/exec/sub.rs b/crates/range/exec/sub.rs index da7c3750..5673d3be 100644 --- a/crates/range/exec/sub.rs +++ b/crates/range/exec/sub.rs @@ -134,16 +134,16 @@ impl RangeSub for RangeConcrete { impl RangeSub for Elem { fn range_sub(&self, other: &Self) -> Option> { match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), _ => None, } } fn range_wrapping_sub(&self, other: &Self) -> Option> { match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), _ => None, } } diff --git a/crates/range/range_string.rs b/crates/range/range_string.rs index eb73511d..a9682746 100644 --- a/crates/range/range_string.rs +++ b/crates/range/range_string.rs @@ -2,7 +2,7 @@ use crate::analyzer::GraphLike; use crate::context::ContextVarNode; use crate::range::elem::RangeElem; use crate::range::elem::RangeOp; -use crate::range::elem_ty::Reference; +use crate::range::elem_ty::Dynamic; use crate::range::elem_ty::RangeExpr; use crate::range::Elem; use crate::range::RangeDyn; @@ -52,7 +52,7 @@ impl ToRangeString for Elem { fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { + Elem::Dynamic(Dynamic { idx, .. }) => { let cvar = ContextVarNode::from(*idx) .first_version(analyzer) .underlying(analyzer) @@ -68,7 +68,7 @@ impl ToRangeString for Elem { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { + Elem::Dynamic(Dynamic { idx, .. }) => { let as_var = ContextVarNode::from(*idx); let name = as_var.display_name(analyzer).unwrap(); RangeElemString::new(name, as_var.loc(analyzer).unwrap()) @@ -229,7 +229,7 @@ impl ToRangeString for RangeExpr { if matches!(self.op, RangeOp::Min | RangeOp::Max) { RangeElemString::new( - format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), + format!("{}{{{}, {}}}", self.op.to_string(), lhs_str.s, rhs_str.s), lhs_str.loc, ) } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { diff --git a/crates/range/solc_range.rs b/crates/range/solc_range.rs index 33d01683..9d244344 100644 --- a/crates/range/solc_range.rs +++ b/crates/range/solc_range.rs @@ -62,6 +62,12 @@ impl From for SolcRange { } } +impl From> for SolcRange { + fn from(elem: Elem) -> Self { + Self::new(elem.clone(), elem, vec![]) + } +} + impl SolcRange { pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { Self { @@ -73,6 +79,13 @@ impl SolcRange { } } + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Elem) { + self.min.replace_dep(to_replace, replacement.clone()); + self.max.replace_dep(to_replace, replacement); + self.min_cached = None; + self.max_cached = None; + } + pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { let min = self.evaled_range_min(analyzer)?; let max = self.evaled_range_max(analyzer)?; @@ -254,7 +267,7 @@ impl SolcRange { vec![], )) } - Builtin::ReferenceBytes + Builtin::DynamicBytes | Builtin::String | Builtin::Array(_) | Builtin::Mapping(_, _) => Some(SolcRange::new( @@ -513,6 +526,22 @@ impl SolcRange { let max = self.max.neq(Elem::from(other)); Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) } + + pub fn into_flattened_range(&self, analyzer: &impl GraphLike) -> Result { + // println!("----- into flattened range -----"); + let flattened_min = self.range_min().flatten(false, analyzer)?; + // println!("flattened minimum: {}", flattened_min); + let simp_min = flattened_min.simplify_minimize(&mut vec![], analyzer)?; + // println!("simplified minimum: {}", simp_min); + // println!("----- min flattend -----"); + let flattened_max = self.range_max().flatten(true, analyzer)?; + // println!("flattened maximum: {}", flattened_max); + let simp_max = flattened_max.simplify_maximize(&mut vec![], analyzer)?; + // println!("simplified maximum: {}", simp_max); + // println!("----- max flattend -----"); + + Ok(SolcRange::new(simp_min, simp_max, self.exclusions.clone())) + } } impl Range for SolcRange { @@ -560,14 +589,25 @@ impl Range for SolcRange { } } - fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result { - println!("simplified range min"); - self.range_min().simplify_minimize(analyzer) + fn simplified_range_min( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result { + self.range_min() + .flatten(false, analyzer)? + .simplify_minimize(exclude, analyzer) } - fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result { - println!("simplified range max"); - self.range_max().simplify_maximize(analyzer) + fn simplified_range_max( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result { + self.range_max() + .flatten(true, analyzer)? + .simplify_maximize(exclude, analyzer) } + fn range_exclusions(&self) -> Vec { self.exclusions.clone() } @@ -601,8 +641,16 @@ pub trait Range { fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; - fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result; - fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result; + fn simplified_range_min( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result; + fn simplified_range_max( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result; fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy>; fn uncache_range_min(&mut self) { @@ -629,6 +677,7 @@ pub trait Range { fn dependent_on(&self) -> Vec { let mut deps = self.range_min().dependent_on(); deps.extend(self.range_max().dependent_on()); + deps.dedup(); deps } diff --git a/shared/src/nodes/mod.rs b/shared/src/nodes/mod.rs index 4e9b9dee..05bd4b50 100644 --- a/shared/src/nodes/mod.rs +++ b/shared/src/nodes/mod.rs @@ -545,7 +545,7 @@ impl VarType { let name = index.name(analyzer)?; let is_const = index.is_const(analyzer)?; if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { - Elem::Dynamic(Dynamic { idx, .. }) => match analyzer.node(*idx) { + Elem::Reference(Reference { idx, .. }) => match analyzer.node(*idx) { Node::ContextVar(_) => { let cvar = ContextVarNode::from(*idx); cvar.name(analyzer).unwrap() == name diff --git a/shared/src/range/elem_ty.rs b/shared/src/range/elem_ty.rs index 8cd49f88..c8609e45 100644 --- a/shared/src/range/elem_ty.rs +++ b/shared/src/range/elem_ty.rs @@ -11,14 +11,14 @@ use std::ops::*; /// A dynamic range element value #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct Dynamic { +pub struct Reference { /// Index of the node that is referenced pub idx: NodeIdx, pub minimized: Option>, pub maximized: Option>, } -impl Dynamic { +impl Reference { pub fn new(idx: NodeIdx) -> Self { Self { idx, @@ -28,7 +28,7 @@ impl Dynamic { } } -impl RangeElem for Dynamic { +impl RangeElem for Reference { fn range_eq(&self, _other: &Self) -> bool { false } @@ -63,14 +63,14 @@ impl RangeElem for Dynamic { if let Some(range) = maybe_range { range.evaled_range_max(analyzer) } else { - Ok(Elem::Dynamic(self.clone())) + Ok(Elem::Reference(self.clone())) } } VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { val: concrete_node.underlying(analyzer)?.clone(), loc: cvar.loc.unwrap_or(Loc::Implicit), })), - _e => Ok(Elem::Dynamic(self.clone())), + _e => Ok(Elem::Reference(self.clone())), } } @@ -88,24 +88,24 @@ impl RangeElem for Dynamic { if let Some(range) = maybe_range { range.evaled_range_min(analyzer) } else { - Ok(Elem::Dynamic(self.clone())) + Ok(Elem::Reference(self.clone())) } } VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { val: concrete_node.underlying(analyzer)?.clone(), loc: cvar.loc.unwrap_or(Loc::Implicit), })), - _e => Ok(Elem::Dynamic(self.clone())), + _e => Ok(Elem::Reference(self.clone())), } } fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { // let cvar = ContextVarNode::from(self.idx); // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Dynamic(self.clone())) + Ok(Elem::Reference(self.clone())) // } // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Dynamic(self.clone())) + // return Ok(Elem::Reference(self.clone())) // } // let cvar = cvar.underlying(analyzer)?; // match &cvar.ty { @@ -116,23 +116,23 @@ impl RangeElem for Dynamic { // if let Some(range) = maybe_range { // range.simplified_range_max(analyzer) // } else { - // Ok(Elem::Dynamic(self.clone())) + // Ok(Elem::Reference(self.clone())) // } // } // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { // val: concrete_node.underlying(analyzer)?.clone(), // loc: cvar.loc.unwrap_or(Loc::Implicit), // })), - // _e => Ok(Elem::Dynamic(self.clone())), + // _e => Ok(Elem::Reference(self.clone())), // } } fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { // let cvar = ContextVarNode::from(self.idx); // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Dynamic(self.clone())) + Ok(Elem::Reference(self.clone())) // } // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Dynamic(self.clone())) + // return Ok(Elem::Reference(self.clone())) // } // let cvar = cvar.underlying(analyzer)?; @@ -144,14 +144,14 @@ impl RangeElem for Dynamic { // if let Some(range) = maybe_range { // range.simplified_range_min(analyzer) // } else { - // Ok(Elem::Dynamic(self.clone())) + // Ok(Elem::Reference(self.clone())) // } // } // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { // val: concrete_node.underlying(analyzer)?.clone(), // loc: cvar.loc.unwrap_or(Loc::Implicit), // })), - // _e => Ok(Elem::Dynamic(self.clone())), + // _e => Ok(Elem::Reference(self.clone())), // } } @@ -563,7 +563,7 @@ pub enum Elem { impl std::fmt::Display for Elem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Elem::Dynamic(Dynamic { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), Elem::ConcreteDyn(..) => write!(f, "range_elem"), Elem::Concrete(RangeConcrete { val, .. }) => { write!(f, "{}", val.as_string()) @@ -587,13 +587,13 @@ impl From for Elem { impl From for Elem { fn from(c: ContextVarNode) -> Self { - Elem::Dynamic(Dynamic::new(c.into())) + Elem::Reference(Dynamic::new(c.into())) } } impl From for Elem { fn from(idx: NodeIdx) -> Self { - Elem::Dynamic(Dynamic::new(idx)) + Elem::Reference(Dynamic::new(idx)) } } @@ -666,7 +666,7 @@ impl Elem { impl From for Elem { fn from(dy: Dynamic) -> Self { - Elem::Dynamic(dy) + Elem::Reference(dy) } } @@ -679,7 +679,7 @@ impl From> for Elem { impl Elem { pub fn node_idx(&self) -> Option { match self { - Self::Dynamic(Dynamic { idx, .. }) => Some(*idx), + Self::Dynamic(Reference { idx, .. }) => Some(*idx), _ => None, } } @@ -701,7 +701,7 @@ impl Elem { val: Concrete::Int(_, val), .. }) if val < &I256::zero() => true, - Elem::Dynamic(dy) => { + Elem::Reference(dy) => { if maximize { dy.maximize(analyzer)?.is_negative(maximize, analyzer)? } else { diff --git a/shared/src/range/range_ops.rs b/shared/src/range/range_ops.rs index f8ae3887..4a2b4f40 100644 --- a/shared/src/range/range_ops.rs +++ b/shared/src/range/range_ops.rs @@ -1412,8 +1412,8 @@ impl RangeCast> for RangeDyn { )), None, ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } @@ -1597,8 +1597,8 @@ impl RangeConcat> for RangeDyn { loc: other.loc, }))) } - (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } diff --git a/shared/src/range/range_string.rs b/shared/src/range/range_string.rs index 98bf18ec..05528fd5 100644 --- a/shared/src/range/range_string.rs +++ b/shared/src/range/range_string.rs @@ -52,7 +52,7 @@ impl ToRangeString for Elem { fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Dynamic(Dynamic { idx, .. }) => { + Elem::Reference(Reference { idx, .. }) => { let cvar = ContextVarNode::from(*idx) .first_version(analyzer) .underlying(analyzer) @@ -68,7 +68,7 @@ impl ToRangeString for Elem { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Dynamic(Dynamic { idx, .. }) => { + Elem::Reference(Reference { idx, .. }) => { let as_var = ContextVarNode::from(*idx); let name = as_var.display_name(analyzer).unwrap(); RangeElemString::new(name, as_var.loc(analyzer).unwrap()) From e54bfe79b57c8553b4dd27a9cd6e9ef6682aead2 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 13:24:29 -0800 Subject: [PATCH 04/71] dynamic -> reference refactor --- crates/range/elem/elem_enum.rs | 50 +++++++++++++++++----------------- crates/range/exec/cast.rs | 4 +-- crates/range/exec/concat.rs | 4 +-- crates/range/range_string.rs | 6 ++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/crates/range/elem/elem_enum.rs b/crates/range/elem/elem_enum.rs index 975e1d7b..b8cb6287 100644 --- a/crates/range/elem/elem_enum.rs +++ b/crates/range/elem/elem_enum.rs @@ -2,7 +2,7 @@ #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Elem { /// A range element that is a reference to another node - Dynamic(Dynamic), + Reference(Reference), /// A concrete range element of type `T`. e.g.: some number like `10` ConcreteDyn(Box>), /// A concrete range element of type `T`. e.g.: some number like `10` @@ -16,7 +16,7 @@ pub enum Elem { impl std::fmt::Display for Elem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Elem::Dynamic(Dynamic { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), Elem::ConcreteDyn(..) => write!(f, "range_elem"), Elem::Concrete(RangeConcrete { val, .. }) => { write!(f, "{}", val.as_string()) @@ -58,20 +58,20 @@ impl From for Elem { impl From for Elem { fn from(c: ContextVarNode) -> Self { - Elem::Dynamic(Dynamic::new(c.into())) + Elem::Reference(Reference::new(c.into())) } } impl From for Elem { fn from(idx: NodeIdx) -> Self { - Elem::Dynamic(Dynamic::new(idx)) + Elem::Reference(Reference::new(idx)) } } impl Elem { pub fn contains_node(&self, node_idx: NodeIdx) -> bool { match self { - Self::Dynamic(d) => d.idx == node_idx, + Self::Reference(d) => d.idx == node_idx, Self::Concrete(_) => false, Self::Expr(expr) => expr.contains_node(node_idx), Self::ConcreteDyn(d) => d.contains_node(node_idx), @@ -142,9 +142,9 @@ impl Elem { } } -impl From for Elem { - fn from(dy: Dynamic) -> Self { - Elem::Dynamic(dy) +impl From for Elem { + fn from(dy: Reference) -> Self { + Elem::Reference(dy) } } @@ -157,7 +157,7 @@ impl From> for Elem { impl Elem { pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { match self { - Self::Dynamic(Dynamic { idx, .. }) => { + Self::Reference(Reference { idx, .. }) => { if *idx == to_replace { *self = replacement; } @@ -176,7 +176,7 @@ impl Elem { pub fn inverse_if_boolean(&self) -> Option { match self { - Self::Dynamic(Dynamic { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( + Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( self.clone(), RangeOp::Not, Elem::Null, @@ -194,7 +194,7 @@ impl Elem { pub fn node_idx(&self) -> Option { match self { - Self::Dynamic(Dynamic { idx, .. }) => Some(*idx), + Self::Reference(Reference { idx, .. }) => Some(*idx), _ => None, } } @@ -216,7 +216,7 @@ impl Elem { val: Concrete::Int(_, val), .. }) if val < &I256::zero() => true, - Elem::Dynamic(dy) => { + Elem::Reference(dy) => { if maximize { dy.maximize(analyzer)?.is_negative(maximize, analyzer)? } else { @@ -272,7 +272,7 @@ impl RangeElem for Elem { fn range_ord(&self, other: &Self) -> Option { match (self, other) { (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), - (Self::Dynamic(a), Self::Dynamic(b)) => a.range_ord(b), + (Self::Reference(a), Self::Reference(b)) => a.range_ord(b), _ => None, } } @@ -283,7 +283,7 @@ impl RangeElem for Elem { analyzer: &impl GraphLike, ) -> Result, GraphError> { match self { - Self::Dynamic(d) => d.flatten(maximize, analyzer), + Self::Reference(d) => d.flatten(maximize, analyzer), Self::Concrete(c) => c.flatten(maximize, analyzer), Self::Expr(expr) => expr.flatten(maximize, analyzer), Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), @@ -293,7 +293,7 @@ impl RangeElem for Elem { fn dependent_on(&self) -> Vec { match self { - Self::Dynamic(d) => d.dependent_on(), + Self::Reference(d) => d.dependent_on(), Self::Concrete(_) => vec![], Self::Expr(expr) => expr.dependent_on(), Self::ConcreteDyn(d) => d.dependent_on(), @@ -303,7 +303,7 @@ impl RangeElem for Elem { fn update_deps(&mut self, mapping: &BTreeMap) { match self { - Self::Dynamic(d) => d.update_deps(mapping), + Self::Reference(d) => d.update_deps(mapping), Self::Concrete(_) => {} Self::Expr(expr) => expr.update_deps(mapping), Self::ConcreteDyn(d) => d.update_deps(mapping), @@ -313,7 +313,7 @@ impl RangeElem for Elem { fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { match self { - Self::Dynamic(ref mut d) => { + Self::Reference(ref mut d) => { if d.idx == node_idx { d.idx = new_idx } @@ -328,7 +328,7 @@ impl RangeElem for Elem { fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { use Elem::*; let res = match self { - Dynamic(dy) => dy.maximize(analyzer)?, + Reference(dy) => dy.maximize(analyzer)?, Concrete(inner) => inner.maximize(analyzer)?, ConcreteDyn(inner) => inner.maximize(analyzer)?, Expr(expr) => expr.maximize(analyzer)?, @@ -340,7 +340,7 @@ impl RangeElem for Elem { fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { use Elem::*; let res = match self { - Dynamic(dy) => dy.minimize(analyzer)?, + Reference(dy) => dy.minimize(analyzer)?, Concrete(inner) => inner.minimize(analyzer)?, ConcreteDyn(inner) => inner.minimize(analyzer)?, Expr(expr) => expr.minimize(analyzer)?, @@ -356,7 +356,7 @@ impl RangeElem for Elem { ) -> Result, GraphError> { use Elem::*; match self { - Dynamic(dy) => dy.simplify_maximize(exclude, analyzer), + Reference(dy) => dy.simplify_maximize(exclude, analyzer), Concrete(inner) => inner.simplify_maximize(exclude, analyzer), ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), Expr(expr) => expr.simplify_maximize(exclude, analyzer), @@ -371,7 +371,7 @@ impl RangeElem for Elem { ) -> Result, GraphError> { use Elem::*; match self { - Dynamic(dy) => dy.simplify_minimize(exclude, analyzer), + Reference(dy) => dy.simplify_minimize(exclude, analyzer), Concrete(inner) => inner.simplify_minimize(exclude, analyzer), ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), Expr(expr) => expr.simplify_minimize(exclude, analyzer), @@ -382,7 +382,7 @@ impl RangeElem for Elem { fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { use Elem::*; match self { - Dynamic(dy) => dy.cache_maximize(analyzer), + Reference(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), Expr(expr) => expr.cache_maximize(analyzer), @@ -393,7 +393,7 @@ impl RangeElem for Elem { fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { use Elem::*; match self { - Dynamic(dy) => dy.cache_minimize(analyzer), + Reference(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), Expr(expr) => expr.cache_minimize(analyzer), @@ -403,7 +403,7 @@ impl RangeElem for Elem { fn uncache(&mut self) { use Elem::*; match self { - Dynamic(dy) => dy.uncache(), + Reference(dy) => dy.uncache(), Concrete(inner) => inner.uncache(), ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), @@ -419,7 +419,7 @@ impl RangeElem for Elem { ) -> Result { use Elem::*; match self { - Dynamic(dy) => dy.contains_op_set(max, op_set, analyzer), + Reference(dy) => dy.contains_op_set(max, op_set, analyzer), Concrete(inner) => inner.contains_op_set(max, op_set, analyzer), ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), Expr(expr) => expr.contains_op_set(max, op_set, analyzer), diff --git a/crates/range/exec/cast.rs b/crates/range/exec/cast.rs index ce78c84d..ec122be9 100644 --- a/crates/range/exec/cast.rs +++ b/crates/range/exec/cast.rs @@ -200,8 +200,8 @@ impl RangeCast> for RangeDyn { )), None, ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } diff --git a/crates/range/exec/concat.rs b/crates/range/exec/concat.rs index c7fa9481..194506e2 100644 --- a/crates/range/exec/concat.rs +++ b/crates/range/exec/concat.rs @@ -127,8 +127,8 @@ impl RangeConcat> for RangeDyn { loc: other.loc, }))) } - (Some((_, l @ Elem::Dynamic(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Dynamic(_)))) => Some(r.clone()), + (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), + (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), _e => None, } diff --git a/crates/range/range_string.rs b/crates/range/range_string.rs index a9682746..e9a6644a 100644 --- a/crates/range/range_string.rs +++ b/crates/range/range_string.rs @@ -2,7 +2,7 @@ use crate::analyzer::GraphLike; use crate::context::ContextVarNode; use crate::range::elem::RangeElem; use crate::range::elem::RangeOp; -use crate::range::elem_ty::Dynamic; +use crate::range::elem_ty::Reference; use crate::range::elem_ty::RangeExpr; use crate::range::Elem; use crate::range::RangeDyn; @@ -52,7 +52,7 @@ impl ToRangeString for Elem { fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Dynamic(Dynamic { idx, .. }) => { + Elem::Reference(Reference { idx, .. }) => { let cvar = ContextVarNode::from(*idx) .first_version(analyzer) .underlying(analyzer) @@ -68,7 +68,7 @@ impl ToRangeString for Elem { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Dynamic(Dynamic { idx, .. }) => { + Elem::Reference(Reference { idx, .. }) => { let as_var = ContextVarNode::from(*idx); let name = as_var.display_name(analyzer).unwrap(); RangeElemString::new(name, as_var.loc(analyzer).unwrap()) From a6890052981cecca7a7c12199fadd2acff678001 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 13:47:44 -0800 Subject: [PATCH 05/71] more restructing --- Cargo.toml | 67 ++++++++++++------- crates/analyzer/Cargo.toml | 16 +++++ crates/analyzer/{ => src}/analyzer_like.rs | 0 crates/analyzer/{ => src}/analyzers/bounds.rs | 0 .../{ => src}/analyzers/func_analyzer/mod.rs | 0 .../analyzers/func_analyzer/report_display.rs | 0 crates/analyzer/{ => src}/analyzers/mod.rs | 0 .../{ => src}/analyzers/var_analyzer/mod.rs | 0 .../analyzers/var_analyzer/report_display.rs | 0 crates/analyzer/{ => src}/lib.rs | 0 crates/graph/Cargo.toml | 20 ++++++ crates/graph/{ => src}/graph_elements.rs | 0 crates/graph/{ => src}/graph_like.rs | 0 crates/graph/{ => src}/lib.rs | 0 crates/graph/{ => src}/nodes/block.rs | 0 crates/graph/{ => src}/nodes/builtin.rs | 0 crates/graph/{ => src}/nodes/concrete.rs | 0 .../{ => src}/nodes/context/context_tys.rs | 0 .../graph/{ => src}/nodes/context/expr_ret.rs | 0 crates/graph/{ => src}/nodes/context/mod.rs | 0 crates/graph/{ => src}/nodes/context/node.rs | 0 .../{ => src}/nodes/context/underlying.rs | 0 crates/graph/{ => src}/nodes/contract_ty.rs | 0 crates/graph/{ => src}/nodes/enum_ty.rs | 0 crates/graph/{ => src}/nodes/err_ty.rs | 0 crates/graph/{ => src}/nodes/func_ty.rs | 0 crates/graph/{ => src}/nodes/mod.rs | 0 crates/graph/{ => src}/nodes/msg.rs | 0 crates/graph/{ => src}/nodes/struct_ty.rs | 0 crates/graph/{ => src}/nodes/ty_ty.rs | 0 crates/graph/{ => src}/nodes/var_ty.rs | 0 crates/graph/{ => src}/search.rs | 0 crates/graph/{ => src}/var_type.rs | 0 crates/range/Cargo.toml | 19 ++++++ crates/range/{ => src}/elem/concrete.rs | 0 crates/range/{ => src}/elem/elem_enum.rs | 0 crates/range/{ => src}/elem/expr.rs | 0 crates/range/{ => src}/elem/map_or_array.rs | 0 crates/range/{ => src}/elem/mod.rs | 8 +-- crates/range/{ => src}/elem/reference.rs | 0 crates/range/{ => src}/exec/add.rs | 0 crates/range/{ => src}/exec/bitwise.rs | 0 crates/range/{ => src}/exec/cast.rs | 0 crates/range/{ => src}/exec/concat.rs | 0 crates/range/{ => src}/exec/div.rs | 0 crates/range/{ => src}/exec/exp.rs | 0 crates/range/{ => src}/exec/logical.rs | 0 crates/range/{ => src}/exec/max.rs | 0 crates/range/{ => src}/exec/min.rs | 0 crates/range/{ => src}/exec/mod.rs | 0 crates/range/{ => src}/exec/modulo.rs | 0 crates/range/{ => src}/exec/mul.rs | 0 crates/range/{ => src}/exec/ord.rs | 0 crates/range/{ => src}/exec/shift.rs | 0 crates/range/{ => src}/exec/sub.rs | 0 crates/range/{ => src}/mod.rs | 0 crates/range/{ => src}/range_string.rs | 9 --- crates/range/{ => src}/solc_range.rs | 18 +---- crates/solc_expressions/Cargo.toml | 20 ++++++ crates/solc_expressions/{ => src}/array.rs | 0 crates/solc_expressions/{ => src}/bin_op.rs | 0 crates/solc_expressions/{ => src}/cmp.rs | 0 crates/solc_expressions/{ => src}/cond_op.rs | 0 crates/solc_expressions/{ => src}/env.rs | 0 .../{ => src}/func_call/internal_call.rs | 0 .../{ => src}/func_call/intrinsic_call.rs | 0 .../{ => src}/func_call/mod.rs | 0 .../{ => src}/func_call/modifier.rs | 0 .../{ => src}/func_call/namespaced_call.rs | 0 crates/solc_expressions/{ => src}/lib.rs | 0 crates/solc_expressions/{ => src}/list.rs | 0 crates/solc_expressions/{ => src}/literal.rs | 0 crates/solc_expressions/{ => src}/loops.rs | 0 .../{ => src}/member_access.rs | 0 crates/solc_expressions/{ => src}/require.rs | 0 crates/solc_expressions/{ => src}/variable.rs | 0 crates/solc_expressions/{ => src}/yul/mod.rs | 0 .../{ => src}/yul/yul_cond_op.rs | 0 .../{ => src}/yul/yul_funcs.rs | 0 79 files changed, 122 insertions(+), 55 deletions(-) create mode 100644 crates/analyzer/Cargo.toml rename crates/analyzer/{ => src}/analyzer_like.rs (100%) rename crates/analyzer/{ => src}/analyzers/bounds.rs (100%) rename crates/analyzer/{ => src}/analyzers/func_analyzer/mod.rs (100%) rename crates/analyzer/{ => src}/analyzers/func_analyzer/report_display.rs (100%) rename crates/analyzer/{ => src}/analyzers/mod.rs (100%) rename crates/analyzer/{ => src}/analyzers/var_analyzer/mod.rs (100%) rename crates/analyzer/{ => src}/analyzers/var_analyzer/report_display.rs (100%) rename crates/analyzer/{ => src}/lib.rs (100%) create mode 100644 crates/graph/Cargo.toml rename crates/graph/{ => src}/graph_elements.rs (100%) rename crates/graph/{ => src}/graph_like.rs (100%) rename crates/graph/{ => src}/lib.rs (100%) rename crates/graph/{ => src}/nodes/block.rs (100%) rename crates/graph/{ => src}/nodes/builtin.rs (100%) rename crates/graph/{ => src}/nodes/concrete.rs (100%) rename crates/graph/{ => src}/nodes/context/context_tys.rs (100%) rename crates/graph/{ => src}/nodes/context/expr_ret.rs (100%) rename crates/graph/{ => src}/nodes/context/mod.rs (100%) rename crates/graph/{ => src}/nodes/context/node.rs (100%) rename crates/graph/{ => src}/nodes/context/underlying.rs (100%) rename crates/graph/{ => src}/nodes/contract_ty.rs (100%) rename crates/graph/{ => src}/nodes/enum_ty.rs (100%) rename crates/graph/{ => src}/nodes/err_ty.rs (100%) rename crates/graph/{ => src}/nodes/func_ty.rs (100%) rename crates/graph/{ => src}/nodes/mod.rs (100%) rename crates/graph/{ => src}/nodes/msg.rs (100%) rename crates/graph/{ => src}/nodes/struct_ty.rs (100%) rename crates/graph/{ => src}/nodes/ty_ty.rs (100%) rename crates/graph/{ => src}/nodes/var_ty.rs (100%) rename crates/graph/{ => src}/search.rs (100%) rename crates/graph/{ => src}/var_type.rs (100%) create mode 100644 crates/range/Cargo.toml rename crates/range/{ => src}/elem/concrete.rs (100%) rename crates/range/{ => src}/elem/elem_enum.rs (100%) rename crates/range/{ => src}/elem/expr.rs (100%) rename crates/range/{ => src}/elem/map_or_array.rs (100%) rename crates/range/{ => src}/elem/mod.rs (97%) rename crates/range/{ => src}/elem/reference.rs (100%) rename crates/range/{ => src}/exec/add.rs (100%) rename crates/range/{ => src}/exec/bitwise.rs (100%) rename crates/range/{ => src}/exec/cast.rs (100%) rename crates/range/{ => src}/exec/concat.rs (100%) rename crates/range/{ => src}/exec/div.rs (100%) rename crates/range/{ => src}/exec/exp.rs (100%) rename crates/range/{ => src}/exec/logical.rs (100%) rename crates/range/{ => src}/exec/max.rs (100%) rename crates/range/{ => src}/exec/min.rs (100%) rename crates/range/{ => src}/exec/mod.rs (100%) rename crates/range/{ => src}/exec/modulo.rs (100%) rename crates/range/{ => src}/exec/mul.rs (100%) rename crates/range/{ => src}/exec/ord.rs (100%) rename crates/range/{ => src}/exec/shift.rs (100%) rename crates/range/{ => src}/exec/sub.rs (100%) rename crates/range/{ => src}/mod.rs (100%) rename crates/range/{ => src}/range_string.rs (96%) rename crates/range/{ => src}/solc_range.rs (98%) create mode 100644 crates/solc_expressions/Cargo.toml rename crates/solc_expressions/{ => src}/array.rs (100%) rename crates/solc_expressions/{ => src}/bin_op.rs (100%) rename crates/solc_expressions/{ => src}/cmp.rs (100%) rename crates/solc_expressions/{ => src}/cond_op.rs (100%) rename crates/solc_expressions/{ => src}/env.rs (100%) rename crates/solc_expressions/{ => src}/func_call/internal_call.rs (100%) rename crates/solc_expressions/{ => src}/func_call/intrinsic_call.rs (100%) rename crates/solc_expressions/{ => src}/func_call/mod.rs (100%) rename crates/solc_expressions/{ => src}/func_call/modifier.rs (100%) rename crates/solc_expressions/{ => src}/func_call/namespaced_call.rs (100%) rename crates/solc_expressions/{ => src}/lib.rs (100%) rename crates/solc_expressions/{ => src}/list.rs (100%) rename crates/solc_expressions/{ => src}/literal.rs (100%) rename crates/solc_expressions/{ => src}/loops.rs (100%) rename crates/solc_expressions/{ => src}/member_access.rs (100%) rename crates/solc_expressions/{ => src}/require.rs (100%) rename crates/solc_expressions/{ => src}/variable.rs (100%) rename crates/solc_expressions/{ => src}/yul/mod.rs (100%) rename crates/solc_expressions/{ => src}/yul/yul_cond_op.rs (100%) rename crates/solc_expressions/{ => src}/yul/yul_funcs.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 09ad9588..11074f5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,31 +1,24 @@ -[package] -name = "pyrometer" -version = "0.1.0" -edition = "2021" -autobenches = false # turns off autodiscovery of benchmarks in ./benches -exclude = ["benches"] # exclude the benches directory from the build +[workspace] +members = [ + "crates/analyzer", + "crates/cli", + "crates/graph", + "crates/queries", + "crates/range", + "crates/solc_expressions", +] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -petgraph = "0.6.2" -solang-parser = { version = "0.2.4", features = ["pt-serde"] } -ethers-core = "*" -ariadne = "0.2.0" -shared = { path = "./shared" } -hex = "0.4.3" -tracing = { version = "0.1", features = ["attributes"] } -tracing-subscriber = "0.3" - -[dev-dependencies] -criterion = { version = "0.4"} # benching -[workspace] -members = ["cli", "shared"] +[workspace.package] +version = "0.2.0" +edition = "2021" +authors = ["Brock Elmore"] +license = "MIT OR Apache-2.0" +homepage = "https://github.com/nascentxyz/pyrometer" +repository = "https://github.com/nascentxyz/pyrometer" +exclude = ["benches/", "tests/"] # exclude the benches directory from the build -# we patch ariadne to allow for counting by bytes because solang uses byte locations not char locations -[patch.crates-io] -ariadne = {git = "https://github.com/brockelmore/ariadne"} [profile.release] debug = true @@ -37,6 +30,32 @@ inline = true [profile.bench] debug = true +[workspace.dependencies] +analyzer = { path = "crates/analyzer" } +graph = { path = "crates/graph" } +queries = { path = "crates/queries" } +range = { path = "crates/range" } +solc_expressions = { path = "crates/solc_expressions" } + +solang-parser = { version = "0.2.4", features = ["pt-serde"] } +tracing = { version = "0.1", features = ["attributes"] } +tracing-subscriber = "0.3" +ethers-core = "*" +hex = "0.4.3" +lazy_static = +ariadne = "0.2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# [dev-dependencies] +# criterion = { version = "0.4"} # benching + +# [workspace] +# members = ["cli", "shared"] + +# we patch ariadne to allow for counting by bytes because solang uses byte locations not char locations +[patch.crates-io] +ariadne = {git = "https://github.com/brockelmore/ariadne"} ###################################### # Benchmarks diff --git a/crates/analyzer/Cargo.toml b/crates/analyzer/Cargo.toml new file mode 100644 index 00000000..03ecba78 --- /dev/null +++ b/crates/analyzer/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "range" +description = "Pyrometer's analyzer traits" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +graph.workspace = true +solang-parser.workspace = true +ariadne.workspace = true \ No newline at end of file diff --git a/crates/analyzer/analyzer_like.rs b/crates/analyzer/src/analyzer_like.rs similarity index 100% rename from crates/analyzer/analyzer_like.rs rename to crates/analyzer/src/analyzer_like.rs diff --git a/crates/analyzer/analyzers/bounds.rs b/crates/analyzer/src/analyzers/bounds.rs similarity index 100% rename from crates/analyzer/analyzers/bounds.rs rename to crates/analyzer/src/analyzers/bounds.rs diff --git a/crates/analyzer/analyzers/func_analyzer/mod.rs b/crates/analyzer/src/analyzers/func_analyzer/mod.rs similarity index 100% rename from crates/analyzer/analyzers/func_analyzer/mod.rs rename to crates/analyzer/src/analyzers/func_analyzer/mod.rs diff --git a/crates/analyzer/analyzers/func_analyzer/report_display.rs b/crates/analyzer/src/analyzers/func_analyzer/report_display.rs similarity index 100% rename from crates/analyzer/analyzers/func_analyzer/report_display.rs rename to crates/analyzer/src/analyzers/func_analyzer/report_display.rs diff --git a/crates/analyzer/analyzers/mod.rs b/crates/analyzer/src/analyzers/mod.rs similarity index 100% rename from crates/analyzer/analyzers/mod.rs rename to crates/analyzer/src/analyzers/mod.rs diff --git a/crates/analyzer/analyzers/var_analyzer/mod.rs b/crates/analyzer/src/analyzers/var_analyzer/mod.rs similarity index 100% rename from crates/analyzer/analyzers/var_analyzer/mod.rs rename to crates/analyzer/src/analyzers/var_analyzer/mod.rs diff --git a/crates/analyzer/analyzers/var_analyzer/report_display.rs b/crates/analyzer/src/analyzers/var_analyzer/report_display.rs similarity index 100% rename from crates/analyzer/analyzers/var_analyzer/report_display.rs rename to crates/analyzer/src/analyzers/var_analyzer/report_display.rs diff --git a/crates/analyzer/lib.rs b/crates/analyzer/src/lib.rs similarity index 100% rename from crates/analyzer/lib.rs rename to crates/analyzer/src/lib.rs diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml new file mode 100644 index 00000000..45bed73e --- /dev/null +++ b/crates/graph/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "range" +description = "Pyrometer's representation of a range" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +solang-parser.workspace = true +ethers-core.workspace = true +hex.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true + +lazy_static = "1.4.0" \ No newline at end of file diff --git a/crates/graph/graph_elements.rs b/crates/graph/src/graph_elements.rs similarity index 100% rename from crates/graph/graph_elements.rs rename to crates/graph/src/graph_elements.rs diff --git a/crates/graph/graph_like.rs b/crates/graph/src/graph_like.rs similarity index 100% rename from crates/graph/graph_like.rs rename to crates/graph/src/graph_like.rs diff --git a/crates/graph/lib.rs b/crates/graph/src/lib.rs similarity index 100% rename from crates/graph/lib.rs rename to crates/graph/src/lib.rs diff --git a/crates/graph/nodes/block.rs b/crates/graph/src/nodes/block.rs similarity index 100% rename from crates/graph/nodes/block.rs rename to crates/graph/src/nodes/block.rs diff --git a/crates/graph/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs similarity index 100% rename from crates/graph/nodes/builtin.rs rename to crates/graph/src/nodes/builtin.rs diff --git a/crates/graph/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs similarity index 100% rename from crates/graph/nodes/concrete.rs rename to crates/graph/src/nodes/concrete.rs diff --git a/crates/graph/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs similarity index 100% rename from crates/graph/nodes/context/context_tys.rs rename to crates/graph/src/nodes/context/context_tys.rs diff --git a/crates/graph/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs similarity index 100% rename from crates/graph/nodes/context/expr_ret.rs rename to crates/graph/src/nodes/context/expr_ret.rs diff --git a/crates/graph/nodes/context/mod.rs b/crates/graph/src/nodes/context/mod.rs similarity index 100% rename from crates/graph/nodes/context/mod.rs rename to crates/graph/src/nodes/context/mod.rs diff --git a/crates/graph/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs similarity index 100% rename from crates/graph/nodes/context/node.rs rename to crates/graph/src/nodes/context/node.rs diff --git a/crates/graph/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs similarity index 100% rename from crates/graph/nodes/context/underlying.rs rename to crates/graph/src/nodes/context/underlying.rs diff --git a/crates/graph/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs similarity index 100% rename from crates/graph/nodes/contract_ty.rs rename to crates/graph/src/nodes/contract_ty.rs diff --git a/crates/graph/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs similarity index 100% rename from crates/graph/nodes/enum_ty.rs rename to crates/graph/src/nodes/enum_ty.rs diff --git a/crates/graph/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs similarity index 100% rename from crates/graph/nodes/err_ty.rs rename to crates/graph/src/nodes/err_ty.rs diff --git a/crates/graph/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs similarity index 100% rename from crates/graph/nodes/func_ty.rs rename to crates/graph/src/nodes/func_ty.rs diff --git a/crates/graph/nodes/mod.rs b/crates/graph/src/nodes/mod.rs similarity index 100% rename from crates/graph/nodes/mod.rs rename to crates/graph/src/nodes/mod.rs diff --git a/crates/graph/nodes/msg.rs b/crates/graph/src/nodes/msg.rs similarity index 100% rename from crates/graph/nodes/msg.rs rename to crates/graph/src/nodes/msg.rs diff --git a/crates/graph/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs similarity index 100% rename from crates/graph/nodes/struct_ty.rs rename to crates/graph/src/nodes/struct_ty.rs diff --git a/crates/graph/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs similarity index 100% rename from crates/graph/nodes/ty_ty.rs rename to crates/graph/src/nodes/ty_ty.rs diff --git a/crates/graph/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs similarity index 100% rename from crates/graph/nodes/var_ty.rs rename to crates/graph/src/nodes/var_ty.rs diff --git a/crates/graph/search.rs b/crates/graph/src/search.rs similarity index 100% rename from crates/graph/search.rs rename to crates/graph/src/search.rs diff --git a/crates/graph/var_type.rs b/crates/graph/src/var_type.rs similarity index 100% rename from crates/graph/var_type.rs rename to crates/graph/src/var_type.rs diff --git a/crates/range/Cargo.toml b/crates/range/Cargo.toml new file mode 100644 index 00000000..0e16aa5d --- /dev/null +++ b/crates/range/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "range" +description = "Pyrometer's representation of a range" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +graph.workspace = true +solang-parser.workspace = true +ethers-core.workspace = true +hex.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true \ No newline at end of file diff --git a/crates/range/elem/concrete.rs b/crates/range/src/elem/concrete.rs similarity index 100% rename from crates/range/elem/concrete.rs rename to crates/range/src/elem/concrete.rs diff --git a/crates/range/elem/elem_enum.rs b/crates/range/src/elem/elem_enum.rs similarity index 100% rename from crates/range/elem/elem_enum.rs rename to crates/range/src/elem/elem_enum.rs diff --git a/crates/range/elem/expr.rs b/crates/range/src/elem/expr.rs similarity index 100% rename from crates/range/elem/expr.rs rename to crates/range/src/elem/expr.rs diff --git a/crates/range/elem/map_or_array.rs b/crates/range/src/elem/map_or_array.rs similarity index 100% rename from crates/range/elem/map_or_array.rs rename to crates/range/src/elem/map_or_array.rs diff --git a/crates/range/elem/mod.rs b/crates/range/src/elem/mod.rs similarity index 97% rename from crates/range/elem/mod.rs rename to crates/range/src/elem/mod.rs index d6a81eda..9eb8b0b9 100644 --- a/crates/range/elem/mod.rs +++ b/crates/range/src/elem/mod.rs @@ -1,10 +1,6 @@ -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::context::ContextVarNode; -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeExpr; -use crate::NodeIdx; + + use std::collections::BTreeMap; mod concrete; diff --git a/crates/range/elem/reference.rs b/crates/range/src/elem/reference.rs similarity index 100% rename from crates/range/elem/reference.rs rename to crates/range/src/elem/reference.rs diff --git a/crates/range/exec/add.rs b/crates/range/src/exec/add.rs similarity index 100% rename from crates/range/exec/add.rs rename to crates/range/src/exec/add.rs diff --git a/crates/range/exec/bitwise.rs b/crates/range/src/exec/bitwise.rs similarity index 100% rename from crates/range/exec/bitwise.rs rename to crates/range/src/exec/bitwise.rs diff --git a/crates/range/exec/cast.rs b/crates/range/src/exec/cast.rs similarity index 100% rename from crates/range/exec/cast.rs rename to crates/range/src/exec/cast.rs diff --git a/crates/range/exec/concat.rs b/crates/range/src/exec/concat.rs similarity index 100% rename from crates/range/exec/concat.rs rename to crates/range/src/exec/concat.rs diff --git a/crates/range/exec/div.rs b/crates/range/src/exec/div.rs similarity index 100% rename from crates/range/exec/div.rs rename to crates/range/src/exec/div.rs diff --git a/crates/range/exec/exp.rs b/crates/range/src/exec/exp.rs similarity index 100% rename from crates/range/exec/exp.rs rename to crates/range/src/exec/exp.rs diff --git a/crates/range/exec/logical.rs b/crates/range/src/exec/logical.rs similarity index 100% rename from crates/range/exec/logical.rs rename to crates/range/src/exec/logical.rs diff --git a/crates/range/exec/max.rs b/crates/range/src/exec/max.rs similarity index 100% rename from crates/range/exec/max.rs rename to crates/range/src/exec/max.rs diff --git a/crates/range/exec/min.rs b/crates/range/src/exec/min.rs similarity index 100% rename from crates/range/exec/min.rs rename to crates/range/src/exec/min.rs diff --git a/crates/range/exec/mod.rs b/crates/range/src/exec/mod.rs similarity index 100% rename from crates/range/exec/mod.rs rename to crates/range/src/exec/mod.rs diff --git a/crates/range/exec/modulo.rs b/crates/range/src/exec/modulo.rs similarity index 100% rename from crates/range/exec/modulo.rs rename to crates/range/src/exec/modulo.rs diff --git a/crates/range/exec/mul.rs b/crates/range/src/exec/mul.rs similarity index 100% rename from crates/range/exec/mul.rs rename to crates/range/src/exec/mul.rs diff --git a/crates/range/exec/ord.rs b/crates/range/src/exec/ord.rs similarity index 100% rename from crates/range/exec/ord.rs rename to crates/range/src/exec/ord.rs diff --git a/crates/range/exec/shift.rs b/crates/range/src/exec/shift.rs similarity index 100% rename from crates/range/exec/shift.rs rename to crates/range/src/exec/shift.rs diff --git a/crates/range/exec/sub.rs b/crates/range/src/exec/sub.rs similarity index 100% rename from crates/range/exec/sub.rs rename to crates/range/src/exec/sub.rs diff --git a/crates/range/mod.rs b/crates/range/src/mod.rs similarity index 100% rename from crates/range/mod.rs rename to crates/range/src/mod.rs diff --git a/crates/range/range_string.rs b/crates/range/src/range_string.rs similarity index 96% rename from crates/range/range_string.rs rename to crates/range/src/range_string.rs index e9a6644a..05d10914 100644 --- a/crates/range/range_string.rs +++ b/crates/range/src/range_string.rs @@ -1,12 +1,3 @@ -use crate::analyzer::GraphLike; -use crate::context::ContextVarNode; -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; -use crate::range::elem_ty::Reference; -use crate::range::elem_ty::RangeExpr; -use crate::range::Elem; -use crate::range::RangeDyn; -use crate::Concrete; use std::collections::BTreeMap; diff --git a/crates/range/solc_range.rs b/crates/range/src/solc_range.rs similarity index 98% rename from crates/range/solc_range.rs rename to crates/range/src/solc_range.rs index 9d244344..86b629ed 100644 --- a/crates/range/solc_range.rs +++ b/crates/range/src/solc_range.rs @@ -1,19 +1,5 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::context::ContextNode; -use crate::context::ContextVarNode; -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; - -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeConcrete; -use crate::range::elem_ty::RangeDyn; -use crate::range::range_string::ToRangeString; -use crate::Builtin; -use crate::Concrete; - -use crate::NodeIdx; + + use ethers_core::types::Address; use ethers_core::types::H256; use ethers_core::types::I256; diff --git a/crates/solc_expressions/Cargo.toml b/crates/solc_expressions/Cargo.toml new file mode 100644 index 00000000..3f244fc1 --- /dev/null +++ b/crates/solc_expressions/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "solc-expressions" +description = "Pyrometer's parsing of solidity based expressions" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +analyzer.workspace = true +graph.workspace = true +solang-parser.workspace = true +ethers-core.workspace = true +hex.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true diff --git a/crates/solc_expressions/array.rs b/crates/solc_expressions/src/array.rs similarity index 100% rename from crates/solc_expressions/array.rs rename to crates/solc_expressions/src/array.rs diff --git a/crates/solc_expressions/bin_op.rs b/crates/solc_expressions/src/bin_op.rs similarity index 100% rename from crates/solc_expressions/bin_op.rs rename to crates/solc_expressions/src/bin_op.rs diff --git a/crates/solc_expressions/cmp.rs b/crates/solc_expressions/src/cmp.rs similarity index 100% rename from crates/solc_expressions/cmp.rs rename to crates/solc_expressions/src/cmp.rs diff --git a/crates/solc_expressions/cond_op.rs b/crates/solc_expressions/src/cond_op.rs similarity index 100% rename from crates/solc_expressions/cond_op.rs rename to crates/solc_expressions/src/cond_op.rs diff --git a/crates/solc_expressions/env.rs b/crates/solc_expressions/src/env.rs similarity index 100% rename from crates/solc_expressions/env.rs rename to crates/solc_expressions/src/env.rs diff --git a/crates/solc_expressions/func_call/internal_call.rs b/crates/solc_expressions/src/func_call/internal_call.rs similarity index 100% rename from crates/solc_expressions/func_call/internal_call.rs rename to crates/solc_expressions/src/func_call/internal_call.rs diff --git a/crates/solc_expressions/func_call/intrinsic_call.rs b/crates/solc_expressions/src/func_call/intrinsic_call.rs similarity index 100% rename from crates/solc_expressions/func_call/intrinsic_call.rs rename to crates/solc_expressions/src/func_call/intrinsic_call.rs diff --git a/crates/solc_expressions/func_call/mod.rs b/crates/solc_expressions/src/func_call/mod.rs similarity index 100% rename from crates/solc_expressions/func_call/mod.rs rename to crates/solc_expressions/src/func_call/mod.rs diff --git a/crates/solc_expressions/func_call/modifier.rs b/crates/solc_expressions/src/func_call/modifier.rs similarity index 100% rename from crates/solc_expressions/func_call/modifier.rs rename to crates/solc_expressions/src/func_call/modifier.rs diff --git a/crates/solc_expressions/func_call/namespaced_call.rs b/crates/solc_expressions/src/func_call/namespaced_call.rs similarity index 100% rename from crates/solc_expressions/func_call/namespaced_call.rs rename to crates/solc_expressions/src/func_call/namespaced_call.rs diff --git a/crates/solc_expressions/lib.rs b/crates/solc_expressions/src/lib.rs similarity index 100% rename from crates/solc_expressions/lib.rs rename to crates/solc_expressions/src/lib.rs diff --git a/crates/solc_expressions/list.rs b/crates/solc_expressions/src/list.rs similarity index 100% rename from crates/solc_expressions/list.rs rename to crates/solc_expressions/src/list.rs diff --git a/crates/solc_expressions/literal.rs b/crates/solc_expressions/src/literal.rs similarity index 100% rename from crates/solc_expressions/literal.rs rename to crates/solc_expressions/src/literal.rs diff --git a/crates/solc_expressions/loops.rs b/crates/solc_expressions/src/loops.rs similarity index 100% rename from crates/solc_expressions/loops.rs rename to crates/solc_expressions/src/loops.rs diff --git a/crates/solc_expressions/member_access.rs b/crates/solc_expressions/src/member_access.rs similarity index 100% rename from crates/solc_expressions/member_access.rs rename to crates/solc_expressions/src/member_access.rs diff --git a/crates/solc_expressions/require.rs b/crates/solc_expressions/src/require.rs similarity index 100% rename from crates/solc_expressions/require.rs rename to crates/solc_expressions/src/require.rs diff --git a/crates/solc_expressions/variable.rs b/crates/solc_expressions/src/variable.rs similarity index 100% rename from crates/solc_expressions/variable.rs rename to crates/solc_expressions/src/variable.rs diff --git a/crates/solc_expressions/yul/mod.rs b/crates/solc_expressions/src/yul/mod.rs similarity index 100% rename from crates/solc_expressions/yul/mod.rs rename to crates/solc_expressions/src/yul/mod.rs diff --git a/crates/solc_expressions/yul/yul_cond_op.rs b/crates/solc_expressions/src/yul/yul_cond_op.rs similarity index 100% rename from crates/solc_expressions/yul/yul_cond_op.rs rename to crates/solc_expressions/src/yul/yul_cond_op.rs diff --git a/crates/solc_expressions/yul/yul_funcs.rs b/crates/solc_expressions/src/yul/yul_funcs.rs similarity index 100% rename from crates/solc_expressions/yul/yul_funcs.rs rename to crates/solc_expressions/src/yul/yul_funcs.rs From 75efb572b201ab38fecadb491a24495d1fe240f6 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 14:00:38 -0800 Subject: [PATCH 06/71] fix up some Cargo.toml's and delete old stuff --- Cargo.toml | 3 +- crates/analyzer/Cargo.toml | 1 + crates/graph/Cargo.toml | 1 + crates/pyrometer/Cargo.toml | 22 + crates/pyrometer/{ => src}/builtin_fns.rs | 0 crates/pyrometer/{ => src}/lib.rs | 0 shared/Cargo.lock | 1427 ----------- shared/Cargo.toml | 15 - shared/src/analyzer.rs | 810 ------ shared/src/context/expr_ret.rs | 247 -- shared/src/context/mod.rs | 134 - shared/src/context/var.rs | 1506 ----------- shared/src/lib.rs | 136 - shared/src/nodes/block.rs | 68 - shared/src/nodes/concrete.rs | 849 ------- shared/src/nodes/contract_ty.rs | 281 -- shared/src/nodes/enum_ty.rs | 126 - shared/src/nodes/err_ty.rs | 105 - shared/src/nodes/func_ty.rs | 879 ------- shared/src/nodes/mod.rs | 1189 --------- shared/src/nodes/msg.rs | 190 -- shared/src/nodes/struct_ty.rs | 199 -- shared/src/nodes/ty_ty.rs | 77 - shared/src/nodes/var_ty.rs | 236 -- shared/src/range/elem.rs | 175 -- shared/src/range/elem_ty.rs | 2258 ----------------- shared/src/range/mod.rs | 749 ------ shared/src/range/range_ops.rs | 1792 ------------- shared/src/range/range_string.rs | 274 -- src/builtin_fns.rs | 816 ------ src/context/analyzers/bounds.rs | 318 --- src/context/analyzers/func_analyzer/mod.rs | 378 --- .../analyzers/func_analyzer/report_display.rs | 92 - src/context/analyzers/mod.rs | 176 -- src/context/analyzers/var_analyzer/mod.rs | 266 -- .../analyzers/var_analyzer/report_display.rs | 106 - src/context/exprs/array.rs | 183 -- src/context/exprs/bin_op.rs | 797 ------ src/context/exprs/cmp.rs | 469 ---- src/context/exprs/cond_op.rs | 194 -- src/context/exprs/env.rs | 449 ---- src/context/exprs/list.rs | 111 - src/context/exprs/literal.rs | 226 -- src/context/exprs/member_access.rs | 1092 -------- src/context/exprs/mod.rs | 184 -- src/context/exprs/require.rs | 1503 ----------- src/context/exprs/variable.rs | 135 - src/context/func_call/internal_call.rs | 287 --- src/context/func_call/intrinsic_call.rs | 1060 -------- src/context/func_call/mod.rs | 1174 --------- src/context/func_call/modifier.rs | 34 - src/context/func_call/namespaced_call.rs | 372 --- src/context/loops.rs | 93 - src/context/mod.rs | 1537 ----------- src/context/queries/mod.rs | 2 - src/context/queries/storage_write/access.rs | 93 - src/context/queries/storage_write/mod.rs | 5 - src/context/queries/storage_write/target.rs | 156 -- src/context/queries/taint.rs | 68 - src/context/yul/mod.rs | 343 --- src/context/yul/yul_cond_op.rs | 365 --- src/context/yul/yul_funcs.rs | 656 ----- src/lib.rs | 1134 --------- 63 files changed, 26 insertions(+), 28597 deletions(-) create mode 100644 crates/pyrometer/Cargo.toml rename crates/pyrometer/{ => src}/builtin_fns.rs (100%) rename crates/pyrometer/{ => src}/lib.rs (100%) delete mode 100644 shared/Cargo.lock delete mode 100644 shared/Cargo.toml delete mode 100644 shared/src/analyzer.rs delete mode 100644 shared/src/context/expr_ret.rs delete mode 100644 shared/src/context/mod.rs delete mode 100644 shared/src/context/var.rs delete mode 100644 shared/src/lib.rs delete mode 100644 shared/src/nodes/block.rs delete mode 100644 shared/src/nodes/concrete.rs delete mode 100644 shared/src/nodes/contract_ty.rs delete mode 100644 shared/src/nodes/enum_ty.rs delete mode 100644 shared/src/nodes/err_ty.rs delete mode 100644 shared/src/nodes/func_ty.rs delete mode 100644 shared/src/nodes/mod.rs delete mode 100644 shared/src/nodes/msg.rs delete mode 100644 shared/src/nodes/struct_ty.rs delete mode 100644 shared/src/nodes/ty_ty.rs delete mode 100644 shared/src/nodes/var_ty.rs delete mode 100644 shared/src/range/elem.rs delete mode 100644 shared/src/range/elem_ty.rs delete mode 100644 shared/src/range/mod.rs delete mode 100644 shared/src/range/range_ops.rs delete mode 100644 shared/src/range/range_string.rs delete mode 100644 src/builtin_fns.rs delete mode 100644 src/context/analyzers/bounds.rs delete mode 100644 src/context/analyzers/func_analyzer/mod.rs delete mode 100644 src/context/analyzers/func_analyzer/report_display.rs delete mode 100644 src/context/analyzers/mod.rs delete mode 100644 src/context/analyzers/var_analyzer/mod.rs delete mode 100644 src/context/analyzers/var_analyzer/report_display.rs delete mode 100644 src/context/exprs/array.rs delete mode 100644 src/context/exprs/bin_op.rs delete mode 100644 src/context/exprs/cmp.rs delete mode 100644 src/context/exprs/cond_op.rs delete mode 100644 src/context/exprs/env.rs delete mode 100644 src/context/exprs/list.rs delete mode 100644 src/context/exprs/literal.rs delete mode 100644 src/context/exprs/member_access.rs delete mode 100644 src/context/exprs/mod.rs delete mode 100644 src/context/exprs/require.rs delete mode 100644 src/context/exprs/variable.rs delete mode 100644 src/context/func_call/internal_call.rs delete mode 100644 src/context/func_call/intrinsic_call.rs delete mode 100644 src/context/func_call/mod.rs delete mode 100644 src/context/func_call/modifier.rs delete mode 100644 src/context/func_call/namespaced_call.rs delete mode 100644 src/context/loops.rs delete mode 100644 src/context/mod.rs delete mode 100644 src/context/queries/mod.rs delete mode 100644 src/context/queries/storage_write/access.rs delete mode 100644 src/context/queries/storage_write/mod.rs delete mode 100644 src/context/queries/storage_write/target.rs delete mode 100644 src/context/queries/taint.rs delete mode 100644 src/context/yul/mod.rs delete mode 100644 src/context/yul/yul_cond_op.rs delete mode 100644 src/context/yul/yul_funcs.rs delete mode 100644 src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 11074f5b..8e29e544 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "crates/analyzer", "crates/cli", "crates/graph", + "crates/pyrometer", "crates/queries", "crates/range", "crates/solc_expressions", @@ -33,6 +34,7 @@ debug = true [workspace.dependencies] analyzer = { path = "crates/analyzer" } graph = { path = "crates/graph" } +pyrometer = { path = "crates/pyrometer" } queries = { path = "crates/queries" } range = { path = "crates/range" } solc_expressions = { path = "crates/solc_expressions" } @@ -42,7 +44,6 @@ tracing = { version = "0.1", features = ["attributes"] } tracing-subscriber = "0.3" ethers-core = "*" hex = "0.4.3" -lazy_static = ariadne = "0.2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/analyzer/Cargo.toml b/crates/analyzer/Cargo.toml index 03ecba78..b89e4fec 100644 --- a/crates/analyzer/Cargo.toml +++ b/crates/analyzer/Cargo.toml @@ -12,5 +12,6 @@ repository.workspace = true [dependencies] graph.workspace = true +range.workspace = true solang-parser.workspace = true ariadne.workspace = true \ No newline at end of file diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml index 45bed73e..1c26fe07 100644 --- a/crates/graph/Cargo.toml +++ b/crates/graph/Cargo.toml @@ -11,6 +11,7 @@ homepage.workspace = true repository.workspace = true [dependencies] +range.workspace = true solang-parser.workspace = true ethers-core.workspace = true hex.workspace = true diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml new file mode 100644 index 00000000..46c81db9 --- /dev/null +++ b/crates/pyrometer/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pyrometer" +description = "Core Pyrometer library and analyzer implementation" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +analyzer.workspace = true +graph.workspace = true +range.workspace = true +solc_expressions.workspace = true +solang-parser.workspace = true +ethers-core.workspace = true +ariadne.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true diff --git a/crates/pyrometer/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs similarity index 100% rename from crates/pyrometer/builtin_fns.rs rename to crates/pyrometer/src/builtin_fns.rs diff --git a/crates/pyrometer/lib.rs b/crates/pyrometer/src/lib.rs similarity index 100% rename from crates/pyrometer/lib.rs rename to crates/pyrometer/src/lib.rs diff --git a/shared/Cargo.lock b/shared/Cargo.lock deleted file mode 100644 index 24f92325..00000000 --- a/shared/Cargo.lock +++ /dev/null @@ -1,1427 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "const-oid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest", - "ff", - "generic-array", - "group", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" -dependencies = [ - "arrayvec", - "bytes", - "chrono", - "elliptic-curve", - "ethabi", - "generic-array", - "hex", - "k256", - "open-fastrlp", - "rand", - "rlp", - "rlp-derive", - "serde", - "serde_json", - "strum", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", - "sha3", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-scale-codec" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared 0.11.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared 0.11.1", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared 0.11.1", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "primitive-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "scale-info" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "shared" -version = "0.1.0" -dependencies = [ - "ethers-core", - "hex", - "lazy_static", - "petgraph", - "solang-parser", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "solang-parser" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9653f278d9531b60f042c29732bb835d519943f4167b1e5684c7e820dd9fec" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "serde", - "unicode-xid", -] - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/shared/Cargo.toml b/shared/Cargo.toml deleted file mode 100644 index 342414da..00000000 --- a/shared/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "shared" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -ethers-core = "*" -petgraph = "0.6.2" -solang-parser = { version = "0.2.4", features = ["pt-serde"] } -lazy_static = "1.4.0" -hex = "0.4.3" -tracing = { version = "0.1", features = ["attributes"] } -tracing-subscriber = "0.3" \ No newline at end of file diff --git a/shared/src/analyzer.rs b/shared/src/analyzer.rs deleted file mode 100644 index 5ca67036..00000000 --- a/shared/src/analyzer.rs +++ /dev/null @@ -1,810 +0,0 @@ -use crate::as_dot_str; - -use crate::FunctionParamNode; - -use crate::range::Range; -use crate::BlockNode; - -use crate::MsgNode; -use std::sync::Arc; -use std::sync::Mutex; - -use crate::context::ContextVarNode; -use crate::range::range_string::ToRangeString; -use crate::{Builtin, Edge, Function, FunctionParam, FunctionReturn, Node, NodeIdx}; -use petgraph::visit::EdgeRef; -use std::collections::BTreeMap; -use std::collections::BTreeSet; - -use petgraph::dot::Dot; -use petgraph::{graph::*, Directed, Direction}; -use std::collections::HashMap; - -#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] -pub enum GraphError { - NodeConfusion(String), - MaxStackDepthReached(String), - MaxStackWidthReached(String), - ChildRedefinition(String), - VariableUpdateInOldContext(String), - DetachedVariable(String), - ExpectedSingle(String), - StackLengthMismatch(String), - UnbreakableRecursion(String), -} - -pub trait AnalyzerLike: GraphLike { - type Expr; - type ExprErr; - /// Gets the builtin functions map - fn builtin_fns(&self) -> &HashMap; - /// Mutably gets the builtin functions map - fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap; - /// Gets the builtin function nodes mapping - fn builtin_fn_nodes(&self) -> &HashMap; - /// Returns the configured max call depth - fn max_depth(&self) -> usize; - /// Returns the configured max fork width - fn max_width(&self) -> usize; - fn builtin_fn_inputs(&self) -> &HashMap, Vec)>; - fn builtins(&self) -> &HashMap; - fn builtins_mut(&mut self) -> &mut HashMap; - fn builtin_or_add(&mut self, builtin: Builtin) -> NodeIdx { - if let Some(idx) = self.builtins().get(&builtin) { - *idx - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins_mut().insert(builtin, idx); - idx - } - } - fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option - where - Self: std::marker::Sized, - { - if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { - Some(*idx) - } else if let Some(func) = self.builtin_fns().get(builtin_name) { - let (inputs, outputs) = self - .builtin_fn_inputs() - .get(builtin_name) - .expect("builtin func but no inputs") - .clone(); - let func_node = self.add_node(Node::Function(func.clone())); - let mut params_strs = vec![]; - inputs.into_iter().for_each(|input| { - let input_node = self.add_node(input); - params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); - self.add_edge(input_node, func_node, Edge::FunctionParam); - }); - outputs.into_iter().for_each(|output| { - let output_node = self.add_node(output); - self.add_edge(output_node, func_node, Edge::FunctionReturn); - }); - - self.add_edge(func_node, self.entry(), Edge::Func); - - self.builtin_fn_nodes_mut() - .insert(builtin_name.to_string(), func_node); - Some(func_node) - } else { - None - } - } - fn user_types(&self) -> &HashMap; - fn user_types_mut(&mut self) -> &mut HashMap; - fn parse_expr(&mut self, expr: &Self::Expr, parent: Option) -> NodeIdx; - fn msg(&mut self) -> MsgNode; - fn block(&mut self) -> BlockNode; - fn entry(&self) -> NodeIdx; - - fn add_expr_err(&mut self, err: Self::ExprErr); - - fn add_if_err(&mut self, err: Result) -> Option { - match err { - Ok(t) => Some(t), - Err(e) => { - self.add_expr_err(e); - None - } - } - } - - fn expr_errs(&self) -> Vec; -} - -pub struct G<'a> { - pub graph: &'a Graph, -} -impl GraphLike for G<'_> { - fn graph_mut(&mut self) -> &mut Graph { - panic!("Should call this") - } - - fn graph(&self) -> &Graph { - self.graph - } -} - -pub trait GraphLike { - fn graph_mut(&mut self) -> &mut Graph; - fn graph(&self) -> &Graph; - - fn add_node(&mut self, node: impl Into) -> NodeIdx { - self.graph_mut().add_node(node.into()) - } - - fn node(&self, node: impl Into) -> &Node { - self.graph() - .node_weight(node.into()) - .expect("Index not in graph") - } - - fn node_mut(&mut self, node: impl Into) -> &mut Node { - self.graph_mut() - .node_weight_mut(node.into()) - .expect("Index not in graph") - } - - fn open_dot(&self) - where - Self: std::marker::Sized, - Self: AnalyzerLike, - { - use std::env::temp_dir; - use std::fs; - use std::io::Write; - use std::process::Command; - let temp_dir = temp_dir(); - let file_name = "dot.dot"; - let mut temp_path = temp_dir.clone(); - temp_path.push(file_name); - let temp_svg_filename: String = format!("{}/dot.svg", &temp_dir.to_string_lossy()); - - let mut file = fs::File::create(temp_path.clone()).unwrap(); - file.write_all(self.dot_str().as_bytes()).unwrap(); - Command::new("dot") - .arg("-Tsvg") - .arg(temp_path) - .arg("-o") - .arg(&temp_svg_filename) - .output() - .expect("You may need to install graphviz, check if command 'dot' is in your $PATH"); - Command::new("open") - .arg(&temp_svg_filename) - .spawn() - .expect("failed to execute process"); - } - - fn add_edge( - &mut self, - from_node: impl Into, - to_node: impl Into, - edge: impl Into, - ) { - self.graph_mut() - .add_edge(from_node.into(), to_node.into(), edge.into()); - } - - fn cluster_str( - &self, - node: NodeIdx, - cluster_num: usize, - is_killed: bool, - handled_nodes: Arc>>, - handled_edges: Arc>>>, - ) -> String { - if self - .graph() - .edges_directed(node, Direction::Outgoing) - .collect::>() - .is_empty() - { - return "".to_string(); - } - let new_graph = self.graph().filter_map( - |_idx, node| match node { - Node::ContextVar(_cvar) => { - // if !cvar.is_symbolic { - // None - // } else { - Some(node.clone()) - // } - } - _ => Some(node.clone()), - }, - |_idx, edge| Some(*edge), - ); - - let g = &G { graph: &new_graph }; - let children = g.children(node); - let children_edges = g.children_edges(node); - let mut cn = cluster_num + 1; - let child_node_str = children - .iter() - .map(|child| { - { - handled_nodes.lock().unwrap().insert(*child); - } - - if g.graph - .edges_directed(*child, Direction::Outgoing) - .collect::>() - .is_empty() - { - return "".to_string(); - } - let post_str = match self.node(*child) { - Node::Context(c) => { - cn += 2; - self.cluster_str( - *child, - cn, - c.killed.is_some(), - handled_nodes.clone(), - handled_edges.clone(), - ) - } - _ => "".to_string(), - }; - - format!( - " {} [label = \"{}\", color = \"{}\"]\n{}\n", - petgraph::graph::GraphIndex::index(child), - as_dot_str(*child, g).replace('\"', "\'"), - self.node(*child).dot_str_color(), - post_str - ) - }) - .collect::>() - .join(""); - - let edge_str = children_edges - .iter() - .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) - .map(|(from, to, edge, idx)| { - handled_edges.lock().unwrap().insert(*idx); - let from = petgraph::graph::GraphIndex::index(from); - let to = petgraph::graph::GraphIndex::index(to); - format!(" {from:} -> {to:} [label = \"{edge:?}\"]\n",) - }) - .collect::>() - .join(""); - format!( - " subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", - cluster_num, - if is_killed && cluster_num % 2 == 0 { - " bgcolor=\"#7a0b0b\"" - } else if is_killed { - " bgcolor=\"#e04646\"" - } else if cluster_num % 2 == 0 { - " bgcolor=\"#545e87\"" - } else { - " bgcolor=\"#1a1b26\"" - }, - format!( - " {} [label = \"{}\", color = \"{}\"]\n", - node.index(), - as_dot_str(node, g).replace('\"', "\'"), - self.node(node).dot_str_color() - ), - child_node_str, - edge_str, - ) - } - - fn dot_str(&self) -> String - where - Self: std::marker::Sized, - Self: AnalyzerLike, - { - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26"; rankdir="BT""##; - dot_str.push(raw_start_str.to_string()); - let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); - let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); - let (nodes, edges) = ( - self.graph().node_indices().collect::>(), - self.graph().edge_indices().collect::>(), - ); - let mut cluster_num = 0; - let mut skip = BTreeSet::default(); - let nodes_str = nodes - .iter() - .filter_map(|node| { - if self - .graph() - .edges_directed(*node, Direction::Outgoing) - .collect::>() - .is_empty() - && !matches!(self.node(*node), Node::Entry) - { - skip.insert(*node); - return None; - } - if !handled_nodes.lock().unwrap().contains(node) { - match self.node(*node) { - Node::Function(_) => { - cluster_num += 2; - Some(self.cluster_str( - *node, - cluster_num, - false, - handled_nodes.clone(), - handled_edges.clone(), - )) - } - n => Some(format!( - "{} [label = \"{}\", color = \"{}\"]", - petgraph::graph::GraphIndex::index(node), - as_dot_str(*node, self).replace('\"', "\'"), - n.dot_str_color() - )), - } - } else { - None - } - }) - .collect::>() - .join("\n "); - let edges_str = edges - .into_iter() - .filter_map(|edge| { - if !handled_edges.lock().unwrap().contains(&edge) { - let (from, to) = self.graph().edge_endpoints(edge).unwrap(); - if skip.contains(&from) || skip.contains(&to) { - return None; - } - let from = from.index(); - let to = to.index(); - Some(format!( - "{from:} -> {to:} [label = \"{:?}\"]", - self.graph().edge_weight(edge).unwrap() - )) - } else { - None - } - }) - .collect::>() - .join("\n "); - - dot_str.push(nodes_str); - dot_str.push(edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - dot_str.join("\n") - } - - fn dot_str_no_tmps(&self) -> String - where - Self: std::marker::Sized, - Self: GraphLike + AnalyzerLike, - { - let new_graph = self.graph().filter_map( - |_idx, node| match node { - Node::ContextVar(cvar) => { - if !cvar.is_symbolic || cvar.tmp_of.is_some() { - None - } else { - Some(node.clone()) - } - } - _ => Some(node.clone()), - }, - |_idx, edge| Some(*edge), - ); - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &new_graph, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - match edge_ref.weight() { - Edge::Context(edge) => format!("label = \"{edge:?}\""), - e => format!("label = \"{e:?}\""), - } - }, - &|_graph, (idx, node_ref)| { - let inner = match node_ref { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { - r.as_dot_str(self) - // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - } else { - "".to_string() - }; - - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(self).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, &G { graph: &new_graph }), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - node_ref.dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - dot_str.join("\n") - } - - fn dot_str_no_tmps_for_ctx(&self, fork_name: String) -> String - where - Self: GraphLike + AnalyzerLike, - Self: Sized, - { - let new_graph = self.graph().filter_map( - |idx, node| match node { - Node::Context(ctx) => { - if ctx.path != fork_name { - None - } else { - Some(node.clone()) - } - } - Node::ContextVar(cvar) => { - if let Some(ctx) = ContextVarNode::from(idx).maybe_ctx(self) { - if ctx.underlying(self).unwrap().path == fork_name && !cvar.is_symbolic { - Some(node.clone()) - } else { - None - } - } else { - None - } - } - _ => Some(node.clone()), - }, - |_idx, edge| Some(*edge), - ); - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &new_graph, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - match edge_ref.weight() { - Edge::Context(edge) => format!("label = \"{edge:?}\""), - e => format!("label = \"{e:?}\""), - } - }, - &|_graph, (idx, node_ref)| { - let inner = match node_ref { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { - format!( - "[{}, {}]", - r.evaled_range_min(self) - .unwrap() - .to_range_string(false, self) - .s, - r.evaled_range_max(self) - .unwrap() - .to_range_string(true, self) - .s - ) - } else { - "".to_string() - }; - - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(self).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, &G { graph: &new_graph }), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - node_ref.dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - dot_str.join("\n") - } -} - -impl Search for T where T: GraphLike {} -pub trait Search: GraphLike { - fn search_for_ancestor(&self, start: NodeIdx, edge_ty: &Edge) -> Option { - let edges = self.graph().edges_directed(start, Direction::Outgoing); - if let Some(edge) = edges.clone().find(|edge| edge.weight() == edge_ty) { - Some(edge.target()) - } else { - edges - .map(|edge| edge.target()) - .filter_map(|node| self.search_for_ancestor(node, edge_ty)) - .take(1) - .next() - } - } - - fn search_for_ancestor_multi(&self, start: NodeIdx, edge_tys: &[Edge]) -> Option { - let edges = self.graph().edges_directed(start, Direction::Outgoing); - if let Some(edge) = edges.clone().find(|edge| edge_tys.contains(edge.weight())) { - Some(edge.target()) - } else { - edges - .map(|edge| edge.target()) - .filter_map(|node| self.search_for_ancestor_multi(node, edge_tys)) - .take(1) - .next() - } - } - /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a set of these - /// - /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d - /// - /// This function would build a set { b, d } if we are looking for `my_edge` and start at a. - fn search_children(&self, start: NodeIdx, edge_ty: &Edge) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .flat_map(|edge| self.search_children(edge.source(), edge_ty)) - .collect::>(), - ); - this_children - } - - fn find_child_exclude_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - exclude_edges: &[Edge], - find_fn: &impl Fn(NodeIdx, &Self) -> Option, - ) -> Option { - let edges = self - .graph() - .edges_directed(start, Direction::Incoming) - .filter(|edge| !exclude_edges.contains(edge.weight())); - if let Some(node) = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .find(|node| find_fn(*node, self).is_some()) - { - Some(node) - } else { - edges - .clone() - .map(|edge| edge.source()) - .find_map(|node| self.find_child_exclude_via(node, edge_ty, exclude_edges, find_fn)) - } - } - - fn search_children_exclude_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - exclude_edges: &[Edge], - ) -> BTreeSet { - let edges = self - .graph() - .edges_directed(start, Direction::Incoming) - .filter(|edge| !exclude_edges.contains(edge.weight())); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .flat_map(|edge| { - self.search_children_exclude_via(edge.source(), edge_ty, exclude_edges) - }) - .collect::>(), - ); - this_children - } - - fn search_children_include_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - include_edges: &[Edge], - ) -> BTreeSet { - let mut edges: Vec<_> = self - .graph() - .edges_directed(start, Direction::Incoming) - .collect(); - edges = edges - .into_iter() - .filter(|edge| include_edges.contains(edge.weight())) - .collect::>(); - let mut this_children: BTreeSet = edges - .iter() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .clone() - .iter() - .flat_map(|edge| { - self.search_children_include_via(edge.source(), edge_ty, include_edges) - }) - .collect::>(), - ); - this_children - } - - fn search_children_depth( - &self, - start: NodeIdx, - edge_ty: &Edge, - max_depth: usize, - curr_depth: usize, - ) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - if curr_depth < max_depth { - this_children.extend( - edges - .flat_map(|edge| { - self.search_children_depth( - edge.source(), - edge_ty, - max_depth, - curr_depth + 1, - ) - }) - .collect::>(), - ); - } - this_children - } - - /// Gets all children recursively - fn children(&self, start: NodeIdx) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = - edges.clone().map(|edge| edge.source()).collect(); - - this_children.extend( - edges - .flat_map(|edge| self.children(edge.source())) - .collect::>(), - ); - this_children - } - - /// Gets all children edges recursively - fn children_edges( - &self, - start: NodeIdx, - ) -> BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children_edges: BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> = edges - .clone() - .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) - .collect(); - - this_children_edges.extend( - edges - .flat_map(|edge| self.children_edges(edge.source())) - .collect::)>>(), - ); - this_children_edges - } - - /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a mapping of these - /// - /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d - /// - /// This function would build a map { a: [b], c: [d] } if we are looking for `my_edge` and start at a. - fn nodes_with_children( - &self, - start: NodeIdx, - edge_ty: &Edge, - ) -> Option>> { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut map: BTreeMap> = Default::default(); - - let this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - if !this_children.is_empty() { - map.insert(start, this_children); - } - map.extend( - edges - .filter_map(|edge| self.nodes_with_children(edge.source(), edge_ty)) - .flatten() - .collect::>>(), - ); - if map.is_empty() { - None - } else { - Some(map) - } - } -} - -pub trait AsDotStr { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String; -} diff --git a/shared/src/context/expr_ret.rs b/shared/src/context/expr_ret.rs deleted file mode 100644 index 00640a60..00000000 --- a/shared/src/context/expr_ret.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::context::GraphError; -use crate::{ContextVarNode, GraphLike, Node, NodeIdx, VarType}; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum KilledKind { - Ended, - Unreachable, - Revert, - ParseError, -} - -impl KilledKind { - pub fn analysis_str(&self) -> &str { - use KilledKind::*; - match self { - Ended => "Execution ended here successfully", - Unreachable => "Unsatisifiable bounds, therefore dead code", - Revert => "Execution guaranteed to revert here!", - ParseError => "Unexpected parse error. This is likely a bug or invalid solidity. See the `errors` section of the CLI output or rerun with `--debug` for more information", - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum ExprRet { - CtxKilled(KilledKind), - Null, - Single(NodeIdx), - SingleLiteral(NodeIdx), - Multi(Vec), -} - -impl ExprRet { - pub fn debug_str(&self, analyzer: &impl GraphLike) -> String { - match self { - ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => match analyzer.node(*inner) { - Node::ContextVar(_) => ContextVarNode::from(*inner).display_name(analyzer).unwrap(), - e => format!("{:?}", e), - }, - ExprRet::Multi(inner) => { - format!( - "[{}]", - inner - .iter() - .map(|i| i.debug_str(analyzer)) - .collect::>() - .join(", ") - ) - } - ExprRet::CtxKilled(kind) => format!("CtxKilled({:?}", kind), - ExprRet::Null => "".to_string(), - } - } - - pub fn take_one(&mut self) -> Result, GraphError> { - match self { - ExprRet::Single(..) | ExprRet::SingleLiteral(..) => { - let ret = self.clone(); - *self = ExprRet::Multi(vec![]); - Ok(Some(ret)) - } - ExprRet::Multi(ref mut inner) => { - let elem = inner.pop(); - Ok(elem) - } - e => Err(GraphError::ExpectedSingle(format!( - "Expected a single return got: {e:?}" - ))), - } - } - - pub fn literals_list(&self) -> Result, GraphError> { - match self { - ExprRet::SingleLiteral(..) => Ok(vec![true]), - ExprRet::Single(..) => Ok(vec![false]), - ExprRet::Multi(ref inner) => { - let mut list = vec![]; - inner.iter().try_for_each(|i| { - list.extend(i.literals_list()?); - Ok(()) - })?; - Ok(list) - } - e => Err(GraphError::ExpectedSingle(format!( - "Expected a single return got: {e:?}" - ))), - } - } - - pub fn expect_single(&self) -> Result { - match self { - ExprRet::Single(inner) => Ok(*inner), - ExprRet::SingleLiteral(inner) => Ok(*inner), - ExprRet::Multi(inner) if inner.len() == 1 => Ok(inner[0].expect_single()?), - e => Err(GraphError::ExpectedSingle(format!( - "Expected a single return got: {e:?}" - ))), - } - } - - pub fn expect_length(&self, len: usize) -> Result<(), GraphError> { - match self { - ExprRet::Single(_) | ExprRet::SingleLiteral(_) => { - if len == 1 { - Ok(()) - } else { - Err(GraphError::StackLengthMismatch(format!( - "Expected an element with {len} elements, return got: 1 element" - ))) - } - } - ExprRet::Multi(inner) => { - if inner.len() == len { - Ok(()) - } else { - Err(GraphError::StackLengthMismatch(format!( - "Expected an element with {len} elements, return got: {} elements", - inner.len() - ))) - } - } - ExprRet::CtxKilled(..) => Err(GraphError::StackLengthMismatch(format!( - "Expected an element with {len} elements, but context was killed" - ))), - ExprRet::Null if len != 0 => Err(GraphError::StackLengthMismatch(format!( - "Expected an element with {len} elements, return got: 0 elements", - ))), - _ => Ok(()), - } - } - - pub fn is_single(&self) -> bool { - match self { - ExprRet::Single(_inner) => true, - ExprRet::SingleLiteral(_inner) => true, - ExprRet::Multi(inner) => inner.len() == 1, - _ => false, - } - } - - pub fn is_killed(&self) -> bool { - matches!(self, ExprRet::CtxKilled(_)) - } - - pub fn killed_kind(&self) -> Option { - match self { - ExprRet::CtxKilled(k) => Some(*k), - ExprRet::Multi(multis) => multis.iter().find_map(|expr_ret| expr_ret.killed_kind()), - _ => None, - } - } - - pub fn has_fork(&self) -> bool { - false - } - - pub fn has_killed(&self) -> bool { - match self { - ExprRet::CtxKilled(_) => true, - ExprRet::Multi(multis) => multis.iter().any(|expr_ret| expr_ret.has_killed()), - _ => false, - } - } - - pub fn has_literal(&self) -> bool { - match self { - ExprRet::SingleLiteral(..) => true, - ExprRet::Multi(multis) => multis.iter().any(|expr_ret| expr_ret.has_literal()), - _ => false, - } - } - - pub fn expect_multi(self) -> Vec { - match self { - ExprRet::Multi(inner) => inner, - _ => panic!("Expected a multi return got single"), - } - } - - pub fn try_as_func_input_str(&self, analyzer: &impl GraphLike) -> String { - match self { - ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { - let idx = inner; - match VarType::try_from_idx(analyzer, *idx) { - Some(var_ty) => { - if let Ok(ty) = var_ty.unresolved_as_resolved(analyzer) { - format!("({})", ty.as_dot_str(analyzer)) - } else { - "".to_string() - } - } - None => "".to_string(), - } - } - ExprRet::Multi(inner) if !self.has_fork() => { - let mut strs = vec![]; - for ret in inner.iter() { - strs.push(ret.try_as_func_input_str(analyzer).replace(['(', ')'], "")); - } - format!("({})", strs.join(", ")) - } - e => todo!("here: {e:?}"), - } - } - - pub fn as_flat_vec(&self) -> Vec { - let mut idxs = vec![]; - match self { - ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => idxs.push(*idx), - ExprRet::Multi(inner) => { - idxs.extend( - inner - .iter() - .flat_map(|expr| expr.as_flat_vec()) - .collect::>(), - ); - } - _ => {} - } - idxs - } - - pub fn as_vec(&self) -> Vec { - match self { - s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => vec![s.clone()], - ExprRet::Multi(inner) => inner.clone(), - _ => { - vec![] - } - } - } - - pub fn flatten(self) -> Self { - match self { - ExprRet::Single(_) | ExprRet::SingleLiteral(_) => self, - ExprRet::Multi(inner) => { - if inner.len() == 1 { - inner[0].to_owned().flatten() - } else { - ExprRet::Multi(inner.into_iter().map(|i| i.flatten()).collect()) - } - } - _ => self, - } - } -} diff --git a/shared/src/context/mod.rs b/shared/src/context/mod.rs deleted file mode 100644 index 7df2b145..00000000 --- a/shared/src/context/mod.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike, Search}; -use crate::as_dot_str; -use crate::nodes::FunctionNode; - -use crate::AsDotStr; -use crate::ContractNode; -use crate::FunctionParamNode; -use crate::StructNode; -use petgraph::dot::Dot; -use std::collections::BTreeSet; - -use crate::{Edge, Node, NodeIdx}; - -use solang_parser::pt::Loc; -use std::collections::BTreeMap; - -mod var; -pub use var::*; -mod expr_ret; -pub use expr_ret::*; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum CallFork { - Call(ContextNode), - Fork(ContextNode, ContextNode), -} - -impl CallFork { - pub fn maybe_call(&self) -> Option { - match self { - CallFork::Call(c) => Some(*c), - _ => None, - } - } - - pub fn maybe_fork(&self) -> Option<(ContextNode, ContextNode)> { - match self { - CallFork::Fork(w1, w2) => Some((*w1, *w2)), - _ => None, - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum ContextEdge { - // Control flow - Context, - Subcontext, - ContextFork, - ContextMerge, - Call, - - // Context Variables - Variable, - InheritedVariable, - - AttrAccess, - Index, - IndexAccess, - StructAccess, - FuncAccess, - - // Variable incoming edges - Assign, - StorageAssign, - MemoryAssign, - Prev, - - // Control flow - Return, - Continue, - InputVariable, - ReturnAssign(bool), - - // Range analysis - Range, -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ModifierState { - pub num: usize, - pub loc: Loc, - pub parent_fn: FunctionNode, - pub parent_caller_ctx: ContextNode, - pub parent_ctx: ContextNode, - pub renamed_inputs: BTreeMap, -} - -impl ModifierState { - pub fn new( - num: usize, - loc: Loc, - parent_fn: FunctionNode, - parent_ctx: ContextNode, - parent_caller_ctx: ContextNode, - renamed_inputs: BTreeMap, - ) -> Self { - Self { - num, - loc, - parent_fn, - parent_ctx, - parent_caller_ctx, - renamed_inputs, - } - } -} - -#[derive(Default, Debug, Clone, Eq, PartialEq)] -pub struct ContextCache { - pub vars: BTreeMap, - pub visible_funcs: Option>, - pub first_ancestor: Option, - pub associated_source: Option, - pub associated_contract: Option, -} - - - - -// 2023-05-13T04:28:34.318383Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_expr_inner{ctx=getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }}:fn_call_expr:call_internal_func:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner: pyrometer::context: Applying to live edges of: getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256).anonymous_fn_call. edges: [ -// "getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256).anonymous_fn_call.average(uint256, uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }.fork{ true }._unsafeAccess(Checkpoint[], uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }", -// "getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256).anonymous_fn_call.average(uint256, uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }.fork{ false }._unsafeAccess(Checkpoint[], uint256).resume{ _upperBinaryLookup(Checkpoint[], uint32, uint256, uint256) }", -// "getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256)" -// ] -// 2023-05-13T04:28:34.318505Z TRACE parse:parse_ctx_stmt_inner:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:parse_ctx_expr_inner{ctx=getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }}:fn_call_expr:call_internal_func:func_call_inner:execute_call_inner:parse_ctx_stmt_inner:parse_ctx_stmt_inner:advance_var_in_ctx{ctx=getAtProbablyRecentBlock(History, uint256).toUint32(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }.fork{ true }.sqrt(uint256).resume{ getAtProbablyRecentBlock(History, uint256) }._upperBinaryLookup(Checkpoint[], uint32, uint256, uint256)}: pyrometer::context: advancing variable: high -// thread 'main' panicked at 'Variable update of high in old context: -// parent: -// , child: Call( -// ContextNode( -// 140171, -// ), -// )' diff --git a/shared/src/context/var.rs b/shared/src/context/var.rs deleted file mode 100644 index 8c227bb4..00000000 --- a/shared/src/context/var.rs +++ /dev/null @@ -1,1506 +0,0 @@ -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::context::GraphError; -use crate::range::elem::RangeElem; -use crate::TyNode; - -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeConcrete; -use crate::range::range_string::ToRangeString; -use crate::range::Range; -use crate::range::SolcRange; -use std::collections::BTreeMap; - -use crate::AsDotStr; -use crate::BuiltInNode; -use crate::Builtin; -use crate::Concrete; -use crate::ContractNode; -use crate::EnumNode; -use crate::FunctionNode; - -use crate::StructNode; -use crate::TypeNode; -use crate::{ - analyzer::Search, context::ContextNode, nodes::ConcreteNode, range::elem::RangeOp, ContextEdge, - Edge, Field, FunctionParam, FunctionReturn, Node, NodeIdx, VarType, -}; - -use petgraph::visit::EdgeRef; -use petgraph::Direction; -use solang_parser::pt::{Loc, StorageLocation}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct ContextVarNode(pub usize); -impl AsDotStr for ContextVarNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - - let range_str = if let Some(r) = underlying.ty.ref_range(analyzer).unwrap() { - format!( - "[{}, {}]", - r.evaled_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s, - r.evaled_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - ) - } else { - "".to_string() - }; - - format!( - "{} - {} -- {} -- range: {}", - underlying.display_name, - self.0, - underlying.ty.as_string(analyzer).unwrap(), - range_str - ) - } -} - -impl From for NodeIdx { - fn from(val: ContextVarNode) -> Self { - val.0.into() - } -} - -impl From for ContextVarNode { - fn from(idx: NodeIdx) -> Self { - ContextVarNode(idx.index()) - } -} - -impl ContextVarNode { - pub fn underlying<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> Result<&'a ContextVar, GraphError> { - match analyzer.node(*self) { - Node::ContextVar(c) => Ok(c), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be ContextVar but it was: {e:?}" - ))), - } - } - - pub fn underlying_mut<'a>( - &self, - analyzer: &'a mut impl GraphLike, - ) -> Result<&'a mut ContextVar, GraphError> { - match analyzer.node_mut(*self) { - Node::ContextVar(c) => Ok(c), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be ContextVar but it was: {e:?}" - ))), - } - } - - pub fn storage<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> Result<&'a Option, GraphError> { - Ok(&self.underlying(analyzer)?.storage) - } - - pub fn is_storage(&self, analyzer: &impl GraphLike) -> Result { - Ok(matches!( - self.underlying(analyzer)?.storage, - Some(StorageLocation::Storage(..)) - )) - } - - pub fn ty<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a VarType, GraphError> { - Ok(&self.underlying(analyzer)?.ty) - } - - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { - self.ty(analyzer)?.is_mapping(analyzer) - } - - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { - self.ty(analyzer)?.is_dyn(analyzer) - } - - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { - self.ty(analyzer)?.is_indexable(analyzer) - } - - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .loc - .expect("No loc for ContextVar")) - } - - pub fn ctx(&self, analyzer: &impl GraphLike) -> ContextNode { - ContextNode::from( - analyzer - .search_for_ancestor(self.0.into(), &Edge::Context(ContextEdge::Variable)) - .into_iter() - .take(1) - .next() - .expect("No associated ctx"), - ) - } - - pub fn maybe_ctx(&self, analyzer: &impl GraphLike) -> Option { - let first = self.first_version(analyzer); - analyzer - .graph() - .edges_directed(first.0.into(), Direction::Outgoing) - .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::Variable)) - .map(|edge| ContextNode::from(edge.target())) - .take(1) - .next() - // Some(ContextNode::from( - // analyzer - // .search_for_ancestor(self.0.into(), &Edge::Context(ContextEdge::Variable)) - // .into_iter() - // .take(1) - // .next()?, - // )) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn update_deps( - &mut self, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { - range.update_deps(*self, ctx, analyzer); - self.set_range_min(analyzer, range.min)?; - self.set_range_max(analyzer, range.max)?; - } - Ok(()) - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.name.clone()) - } - - pub fn display_name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.display_name.clone()) - } - - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - self.underlying(analyzer)?.ty.range(analyzer) - } - - pub fn ref_range<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> Result>, GraphError> { - self.underlying(analyzer)?.ty.ref_range(analyzer) - } - - pub fn range_min( - &self, - analyzer: &impl GraphLike, - ) -> Result>, GraphError> { - if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.range_min().into_owned())) - } else { - Ok(None) - } - } - - pub fn range_max( - &self, - analyzer: &impl GraphLike, - ) -> Result>, GraphError> { - if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.range_max().into_owned())) - } else { - Ok(None) - } - } - - pub fn evaled_range_min( - &self, - analyzer: &impl GraphLike, - ) -> Result>, GraphError> { - if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.evaled_range_min(analyzer)?)) - } else { - Ok(None) - } - } - - pub fn evaled_range_max( - &self, - analyzer: &impl GraphLike, - ) -> Result>, GraphError> { - if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.evaled_range_max(analyzer)?)) - } else { - Ok(None) - } - } - - pub fn return_assignments(&self, analyzer: &impl GraphLike) -> Vec { - let latest = self.latest_version(analyzer); - let mut earlier = latest; - let mut return_assignments = vec![]; - while let Some(prev) = earlier.previous_version(analyzer) { - if earlier.is_return_assignment(analyzer) { - return_assignments.push(earlier) - } - earlier = prev; - } - return_assignments - } - - pub fn ext_return_assignments(&self, analyzer: &impl GraphLike) -> Vec { - let latest = self.latest_version(analyzer); - let mut earlier = latest; - let mut return_assignments = vec![]; - if earlier.is_ext_return_assignment(analyzer) { - return_assignments.push(earlier) - } - while let Some(prev) = earlier.previous_version(analyzer) { - earlier = prev; - if earlier.is_ext_return_assignment(analyzer) { - return_assignments.push(earlier) - } - } - return_assignments - } - - pub fn is_return_assignment(&self, analyzer: &impl GraphLike) -> bool { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .any(|edge| { - Edge::Context(ContextEdge::ReturnAssign(true)) == *edge.weight() - || Edge::Context(ContextEdge::ReturnAssign(false)) == *edge.weight() - }) - } - - pub fn is_ext_return_assignment(&self, analyzer: &impl GraphLike) -> bool { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .any(|edge| Edge::Context(ContextEdge::ReturnAssign(true)) == *edge.weight()) - } - - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - underlying.ty.is_const(analyzer) - } - - pub fn is_symbolic(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_symbolic) - } - - pub fn is_tmp(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - Ok(underlying.is_tmp()) - } - - pub fn is_return_node(&self, analyzer: &impl GraphLike) -> Result { - if let Some(ctx) = self.maybe_ctx(analyzer) { - return Ok(ctx - .underlying(analyzer)? - .ret - .iter() - .any(|(_, node)| node.name(analyzer).unwrap() == self.name(analyzer).unwrap())); - } - Ok(false) - } - - pub fn is_return_node_in_any(&self, ctxs: &[ContextNode], analyzer: &impl GraphLike) -> bool { - ctxs.iter().any(|ctx| { - ctx.underlying(analyzer) - .unwrap() - .ret - .iter() - .any(|(_, node)| node.name(analyzer).unwrap() == self.name(analyzer).unwrap()) - }) - } - - pub fn tmp_of(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.tmp_of()) - } - - pub fn is_len_var(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.name(analyzer)?.ends_with(".length") - && analyzer - .search_for_ancestor( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::AttrAccess), - ) - .is_some()) - } - - pub fn is_array_index_access(&self, analyzer: &impl GraphLike) -> bool { - analyzer - .search_for_ancestor( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::IndexAccess), - ) - .is_some() - } - - pub fn len_var_to_array( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - if self.name(analyzer)?.ends_with(".length") { - if let Some(arr) = analyzer.search_for_ancestor( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::AttrAccess), - ) { - Ok(Some(ContextVarNode::from(arr).latest_version(analyzer))) - } else { - Ok(None) - } - } else { - Ok(None) - } - } - - pub fn index_to_array(&self, analyzer: &impl GraphLike) -> Option { - let arr = analyzer - .graph() - .edges_directed(self.first_version(analyzer).into(), Direction::Outgoing) - .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) - .map(|edge| edge.target()) - .take(1) - .next()?; - Some(ContextVarNode::from(arr).latest_version(analyzer)) - } - - pub fn index_access_to_index(&self, analyzer: &impl GraphLike) -> Option { - let index = analyzer.find_child_exclude_via( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::Index), - &[], - &|idx, _| Some(idx), - )?; - Some(ContextVarNode::from(index)) - } - - pub fn as_range_elem( - &self, - analyzer: &impl GraphLike, - loc: Loc, - ) -> Result, GraphError> { - match self.underlying(analyzer)?.ty { - VarType::Concrete(c) => Ok(Elem::Concrete(RangeConcrete { - val: c.underlying(analyzer)?.clone(), - loc, - })), - _ => Ok(Elem::from(*self)), - } - } - - pub fn cache_range(&self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { - range.cache_eval(analyzer)?; - self.set_range(analyzer, range)?; - } - Ok(()) - } - - pub fn set_range( - &self, - analyzer: &mut impl GraphLike, - new_range: SolcRange, - ) -> Result<(), GraphError> { - let underlying = self.underlying_mut(analyzer)?; - underlying.set_range(new_range); - Ok(()) - } - - pub fn fallback_range( - &self, - analyzer: &mut impl GraphLike, - ) -> Result, GraphError> { - let underlying = self.underlying(analyzer)?; - underlying.fallback_range(analyzer) - } - - pub fn needs_fallback(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.needs_fallback()) - } - // #[tracing::instrument(level = "trace", skip_all)] - pub fn set_range_min( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - mut new_min: Elem, - ) -> Result<(), GraphError> { - if new_min.contains_node((*self).into()) { - if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into()); - } else { - return Err(GraphError::UnbreakableRecursion(format!("The variable {}'s range is self-referential and we cannot break the recursion.", self.display_name(analyzer)?))); - } - } - - tracing::trace!( - "setting range minimum: {} (node idx: {}), current:\n{:#?}, new_min:\n{:#?}", - self.display_name(analyzer)?, - self.0, - self.range_min(analyzer)?, - new_min - ); - - if self.is_concrete(analyzer)? { - let mut new_ty = self.ty(analyzer)?.clone(); - new_ty.concrete_to_builtin(analyzer)?; - self.underlying_mut(analyzer)?.ty = new_ty; - self.set_range_min(analyzer, new_min)?; - } else { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - self.underlying_mut(analyzer)? - .set_range_min(new_min, fallback); - } - self.cache_range(analyzer)?; - Ok(()) - } - - // #[tracing::instrument(level = "trace", skip_all)] - pub fn set_range_max( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - mut new_max: Elem, - ) -> Result<(), GraphError> { - if new_max.contains_node((*self).into()) { - if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into()); - } - } - - tracing::trace!( - "setting range maximum: {:?}, {}, current:\n{:#?}, new:\n{:#?}", - self, - self.display_name(analyzer)?, - self.ref_range(analyzer)?.unwrap().range_max(), // .unwrap() - new_max - ); - - if self.is_concrete(analyzer)? { - let mut new_ty = self.ty(analyzer)?.clone(); - new_ty.concrete_to_builtin(analyzer)?; - self.underlying_mut(analyzer)?.ty = new_ty; - self.set_range_max(analyzer, new_max)?; - } else { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - - self.underlying_mut(analyzer)? - .set_range_max(new_max, fallback) - } - - self.cache_range(analyzer)?; - Ok(()) - } - - pub fn set_range_exclusions( - &self, - analyzer: &mut impl GraphLike, - new_exclusions: Vec>, - ) -> Result<(), GraphError> { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - self.underlying_mut(analyzer)? - .set_range_exclusions(new_exclusions, fallback); - Ok(()) - } - - pub fn try_set_range_min( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - mut new_min: Elem, - ) -> Result { - if new_min.contains_node((*self).into()) { - if let Some(prev) = self.previous_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into()); - } - } - - if self.is_concrete(analyzer)? { - let mut new_ty = self.ty(analyzer)?.clone(); - new_ty.concrete_to_builtin(analyzer)?; - self.underlying_mut(analyzer)?.ty = new_ty; - self.try_set_range_min(analyzer, new_min) - } else { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - Ok(self - .underlying_mut(analyzer)? - .try_set_range_min(new_min, fallback)) - } - } - - pub fn try_set_range_max( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - mut new_max: Elem, - ) -> Result { - if new_max.contains_node((*self).into()) { - if let Some(prev) = self.previous_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into()); - } - } - - if self.is_concrete(analyzer)? { - let mut new_ty = self.ty(analyzer)?.clone(); - new_ty.concrete_to_builtin(analyzer)?; - self.underlying_mut(analyzer)?.ty = new_ty; - self.try_set_range_max(analyzer, new_max) - } else { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - Ok(self - .underlying_mut(analyzer)? - .try_set_range_max(new_max, fallback)) - } - } - - pub fn try_set_range_exclusions( - &self, - analyzer: &mut impl GraphLike, - new_exclusions: Vec>, - ) -> Result { - let fallback = if self.needs_fallback(analyzer)? { - self.fallback_range(analyzer)? - } else { - None - }; - Ok(self - .underlying_mut(analyzer)? - .try_set_range_exclusions(new_exclusions, fallback)) - } - - pub fn latest_version(&self, analyzer: &impl GraphLike) -> Self { - let mut latest = *self; - while let Some(next) = latest.next_version(analyzer) { - latest = next; - } - latest - } - - pub fn latest_version_less_than(&self, idx: NodeIdx, analyzer: &impl GraphLike) -> Self { - let mut latest = *self; - while let Some(next) = latest.next_version(analyzer) { - if next.0 <= idx.index() { - latest = next; - } else { - break; - } - } - latest - } - - pub fn latest_version_in_ctx( - &self, - ctx: ContextNode, - analyzer: &impl GraphLike, - ) -> Result { - if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { - Ok(cvar.latest_version(analyzer)) - } else { - Ok(*self) - } - } - - pub fn latest_version_in_ctx_less_than( - &self, - idx: NodeIdx, - ctx: ContextNode, - analyzer: &impl GraphLike, - ) -> Result { - if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { - Ok(cvar.latest_version_less_than(idx, analyzer)) - } else { - Ok(*self) - } - } - - pub fn first_version(&self, analyzer: &impl GraphLike) -> Self { - let mut earlier = *self; - while let Some(prev) = earlier.previous_version(analyzer) { - earlier = prev; - } - earlier - } - - pub fn num_versions(&self, analyzer: &impl GraphLike) -> usize { - let mut count = 1; - let mut earlier = self.latest_version(analyzer); - while let Some(prev) = earlier.previous_version(analyzer) { - earlier = prev; - count += 1; - } - count - } - - pub fn next_version(&self, analyzer: &impl GraphLike) -> Option { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::Context(ContextEdge::Prev) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.source())) - .take(1) - .next() - } - - pub fn previous_version(&self, analyzer: &impl GraphLike) -> Option { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::Prev) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - } - - pub fn previous_or_inherited_version(&self, analyzer: &impl GraphLike) -> Option { - if let Some(prev) = self.previous_version(analyzer) { - Some(prev) - } else { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - } - } - - pub fn range_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(range) = self.ref_range(analyzer)? { - Ok(range.dependent_on()) - } else { - Ok(vec![]) - } - } - - pub fn dependent_on( - &self, - analyzer: &impl GraphLike, - return_self: bool, - ) -> Result, GraphError> { - let underlying = self.underlying(analyzer)?; - if let Some(tmp) = underlying.tmp_of() { - let mut nodes = tmp.lhs.dependent_on(analyzer, true)?; - if let Some(rhs) = tmp.rhs { - nodes.extend(rhs.dependent_on(analyzer, true)?); - } - Ok(nodes) - } else if return_self { - Ok(vec![*self]) - } else { - Ok(vec![]) - } - } - - pub fn graph_dependent_on( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let underlying = self.underlying(analyzer)?; - let mut tree = BTreeMap::default(); - if let Some(tmp) = underlying.tmp_of() { - tree.insert(*self, tmp); - tmp.lhs - .graph_dependent_on(analyzer)? - .into_iter() - .for_each(|(key, v)| { - if let Some(_v) = tree.get_mut(&key) { - panic!("here") - } else { - tree.insert(key, v); - } - }); - if let Some(rhs) = tmp.rhs { - rhs.graph_dependent_on(analyzer)? - .into_iter() - .for_each(|(key, v)| { - if let Some(_v) = tree.get_mut(&key) { - panic!("here") - } else { - tree.insert(key, v); - } - }); - } - } - - Ok(tree) - } - - pub fn is_concrete(&self, analyzer: &impl GraphLike) -> Result { - Ok(matches!(self.ty(analyzer)?, VarType::Concrete(_))) - } - - pub fn as_concrete(&self, analyzer: &impl GraphLike) -> Result { - match &self.ty(analyzer)? { - VarType::Concrete(c) => Ok(c.underlying(analyzer)?.clone()), - e => Err(GraphError::NodeConfusion(format!( - "Expected variable type to be concrete but was: {e:?}" - ))), - } - } - - pub fn as_cast_tmp( - &self, - loc: Loc, - ctx: ContextNode, - cast_ty: Builtin, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let new_underlying = self - .underlying(analyzer)? - .clone() - .as_cast_tmp(loc, ctx, cast_ty, analyzer)?; - let node = analyzer.add_node(Node::ContextVar(new_underlying)); - ctx.add_var(node.into(), analyzer)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(node.into()) - } - - pub fn as_tmp( - &self, - loc: Loc, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let new_underlying = self - .underlying(analyzer)? - .clone() - .as_tmp(loc, ctx, analyzer)?; - Ok(analyzer.add_node(Node::ContextVar(new_underlying)).into()) - } - - pub fn ty_eq(&self, other: &Self, analyzer: &mut impl GraphLike) -> Result { - self.ty(analyzer)?.ty_eq(other.ty(analyzer)?, analyzer) - } - - pub fn cast_from( - &self, - other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let to_ty = other.ty(analyzer)?.clone(); - self.cast_from_ty(to_ty, analyzer)?; - Ok(()) - } - - pub fn literal_cast_from( - &self, - other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let to_ty = other.ty(analyzer)?.clone(); - self.literal_cast_from_ty(to_ty, analyzer)?; - Ok(()) - } - - pub fn cast_from_ty( - &self, - to_ty: VarType, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let from_ty = self.ty(analyzer)?.clone(); - if !from_ty.ty_eq(&to_ty, analyzer)? { - if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { - self.underlying_mut(analyzer)?.ty = new_ty; - } - if let (Some(r), Some(r2)) = (self.range(analyzer)?, to_ty.range(analyzer)?) { - let min = r.min.cast(r2.min); - let max = r.max.cast(r2.max); - self.set_range_min(analyzer, min)?; - self.set_range_max(analyzer, max)?; - } - } - - if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { - // update name - let display_name = cnode.underlying(analyzer)?.as_string(); - self.underlying_mut(analyzer)?.display_name = display_name; - } - Ok(()) - } - - pub fn literal_cast_from_ty( - &self, - to_ty: VarType, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let from_ty = self.ty(analyzer)?.clone(); - if !from_ty.ty_eq(&to_ty, analyzer)? { - if let Some(new_ty) = from_ty.try_literal_cast(&to_ty, analyzer)? { - self.underlying_mut(analyzer)?.ty = new_ty; - } - // we dont need to update the ranges because a literal by definition is concrete - } - - if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { - // update name - let display_name = cnode.underlying(analyzer)?.as_string(); - self.underlying_mut(analyzer)?.display_name = display_name; - } - Ok(()) - } - - pub fn try_increase_size( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let from_ty = self.ty(analyzer)?.clone(); - self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer)?; - Ok(()) - } - - pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { - self.ty(analyzer)?.is_int(analyzer) - } - - pub fn sol_delete_range(&mut self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { - let ty = self.ty(analyzer)?; - if let Some(delete_range) = ty.delete_range_result(analyzer)? { - self.set_range(analyzer, delete_range)?; - } - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ContextVar { - pub loc: Option, - pub name: String, - pub display_name: String, - pub storage: Option, - pub is_tmp: bool, - pub tmp_of: Option, - pub is_symbolic: bool, - pub is_return: bool, - pub ty: VarType, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TmpConstruction { - pub lhs: ContextVarNode, - pub op: RangeOp, - pub rhs: Option, -} - -impl TmpConstruction { - pub fn new(lhs: ContextVarNode, op: RangeOp, rhs: Option) -> Self { - Self { lhs, op, rhs } - } -} - -impl ContextVar { - pub fn eq_ignore_loc(&self, other: &Self) -> bool { - self.name == other.name - && self.display_name == other.display_name - && self.storage == other.storage - && self.is_tmp == other.is_tmp - && self.tmp_of == other.tmp_of - && self.is_symbolic == other.is_symbolic - && self.is_return == other.is_return - && self.ty == other.ty - } - - pub fn is_tmp(&self) -> bool { - self.is_tmp || self.tmp_of.is_some() - } - - pub fn tmp_of(&self) -> Option { - self.tmp_of - } - - pub fn new_from_concrete( - loc: Loc, - ctx: ContextNode, - concrete_node: ConcreteNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let name = format!( - "tmp_{}({})", - ctx.new_tmp(analyzer)?, - concrete_node.underlying(analyzer)?.as_string() - ); - Ok(ContextVar { - loc: Some(loc), - name, - display_name: concrete_node.underlying(analyzer)?.as_string(), - storage: None, - is_tmp: true, - tmp_of: None, - is_symbolic: false, - is_return: false, - ty: VarType::Concrete(concrete_node), - }) - } - - pub fn as_cast_tmp( - &self, - loc: Loc, - ctx: ContextNode, - cast_ty: Builtin, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let mut new_tmp = self.clone(); - new_tmp.loc = Some(loc); - new_tmp.is_tmp = true; - new_tmp.name = format!( - "tmp_{}({}({}))", - ctx.new_tmp(analyzer)?, - cast_ty.as_string(analyzer)?, - self.name - ); - new_tmp.display_name = format!("{}({})", cast_ty.as_string(analyzer)?, self.display_name); - Ok(new_tmp) - } - - pub fn as_tmp( - &self, - loc: Loc, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let mut new_tmp = self.clone(); - new_tmp.loc = Some(loc); - new_tmp.is_tmp = true; - new_tmp.name = format!("tmp{}({})", ctx.new_tmp(analyzer)?, self.name); - new_tmp.display_name = format!("tmp_{}", self.name); - Ok(new_tmp) - } - - pub fn new_from_contract( - loc: Loc, - contract_node: ContractNode, - analyzer: &impl GraphLike, - ) -> Result { - Ok(ContextVar { - loc: Some(loc), - name: contract_node.name(analyzer)?, - display_name: contract_node.name(analyzer)?, - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::User( - TypeNode::Contract(contract_node), - SolcRange::try_from_builtin(&Builtin::Address), - ), - }) - } - - pub fn new_from_struct( - loc: Loc, - struct_node: StructNode, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - Ok(ContextVar { - loc: Some(loc), - name: format!( - "tmp_struct_{}_{}", - ctx.new_tmp(analyzer)?, - struct_node.name(analyzer)? - ), - display_name: struct_node.name(analyzer)?, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::User(TypeNode::Struct(struct_node), None), - }) - } - - pub fn new_from_ty( - loc: Loc, - ty_node: TyNode, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - Ok(ContextVar { - loc: Some(loc), - name: format!( - "tmp_ty_{}_{}", - ctx.new_tmp(analyzer)?, - ty_node.name(analyzer)? - ), - display_name: ty_node.name(analyzer)?, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::try_from_idx(analyzer, ty_node.0.into()).unwrap(), - }) - } - - pub fn new_from_builtin( - loc: Loc, - bn_node: BuiltInNode, - analyzer: &impl GraphLike, - ) -> Result { - Ok(ContextVar { - loc: Some(loc), - name: format!("tmp_{}", bn_node.underlying(analyzer)?.as_string(analyzer)?), - display_name: format!("tmp_{}", bn_node.underlying(analyzer)?.as_string(analyzer)?), - storage: None, - is_tmp: true, - tmp_of: None, - is_symbolic: false, - is_return: false, - ty: VarType::try_from_idx(analyzer, bn_node.into()).unwrap(), - }) - } - - pub fn fallback_range( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - match &self.ty { - VarType::User(TypeNode::Contract(_), ref maybe_range) => { - if let Some(range) = maybe_range { - Ok(Some(range.clone())) - } else { - Ok(SolcRange::try_from_builtin(&Builtin::Address)) - } - } - VarType::User(TypeNode::Enum(enum_node), ref maybe_range) => { - if let Some(range) = maybe_range { - Ok(Some(range.clone())) - } else { - Ok(enum_node.maybe_default_range(analyzer)?) - } - } - VarType::User(TypeNode::Ty(ty_node), ref maybe_range) => { - if let Some(range) = maybe_range { - Ok(Some(range.clone())) - } else { - let underlying = - BuiltInNode::from(ty_node.underlying(analyzer)?.ty).underlying(analyzer)?; - Ok(SolcRange::try_from_builtin(underlying)) - } - } - VarType::BuiltIn(bn, ref maybe_range) => { - if let Some(range) = maybe_range { - Ok(Some(range.clone())) - } else { - let underlying = bn.underlying(analyzer)?; - Ok(SolcRange::try_from_builtin(underlying)) - } - } - VarType::Concrete(cn) => Ok(SolcRange::from(cn.underlying(analyzer)?.clone())), - _ => Ok(None), - } - } - - pub fn set_range(&mut self, new_range: SolcRange) { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - *maybe_range = Some(new_range); - } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin: {e:?}"), - } - } - - pub fn needs_fallback(&self) -> bool { - match &self.ty { - VarType::User(TypeNode::Contract(_), ref maybe_range) - | VarType::User(TypeNode::Enum(_), ref maybe_range) - | VarType::User(TypeNode::Ty(_), ref maybe_range) - | VarType::BuiltIn(_, ref maybe_range) => maybe_range.is_some(), - _ => false, - } - } - - // #[tracing::instrument(level = "trace", skip_all)] - pub fn set_range_min(&mut self, new_min: Elem, fallback_range: Option) { - // tracing::trace!("Setting range min in underlying: {:?}", self.ty); - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_min(new_min); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_min(new_min); - *maybe_range = Some(fr); - } - } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin: {e:?}"), - } - } - - pub fn try_set_range_min( - &mut self, - new_min: Elem, - fallback_range: Option, - ) -> bool { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_min(new_min); - true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_min(new_min); - *maybe_range = Some(fr); - true - } - } - VarType::Concrete(_) => true, - _ => false, - } - } - - pub fn set_range_max(&mut self, new_max: Elem, fallback_range: Option) { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_max(new_max); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_max(new_max); - *maybe_range = Some(fr); - } - } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin or concrete: {e:?}"), - } - } - - pub fn set_range_exclusions( - &mut self, - new_exclusions: Vec>, - fallback_range: Option, - ) { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_exclusions(new_exclusions); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_exclusions(new_exclusions); - *maybe_range = Some(fr); - } - } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin or concrete: {e:?}"), - } - } - - pub fn try_set_range_max( - &mut self, - new_max: Elem, - fallback_range: Option, - ) -> bool { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_max(new_max); - true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_max(new_max); - *maybe_range = Some(fr); - true - } - } - VarType::Concrete(_) => true, - _ => false, - } - } - - pub fn try_set_range_exclusions( - &mut self, - new_exclusions: Vec>, - fallback_range: Option, - ) -> bool { - match &mut self.ty { - VarType::User(TypeNode::Contract(_), ref mut maybe_range) - | VarType::User(TypeNode::Enum(_), ref mut maybe_range) - | VarType::User(TypeNode::Ty(_), ref mut maybe_range) - | VarType::BuiltIn(_, ref mut maybe_range) => { - if let Some(range) = maybe_range { - range.set_range_exclusions(new_exclusions); - true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); - fr.set_range_exclusions(new_exclusions); - *maybe_range = Some(fr); - true - } - } - VarType::Concrete(_) => true, - _ => false, - } - } - - pub fn maybe_from_user_ty( - analyzer: &impl GraphLike, - loc: Loc, - node_idx: NodeIdx, - ) -> Option { - if let Some(ty) = VarType::try_from_idx(analyzer, node_idx) { - let (name, storage) = match analyzer.node(node_idx) { - Node::Contract(c) => { - let name = c.name.clone().expect("Contract had no name").name; - (name, None) - } - Node::Function(f) => { - let name = f.name.clone().expect("Function had no name").name; - (name, None) - } - Node::Struct(s) => { - let name = s.name.clone().expect("Struct had no name").name; - (name, None) - } - Node::Enum(e) => { - let name = e.name.clone().expect("Enum had no name").name; - (name, None) - } - Node::Var(var) => { - let name = var.name.clone().expect("Variable had no name").name; - let storage = if var.in_contract { - if !var.attrs.iter().any(|attr| { - matches!(attr, solang_parser::pt::VariableAttribute::Constant(_)) - }) { - Some(StorageLocation::Storage(var.loc)) - } else { - None - } - } else { - None - }; - (name, storage) - } - Node::Ty(ty) => { - let name = &ty.name.name; - (name.clone(), None) - } - _ => return None, - }; - - Some(ContextVar { - loc: Some(loc), - name: name.clone(), - display_name: name, - storage, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - }) - } else { - None - } - } - - pub fn maybe_new_from_field( - analyzer: &impl GraphLike, - loc: Loc, - parent_var: &ContextVar, - field: Field, - ) -> Option { - if let Some(ty) = VarType::try_from_idx(analyzer, field.ty) { - Some(ContextVar { - loc: Some(loc), - name: parent_var.name.clone() - + "." - + &field.name.clone().expect("Field had no name").name, - display_name: parent_var.name.clone() - + "." - + &field.name.expect("Field had no name").name, - storage: parent_var.storage.clone(), - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - }) - } else { - None - } - } - - pub fn new_from_enum_variant( - analyzer: &mut (impl GraphLike + AnalyzerLike), - ctx: ContextNode, - loc: Loc, - enum_node: EnumNode, - variant: String, - ) -> Result { - let enum_name = enum_node.name(analyzer)?; - Ok(ContextVar { - loc: Some(loc), - name: format!("{}.{}_{}", enum_name, variant, ctx.new_tmp(analyzer)?), - display_name: format!("{}.{}", enum_name, variant), - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::User( - TypeNode::Enum(enum_node), - Some(enum_node.range_from_variant(variant, analyzer)?), - ), - }) - } - - pub fn new_from_index( - analyzer: &mut (impl GraphLike + AnalyzerLike), - loc: Loc, - parent_name: String, - parent_display_name: String, - parent_storage: StorageLocation, - parent_var: &BuiltInNode, - index: ContextVarNode, - ) -> Result { - Ok(ContextVar { - loc: Some(loc), - name: parent_name + "[" + &index.name(analyzer)? + "]", - display_name: parent_display_name + "[" + &index.display_name(analyzer)? + "]", - storage: Some(parent_storage), - is_tmp: false, - tmp_of: None, - is_symbolic: index.underlying(analyzer)?.is_symbolic, - is_return: false, - ty: parent_var.dynamic_underlying_ty(analyzer)?, - }) - } - - pub fn new_from_func( - analyzer: &mut (impl GraphLike + AnalyzerLike), - func: FunctionNode, - ) -> Result { - Ok(ContextVar { - loc: Some(func.underlying(analyzer)?.loc), - name: func.name(analyzer)?, - display_name: func.name(analyzer)?, - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: false, - is_return: false, - ty: VarType::User(TypeNode::Func(func), None), - }) - } - - pub fn maybe_new_from_func_param( - analyzer: &impl GraphLike, - param: FunctionParam, - ) -> Option { - if let Some(name) = param.name { - if let Some(ty) = VarType::try_from_idx(analyzer, param.ty) { - Some(ContextVar { - loc: Some(param.loc), - name: name.name.clone(), - display_name: name.name, - storage: param.storage, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - }) - } else { - None - } - } else { - None - } - } - - pub fn maybe_new_from_func_ret(analyzer: &impl GraphLike, ret: FunctionReturn) -> Option { - if let Some(name) = ret.name { - if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { - Some(ContextVar { - loc: Some(ret.loc), - name: name.name.clone(), - display_name: name.name, - storage: ret.storage, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: true, - ty, - }) - } else { - None - } - } else { - None - } - } - - pub fn new_from_func_ret( - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ret: FunctionReturn, - ) -> Result, GraphError> { - let (is_tmp, name) = if let Some(name) = ret.name { - (false, name.name) - } else { - (true, format!("tmp_func_ret_{}", ctx.new_tmp(analyzer)?)) - }; - - if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { - Ok(Some(ContextVar { - loc: Some(ret.loc), - name: name.clone(), - display_name: name, - storage: ret.storage, - is_tmp, - tmp_of: None, - is_symbolic: true, - is_return: true, - ty, - })) - } else { - Ok(None) - } - } -} diff --git a/shared/src/lib.rs b/shared/src/lib.rs deleted file mode 100644 index 1f86957f..00000000 --- a/shared/src/lib.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::analyzer::GraphLike; -use crate::context::ContextVarNode; -use std::collections::HashMap; - -use crate::analyzer::AsDotStr; -use crate::context::ContextNode; -use crate::{ - context::{Context, ContextEdge, ContextVar}, - nodes::*, -}; -use lazy_static::lazy_static; -use petgraph::graph::*; -use solang_parser::pt::Identifier; - -pub mod analyzer; -pub mod context; -pub mod nodes; -pub mod range; - -pub type NodeIdx = NodeIndex; -pub type EdgeIdx = EdgeIndex; - -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum Node { - Context(Context), - ContextVar(ContextVar), - ContextFork, - FunctionCall, - Builtin(Builtin), - VarType(VarType), - Entry, - SourceUnit(usize), - SourceUnitPart(usize, usize), - Contract(Contract), - Function(Function), - FunctionParam(FunctionParam), - FunctionReturn(FunctionReturn), - Struct(Struct), - Enum(Enum), - Error(Error), - ErrorParam(ErrorParam), - Field(Field), - Var(Var), - Ty(Ty), - Unresolved(Identifier), - Concrete(Concrete), - Msg(Msg), - Block(Block), -} - -pub fn as_dot_str(idx: NodeIdx, analyzer: &impl GraphLike) -> String { - use crate::Node::*; - match analyzer.node(idx) { - Context(_) => ContextNode::from(idx).as_dot_str(analyzer), - ContextVar(_) => ContextVarNode::from(idx).as_dot_str(analyzer), - ContextFork => "Context Fork".to_string(), - FunctionCall => "Function Call".to_string(), - Builtin(bi) => bi.as_string(analyzer).unwrap(), - VarType(v_ty) => v_ty.as_dot_str(analyzer), - Contract(_c) => ContractNode::from(idx).as_dot_str(analyzer), - Function(_f) => FunctionNode::from(idx).as_dot_str(analyzer), - FunctionParam(_fp) => FunctionParamNode::from(idx).as_dot_str(analyzer), - FunctionReturn(_fr) => FunctionReturnNode::from(idx).as_dot_str(analyzer), - Struct(_s) => StructNode::from(idx).as_dot_str(analyzer), - Enum(_e) => EnumNode::from(idx).as_dot_str(analyzer), - Field(_f) => FieldNode::from(idx).as_dot_str(analyzer), - Var(_v) => VarNode::from(idx).as_dot_str(analyzer), - Ty(_t) => TyNode::from(idx).as_dot_str(analyzer), - // Concrete(c) => c.as_human_string(), - e => format!("{e:?}"), - } -} - -impl Node { - pub fn dot_str_color(&self) -> String { - use crate::Node::*; - let c = match self { - Context(_) => TOKYO_NIGHT_COLORS.get("purple").unwrap(), - ContextVar(_) => TOKYO_NIGHT_COLORS.get("orange").unwrap(), - FunctionCall => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), - Contract(_c) => TOKYO_NIGHT_COLORS.get("green").unwrap(), - Function(_f) => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), - Struct(_s) => TOKYO_NIGHT_COLORS.get("yellow").unwrap(), - Enum(_e) => TOKYO_NIGHT_COLORS.get("yellow").unwrap(), - _ => TOKYO_NIGHT_COLORS.get("default").unwrap(), - }; - c.to_string() - } -} - -lazy_static! { - pub static ref TOKYO_NIGHT_COLORS: HashMap<&'static str, &'static str> = { - let mut m = HashMap::new(); - m.insert("red", "#f7768e"); - m.insert("orange", "#ff9e64"); - m.insert("yellow", "#e0af68"); - m.insert("green", "#9ece6a"); - m.insert("cyan", "#73daca"); - m.insert("teal", "#2ac3de"); - m.insert("darkblue", "#7aa2f7"); - m.insert("purple", "#bb9af7"); - m.insert("bg", "#1a1b26"); - m.insert("font", "#c0caf5"); - m.insert("deepred", "#703440"); - m.insert("default", "#565f89"); - m - }; -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum Edge { - Source, - Part, - Import, - Context(ContextEdge), - Contract, - InheritedContract, - Field, - Enum, - Struct, - Error, - ErrorParam, - Event, - Var, - Ty, - Func, - FunctionParam, - FunctionReturn, - FuncModifier(usize), - Modifier, - FallbackFunc, - Constructor, - ReceiveFunc, - LibraryFunction(NodeIdx), - BuiltinFunction, -} diff --git a/shared/src/nodes/block.rs b/shared/src/nodes/block.rs deleted file mode 100644 index e5cd8201..00000000 --- a/shared/src/nodes/block.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; - -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::H256; -use ethers_core::types::U256; - -/// An index in the graph that references a Block node -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct BlockNode(pub usize); - -impl BlockNode { - /// Gets the underlying node data for the block environment - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Block, GraphError> { - match analyzer.node(*self) { - Node::Block(st) => Ok(st), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Msg but it was: {e:?}" - ))), - } - } -} - -impl AsDotStr for BlockNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - format!("block {{ {:?} }}", self.underlying(analyzer).unwrap()) - } -} - -impl From for NodeIdx { - fn from(val: BlockNode) -> Self { - val.0.into() - } -} - -impl From for BlockNode { - fn from(idx: NodeIdx) -> Self { - BlockNode(idx.index()) - } -} - -/// Represents block-based environment variables available in solidity. These can -/// be set in the configuration (TODO) - if they are not set they are assumed to be -/// in their types default full range (e.g.: `uint256 -> [0, 2**256 - 1]`). -#[derive(Debug, Default, Clone, Eq, PartialEq)] -pub struct Block { - /// The block's hash - pub hash: Option, - /// The block's basefee - pub basefee: Option, - /// The chain id - pub chainid: Option, - /// The block coinbase - pub coinbase: Option
, - /// The block difficulty - pub difficulty: Option, - /// The block gas limit - pub gaslimit: Option, - /// The block number - pub number: Option, - /// The block's prevrandao - pub prevrandao: Option, - /// The block's timestamp - pub timestamp: Option, -} diff --git a/shared/src/nodes/concrete.rs b/shared/src/nodes/concrete.rs deleted file mode 100644 index 542c83f6..00000000 --- a/shared/src/nodes/concrete.rs +++ /dev/null @@ -1,849 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::Builtin; -use crate::VarType; -use crate::{Node, NodeIdx}; -use ethers_core::types::{Address, H256, I256, U256}; - -/// An index in the graph that references a [`Concrete`] node -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct ConcreteNode(pub usize); - -impl ConcreteNode { - /// Gets the underlying node data for the [`Concrete`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Concrete, GraphError> { - match analyzer.node(*self) { - Node::Concrete(c) => Ok(c), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Concrete but it was: {e:?}" - ))), - } - } - - pub fn max_size( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let c = self.underlying(analyzer)?.max_size(); - Ok(analyzer.add_node(Node::Concrete(c)).into()) - } - - pub fn dynamic_underlying_ty( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let builtin = self.underlying(analyzer)?.dynamic_underlying_ty().unwrap(); - let bn = analyzer.builtin_or_add(builtin); - let v_ty = VarType::try_from_idx(analyzer, bn).unwrap(); - Ok(v_ty) - } - - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_dyn()) - } - - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_sized_array()) - } - - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.maybe_array_size()) - } - - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_indexable()) - } -} - -impl From for ConcreteNode { - fn from(idx: NodeIdx) -> Self { - ConcreteNode(idx.index()) - } -} - -impl From for NodeIdx { - fn from(val: ConcreteNode) -> Self { - val.0.into() - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum DynCapacity { - Cap(U256), - Unlimited, -} - -/// EVM/Solidity basic concrete types -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum Concrete { - /// An unsigned integer, in the form of (bits, value) - Uint(u16, U256), - /// A signed integer, in the form of (bits, value) - Int(u16, I256), - /// An fixed length bytes, in the form of (bytes, value) - Bytes(u8, H256), - /// A 20 byte address - Address(Address), - /// A boolean - Bool(bool), - /// A vector of bytes - DynBytes(Vec), - /// A string, (TODO: solidity doesn't enforce utf-8 encoding like rust. Likely this type - /// should be modeled with a `Vec` instead.) - String(String), - /// An array of concrete values - Array(Vec), -} - -impl From for Concrete { - fn from(u: U256) -> Self { - Concrete::Uint(256, u) - } -} - -impl From for Concrete { - fn from(u: I256) -> Self { - Concrete::Int(256, u) - } -} - -impl From> for Concrete { - fn from(u: Vec) -> Self { - Concrete::DynBytes(u) - } -} - -impl From for Concrete { - fn from(u: H256) -> Self { - Concrete::Bytes(32, u) - } -} - -impl From<[u8; N]> for Concrete { - fn from(u: [u8; N]) -> Self { - assert!(N <= 32); - let mut h = H256::default(); - h.assign_from_slice(&u[..]); - Concrete::Bytes(N.try_into().unwrap(), h) - } -} - -impl From
for Concrete { - fn from(u: Address) -> Self { - Concrete::Address(u) - } -} - -impl From for Concrete { - fn from(u: bool) -> Self { - Concrete::Bool(u) - } -} - -impl From for Concrete { - fn from(u: String) -> Self { - Concrete::String(u) - } -} - -impl> From> for Concrete { - fn from(u: Vec) -> Self { - Concrete::Array(u.into_iter().map(|t| t.into()).collect()) - } -} - -impl Concrete { - pub fn is_dyn(&self) -> bool { - matches!( - self, - Concrete::DynBytes(..) | Concrete::String(..) | Concrete::Array(..) - ) - } - - pub fn is_sized_array(&self) -> bool { - matches!(self, Concrete::DynBytes(..) | Concrete::Array(..)) - } - - pub fn dynamic_underlying_ty(&self) -> Option { - match self { - Concrete::DynBytes(_v) => Some(Builtin::Bytes(1)), - Concrete::Array(v) => v.first().map(|inner| inner.as_builtin()), - Concrete::String(_v) => Some(Builtin::Bytes(1)), - Concrete::Bytes(_, _) => Some(Builtin::Bytes(1)), - _ => None, - } - } - - pub fn maybe_array_size(&self) -> Option { - match self { - Concrete::DynBytes(v) => Some(U256::from(v.len())), - Concrete::Array(v) => Some(U256::from(v.len())), - Concrete::String(v) => Some(U256::from(v.len())), - Concrete::Bytes(s, _) => Some(U256::from(*s)), - _ => None, - } - } - - pub fn is_indexable(&self) -> bool { - self.is_dyn() || matches!(self, Concrete::Bytes(..)) - } - - /// Convert a U256 back into it's original type. This is used mostly - /// for range calculations to improve ergonomics. Basically - /// the EVM only operates on U256 words, so most of this should - /// be fine. - pub fn u256_as_original(&self, uint: U256) -> Self { - match self { - Concrete::Uint(size, _) => Concrete::Uint(*size, uint), - Concrete::Int(size, _) => Concrete::Int(*size, I256::from_raw(uint)), - Concrete::Bytes(size, _) => { - let mut h = H256::default(); - uint.to_big_endian(h.as_mut()); - Concrete::Bytes(*size, h) - } - Concrete::Address(_) => { - let mut bytes = [0u8; 32]; - uint.to_big_endian(&mut bytes); - Concrete::Address(Address::from_slice(&bytes[12..])) - } - Concrete::Bool(_) => { - if uint > U256::zero() { - Concrete::Bool(true) - } else { - Concrete::Bool(false) - } - } - e => todo!("Unsupported: {e:?}"), - } - } - - /// Cast from one concrete variant given another concrete variant - pub fn cast_from(self, other: &Self) -> Option { - self.cast(other.as_builtin()) - } - - /// Cast from one concrete variant given another concrete variant, but since its a literal - /// uint to bytesX are right padded - pub fn literal_cast_from(self, other: &Self) -> Option { - self.literal_cast(other.as_builtin()) - } - - pub fn equivalent_ty(&self, other: &Self) -> bool { - match (self, other) { - (Concrete::Uint(size, _), Concrete::Uint(other_size, _)) if size == other_size => true, - (Concrete::Int(size, _), Concrete::Int(other_size, _)) if size == other_size => true, - (Concrete::Bytes(size, _), Concrete::Bytes(other_size, _)) if size == other_size => { - true - } - (Concrete::Address(_), Concrete::Address(_)) => true, - (Concrete::Bool(_), Concrete::Bool(_)) => true, - (Concrete::DynBytes(_), Concrete::DynBytes(_)) => true, - (Concrete::String(_), Concrete::String(_)) => true, - (Concrete::Array(v0), Concrete::Array(v1)) => { - if v0.is_empty() || v1.is_empty() { - true - } else { - v0[0].equivalent_ty(&v1[0]) - } - } - _ => false, - } - } - - pub fn is_int(&self) -> bool { - matches!(self, Concrete::Int(_, _)) - } - - pub fn literal_cast(self, builtin: Builtin) -> Option { - match self { - Concrete::Uint(_, val) => match builtin { - Builtin::Bytes(size) => { - let mask = if size == 32 { - U256::MAX - } else { - U256::from(2).pow((size as u16 * 8).into()) - 1 - }; - - let h = H256::from_slice( - &(val & mask) - .0 - .iter() - .flat_map(|v| v.to_le_bytes()) - .collect::>()[..], - ); - Some(Concrete::Bytes(size, h)) - } - _ => self.cast(builtin), - }, - _ => self.cast(builtin), - } - } - - pub fn concat(self, other: &Self) -> Option { - match (self, other) { - (Concrete::String(a), Concrete::String(b)) => Some(Concrete::from(format!("{a}{b}"))), - (Concrete::DynBytes(mut a), Concrete::DynBytes(b)) => { - a.extend(b); - Some(Concrete::from(a)) - } - _ => None, - } - } - - /// Cast the concrete to another type as denoted by a [`Builtin`]. - pub fn cast(self, builtin: Builtin) -> Option { - match self { - Concrete::Uint(r_size, val) => { - match builtin { - Builtin::Address => { - let mut bytes = [0u8; 32]; - val.to_big_endian(&mut bytes); - Some(Concrete::Address(Address::from_slice(&bytes[12..]))) - } - Builtin::Uint(size) => { - // no op - if r_size == size { - Some(self) - } else { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - if val < mask { - Some(Concrete::Uint(size, val)) - } else { - Some(Concrete::Uint(size, mask)) - } - } - } - Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), - Builtin::Bytes(size) => { - let mask = if size == 32 { - U256::MAX - } else { - let v = U256::from(2).pow((size as u16 * 8).into()) - 1; - v << v.leading_zeros() - }; - - // let h = H256::from_slice(&(val & mask).0.iter().flat_map(|v| v.to_le_bytes()).collect::>()[..]); - let mut h = H256::default(); - (val & mask).to_big_endian(&mut h.0); - Some(Concrete::Bytes(size, h)) - } - Builtin::Bool => { - if val > U256::zero() { - Some(Concrete::from(true)) - } else { - Some(Concrete::from(false)) - } - } - _ => None, - } - } - Concrete::Int(r_size, val) => match builtin { - Builtin::Address => { - let mut bytes = [0u8; 32]; - val.to_big_endian(&mut bytes); - Some(Concrete::Address(Address::from_slice(&bytes[12..]))) - } - Builtin::Uint(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - Some(Concrete::Uint(size, val.into_raw() & mask)) - } - Builtin::Int(size) => { - // no op - if r_size == size { - Some(self) - } else { - let mask = if size == 256 { - U256::MAX / 2 - } else { - U256::from(2).pow((size - 1).into()) - 1 - }; - - let (sign, abs) = val.into_sign_and_abs(); - if abs < mask { - Some(Concrete::Int(size, val)) - } else { - Some(Concrete::Int( - size, - I256::checked_from_sign_and_abs(sign, mask).unwrap(), - )) - } - } - } - Builtin::Bytes(size) => { - let mask = if size == 32 { - U256::MAX - } else { - U256::from(2).pow((size as u16 * 8).into()) - 1 - }; - let mut h = H256::default(); - (val.into_raw() & mask).to_big_endian(h.as_mut()); - Some(Concrete::Bytes(size, h)) - } - Builtin::Bool => { - if val.abs() > I256::from(0i32) { - Some(Concrete::from(true)) - } else { - Some(Concrete::from(false)) - } - } - _ => None, - }, - Concrete::Bytes(cap, b) => match builtin { - Builtin::Address => Some(Concrete::Address(Address::from_slice(&b[12..]))), - Builtin::Uint(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - let val = U256::from_big_endian(b.as_bytes()); - Some(Concrete::Uint(size, val & mask)) - } - Builtin::Int(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - let val = U256::from_big_endian(b.as_bytes()); - Some(Concrete::Int(size, I256::from_raw(val & mask))) - } - Builtin::Bytes(size) => { - let mut h = H256::default(); - (0..size).for_each(|i| h.0[i as usize] = b.0[i as usize]); - Some(Concrete::Bytes(size, h)) - } - Builtin::DynamicBytes => { - let mut bytes = vec![0; cap.into()]; - b.0.into_iter() - .take(cap.into()) - .enumerate() - .for_each(|(i, b)| bytes[i] = b); - Some(Concrete::DynBytes(bytes)) - } - _ => None, - }, - Concrete::Address(a) => match builtin { - Builtin::Address => Some(self), - Builtin::Uint(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - let val = U256::from_big_endian(a.as_bytes()); - Some(Concrete::Uint(size, val & mask)) - } - Builtin::Int(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - let val = U256::from_big_endian(a.as_bytes()); - Some(Concrete::Int(size, I256::from_raw(val & mask))) - } - Builtin::Bytes(size) => { - let val = U256::from_big_endian(a.as_bytes()); - let mask = if size == 32 { - U256::MAX - } else { - U256::from(2).pow((size as u16 * 8).into()) - 1 - }; - - let mut h = H256::default(); - (val & mask).to_big_endian(h.as_mut()); - Some(Concrete::Bytes(size, h)) - } - _ => None, - }, - Concrete::String(s) => match builtin { - Builtin::Bytes(size) => { - let as_bytes = s.as_bytes(); - if as_bytes.len() <= size.into() { - let mut h = H256::default(); - as_bytes.iter().enumerate().for_each(|(i, byte)| { - h.0[i] = *byte; - }); - Some(Concrete::Bytes(size, h)) - } else { - None - } - } - Builtin::DynamicBytes => Some(Concrete::DynBytes(s.as_bytes().to_vec())), - _ => None, - }, - Concrete::DynBytes(ref b) => match builtin { - Builtin::Bytes(size) => { - if b.len() <= size.into() { - let mut h = H256::default(); - b.iter().enumerate().for_each(|(i, byte)| { - h.0[i] = *byte; - }); - Some(Concrete::Bytes(size, h)) - } else { - None - } - } - Builtin::DynamicBytes => Some(self), - Builtin::String => todo!(), - _ => None, - }, - Concrete::Bool(ref b) => match builtin { - Builtin::Bool => Some(self), - Builtin::Uint(_) => { - if *b { - Some(Concrete::from(U256::from(1))) - } else { - Some(Concrete::from(U256::zero())) - } - } - Builtin::Int(_) => { - if *b { - Some(Concrete::from(I256::from(1i32))) - } else { - Some(Concrete::from(I256::zero())) - } - } - _ => None, - }, - _ => None, - } - } - - /// Converts a concrete into a [`Builtin`]. - pub fn as_builtin(&self) -> Builtin { - match self { - Concrete::Uint(size, _) => Builtin::Uint(*size), - Concrete::Int(size, _) => Builtin::Int(*size), - Concrete::Bytes(size, _) => Builtin::Bytes(*size), - Concrete::Address(_) => Builtin::Address, - Concrete::Bool(_b) => Builtin::Bool, - Concrete::DynBytes(_) => Builtin::DynamicBytes, - Concrete::String(_) => Builtin::String, - _ => panic!("uncastable to builtin"), - } - } - - /// Converts a concrete into a `U256`. - pub fn into_u256(&self) -> Option { - match self { - Concrete::Uint(_, val) => Some(*val), - Concrete::Int(_, val) => { - if val >= &I256::from(0) { - Some(val.into_raw()) - } else { - None - } - } - Concrete::Bytes(_, b) => Some(U256::from_big_endian(b.as_bytes())), - Concrete::Address(a) => Some(U256::from_big_endian(a.as_bytes())), - Concrete::Bool(b) => { - if *b { - Some(1.into()) - } else { - Some(0.into()) - } - } - _ => None, - } - } - - pub fn max_size(&self) -> Self { - match self { - Concrete::Uint(_, val) => Concrete::Uint(256, *val), - Concrete::Int(_, val) => Concrete::Int(256, *val), - Concrete::Bytes(_, val) => Concrete::Bytes(32, *val), - _ => self.clone(), - } - } - - /// Gets the default max for a given concrete variant. - pub fn max(&self) -> Option { - match self { - Concrete::Uint(size, _) => { - let max = if *size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(*size)) - 1 - }; - Some(Concrete::Uint(*size, max)) - } - Concrete::Int(size, _) => { - let max: I256 = - I256::from_raw((U256::from(1u8) << U256::from(*size - 1)) - U256::from(1)); - Some(Concrete::Int(*size, max)) - } - Concrete::Bytes(size, _) => { - let size = *size as u16 * 8; - let max = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(size)) - 1 - }; - - let mut h = H256::default(); - max.to_big_endian(h.as_mut()); - Some(Concrete::Bytes((size / 8) as u8, h)) - } - Concrete::Address(_) => Some(Concrete::Address(Address::from_slice(&[0xff; 20]))), - Concrete::Bool(_) => Some(Concrete::Bool(true)), - _ => None, - } - } - - pub fn possible_builtins_from_ty_inf(&self) -> Vec { - let mut builtins = vec![]; - match self { - Concrete::Uint(_size, val) => { - let mut min_bits = (256 - val.leading_zeros()) as u16; - let mut s = 256; - while s > min_bits { - builtins.push(Builtin::Uint(s)); - s -= 8; - } - // now ints - min_bits = min_bits.saturating_sub(1); - let mut s = 255; - while s > min_bits { - builtins.push(Builtin::Int(s + 1)); - s = s.saturating_sub(8); - } - } - Concrete::Int(size, val) => { - // if we evaled it as a int, it must be negative - let (abs, is_min) = val.overflowing_abs(); - if is_min { - builtins.push(Builtin::Int(*size)) - } else { - let min_bits = (255 - abs.leading_zeros()) as u16; - let mut s = *size; - while s > min_bits { - builtins.push(Builtin::Int(s)); - s -= 8; - } - } - } - Concrete::Bytes(size, val) => { - let min_bytes: u8 = - val.as_fixed_bytes() - .iter() - .rev() - .enumerate() - .fold(0, |mut acc, (i, v)| { - if v != &0x00u8 { - acc = i as u8; - acc - } else { - acc - } - }); - let mut s = *size; - while s > min_bytes { - builtins.push(Builtin::Bytes(s)); - s -= 1; - } - } - _ => {} - } - builtins - } - - /// Gets the smallest increment for a given type - pub fn one(&self) -> Option { - match self { - Concrete::Uint(size, _) => Some(Concrete::Uint(*size, U256::from(1))), - Concrete::Int(size, _) => Some(Concrete::Int(*size, I256::from(1))), - Concrete::Bytes(size, _) => { - let mut b = [0x00; 32]; - b[0] = 0x01; - Some(Concrete::Bytes(size / 8, H256::from(b))) - } - Concrete::Address(_) => { - let mut b = [0x00; 20]; - b[19] = 0x01; - Some(Concrete::Address(Address::from_slice(&b))) - } - Concrete::Bool(_) => Some(Concrete::Bool(true)), - _ => None, - } - } - - /// Gets the default min for a given concrete variant. - pub fn min(&self) -> Option { - match self { - Concrete::Uint(size, _) => Some(Concrete::Uint(*size, 0.into())), - Concrete::Int(size, _) => { - let max = if size == &256u16 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*size - 1)) - I256::from(1) - }; - - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(Concrete::Int(*size, min)) - } - Concrete::Bytes(size, _) => { - let min = U256::zero(); - let mut h = H256::default(); - min.to_big_endian(h.as_mut()); - Some(Concrete::Bytes(*size, h)) - } - Concrete::Address(_) => Some(Concrete::Address(Address::from_slice(&[0x00; 20]))), - Concrete::Bool(_) => Some(Concrete::Bool(false)), - Concrete::String(_) => Some(Concrete::String("".to_string())), - Concrete::DynBytes(_) => Some(Concrete::DynBytes(vec![])), - Concrete::Array(_) => Some(Concrete::Array(vec![])), - } - } - - /// Gets the size of some concrete type - pub fn int_size(&self) -> Option { - match self { - Concrete::Uint(size, _) => Some(*size), - Concrete::Int(size, _) => Some(*size), - Concrete::Bytes(size, _) => Some(*size as u16), - _ => None, - } - } - - /// If its `Concrete::Uint`, gets the value - pub fn uint_val(&self) -> Option { - match self { - Concrete::Uint(_, val) => Some(*val), - _ => None, - } - } - - /// If its `Concrete::Int`, gets the value - pub fn int_val(&self) -> Option { - match self { - Concrete::Int(_, val) => Some(*val), - _ => None, - } - } - - /// Converts to a string - pub fn as_string(&self) -> String { - match self { - Concrete::Uint(_, val) => val.to_string(), - Concrete::Int(_, val) => val.to_string(), - Concrete::Bytes(size, b) => format!( - "0x{}", - b.0.iter() - .take(*size as usize) - .map(|byte| format!("{byte:02x}")) - .collect::>() - .join("") - ), - Concrete::String(s) => s.to_string(), - Concrete::Bool(b) => b.to_string(), - Concrete::Address(a) => a.to_string(), - Concrete::DynBytes(a) => { - if a.is_empty() { - "0x".to_string() - } else { - hex::encode(a) - } - } - Concrete::Array(arr) => format!( - "[{}]", - arr.iter() - .map(|i| i.as_string()) - .collect::>() - .join(", ") - ), - } - } - - /// Converts to a human readable string. For integers, this means trying to find a - /// power of 2 that is close to the value. - pub fn as_human_string(&self) -> String { - match self { - Concrete::Uint(_, val) => { - let cutoff = U256::from(2).pow(U256::from(32)); - if val < &cutoff { - val.to_string() - } else { - for size in 32..=255 { - let pow2 = U256::from(2).pow(U256::from(size)); - if val < &pow2 { - let diff = pow2 - val; - if diff < cutoff { - return format!("2**{size} - {diff}"); - } - } else if *val == pow2 { - return format!("2**{size}"); - } else { - let diff = val - pow2; - if diff < cutoff { - return format!("2**{size} + {diff}"); - } - } - } - - let pow2 = U256::MAX; - if val < &pow2 { - let diff = pow2 - val; - if diff < cutoff { - return format!("2**{} - {}", 256, diff + 1); - } - } else if *val == pow2 { - return format!("2**{} - 1", 256); - } - - val.to_string() - } - } - Concrete::Int(size, val) => { - let cutoff = I256::from(2).pow(32); - if val < &cutoff && val > &(I256::from(-1i32) * cutoff) { - return val.to_string(); - } - - if val > &I256::from(0) { - let val = val.into_sign_and_abs().1; - Concrete::Uint(*size, val).as_human_string() - } else { - let val = val.into_sign_and_abs().1; - format!("-1 * {}", Concrete::Uint(*size, val).as_human_string()) - } - } - Concrete::Bytes(size, b) => { - format!( - "0x{}", - b.0.iter() - .take(*size as usize) - .map(|byte| format!("{byte:02x}")) - .collect::>() - .join("") - ) - } - Concrete::String(s) => s.to_string(), - Concrete::Bool(b) => b.to_string(), - Concrete::Address(a) => format!("{a:?}"), - Concrete::DynBytes(a) => { - if a.is_empty() { - "0x".to_string() - } else { - hex::encode(a) - } - } - Concrete::Array(arr) => format!( - "[{}]", - arr.iter() - .map(|i| i.as_human_string()) - .collect::>() - .join(", ") - ), - } - } -} diff --git a/shared/src/nodes/contract_ty.rs b/shared/src/nodes/contract_ty.rs deleted file mode 100644 index e9654238..00000000 --- a/shared/src/nodes/contract_ty.rs +++ /dev/null @@ -1,281 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::Search; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::AsDotStr; -use crate::Edge; -use crate::FunctionNode; -use crate::Node; -use crate::NodeIdx; -use crate::StructNode; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{ContractDefinition, ContractTy, Identifier, Loc}; -use std::collections::BTreeMap; - -/// An index in the graph that references a [`Contract`] node -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct ContractNode(pub usize); - -impl AsDotStr for ContractNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "{} {}", - underlying.ty, - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - }, - ) - } -} - -impl ContractNode { - /// Gets the underlying node data for the [`Contract`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Contract, GraphError> { - match analyzer.node(*self) { - Node::Contract(contract) => Ok(contract), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Contract but it was: {e:?}" - ))), - } - } - - pub fn super_contracts(&self, analyzer: &impl GraphLike) -> Vec { - analyzer - .graph() - .edges_directed((*self).into(), Direction::Incoming) - .filter(|edge| edge.weight() == &Edge::InheritedContract) - .map(|edge| ContractNode::from(edge.source())) - .collect() - } - - pub fn inherit(&self, inherits: Vec, analyzer: &mut (impl GraphLike + AnalyzerLike)) { - let src = self.associated_source(analyzer); - let all_contracts = analyzer.search_children_include_via( - src, - &Edge::Contract, - &[ - Edge::Import, - Edge::Part, - Edge::Contract, - Edge::InheritedContract, - ], - ); - // we unwrap the name call because we dont really wanna bubble up thru an iteration - inherits.iter().for_each(|inherited_name| { - let found = all_contracts - .iter() - .find(|contract| { - &ContractNode::from(**contract).name(analyzer).unwrap() == inherited_name - }) - .unwrap_or_else(|| { - panic!( - "Could not find inherited contract: {inherited_name} for contract {:?}", - self.name(analyzer) - ) - }); - analyzer.add_edge(*found, *self, Edge::InheritedContract); - }); - } - - pub fn direct_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { - self.underlying(analyzer).unwrap().inherits.clone() - } - - pub fn all_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { - let mut inherits = self.direct_inherited_contracts(analyzer); - inherits.extend( - inherits - .iter() - .flat_map(|i| i.direct_inherited_contracts(analyzer)) - .collect::>(), - ); - inherits.into_iter().collect::>() - } - - /// Gets the name from the underlying node data for the [`Contract`] - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed contract") - .name) - } - - /// Tries to Get the name from the underlying node data for the [`Contract`] - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(ident) = self.underlying(analyzer)?.name.clone() { - Ok(Some(ident.name)) - } else { - Ok(None) - } - } - - /// Gets the sourcecode location from the underlying node data for the [`Contract`] - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.loc) - } - - /// Gets all associated functions from the underlying node data for the [`Contract`] - pub fn funcs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { - analyzer - .search_children_depth(self.0.into(), &Edge::Func, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect() - } - - pub fn funcs_mapping( - &self, - analyzer: &(impl GraphLike + Search + AnalyzerLike), - ) -> BTreeMap { - analyzer - .search_children_depth(self.0.into(), &Edge::Func, 1, 0) - .into_iter() - .map(|i| { - let fn_node = FunctionNode::from(i); - (fn_node.name(analyzer).unwrap(), fn_node) - }) - .collect::>() - } - - pub fn linearized_functions( - &self, - analyzer: &(impl GraphLike + Search + AnalyzerLike), - ) -> BTreeMap { - let mut mapping = self.funcs_mapping(analyzer); - self.direct_inherited_contracts(analyzer) - .iter() - .for_each(|inherited| { - inherited - .linearized_functions(analyzer) - .iter() - .for_each(|(name, func)| { - if !mapping.contains_key(name) { - mapping.insert(name.to_string(), *func); - } - }); - }); - mapping - } - - pub fn structs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { - analyzer - .search_children_depth(self.0.into(), &Edge::Struct, 1, 0) - .into_iter() - .map(StructNode::from) - .collect() - } - - /// Gets all associated modifiers from the underlying node data for the [`Contract`] - pub fn modifiers(&self, analyzer: &(impl GraphLike + Search)) -> Vec { - analyzer - .search_children_depth(self.0.into(), &Edge::Modifier, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect() - } - - pub fn associated_source_unit_part(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { - analyzer - .search_for_ancestor(self.0.into(), &Edge::Contract) - .expect("detached contract") - } - - pub fn associated_source(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { - let sup = self.associated_source_unit_part(analyzer); - analyzer - .search_for_ancestor(sup, &Edge::Part) - .expect("detached source unit part") - } -} - -impl From for NodeIdx { - fn from(val: ContractNode) -> Self { - val.0.into() - } -} - -impl From for ContractNode { - fn from(idx: NodeIdx) -> Self { - ContractNode(idx.index()) - } -} - -/// A solidity contract representation -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Contract { - /// Sourcecode location - pub loc: Loc, - /// The type of contract - pub ty: ContractTy, - /// An optional name in the form of an identifier (`(Loc, String)`) - pub name: Option, - /// A list of contracts that this contract inherits (TODO: inheritance linearization) - pub inherits: Vec, -} - -impl From for Node { - fn from(val: Contract) -> Self { - Node::Contract(val) - } -} - -impl Contract { - /// Constructs a new contract from a `ContractDefinition` with imports - pub fn from_w_imports( - con: ContractDefinition, - source: NodeIdx, - imports: &[(Option, String, String, usize)], - analyzer: &impl GraphLike, - ) -> (Contract, Vec) { - let mut inherits = vec![]; - let mut unhandled_inherits = vec![]; - con.base.iter().for_each(|base| { - let inherited_name = &base.name.identifiers[0].name; - let mut found = false; - for contract in analyzer - .search_children_exclude_via(source, &Edge::Contract, &[Edge::Func]) - .into_iter() - { - let name = ContractNode::from(contract).name(analyzer).unwrap(); - if &name == inherited_name { - inherits.push(ContractNode::from(contract)); - found = true; - break; - } - } - - if !found { - for entry in imports.iter().filter_map(|import| import.0) { - for contract in analyzer - .search_children_exclude_via(entry, &Edge::Contract, &[Edge::Func]) - .into_iter() - { - let name = ContractNode::from(contract).name(analyzer).unwrap(); - if &name == inherited_name { - inherits.push(ContractNode::from(contract)); - found = true; - break; - } - } - } - } - - if !found { - unhandled_inherits.push(inherited_name.clone()); - } - }); - ( - Contract { - loc: con.loc, - ty: con.ty, - name: con.name, - inherits, - }, - unhandled_inherits, - ) - } -} diff --git a/shared/src/nodes/enum_ty.rs b/shared/src/nodes/enum_ty.rs deleted file mode 100644 index eaf55308..00000000 --- a/shared/src/nodes/enum_ty.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::range::SolcRange; -use crate::AsDotStr; -use crate::Concrete; -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::U256; -use solang_parser::pt::{EnumDefinition, Identifier, Loc}; - -/// An index in the graph that references a [`Enum`] node -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct EnumNode(pub usize); - -impl AsDotStr for EnumNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "enum {} {{ {} }}", - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - }, - "..." - ) - } -} - -impl EnumNode { - /// Gets the underlying node data for the [`Enum`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Enum, GraphError> { - match analyzer.node(*self) { - Node::Enum(e) => Ok(e), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Contract but it was: {e:?}" - ))), - } - } - - /// Gets the name of the enum from the underlying node data for the [`Enum`] - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed contract") - .name) - } - - pub fn variants(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.variants()) - } - - pub fn maybe_default_range( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let variants = self.variants(analyzer)?; - if !variants.is_empty() { - let min = Concrete::from(variants.first().unwrap().clone()).into(); - let max = Concrete::from(variants.last().unwrap().clone()).into(); - Ok(Some(SolcRange::new(min, max, vec![]))) - } else { - Ok(None) - } - } - - pub fn range_from_variant( - &self, - variant: String, - analyzer: &impl GraphLike, - ) -> Result { - let variants = self.variants(analyzer)?; - assert!(variants.contains(&variant)); - let val = U256::from(variants.iter().position(|v| v == &variant).unwrap()); - let min = Concrete::from(val).into(); - let max = Concrete::from(val).into(); - Ok(SolcRange::new(min, max, vec![])) - } -} - -impl From for NodeIdx { - fn from(val: EnumNode) -> Self { - val.0.into() - } -} - -impl From for EnumNode { - fn from(idx: NodeIdx) -> Self { - EnumNode(idx.index()) - } -} - -/// A solidity enum representation -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Enum { - pub loc: Loc, - pub name: Option, - pub values: Vec>, -} - -impl Enum { - pub fn variants(&self) -> Vec { - self.values - .iter() - .map(|ident| ident.clone().unwrap().name) - .collect() - } -} - -impl From for Node { - fn from(val: Enum) -> Self { - Node::Enum(val) - } -} - -impl From for Enum { - fn from(enu: EnumDefinition) -> Enum { - Enum { - loc: enu.loc, - name: enu.name, - values: enu.values, - } - } -} diff --git a/shared/src/nodes/err_ty.rs b/shared/src/nodes/err_ty.rs deleted file mode 100644 index 1830035d..00000000 --- a/shared/src/nodes/err_ty.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::AsDotStr; -use crate::{Node, NodeIdx}; -use solang_parser::pt::{ErrorDefinition, ErrorParameter, Expression, Identifier, Loc}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct ErrorNode(pub usize); -impl ErrorNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Error, GraphError> { - match analyzer.node(*self) { - Node::Error(err) => Ok(err), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Var but it was: {e:?}" - ))), - } - } -} -impl AsDotStr for ErrorNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "error {}", - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - }, - ) - } -} - -impl From for NodeIdx { - fn from(val: ErrorNode) -> Self { - val.0.into() - } -} - -impl From for ErrorNode { - fn from(idx: NodeIdx) -> Self { - ErrorNode(idx.index()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Error { - pub loc: Loc, - pub name: Option, -} - -impl From for Node { - fn from(val: Error) -> Self { - Node::Error(val) - } -} - -impl From for Error { - fn from(con: ErrorDefinition) -> Error { - Error { - loc: con.loc, - name: con.name, - } - } -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct ErrorParamNode(pub usize); - -impl From for ErrorParamNode { - fn from(idx: NodeIdx) -> Self { - ErrorParamNode(idx.index()) - } -} - -impl From for NodeIdx { - fn from(val: ErrorParamNode) -> Self { - val.0.into() - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ErrorParam { - pub loc: Loc, - pub ty: NodeIdx, - pub name: Option, -} - -impl From for Node { - fn from(val: ErrorParam) -> Self { - Node::ErrorParam(val) - } -} - -impl ErrorParam { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - param: ErrorParameter, - ) -> Self { - ErrorParam { - loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), - name: param.name, - } - } -} diff --git a/shared/src/nodes/func_ty.rs b/shared/src/nodes/func_ty.rs deleted file mode 100644 index cbcd9f12..00000000 --- a/shared/src/nodes/func_ty.rs +++ /dev/null @@ -1,879 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::Search; -use crate::context::{ContextEdge, ContextNode}; -use crate::nodes::ContractNode; -use crate::range::SolcRange; -use crate::Edge; -use crate::VarType; -use crate::{ - analyzer::{AnalyzerLike, GraphLike}, - Node, NodeIdx, -}; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::ParameterList; -use solang_parser::pt::Statement; -use solang_parser::pt::Type; -use solang_parser::pt::VariableDefinition; -use solang_parser::pt::{ - Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, - Parameter, StorageLocation, Visibility, -}; -use std::collections::BTreeMap; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct FunctionNode(pub usize); -impl FunctionNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Function, GraphError> { - match analyzer.node(*self) { - Node::Function(func) => Ok(func), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Function but it was: {e:?}" - ))), - } - } - - pub fn body_loc(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(body_stmt) = &self.underlying(analyzer)?.body { - Ok(Some(body_stmt.loc())) - } else { - Ok(None) - } - } - - pub fn definition_loc(&self, analyzer: &impl GraphLike) -> Result { - let underlying = &self.underlying(analyzer)?; - Ok(underlying.loc) - } - - /// Gets an ordered list of modifiers for a given function - pub fn modifiers(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> Vec { - if let Some(mods) = &self.underlying(analyzer).unwrap().cache.modifiers { - mods.values().copied().collect() - } else { - let mods = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter_map(|edge| { - if let Edge::FuncModifier(order) = *edge.weight() { - Some((order, FunctionNode::from(edge.source()))) - } else { - None - } - }) - .collect::>(); - self.underlying_mut(analyzer).unwrap().cache.modifiers = Some(mods.clone()); - mods.values().copied().collect() - } - } - - pub fn modifiers_set(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.modifiers_set) - } - - pub fn modifier_input_vars( - &self, - mod_num: usize, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let modifiers = self.underlying(analyzer)?.modifiers_as_base(); - if let Some(modifier) = modifiers.get(mod_num) { - if let Some(args) = &modifier.args { - Ok(args.to_vec()) - } else { - Ok(vec![]) - } - } else { - Ok(vec![]) - } - } - - pub fn underlying_mut<'a>( - &self, - analyzer: &'a mut (impl GraphLike + AnalyzerLike), - ) -> Result<&'a mut Function, GraphError> { - match analyzer.node_mut(*self) { - Node::Function(func) => Ok(func), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Function but it was: {e:?}" - ))), - } - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - match self.underlying(analyzer)?.ty { - FunctionTy::Constructor => Ok(format!( - "constructor({})", - self.params(analyzer) - .iter() - .map(|param| { param.ty_str(analyzer).unwrap() }) - .collect::>() - .join(", ") - )), - FunctionTy::Receive => Ok("receive()".to_string()), - FunctionTy::Fallback => Ok("fallback()".to_string()), - _ => Ok(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed function") - .name), - } - } - - pub fn loc_specified_name( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(con) = self.maybe_associated_contract(analyzer) { - Ok(format!("{}.{}", con.name(analyzer)?, self.name(analyzer)?)) - } else { - self.name(analyzer) - } - } - - pub fn body_ctx(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> ContextNode { - if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { - body_ctx - } else { - let body_ctx = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::Context(ContextEdge::Context) == *edge.weight()) - .map(|edge| ContextNode::from(edge.source())) - .take(1) - .next() - .expect("No context for function"); - - self.underlying_mut(analyzer).unwrap().cache.body_ctx = Some(body_ctx); - body_ctx - } - } - - pub fn maybe_body_ctx( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { - Some(body_ctx) - } else { - let body_ctx = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::Context(ContextEdge::Context) == *edge.weight()) - .map(|edge| ContextNode::from(edge.source())) - .take(1) - .next(); - if let Some(b) = body_ctx { - self.underlying_mut(analyzer).unwrap().cache.body_ctx = Some(b); - } - - body_ctx - } - } - - pub fn maybe_associated_contract( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - if let Some(maybe_contract) = self - .underlying(analyzer) - .unwrap() - .cache - .maybe_associated_contract - { - maybe_contract - } else { - let contract = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| { - matches!( - *edge.weight(), - Edge::Func - | Edge::Modifier - | Edge::Constructor - | Edge::ReceiveFunc - | Edge::FallbackFunc - ) - }) - .filter_map(|edge| { - let node = edge.target(); - match analyzer.node(node) { - Node::Contract(_) => Some(ContractNode::from(node)), - _ => None, - } - }) - .take(1) - .next(); - self.underlying_mut(analyzer) - .unwrap() - .cache - .maybe_associated_contract = Some(contract); - contract - } - } - - pub fn maybe_associated_source_unit_part( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - if let Some(sup) = self - .underlying(analyzer) - .unwrap() - .cache - .associated_source_unit_part - { - Some(sup) - } else { - let parent = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| { - matches!( - *edge.weight(), - Edge::Func - | Edge::Modifier - | Edge::Constructor - | Edge::ReceiveFunc - | Edge::FallbackFunc - ) - }) - .map(|edge| edge.target()) - .take(1) - .next()?; - let sup = match analyzer.node(parent) { - Node::Contract(_) => { - ContractNode::from(parent).associated_source_unit_part(analyzer) - } - Node::SourceUnitPart(..) => parent, - _e => return None, - }; - self.underlying_mut(analyzer) - .unwrap() - .cache - .associated_source_unit_part = Some(sup); - Some(sup) - } - } - - pub fn associated_source(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> NodeIdx { - if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { - src - } else { - let sup = self - .maybe_associated_source_unit_part(analyzer) - .expect("No associated source unit part"); - let src = analyzer - .search_for_ancestor(sup, &Edge::Part) - .expect("detached function"); - self.underlying_mut(analyzer) - .unwrap() - .cache - .associated_source = Some(src); - src - } - } - - pub fn maybe_associated_source( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { - Some(src) - } else { - let sup = self.maybe_associated_source_unit_part(analyzer)?; - let src = analyzer.search_for_ancestor(sup, &Edge::Part)?; - self.underlying_mut(analyzer) - .unwrap() - .cache - .associated_source = Some(src); - Some(src) - } - } - - pub fn params(&self, analyzer: &impl GraphLike) -> Vec { - if let Some(params) = &self.underlying(analyzer).unwrap().cache.params { - params.to_vec() - } else { - let mut params = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::FunctionParam == *edge.weight()) - .map(|edge| FunctionParamNode::from(edge.source())) - .collect::>(); - params.sort_by(|a, b| { - a.underlying(analyzer) - .unwrap() - .order - .cmp(&b.underlying(analyzer).unwrap().order) - }); - params - } - } - - pub fn set_params_and_ret( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying = self.underlying(analyzer)?.clone(); - let mut params_strs = vec![]; - let params = underlying - .params - .into_iter() - .enumerate() - .filter_map(|(i, (_loc, input))| { - if let Some(input) = input { - let param = FunctionParam::new(analyzer, input, i); - let input_node = analyzer.add_node(param); - params_strs.push( - FunctionParamNode::from(input_node) - .ty_str(analyzer) - .unwrap(), - ); - analyzer.add_edge(input_node, *self, Edge::FunctionParam); - Some(input_node.into()) - } else { - None - } - }) - .collect(); - let rets = underlying - .returns - .into_iter() - .filter_map(|(_loc, output)| { - if let Some(output) = output { - let ret = FunctionReturn::new(analyzer, output); - let output_node = analyzer.add_node(ret); - analyzer.add_edge(output_node, *self, Edge::FunctionReturn); - Some(output_node.into()) - } else { - None - } - }) - .collect(); - - let underlying_mut = self.underlying_mut(analyzer)?; - if let Some(ref mut name) = underlying_mut.name { - name.name = format!("{}({})", name.name, params_strs.join(", ")); - } - underlying_mut.cache.params = Some(params); - underlying_mut.cache.returns = Some(rets); - Ok(()) - } - - pub fn returns<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> impl Iterator + 'a { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::FunctionReturn == *edge.weight()) - .map(|edge| FunctionReturnNode::from(edge.source())) - } - - pub fn is_public_or_ext(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.attributes.iter().any(|attr| { - matches!( - attr, - FunctionAttribute::Visibility(Visibility::Public(_)) - | FunctionAttribute::Visibility(Visibility::External(_)) - ) - })) - } - - pub fn get_overriding( - &self, - other: &Self, - analyzer: &impl GraphLike, - ) -> Result { - let self_attrs = &self.underlying(analyzer)?.attributes; - let other_attrs = &other.underlying(analyzer)?.attributes; - let self_virt_over_attr = self_attrs.iter().find(|attr| { - // TODO: grab the override specifier if needed? - matches!( - attr, - FunctionAttribute::Virtual(_) | FunctionAttribute::Override(_, _) - ) - }); - let other_virt_over_attr = other_attrs.iter().find(|attr| { - // TODO: grab the override specifier if needed? - matches!( - attr, - FunctionAttribute::Virtual(_) | FunctionAttribute::Override(_, _) - ) - }); - match (self_virt_over_attr, other_virt_over_attr) { - (Some(FunctionAttribute::Virtual(_)), Some(FunctionAttribute::Virtual(_))) => Ok(*self), - (Some(FunctionAttribute::Virtual(_)), Some(FunctionAttribute::Override(_, _))) => { - Ok(*other) - } - (Some(FunctionAttribute::Override(_, _)), Some(FunctionAttribute::Virtual(_))) => { - Ok(*self) - } - (Some(FunctionAttribute::Override(_, _)), Some(FunctionAttribute::Override(_, _))) => { - Ok(*self) - } - (_, _) => Ok(*self), - } - } -} - -impl AsDotStr for FunctionNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let inputs = self - .params(analyzer) - .iter() - .map(|param_node: &FunctionParamNode| param_node.as_dot_str(analyzer)) - .collect::>() - .join(", "); - - let attrs = self - .underlying(analyzer) - .unwrap() - .attributes - .iter() - .map(|attr| match attr { - FunctionAttribute::Mutability(inner) => format!("{inner}"), - FunctionAttribute::Visibility(inner) => format!("{inner}"), - FunctionAttribute::Virtual(_) => "virtual".to_string(), - FunctionAttribute::Immutable(_) => "immutable".to_string(), - FunctionAttribute::Override(_, _) => "override".to_string(), - _ => "".to_string(), - }) - .collect::>() - .join(" "); - format!( - "{} {}({}) {}", - self.underlying(analyzer).unwrap().ty, - self.name(analyzer).unwrap(), - inputs, - attrs - ) - } -} - -impl From for NodeIdx { - fn from(val: FunctionNode) -> Self { - val.0.into() - } -} - -impl From for FunctionNode { - fn from(idx: NodeIdx) -> Self { - FunctionNode(idx.index()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Function { - pub loc: Loc, - pub ty: FunctionTy, - pub name: Option, - pub name_loc: Loc, - pub attributes: Vec, - pub body: Option, - pub params: ParameterList, - pub returns: ParameterList, - pub modifiers_set: bool, - pub cache: FunctionCache, -} - -#[derive(Debug, Clone, Eq, PartialEq, Default)] -pub struct FunctionCache { - pub returns: Option>, - pub params: Option>, - pub body_ctx: Option, - pub modifiers: Option>, - pub maybe_associated_contract: Option>, - pub associated_source: Option, - pub associated_source_unit_part: Option, -} - -impl Default for Function { - fn default() -> Self { - Self { - loc: Loc::Implicit, - ty: FunctionTy::Function, - name: None, - name_loc: Loc::Implicit, - attributes: vec![], - body: None, - params: vec![], - returns: vec![], - modifiers_set: false, - cache: Default::default(), - } - } -} - -impl Function { - pub fn modifiers_as_base(&self) -> Vec<&Base> { - self.attributes - .iter() - .filter_map(|attr| match attr { - FunctionAttribute::BaseOrModifier(_, base) => Some(base), - _ => None, - }) - .collect() - } -} - -impl From for Node { - fn from(val: Function) -> Self { - Node::Function(val) - } -} - -impl From for Function { - fn from(func: FunctionDefinition) -> Function { - Function { - loc: func.loc, - ty: func.ty, - name: func.name, - name_loc: func.name_loc, - attributes: func.attributes, - body: func.body, - params: func.params, - returns: func.returns, - modifiers_set: false, - cache: Default::default(), - } - } -} - -pub fn var_def_to_ret(expr: Expression) -> (Loc, Option) { - match expr { - Expression::Type(ty_loc, ref ty) => match ty { - Type::Mapping { value: v_ty, .. } => var_def_to_ret(*v_ty.clone()), - Type::Address - | Type::AddressPayable - | Type::Payable - | Type::Bool - | Type::String - | Type::Int(_) - | Type::Uint(_) - | Type::Bytes(_) - | Type::Rational - | Type::DynamicBytes => ( - ty_loc, - Some(Parameter { - loc: ty_loc, - ty: expr, - storage: None, - name: None, - }), - ), - e => panic!("Unsupported type: {e:?}"), - }, - Expression::ArraySubscript(_loc, sub_expr, _) => { - // its an array, add the index as a parameter - var_def_to_ret(*sub_expr) - } - e => ( - Loc::Implicit, - Some(Parameter { - loc: Loc::Implicit, - ty: e, - storage: None, - name: None, - }), - ), - } -} -pub fn var_def_to_params(expr: Expression) -> Vec<(Loc, Option)> { - let mut params = vec![]; - match expr { - Expression::Type(ty_loc, ref ty) => { - match ty { - Type::Mapping { - loc, - key: key_ty, - value: v_ty, - .. - } => { - params.push(( - ty_loc, - Some(Parameter { - loc: *loc, - ty: *key_ty.clone(), - storage: None, - name: None, - }), - )); - params.extend(var_def_to_params(*v_ty.clone())); - } - Type::Address - | Type::AddressPayable - | Type::Payable - | Type::Bool - | Type::String - | Type::Int(_) - | Type::Uint(_) - | Type::Bytes(_) - | Type::Rational - | Type::DynamicBytes => { - // if !is_recursion { - // params.push((ty_loc, Some(Parameter { - // loc: ty_loc, - // ty: expr, - // storage: None, - // name: None, - // }))); - // } - } - e => panic!("Unsupported type: {e:?}"), - } - } - Expression::ArraySubscript(loc, sub_expr, _) => { - // its an array, add the index as a parameter - params.push(( - loc, - Some(Parameter { - loc, - ty: Expression::Type(loc, Type::Uint(256)), - storage: None, - name: None, - }), - )); - params.extend(var_def_to_params(*sub_expr)); - } - _e => {} - } - - params -} - -impl From for Function { - fn from(var: VariableDefinition) -> Function { - let ret = var_def_to_ret(var.ty.clone()); - Function { - loc: var.loc, - ty: FunctionTy::Function, - name: var.name.clone(), - name_loc: var.loc, - attributes: vec![FunctionAttribute::Visibility(Visibility::Public(Some( - var.loc, - )))], - body: None, - params: var_def_to_params(var.ty), - returns: vec![ret], - modifiers_set: true, - cache: Default::default(), - } - } -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct FunctionParamNode(pub usize); - -impl AsDotStr for FunctionParamNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) - .expect("Non-typeable as type"); - format!( - "{}{}{}", - var_ty.as_dot_str(analyzer), - if let Some(stor) = &self.underlying(analyzer).unwrap().storage { - format!(" {stor} ") - } else { - "".to_string() - }, - if let Some(name) = self.maybe_name(analyzer).unwrap() { - name - } else { - "".to_string() - } - ) - } -} - -impl FunctionParamNode { - pub fn underlying<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> Result<&'a FunctionParam, GraphError> { - match analyzer.node(*self) { - Node::FunctionParam(param) => Ok(param), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be FunctionParam but it was: {e:?}" - ))), - } - } - - pub fn name(&self, analyzer: &'_ impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed function parameter") - .name) - } - - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(ident) = self.underlying(analyzer)?.name.clone() { - Ok(Some(ident.name)) - } else { - Ok(None) - } - } - - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let ty_node = self.underlying(analyzer)?.ty; - if let Some(var_ty) = VarType::try_from_idx(analyzer, ty_node) { - Ok(var_ty.range(analyzer)?) - } else { - Ok(None) - } - } - - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.loc) - } - - pub fn ty_str(&self, analyzer: &impl GraphLike) -> Result { - let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer)?.ty).ok_or( - GraphError::NodeConfusion("Non-typeable as type".to_string()), - )?; - Ok(var_ty.as_dot_str(analyzer)) - } - - pub fn ty(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.ty) - } -} - -impl From for NodeIdx { - fn from(val: FunctionParamNode) -> Self { - val.0.into() - } -} - -impl From for FunctionParamNode { - fn from(idx: NodeIdx) -> Self { - FunctionParamNode(idx.index()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct FunctionParam { - pub loc: Loc, - pub ty: NodeIdx, - pub order: usize, - pub storage: Option, - pub name: Option, -} - -impl From for Node { - fn from(val: FunctionParam) -> Self { - Node::FunctionParam(val) - } -} - -impl FunctionParam { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - param: Parameter, - order: usize, - ) -> Self { - FunctionParam { - loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), - order, - storage: param.storage, - name: param.name, - } - } -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct FunctionReturnNode(pub usize); - -impl AsDotStr for FunctionReturnNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) - .expect("Non-typeable as type"); - format!( - "{}{}{}", - var_ty.as_dot_str(analyzer), - if let Some(stor) = &self.underlying(analyzer).unwrap().storage { - format!(" {stor} ") - } else { - "".to_string() - }, - if let Some(name) = self.maybe_name(analyzer).unwrap() { - name - } else { - "".to_string() - } - ) - } -} - -impl FunctionReturnNode { - pub fn underlying<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> Result<&'a FunctionReturn, GraphError> { - match analyzer.node(*self) { - Node::FunctionReturn(ret) => Ok(ret), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be FunctionReturn but it was: {e:?}" - ))), - } - } - - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(ident) = self.underlying(analyzer)?.name.clone() { - Ok(Some(ident.name)) - } else { - Ok(None) - } - } - - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.loc) - } -} - -impl From for NodeIdx { - fn from(val: FunctionReturnNode) -> Self { - val.0.into() - } -} - -impl From for FunctionReturnNode { - fn from(idx: NodeIdx) -> Self { - FunctionReturnNode(idx.index()) - } -} - -impl From for Node { - fn from(val: FunctionReturn) -> Self { - Node::FunctionReturn(val) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct FunctionReturn { - pub loc: Loc, - pub ty: NodeIdx, - pub storage: Option, - pub name: Option, -} - -impl FunctionReturn { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - param: Parameter, - ) -> Self { - FunctionReturn { - loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), - storage: param.storage, - name: param.name, - } - } -} diff --git a/shared/src/nodes/mod.rs b/shared/src/nodes/mod.rs deleted file mode 100644 index 05bd4b50..00000000 --- a/shared/src/nodes/mod.rs +++ /dev/null @@ -1,1189 +0,0 @@ -//! Solidity and EVM specific representations as nodes in the graph -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::range::elem::RangeElem; -use crate::range::elem_ty::Dynamic; -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeDyn; -use crate::range::Range; -use crate::range::SolcRange; -use crate::ContextVarNode; - -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::H256; -use ethers_core::types::I256; -use ethers_core::types::U256; -use solang_parser::pt::{Expression, Loc, Type}; - -mod contract_ty; -pub use contract_ty::*; -mod enum_ty; -pub use enum_ty::*; -mod struct_ty; -pub use struct_ty::*; -mod func_ty; -pub use func_ty::*; -mod err_ty; -pub use err_ty::*; -mod var_ty; -pub use var_ty::*; -mod ty_ty; -pub use ty_ty::*; -mod concrete; -pub use concrete::*; -mod msg; -pub use msg::*; -mod block; -pub use block::*; - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum VarType { - User(TypeNode, Option), - BuiltIn(BuiltInNode, Option), - Concrete(ConcreteNode), -} - -impl AsDotStr for VarType { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - self.as_string(analyzer).unwrap() - } -} - -impl VarType { - pub fn set_range(&mut self, new_range: SolcRange) -> Result<(), GraphError> { - match self { - VarType::User(TypeNode::Enum(_), ref mut r) - | VarType::User(TypeNode::Contract(_), ref mut r) - | VarType::User(TypeNode::Ty(_), ref mut r) - | VarType::BuiltIn(_, ref mut r) => { - *r = Some(new_range); - Ok(()) - } - _ => Err(GraphError::NodeConfusion( - "This type cannot have a range".to_string(), - )), - } - } - - pub fn possible_builtins_from_ty_inf(&self, analyzer: &impl GraphLike) -> Vec { - match self { - Self::BuiltIn(bn, _) => bn - .underlying(analyzer) - .unwrap() - .possible_builtins_from_ty_inf(), - Self::Concrete(c) => c - .underlying(analyzer) - .unwrap() - .possible_builtins_from_ty_inf(), - _ => vec![], - } - } - - pub fn ty_idx(&self) -> NodeIdx { - match self { - Self::User(ty_node, _) => (*ty_node).into(), - Self::BuiltIn(bn, _) => (*bn).into(), - Self::Concrete(c) => (*c).into(), - } - } - - pub fn is_dyn_builtin(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::BuiltIn(node, _) => node.is_dyn(analyzer), - _ => Ok(false), - } - } - - pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { - match self { - VarType::User(TypeNode::Unresolved(n), _) => match analyzer.node(*n) { - Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( - "Expected the type \"{}\" to be resolved by now", - ident.name - ))), - _ => { - if let Some(ty) = VarType::try_from_idx(analyzer, *n) { - Ok(ty) - } else { - Err(GraphError::NodeConfusion( - "Tried to type a non-typeable element".to_string(), - )) - } - } - }, - _ => Ok(self.clone()), - } - } - - pub fn concrete_to_builtin( - &mut self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - if let VarType::Concrete(cnode) = self { - let c = cnode.underlying(analyzer)?.clone(); - match c { - crate::Concrete::Uint(ref size, _) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::Uint(*size))), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::Int(ref size, _) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::Int(*size))), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::Bool(_) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bool)), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::Address(_) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::Address)), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::Bytes(ref s, _) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bytes(*s))), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::String(_) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::String)), - SolcRange::from(c), - ); - *self = new_ty; - } - crate::Concrete::DynBytes(_) => { - let new_ty = VarType::BuiltIn( - BuiltInNode::from(analyzer.builtin_or_add(Builtin::DynamicBytes)), - SolcRange::from(c), - ); - *self = new_ty; - } - // Concrete::Array(Vec), - _ => {} - } - } - Ok(()) - } - - pub fn try_from_idx(analyzer: &impl GraphLike, node: NodeIdx) -> Option { - // get node, check if typeable and convert idx into vartype - match analyzer.node(node) { - Node::VarType(a) => Some(a.clone()), - Node::Builtin(b) => Some(VarType::BuiltIn( - node.into(), - SolcRange::try_from_builtin(b), - )), - Node::Contract(_) => Some(VarType::User( - TypeNode::Contract(node.into()), - SolcRange::try_from_builtin(&Builtin::Address), - )), - Node::Function(_) => Some(VarType::User(TypeNode::Func(node.into()), None)), - Node::Struct(_) => Some(VarType::User(TypeNode::Struct(node.into()), None)), - Node::Enum(enu) => { - let variants = enu.variants(); - let range = if !variants.is_empty() { - let min = Concrete::from(U256::zero()).into(); - let max = Concrete::from(U256::from(variants.len() - 1)).into(); - Some(SolcRange::new(min, max, vec![])) - } else { - None - }; - Some(VarType::User(TypeNode::Enum(node.into()), range)) - } - Node::Unresolved(_n) => Some(VarType::User(TypeNode::Unresolved(node), None)), - Node::Concrete(_) => Some(VarType::Concrete(node.into())), - Node::ContextVar(cvar) => Some(cvar.ty.clone()), - Node::Var(var) => VarType::try_from_idx(analyzer, var.ty), - Node::Ty(ty) => { - let range = SolcRange::try_from_builtin( - BuiltInNode::from(ty.ty).underlying(analyzer).unwrap(), - )?; - Some(VarType::User(TypeNode::Ty(node.into()), Some(range))) - } - Node::FunctionParam(inner) => VarType::try_from_idx(analyzer, inner.ty), - Node::Error(..) - | Node::ContextFork - | Node::FunctionCall - | Node::FunctionReturn(..) - | Node::ErrorParam(..) - | Node::Field(..) - | Node::SourceUnitPart(..) - | Node::SourceUnit(..) - | Node::Entry - | Node::Context(..) - | Node::Msg(_) - | Node::Block(_) => None, - } - } - - pub fn requires_input(&self, analyzer: &impl GraphLike) -> Result { - match self { - VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.requires_input()), - _ => Ok(false), - } - } - - pub fn try_cast( - self, - other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - match (self, other) { - (l, Self::User(TypeNode::Ty(ty), o_r)) => { - let t = Self::BuiltIn(BuiltInNode::from(ty.underlying(analyzer)?.ty), o_r.clone()); - l.try_cast(&t, analyzer) - } - (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Contract(cn), _)) => { - match from_bn.underlying(analyzer)? { - Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { - Ok(Some(Self::User(TypeNode::Contract(*cn), sr))) - } - _ => Ok(None), - } - } - (Self::User(TypeNode::Contract(_cn), sr), Self::BuiltIn(to_bn, _)) => { - match to_bn.underlying(analyzer)? { - Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { - Ok(Some(Self::BuiltIn(*to_bn, sr))) - } - _ => Ok(None), - } - } - (Self::BuiltIn(from_bn, sr), Self::BuiltIn(to_bn, _)) => { - if from_bn.implicitly_castable_to(to_bn, analyzer)? { - Ok(Some(Self::BuiltIn(*to_bn, sr))) - } else { - Ok(None) - } - } - (Self::Concrete(from_c), Self::BuiltIn(to_bn, _)) => { - let c = from_c.underlying(analyzer)?.clone(); - let b = to_bn.underlying(analyzer)?; - if let Some(casted) = c.cast(b.clone()) { - let node = analyzer.add_node(Node::Concrete(casted)); - Ok(Some(Self::Concrete(node.into()))) - } else { - Ok(None) - } - } - (Self::Concrete(from_c), Self::Concrete(to_c)) => { - let c = from_c.underlying(analyzer)?.clone(); - let to_c = to_c.underlying(analyzer)?; - if let Some(casted) = c.cast_from(to_c) { - let node = analyzer.add_node(Node::Concrete(casted)); - Ok(Some(Self::Concrete(node.into()))) - } else { - Ok(None) - } - } - _ => Ok(None), - } - } - - pub fn try_literal_cast( - self, - other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - match (self, other) { - (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Ty(ty), _)) => { - if ty.underlying(analyzer)?.ty == from_bn.into() { - Ok(Some(Self::User(TypeNode::Ty(*ty), sr))) - } else { - Ok(None) - } - } - (Self::Concrete(from_c), Self::User(TypeNode::Ty(ty), _)) => { - let concrete_underlying = from_c.underlying(analyzer)?.clone(); - let as_bn = analyzer.builtin_or_add(concrete_underlying.as_builtin()); - if ty.underlying(analyzer)?.ty == as_bn { - Ok(Some(Self::User( - TypeNode::Ty(*ty), - SolcRange::from(concrete_underlying), - ))) - } else { - Ok(None) - } - } - (Self::BuiltIn(from_bn, sr), Self::BuiltIn(to_bn, _)) => { - if from_bn.implicitly_castable_to(to_bn, analyzer)? { - Ok(Some(Self::BuiltIn(*to_bn, sr))) - } else { - Ok(None) - } - } - (Self::Concrete(from_c), Self::BuiltIn(to_bn, _)) => { - let c = from_c.underlying(analyzer)?.clone(); - let b = to_bn.underlying(analyzer)?; - if let Some(casted) = c.literal_cast(b.clone()) { - let node = analyzer.add_node(Node::Concrete(casted)); - Ok(Some(Self::Concrete(node.into()))) - } else { - Ok(None) - } - } - (Self::Concrete(from_c), Self::Concrete(to_c)) => { - let c = from_c.underlying(analyzer)?.clone(); - let to_c = to_c.underlying(analyzer)?; - if let Some(casted) = c.literal_cast_from(to_c) { - let node = analyzer.add_node(Node::Concrete(casted)); - Ok(Some(Self::Concrete(node.into()))) - } else { - Ok(None) - } - } - _ => Ok(None), - } - } - - pub fn implicitly_castable_to( - &self, - other: &Self, - analyzer: &impl GraphLike, - ) -> Result { - match (self, other) { - (Self::BuiltIn(from_bn, _), Self::BuiltIn(to_bn, _)) => { - from_bn.implicitly_castable_to(to_bn, analyzer) - } - (Self::Concrete(from_c), Self::BuiltIn(_to_bn, _)) => { - todo!("here, {from_c:?}") - } - _ => Ok(false), - } - } - - pub fn max_size( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match self { - Self::BuiltIn(from_bn, _r) => { - let bn = from_bn.max_size(analyzer)?; - Ok(Self::BuiltIn( - bn, - SolcRange::try_from_builtin(bn.underlying(analyzer)?), - )) - } - Self::Concrete(from_c) => Ok(Self::Concrete(from_c.max_size(analyzer)?)), - _ => Ok(self.clone()), - } - } - - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - match self { - Self::User(_, Some(range)) => Ok(Some(range.clone())), - Self::BuiltIn(_, Some(range)) => Ok(Some(range.clone())), - Self::BuiltIn(bn, None) => Ok(SolcRange::try_from_builtin(bn.underlying(analyzer)?)), - Self::Concrete(cnode) => Ok(SolcRange::from(cnode.underlying(analyzer)?.clone())), - _ => Ok(None), - } - } - - pub fn ref_range( - &self, - analyzer: &impl GraphLike, - ) -> Result>, GraphError> { - match self { - Self::User(_, Some(range)) => Ok(Some(std::borrow::Cow::Borrowed(range))), - Self::BuiltIn(_, Some(range)) => Ok(Some(std::borrow::Cow::Borrowed(range))), - Self::BuiltIn(bn, None) => { - if let Some(r) = SolcRange::try_from_builtin(bn.underlying(analyzer)?) { - Ok(Some(std::borrow::Cow::Owned(r))) - } else { - Ok(None) - } - } - Self::Concrete(cnode) => { - if let Some(r) = SolcRange::from(cnode.underlying(analyzer)?.clone()) { - Ok(Some(std::borrow::Cow::Owned(r))) - } else { - Ok(None) - } - } - _ => Ok(None), - } - } - - pub fn delete_range_result( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - match self { - Self::User(TypeNode::Contract(_), _) => { - let zero = Concrete::Address(Address::from_slice(&[0x00; 20])); - Ok(Some(SolcRange::new( - zero.clone().into(), - zero.into(), - vec![], - ))) - } - Self::User(TypeNode::Enum(enum_node), _) => { - if let Some(first) = enum_node.variants(analyzer)?.first() { - let zero = Concrete::from(first.clone()); - Ok(Some(SolcRange::new( - zero.clone().into(), - zero.into(), - vec![], - ))) - } else { - Ok(None) - } - } - Self::User(TypeNode::Ty(ty), _) => { - BuiltInNode::from(ty.underlying(analyzer)?.ty).zero_range(analyzer) - } - Self::BuiltIn(bn, None) => bn.zero_range(analyzer), - Self::Concrete(cnode) => Ok(cnode.underlying(analyzer)?.as_builtin().zero_range()), - _ => Ok(None), - } - } - - pub fn default_range( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - match self { - Self::User(TypeNode::Contract(_), _) => { - Ok(SolcRange::try_from_builtin(&Builtin::Address)) - } - Self::User(TypeNode::Enum(enu), _) => enu.maybe_default_range(analyzer), - Self::User(TypeNode::Ty(ty), _) => Ok(SolcRange::try_from_builtin( - BuiltInNode::from(ty.underlying(analyzer)?.ty).underlying(analyzer)?, - )), - Self::BuiltIn(bn, _) => Ok(SolcRange::try_from_builtin(bn.underlying(analyzer)?)), - Self::Concrete(cnode) => Ok(SolcRange::from(cnode.underlying(analyzer)?.clone())), - _ => Ok(None), - } - } - - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::Concrete(_) => Ok(true), - Self::User(TypeNode::Func(_), _) => Ok(false), - _ => { - if let Some(range) = self.ref_range(analyzer)? { - let min = range.evaled_range_min(analyzer)?; - let max = range.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max)) - } else { - Ok(false) - } - } - } - } - - pub fn func_node(&self, _analyzer: &impl GraphLike) -> Option { - match self { - Self::User(TypeNode::Func(func_node), _) => Some(*func_node), - _ => None, - } - } - - pub fn evaled_range( - &self, - analyzer: &impl GraphLike, - ) -> Result, Elem)>, GraphError> { - Ok(self.ref_range(analyzer)?.map(|range| { - ( - range.evaled_range_min(analyzer).unwrap(), - range.evaled_range_max(analyzer).unwrap(), - ) - })) - } - - pub fn try_match_index_dynamic_ty( - &self, - index: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - match self { - Self::BuiltIn(_node, None) => Ok(None), - Self::BuiltIn(node, Some(r)) => { - if let Builtin::Bytes(size) = node.underlying(analyzer)? { - if r.is_const(analyzer)? && index.is_const(analyzer)? { - let Some(min) = r.evaled_range_min(analyzer)?.maybe_concrete() else { - return Ok(None); - }; - let Concrete::Bytes(_, val) = min.val else { - return Ok(None); - }; - let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() else { - return Ok(None) - }; - let Concrete::Uint(_, idx) = idx.val else { - return Ok(None); - }; - if idx.low_u32() < (*size as u32) { - let mut h = H256::default(); - h.0[0] = val.0[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Ok(None) - } else { - // check if the index exists as a key - let min = r.range_min(); - if let Some(map) = min.dyn_map() { - let name = index.name(analyzer)?; - let is_const = index.is_const(analyzer)?; - if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { - Elem::Reference(Reference { idx, .. }) => match analyzer.node(*idx) { - Node::ContextVar(_) => { - let cvar = ContextVarNode::from(*idx); - cvar.name(analyzer).unwrap() == name - } - _ => false, - }, - c @ Elem::Concrete(..) if is_const => { - let index_val = index.evaled_range_min(analyzer).unwrap().unwrap(); - index_val.range_eq(c) - } - _ => false, - }) { - if let Some(idx) = val.node_idx() { - return Ok(idx.into()); - } else if let Some(c) = val.concrete() { - let cnode = analyzer.add_node(Node::Concrete(c)); - return Ok(cnode.into()); - } - } - } - Ok(None) - } - } - Self::Concrete(node) => { - if index.is_const(analyzer)? { - let idx = index - .evaled_range_min(analyzer) - .unwrap() - .unwrap() - .concrete() - .unwrap() - .uint_val() - .unwrap(); - match node.underlying(analyzer)? { - Concrete::Bytes(size, val) => { - if idx.low_u32() < (*size as u32) { - let mut h = H256::default(); - h.0[0] = val.0[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::DynBytes(elems) => { - if idx.low_u32() < (elems.len() as u32) { - let mut h = H256::default(); - h.0[0] = elems[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::String(st) => { - if idx.low_u32() < (st.len() as u32) { - let mut h = H256::default(); - h.0[0] = st.as_bytes()[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::Array(elems) => { - if idx.low_u32() < (elems.len() as u32) { - let elem = &elems[idx.low_u32() as usize]; - let node = analyzer.add_node(Node::Concrete(elem.clone())); - return Ok(Some(node)); - } - } - _ => {} - } - } - Ok(None) - } - _ => Ok(None), - } - } - - pub fn get_index_dynamic_ty( - &self, - index: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { - Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) - } else { - match self { - Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), - Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin but it was: {e:?}" - ))), - } - } - } - - pub fn dynamic_underlying_ty( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match self { - Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), - Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin but it was: {e:?}" - ))), - } - } - - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::BuiltIn(node, _) => Ok(node.is_mapping(analyzer)?), - _ => Ok(false), - } - } - - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::BuiltIn(node, _) => node.is_sized_array(analyzer), - Self::Concrete(node) => node.is_sized_array(analyzer), - _ => Ok(false), - } - } - - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - match self { - Self::BuiltIn(node, _) => node.maybe_array_size(analyzer), - Self::Concrete(node) => node.maybe_array_size(analyzer), - _ => Ok(None), - } - } - - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::BuiltIn(node, _) => Ok(node.is_dyn(analyzer)?), - Self::Concrete(node) => Ok(node.is_dyn(analyzer)?), - _ => Ok(false), - } - } - - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { - match self { - Self::BuiltIn(node, _) => Ok(node.is_indexable(analyzer)?), - Self::Concrete(node) => Ok(node.is_indexable(analyzer)?), - _ => Ok(false), - } - } - - pub fn ty_eq(&self, other: &Self, analyzer: &impl GraphLike) -> Result { - match (self, other) { - (VarType::User(s, _), VarType::User(o, _)) => { - Ok(s.unresolved_as_resolved(analyzer)? == o.unresolved_as_resolved(analyzer)?) - } - (VarType::BuiltIn(s, _), VarType::BuiltIn(o, _)) => { - match (s.underlying(analyzer)?, o.underlying(analyzer)?) { - (Builtin::Array(l), Builtin::Array(r)) => Ok(l - .unresolved_as_resolved(analyzer)? - == r.unresolved_as_resolved(analyzer)?), - (Builtin::SizedArray(l_size, l), Builtin::SizedArray(r_size, r)) => Ok(l - .unresolved_as_resolved(analyzer)? - == r.unresolved_as_resolved(analyzer)? - && l_size == r_size), - (Builtin::Mapping(lk, lv), Builtin::Mapping(rk, rv)) => Ok(lk - .unresolved_as_resolved(analyzer)? - == rk.unresolved_as_resolved(analyzer)? - && lv.unresolved_as_resolved(analyzer)? - == rv.unresolved_as_resolved(analyzer)?), - (l, r) => Ok(l == r), - } - } - (VarType::Concrete(s), VarType::Concrete(o)) => Ok(s - .underlying(analyzer)? - .equivalent_ty(o.underlying(analyzer)?)), - _ => Ok(false), - } - } - - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { - match self { - VarType::User(ty_node, _) => ty_node.as_string(analyzer), - VarType::BuiltIn(bn, _) => match analyzer.node(*bn) { - Node::Builtin(bi) => bi.as_string(analyzer), - _ => unreachable!(), - }, - VarType::Concrete(c) => c.underlying(analyzer)?.as_builtin().as_string(analyzer), - } - } - - pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { - match self { - VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.is_int()), - VarType::Concrete(c) => Ok(c.underlying(analyzer)?.is_int()), - _ => Ok(false), - } - } - - pub fn as_builtin(&self, analyzer: &impl GraphLike) -> Result { - match self { - VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.clone()), - VarType::Concrete(c) => Ok(c.underlying(analyzer)?.as_builtin()), - e => Err(GraphError::NodeConfusion(format!( - "Expected to be builtin castable but wasnt: {e:?}" - ))), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub enum TypeNode { - Contract(ContractNode), - Struct(StructNode), - Enum(EnumNode), - Ty(TyNode), - Func(FunctionNode), - Unresolved(NodeIdx), -} - -impl TypeNode { - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { - match self { - TypeNode::Contract(n) => n.name(analyzer), - TypeNode::Struct(n) => n.name(analyzer), - TypeNode::Enum(n) => n.name(analyzer), - TypeNode::Ty(n) => n.name(analyzer), - TypeNode::Func(n) => Ok(format!("function {}", n.name(analyzer)?)), - TypeNode::Unresolved(n) => Ok(format!("UnresolvedType<{:?}>", analyzer.node(*n))), - } - } - - pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { - match self { - TypeNode::Unresolved(n) => match analyzer.node(*n) { - Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( - "Expected the type \"{}\" to be resolved by now", - ident.name - ))), - Node::Contract(..) => Ok(TypeNode::Contract((*n).into())), - Node::Struct(..) => Ok(TypeNode::Struct((*n).into())), - Node::Enum(..) => Ok(TypeNode::Enum((*n).into())), - Node::Ty(..) => Ok(TypeNode::Ty((*n).into())), - Node::Function(..) => Ok(TypeNode::Func((*n).into())), - _ => Err(GraphError::NodeConfusion( - "Tried to type a non-typeable element".to_string(), - )), - }, - _ => Ok(*self), - } - } -} - -impl From for NodeIdx { - fn from(val: TypeNode) -> Self { - match val { - TypeNode::Contract(n) => n.into(), - TypeNode::Struct(n) => n.into(), - TypeNode::Enum(n) => n.into(), - TypeNode::Ty(n) => n.into(), - TypeNode::Func(n) => n.into(), - TypeNode::Unresolved(n) => n, - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] -pub struct BuiltInNode(pub usize); - -impl BuiltInNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Builtin, GraphError> { - match analyzer.node(*self) { - Node::Builtin(b) => Ok(b), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin but it was: {e:?}" - ))), - } - } - - pub fn num_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let underlying = self.underlying(analyzer)?; - Ok(underlying.num_size()) - } - - pub fn implicitly_castable_to( - &self, - other: &Self, - analyzer: &impl GraphLike, - ) -> Result { - Ok(self - .underlying(analyzer)? - .implicitly_castable_to(other.underlying(analyzer)?)) - } - - pub fn max_size( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let m = self.underlying(analyzer)?.max_size(); - Ok(analyzer.builtin_or_add(m).into()) - } - - pub fn dynamic_underlying_ty( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match self.underlying(analyzer)? { - Builtin::Array(v_ty) | Builtin::SizedArray(_, v_ty) => { - v_ty.unresolved_as_resolved(analyzer) - } - Builtin::Mapping(_, v_ty) => v_ty.unresolved_as_resolved(analyzer), - Builtin::DynamicBytes | Builtin::Bytes(_) => Ok(VarType::BuiltIn( - analyzer.builtin_or_add(Builtin::Bytes(1)).into(), - Some(SolcRange::new( - Elem::from(Concrete::from(vec![0x00])), - Elem::from(Concrete::from(vec![0xff])), - vec![], - )), - )), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin::Array but it was: {e:?}" - ))), - } - } - - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { - Ok(matches!(self.underlying(analyzer)?, Builtin::Mapping(_, _))) - } - - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { - Ok(matches!( - self.underlying(analyzer)?, - Builtin::SizedArray(_, _) - )) - } - - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - match self.underlying(analyzer)? { - Builtin::SizedArray(s, _) => Ok(Some(*s)), - Builtin::Bytes(s) => Ok(Some(U256::from(*s))), - _ => Ok(None), - } - } - - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_dyn()) - } - - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.is_indexable()) - } - - pub fn zero_range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.zero_range()) - } -} - -impl From for BuiltInNode { - fn from(idx: NodeIdx) -> Self { - BuiltInNode(idx.index()) - } -} - -impl From for NodeIdx { - fn from(val: BuiltInNode) -> Self { - val.0.into() - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum Builtin { - Address, - AddressPayable, - Payable, - Bool, - String, - Int(u16), - Uint(u16), - Bytes(u8), - Rational, - DynamicBytes, - Array(VarType), - SizedArray(U256, VarType), - Mapping(VarType, VarType), - Func(Vec, Vec), -} - -impl Builtin { - pub fn unresolved_as_resolved( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match self { - Builtin::Array(n) => Ok(Builtin::Array(n.unresolved_as_resolved(analyzer)?)), - Builtin::SizedArray(s, n) => { - Ok(Builtin::SizedArray(*s, n.unresolved_as_resolved(analyzer)?)) - } - Builtin::Mapping(k, v) => Ok(Builtin::Mapping( - k.unresolved_as_resolved(analyzer)?, - v.unresolved_as_resolved(analyzer)?, - )), - _ => Ok(self.clone()), - } - } - - pub fn possible_builtins_from_ty_inf(&self) -> Vec { - let mut builtins = vec![]; - match self { - Builtin::Uint(size) => { - let mut s = *size; - while s > 0 { - builtins.push(Builtin::Uint(s)); - s -= 8; - } - } - Builtin::Int(size) => { - let mut s = *size; - while s > 0 { - builtins.push(Builtin::Int(s)); - s -= 8; - } - } - Builtin::Bytes(size) => { - let mut s = *size; - while s > 0 { - builtins.push(Builtin::Bytes(s)); - s -= 1; - } - } - _ => {} - } - builtins - } - - pub fn zero_range(&self) -> Option { - match self { - Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { - let zero = Concrete::Address(Address::from_slice(&[0x00; 20])); - Some(SolcRange::new(zero.clone().into(), zero.into(), vec![])) - } - Builtin::Bool => SolcRange::from(Concrete::from(false)), - Builtin::String => SolcRange::from(Concrete::from("".to_string())), - Builtin::Int(_) => SolcRange::from(Concrete::from(I256::from(0))), - Builtin::Uint(_) => SolcRange::from(Concrete::from(U256::from(0))), - Builtin::Bytes(s) => SolcRange::from(Concrete::Bytes(*s, H256::zero())), - Builtin::DynamicBytes | Builtin::Array(_) | Builtin::Mapping(_, _) => { - let zero = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::zero())), - val: Default::default(), - loc: Loc::Implicit, - })); - Some(SolcRange::new(zero.clone(), zero, vec![])) - } - Builtin::SizedArray(s, _) => { - let sized = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })); - Some(SolcRange::new(sized.clone(), sized, vec![])) - } - Builtin::Rational | Builtin::Func(_, _) => None, - } - } - pub fn try_from_ty( - ty: Type, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - use Type::*; - match ty { - Address => Some(Builtin::Address), - AddressPayable => Some(Builtin::AddressPayable), - Payable => Some(Builtin::Payable), - Bool => Some(Builtin::Bool), - String => Some(Builtin::String), - Int(size) => Some(Builtin::Int(size)), - Uint(size) => Some(Builtin::Uint(size)), - Bytes(size) => Some(Builtin::Bytes(size)), - Rational => Some(Builtin::Rational), - DynamicBytes => Some(Builtin::DynamicBytes), - Mapping { key, value, .. } => { - let key_idx = analyzer.parse_expr(&key, None); - let val_idx = analyzer.parse_expr(&value, None); - let key_var_ty = VarType::try_from_idx(analyzer, key_idx)?; - let val_var_ty = VarType::try_from_idx(analyzer, val_idx)?; - Some(Builtin::Mapping(key_var_ty, val_var_ty)) - } - Function { - params, - attributes: _, - returns, - } => { - let inputs = params - .iter() - .filter_map(|(_, param)| param.as_ref()) - .map(|param| analyzer.parse_expr(¶m.ty, None)) - .collect::>(); - let inputs = inputs - .iter() - .map(|idx| VarType::try_from_idx(analyzer, *idx).expect("Couldn't parse param")) - .collect::>(); - let mut outputs = vec![]; - if let Some((params, _attrs)) = returns { - let tmp_outputs = params - .iter() - .filter_map(|(_, param)| param.as_ref()) - .map(|param| analyzer.parse_expr(¶m.ty, None)) - .collect::>(); - outputs = tmp_outputs - .iter() - .map(|idx| { - VarType::try_from_idx(analyzer, *idx) - .expect("Couldn't parse output param") - }) - .collect::>(); - } - Some(Builtin::Func(inputs, outputs)) - } - } - } - - pub fn is_dyn(&self) -> bool { - matches!( - self, - Builtin::DynamicBytes - | Builtin::Array(..) - | Builtin::SizedArray(..) - | Builtin::Mapping(..) - | Builtin::String - ) - } - - pub fn requires_input(&self) -> bool { - matches!( - self, - Builtin::Array(..) | Builtin::SizedArray(..) | Builtin::Mapping(..) - ) - } - - pub fn num_size(&self) -> Option { - match self { - Builtin::Uint(size) => Some(*size), - Builtin::Int(size) => Some(*size), - _ => None, - } - } - - pub fn is_int(&self) -> bool { - matches!(self, Builtin::Int(_)) - } - - pub fn is_indexable(&self) -> bool { - matches!( - self, - Builtin::DynamicBytes - | Builtin::Array(..) - | Builtin::SizedArray(..) - | Builtin::Mapping(..) - | Builtin::Bytes(..) - | Builtin::String - ) - } - - pub fn implicitly_castable_to(&self, other: &Self) -> bool { - use Builtin::*; - match (self, other) { - (Address, Address) => true, - (Address, AddressPayable) => true, - (Address, Payable) => true, - (AddressPayable, Address) => true, - (AddressPayable, Payable) => true, - (AddressPayable, AddressPayable) => true, - (Payable, Address) => true, - (Payable, AddressPayable) => true, - (Payable, Payable) => true, - (Bool, Bool) => true, - (Rational, Rational) => true, - (DynamicBytes, DynamicBytes) => true, - (String, String) => true, - (Uint(from_size), Uint(to_size)) => from_size <= to_size, - (Int(from_size), Int(to_size)) => from_size <= to_size, - (Bytes(from_size), Bytes(to_size)) => from_size <= to_size, - _ => false, - } - } - - pub fn max_size(&self) -> Self { - use Builtin::*; - match self { - Uint(_) => Uint(256), - Int(_from_size) => Uint(256), - Bytes(_from_size) => Uint(32), - _ => self.clone(), - } - } - - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { - use Builtin::*; - match self { - Address => Ok("address".to_string()), - AddressPayable => Ok("address".to_string()), - Payable => Ok("address".to_string()), - Bool => Ok("bool".to_string()), - String => Ok("string".to_string()), - Int(size) => Ok(format!("int{size}")), - Uint(size) => Ok(format!("uint{size}")), - Bytes(size) => Ok(format!("bytes{size}")), - Rational => Ok("rational".to_string()), - DynamicBytes => Ok("bytes".to_string()), - Array(v_ty) => Ok(format!( - "{}[]", - v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)? - )), - SizedArray(s, v_ty) => Ok(format!( - "{}[{}]", - v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)?, - s - )), - Mapping(key_ty, v_ty) => Ok(format!( - "mapping ({} => {})", - key_ty - .unresolved_as_resolved(analyzer)? - .as_string(analyzer)?, - v_ty.unresolved_as_resolved(analyzer)?.as_string(analyzer)? - )), - Func(inputs, outputs) => Ok(format!( - "function({}) returns ({})", - inputs - .iter() - .map(|input| input.as_string(analyzer).unwrap()) - .collect::>() - .join(", "), - outputs - .iter() - .map(|output| output.as_string(analyzer).unwrap()) - .collect::>() - .join(", ") - )), - } - } -} diff --git a/shared/src/nodes/msg.rs b/shared/src/nodes/msg.rs deleted file mode 100644 index b7f24095..00000000 --- a/shared/src/nodes/msg.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Builtin; -use crate::Concrete; -use crate::ContextNode; -use crate::ContextVar; - -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::U256; -use solang_parser::pt::Loc; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct MsgNode(pub usize); - -impl MsgNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Msg, GraphError> { - match analyzer.node(*self) { - Node::Msg(st) => Ok(st), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Msg but it was: {e:?}" - ))), - } - } -} - -impl AsDotStr for MsgNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - format!("msg {{ {:?} }}", self.underlying(analyzer).unwrap()) - } -} - -impl From for NodeIdx { - fn from(val: MsgNode) -> Self { - val.0.into() - } -} - -impl From for MsgNode { - fn from(idx: NodeIdx) -> Self { - MsgNode(idx.index()) - } -} - -#[derive(Debug, Clone, Default, Eq, PartialEq)] -pub struct Msg { - pub data: Option>, - pub sender: Option
, - pub sig: Option<[u8; 4]>, - pub value: Option, - pub origin: Option
, - pub gasprice: Option, - pub gaslimit: Option, -} - -impl Msg { - pub fn context_var_from_str( - &self, - elem: &str, - loc: Loc, - ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let (node, name) = match elem { - "data" => { - if let Some(d) = self.data.clone() { - let c = Concrete::from(d); - (analyzer.add_node(Node::Concrete(c)), "msg.data".to_string()) - } else { - let b = Builtin::DynamicBytes; - let node = analyzer.builtin_or_add(b); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "msg.data".to_string(); - var.display_name = "msg.data".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "sender" => { - if let Some(d) = self.sender { - let c = Concrete::from(d); - ( - analyzer.add_node(Node::Concrete(c)), - "msg.sender".to_string(), - ) - } else { - let node = analyzer.builtin_or_add(Builtin::Address); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "msg.sender".to_string(); - var.display_name = "msg.sender".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "sig" => { - if let Some(d) = self.sig { - let c = Concrete::from(d); - (analyzer.add_node(Node::Concrete(c)), "msg.sig".to_string()) - } else { - let node = analyzer.builtin_or_add(Builtin::Bytes(4)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "msg.sig".to_string(); - var.display_name = "msg.sig".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "value" => { - if let Some(d) = self.value { - let c = Concrete::from(d); - ( - analyzer.add_node(Node::Concrete(c)), - "msg.value".to_string(), - ) - } else { - let node = analyzer.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "msg.value".to_string(); - var.display_name = "msg.value".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "origin" => { - if let Some(d) = self.origin { - let c = Concrete::from(d); - ( - analyzer.add_node(Node::Concrete(c)), - "tx.origin".to_string(), - ) - } else { - let node = analyzer.builtin_or_add(Builtin::Address); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "tx.origin".to_string(); - var.display_name = "tx.origin".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "gasprice" => { - if let Some(d) = self.gasprice { - let c = Concrete::from(d); - ( - analyzer.add_node(Node::Concrete(c)), - "tx.gasprice".to_string(), - ) - } else { - let node = analyzer.builtin_or_add(Builtin::Uint(64)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.name = "tx.gasprice".to_string(); - var.display_name = "tx.gasprice".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - "gaslimit" => { - if let Some(d) = self.gaslimit { - let c = Concrete::from(d); - (analyzer.add_node(Node::Concrete(c)), "".to_string()) - } else { - let node = analyzer.builtin_or_add(Builtin::Uint(64)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), analyzer)?; - var.is_tmp = false; - var.is_symbolic = true; - return Ok(var); - } - } - e => { - return Err(GraphError::NodeConfusion(format!( - "Unknown msg attribute: {e:?}" - ))) - } - }; - - let mut var = ContextVar::new_from_concrete(loc, ctx, node.into(), analyzer)?; - var.name = name.clone(); - var.display_name = name; - var.is_tmp = false; - var.is_symbolic = true; - Ok(var) - } -} diff --git a/shared/src/nodes/struct_ty.rs b/shared/src/nodes/struct_ty.rs deleted file mode 100644 index 2ede9a0f..00000000 --- a/shared/src/nodes/struct_ty.rs +++ /dev/null @@ -1,199 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Edge; - -use crate::Node; -use crate::NodeIdx; -use crate::VarType; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableDeclaration}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct StructNode(pub usize); - -impl StructNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Struct, GraphError> { - match analyzer.node(*self) { - Node::Struct(st) => Ok(st), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Struct but it was: {e:?}" - ))), - } - } - - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.loc) - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .as_ref() - .expect("Struct wasn't named") - .to_string()) - } - - pub fn fields(&self, analyzer: &impl GraphLike) -> Vec { - let mut fields: Vec<_> = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::Field == *edge.weight()) - .map(|edge| FieldNode::from(edge.source())) - .collect(); - fields.sort_by(|a, b| a.0.cmp(&b.0)); - fields - } - - pub fn find_field(&self, analyzer: &impl GraphLike, ident: &Identifier) -> Option { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::Field == *edge.weight()) - .map(|edge| FieldNode::from(edge.source())) - .find(|field_node| field_node.name(analyzer).unwrap() == ident.name) - } -} - -impl AsDotStr for StructNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "struct {} {{ {} }}", - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - }, - self.fields(analyzer) - .iter() - .map(|field_node| { field_node.as_dot_str(analyzer) }) - .collect::>() - .join("; ") - ) - } -} - -impl From for NodeIdx { - fn from(val: StructNode) -> Self { - val.0.into() - } -} - -impl From for StructNode { - fn from(idx: NodeIdx) -> Self { - StructNode(idx.index()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Struct { - pub loc: Loc, - pub name: Option, -} - -impl Struct { - pub fn maybe_from_node(node: Node) -> Option { - match node { - Node::Struct(s) => Some(s), - _ => None, - } - } -} - -impl From for Node { - fn from(val: Struct) -> Self { - Node::Struct(val) - } -} - -impl From for Struct { - fn from(con: StructDefinition) -> Struct { - Struct { - loc: con.loc, - name: con.name, - } - } -} - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct FieldNode(pub usize); - -impl FieldNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Field, GraphError> { - match analyzer.node(*self) { - Node::Field(field) => Ok(field), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Field but it was: {e:?}" - ))), - } - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .as_ref() - .expect("Struct wasn't named") - .to_string()) - } -} - -impl AsDotStr for FieldNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "{} {}", - if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) - } else { - "".to_string() - }, - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - } - ) - } -} - -impl From for FieldNode { - fn from(idx: NodeIdx) -> Self { - FieldNode(idx.index()) - } -} - -impl From for NodeIdx { - fn from(val: FieldNode) -> Self { - val.0.into() - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Field { - pub loc: Loc, - pub ty: NodeIdx, - pub name: Option, -} - -impl From for Node { - fn from(val: Field) -> Self { - Node::Field(val) - } -} - -impl Field { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - var_def: VariableDeclaration, - ) -> Field { - let ty_idx = analyzer.parse_expr(&var_def.ty, None); - Field { - loc: var_def.loc, - ty: ty_idx, - name: var_def.name, - } - } -} diff --git a/shared/src/nodes/ty_ty.rs b/shared/src/nodes/ty_ty.rs deleted file mode 100644 index 83b76527..00000000 --- a/shared/src/nodes/ty_ty.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Node; -use crate::NodeIdx; -use crate::VarType; -use solang_parser::pt::{Expression, Identifier, Loc, TypeDefinition}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct TyNode(pub usize); -impl TyNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Ty, GraphError> { - match analyzer.node(*self) { - Node::Ty(ty) => Ok(ty), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be TypeNode but it was: {e:?}" - ))), - } - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.name.to_string()) - } -} - -impl From for NodeIdx { - fn from(val: TyNode) -> Self { - val.0.into() - } -} - -impl From for TyNode { - fn from(idx: NodeIdx) -> Self { - TyNode(idx.index()) - } -} - -impl AsDotStr for TyNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "{} {}", - if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) - } else { - "".to_string() - }, - underlying.name.name, - ) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Ty { - pub loc: Loc, - pub ty: NodeIdx, - pub name: Identifier, -} - -impl From for Node { - fn from(val: Ty) -> Self { - Node::Ty(val) - } -} - -impl Ty { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - ty: TypeDefinition, - ) -> Ty { - Ty { - loc: ty.loc, - ty: analyzer.parse_expr(&ty.ty, None), - name: ty.name, - } - } -} diff --git a/shared/src/nodes/var_ty.rs b/shared/src/nodes/var_ty.rs deleted file mode 100644 index c15d1285..00000000 --- a/shared/src/nodes/var_ty.rs +++ /dev/null @@ -1,236 +0,0 @@ -use crate::analyzer::Search; -use crate::nodes::GraphError; - -use crate::ContractNode; -use crate::VarType; -use crate::{ - analyzer::{AnalyzerLike, AsDotStr, GraphLike}, - Node, NodeIdx, -}; -use crate::{ContextVar, Edge}; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{ - Expression, Identifier, Loc, VariableAttribute, VariableDefinition, Visibility, -}; - -#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct VarNode(pub usize); - -impl VarNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Var, GraphError> { - match analyzer.node(*self) { - Node::Var(func) => Ok(func), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Var but it was: {e:?}" - ))), - } - } - - pub fn underlying_mut<'a>( - &self, - analyzer: &'a mut impl GraphLike, - ) -> Result<&'a mut Var, GraphError> { - match analyzer.node_mut(*self) { - Node::Var(func) => Ok(func), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Var but it was: {e:?}" - ))), - } - } - - pub fn parse_initializer( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - parent: NodeIdx, - ) -> Result<(), GraphError> { - if let Some(expr) = self.underlying(analyzer)?.initializer_expr.clone() { - tracing::trace!("Parsing variable initializer"); - let init = analyzer.parse_expr(&expr, Some(parent)); - let underlying = self.underlying(analyzer)?.clone(); - let mut set = false; - if let Some(ty) = VarType::try_from_idx(analyzer, underlying.ty) { - if let Some(initer) = VarType::try_from_idx(analyzer, init) { - if let Some(initer) = initer.try_cast(&ty, analyzer)? { - set = true; - self.underlying_mut(analyzer)?.initializer = Some(initer.ty_idx()); - } - } - } - - if !set { - self.underlying_mut(analyzer)?.initializer = Some(init); - } - } - Ok(()) - } - - pub fn maybe_associated_contract(&self, analyzer: &impl GraphLike) -> Option { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| matches!(*edge.weight(), Edge::Var)) - .filter_map(|edge| { - let node = edge.target(); - match analyzer.node(node) { - Node::Contract(_) => Some(ContractNode::from(node)), - _ => None, - } - }) - .take(1) - .next() - .map(ContractNode::from) - } - - pub fn maybe_associated_source_unit_part(&self, analyzer: &impl GraphLike) -> Option { - if let Some(con) = self.maybe_associated_contract(analyzer) { - Some(con.associated_source_unit_part(analyzer)) - } else { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| matches!(*edge.weight(), Edge::Var)) - .filter_map(|edge| { - let node = edge.target(); - match analyzer.node(node) { - Node::SourceUnitPart(..) => Some(node), - _ => None, - } - }) - .take(1) - .next() - } - } - - pub fn maybe_associated_source(&self, analyzer: &(impl GraphLike + Search)) -> Option { - let sup = self.maybe_associated_source_unit_part(analyzer)?; - analyzer.search_for_ancestor(sup, &Edge::Part) - } - - pub fn name(&self, analyzer: &impl GraphLike) -> Result { - Ok(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed function") - .name) - } - - pub fn const_value( - &self, - loc: Loc, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let attrs = &self.underlying(analyzer)?.attrs; - if attrs - .iter() - .any(|attr| matches!(attr, VariableAttribute::Constant(_))) - { - if let Some(init) = self.underlying(analyzer)?.initializer { - if let Some(ty) = VarType::try_from_idx(analyzer, init) { - return Ok(Some(ContextVar { - loc: Some(loc), - name: self.name(analyzer)?, - display_name: self.name(analyzer)?, - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - })); - } - } - } - Ok(None) - } -} - -impl AsDotStr for VarNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - let underlying = self.underlying(analyzer).unwrap(); - format!( - "{}{} {}", - if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) - } else { - "".to_string() - }, - underlying - .attrs - .iter() - .map(|attr| { - match attr { - VariableAttribute::Visibility(vis) => format!(" {vis}"), - VariableAttribute::Constant(_) => " constant".to_string(), - VariableAttribute::Immutable(_) => " immutable".to_string(), - VariableAttribute::Override(_, _) => " override".to_string(), - } - }) - .collect::>() - .join(" "), - if let Some(name) = &underlying.name { - name.name.clone() - } else { - "".to_string() - } - ) - } -} - -impl From for NodeIdx { - fn from(val: VarNode) -> Self { - val.0.into() - } -} - -impl From for VarNode { - fn from(idx: NodeIdx) -> Self { - VarNode(idx.index()) - } -} - -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct Var { - pub loc: Loc, - pub ty: NodeIdx, - pub attrs: Vec, - pub name: Option, - pub initializer: Option, - pub initializer_expr: Option, - pub in_contract: bool, -} - -impl From for Node { - fn from(val: Var) -> Self { - Node::Var(val) - } -} - -impl Var { - pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), - var: VariableDefinition, - in_contract: bool, - ) -> Var { - tracing::trace!("Parsing Var type"); - let ty = analyzer.parse_expr(&var.ty, None); - Var { - loc: var.loc, - ty, - attrs: var.attrs, - name: var.name, - initializer: None, - initializer_expr: var.initializer, - in_contract, - } - } - - pub fn is_public(&self) -> bool { - self.attrs.iter().any(|var_attr| { - matches!( - var_attr, - VariableAttribute::Visibility(Visibility::Public(_)) - ) - }) - } -} diff --git a/shared/src/range/elem.rs b/shared/src/range/elem.rs deleted file mode 100644 index 5b8d8aaf..00000000 --- a/shared/src/range/elem.rs +++ /dev/null @@ -1,175 +0,0 @@ -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::context::ContextVarNode; -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeExpr; - -use crate::NodeIdx; -use std::collections::BTreeMap; - -/// An operation to be performed on a range element -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum RangeOp { - /// Addition - Add(bool), - /// Multiplication - Mul(bool), - /// Subtraction - Sub(bool), - /// Division - Div(bool), - /// Modulos - Mod, - /// Minimum - Min, - /// Maximum - Max, - /// Less than - Lt, - /// Less than or equal - Lte, - /// Geater than - Gt, - /// Greater than or equal - Gte, - /// Equal - Eq, - /// Not Equal - Neq, - /// Logical Not - Not, - /// Bitwise shift left - Shl, - /// Bitwise shift right - Shr, - /// Logical AND - And, - /// Logical OR - Or, - /// Catch-all requirement statement - Where, - /// Cast from one type to another - Cast, - /// Bitwise AND - BitAnd, - /// Bitwise OR - BitOr, - /// Bitwise XOR - BitXor, - /// Bitwise Not - BitNot, - /// Exponentiation - Exp, - /// Concatenation - Concat, -} - -impl RangeOp { - /// Attempts to return the inverse range operation (e.g.: `RangeOp::Add => RangeOp::Sub`) - pub fn inverse(self) -> Option { - use RangeOp::*; - match self { - Add(i) => Some(Sub(i)), - Mul(i) => Some(Div(i)), - Sub(i) => Some(Add(i)), - Div(i) => Some(Mul(i)), - Shl => Some(Shr), - Shr => Some(Shl), - Eq => Some(Neq), - Neq => Some(Eq), - _ => None, // e => panic!("tried to inverse unreversable op: {:?}", e), - } - } - - pub fn require_parts(self) -> Option<(Self, Self, (Self, Self))> { - use RangeOp::*; - let t = match self { - Eq => (Eq, Neq, (Neq, Eq)), - Neq => (Neq, Eq, (Eq, Neq)), - Lte => (Lte, Gte, (Gte, Lte)), - Gte => (Gte, Lte, (Lte, Gte)), - Gt => (Gt, Lt, (Lt, Gt)), - Lt => (Lt, Gt, (Gt, Lt)), - _ => return None, - }; - Some(t) - } -} - -impl ToString for RangeOp { - fn to_string(&self) -> String { - use RangeOp::*; - match self { - Add(..) => "+".to_string(), - Mul(..) => "*".to_string(), - Sub(..) => "-".to_string(), - Div(..) => "/".to_string(), - Shl => "<<".to_string(), - Shr => ">>".to_string(), - Mod => "%".to_string(), - Exp => "**".to_string(), - Min => "min".to_string(), - Max => "max".to_string(), - Lt => "<".to_string(), - Gt => ">".to_string(), - Lte => "<=".to_string(), - Gte => ">=".to_string(), - Eq => "==".to_string(), - Neq => "!=".to_string(), - Not => "!".to_string(), - And => "&&".to_string(), - Or => "||".to_string(), - Where => "where".to_string(), - Cast => "cast".to_string(), - BitAnd => "&".to_string(), - BitOr => "|".to_string(), - BitXor => "^".to_string(), - BitNot => "~".to_string(), - Concat => "concat".to_string(), - } - } -} - -pub trait RangeElem { - /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; - /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; - fn uncache(&mut self); - /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; - /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; - /// Checks if two range elements are equal - fn range_eq(&self, other: &Self) -> bool; - /// Tries to compare the ordering of two range elements - fn range_ord(&self, other: &Self) -> Option; - /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). - fn range_op(lhs: Elem, rhs: Elem, op: RangeOp) -> Elem - where - Self: Sized, - { - Elem::Expr(RangeExpr::new(lhs, op, rhs)) - } - /// Traverses the range expression and finds all nodes that are dynamically pointed to - /// and returns it in a vector. - fn dependent_on(&self) -> Vec; - /// Traverses the range expression and updates stale pointers from older versions - /// of a variable to a newer version. - /// - /// e.g.: `uint256 z = x + 100`, followed by `require(x < 100)`. Initially, - /// without the `require` statement, `z`'s max is `2**256 - 1`, but with - /// the introduction of the `require` statement, we do a little backtracking - /// and can update `z`'s max to be `200`. - fn update_deps(&mut self, mapping: &BTreeMap); - /// Attempts to replace range elements that form a cyclic dependency by replacing - /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now - /// but in theory it can make sense. - /// - /// e.g.: take the basic expression `x + y`, in normal checked solidity math - /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a - /// cyclic dependency. - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); -} diff --git a/shared/src/range/elem_ty.rs b/shared/src/range/elem_ty.rs deleted file mode 100644 index c8609e45..00000000 --- a/shared/src/range/elem_ty.rs +++ /dev/null @@ -1,2258 +0,0 @@ -use crate::analyzer::GraphError; -use crate::context::ContextVarNode; -use crate::nodes::{TypeNode, VarType}; -use crate::range::range_ops::*; -use crate::range::Range; -use crate::range::{elem::RangeOp, *}; -use crate::{Concrete, NodeIdx}; -use solang_parser::pt::Loc; -use std::collections::BTreeMap; -use std::ops::*; - -/// A dynamic range element value -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct Reference { - /// Index of the node that is referenced - pub idx: NodeIdx, - pub minimized: Option>, - pub maximized: Option>, -} - -impl Reference { - pub fn new(idx: NodeIdx) -> Self { - Self { - idx, - minimized: None, - maximized: None, - } - } -} - -impl RangeElem for Reference { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn range_ord(&self, _other: &Self) -> Option { - todo!() - } - - fn dependent_on(&self) -> Vec { - vec![ContextVarNode::from(self.idx)] - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { - self.idx = NodeIdx::from(new.0); - } - } - - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - return Ok(*cached); - } - - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - range.evaled_range_max(analyzer) - } else { - Ok(Elem::Reference(self.clone())) - } - } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), - _e => Ok(Elem::Reference(self.clone())), - } - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - return Ok(*cached); - } - - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - range.evaled_range_min(analyzer) - } else { - Ok(Elem::Reference(self.clone())) - } - } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), - _e => Ok(Elem::Reference(self.clone())), - } - } - - fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - // let cvar = ContextVarNode::from(self.idx); - // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Reference(self.clone())) - // } - // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Reference(self.clone())) - // } - // let cvar = cvar.underlying(analyzer)?; - // match &cvar.ty { - // VarType::User(TypeNode::Contract(_), maybe_range) - // | VarType::User(TypeNode::Enum(_), maybe_range) - // | VarType::User(TypeNode::Ty(_), maybe_range) - // | VarType::BuiltIn(_, maybe_range) => { - // if let Some(range) = maybe_range { - // range.simplified_range_max(analyzer) - // } else { - // Ok(Elem::Reference(self.clone())) - // } - // } - // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - // val: concrete_node.underlying(analyzer)?.clone(), - // loc: cvar.loc.unwrap_or(Loc::Implicit), - // })), - // _e => Ok(Elem::Reference(self.clone())), - // } - } - fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - // let cvar = ContextVarNode::from(self.idx); - // if cvar.is_symbolic(analyzer)? { - Ok(Elem::Reference(self.clone())) - // } - // if !cvar.is_tmp(analyzer)? { - // return Ok(Elem::Reference(self.clone())) - // } - // let cvar = cvar.underlying(analyzer)?; - - // match &cvar.ty { - // VarType::User(TypeNode::Contract(_), maybe_range) - // | VarType::User(TypeNode::Enum(_), maybe_range) - // | VarType::User(TypeNode::Ty(_), maybe_range) - // | VarType::BuiltIn(_, maybe_range) => { - // if let Some(range) = maybe_range { - // range.simplified_range_min(analyzer) - // } else { - // Ok(Elem::Reference(self.clone())) - // } - // } - // VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - // val: concrete_node.underlying(analyzer)?.clone(), - // loc: cvar.loc.unwrap_or(Loc::Implicit), - // })), - // _e => Ok(Elem::Reference(self.clone())), - // } - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); - } - Ok(()) - } - - fn uncache(&mut self) { - self.minimized = None; - self.maximized = None; - } -} - -/// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeDyn { - pub minimized: Option>, - pub maximized: Option>, - pub len: Elem, - pub val: BTreeMap, Elem>, - pub loc: Loc, -} -impl RangeDyn { - pub fn set_len(&mut self, new_len: Elem) { - self.len = new_len; - } - - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - self.len.contains_node(node_idx) - // || self.val.iter().any(|(k, v)| k.contains_node(node_idx) || v.contains_node(node_idx)) - } -} - -impl RangeElem for RangeDyn { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn range_ord(&self, _other: &Self) -> Option { - todo!() - } - - fn dependent_on(&self) -> Vec { - let mut deps: Vec = self.len.dependent_on(); - deps.extend( - self.val - .iter() - .flat_map(|(_, val)| val.dependent_on()) - .collect::>(), - ); - deps - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - self.len.update_deps(mapping); - self.val - .iter_mut() - .for_each(|(_, val)| val.update_deps(mapping)); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.len.filter_recursion(node_idx, new_idx); - self.val = self - .val - .clone() - .into_iter() - .map(|(mut k, mut v)| { - k.filter_recursion(node_idx, new_idx); - v.filter_recursion(node_idx, new_idx); - (k, v) - }) - .collect(); - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - return Ok(*cached); - } - - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.maximize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.maximize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - return Ok(*cached); - } - - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.minimize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.minimize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_maximize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_maximize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_minimize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_minimize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); - } - Ok(()) - } - - fn uncache(&mut self) { - self.minimized = None; - self.maximized = None; - } -} - -/// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeConcrete { - pub val: T, - pub loc: Loc, -} - -impl From for RangeConcrete { - fn from(c: Concrete) -> Self { - Self { - val: c, - loc: Loc::Implicit, - } - } -} - -impl RangeElem for RangeConcrete { - // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { - // Elem::Concrete(self.clone()) - // } - - fn range_eq(&self, other: &Self) -> bool { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(self_val), Some(other_val)) => self_val == other_val, - _ => match (&self.val, &other.val) { - (Concrete::Int(_, s), Concrete::Int(_, o)) => s == o, - (Concrete::DynBytes(s), Concrete::DynBytes(o)) => s == o, - (Concrete::String(s), Concrete::String(o)) => s == o, - (Concrete::DynBytes(s), Concrete::String(o)) => s == o.as_bytes(), - (Concrete::String(s), Concrete::DynBytes(o)) => s.as_bytes() == o, - (Concrete::Array(a), Concrete::Array(b)) => { - if a.len() == b.len() { - a.iter().zip(b.iter()).all(|(a, b)| { - let a = RangeConcrete { - val: a.clone(), - loc: self.loc, - }; - - let b = RangeConcrete { - val: b.clone(), - loc: other.loc, - }; - - a.range_eq(&b) - }) - } else { - false - } - } - _ => false, - }, - } - } - - fn range_ord(&self, other: &Self) -> Option { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), - (Some(_), _) => { - match other.val { - Concrete::Int(_, _) => { - // if we couldnt convert an int to uint, its negative - // so self must be > other - Some(std::cmp::Ordering::Greater) - } - _ => None, - } - } - (_, Some(_)) => { - match self.val { - Concrete::Int(_, _) => { - // if we couldnt convert an int to uint, its negative - // so self must be < other - Some(std::cmp::Ordering::Less) - } - _ => None, - } - } - _ => { - match (&self.val, &other.val) { - // two negatives - (Concrete::Int(_, s), Concrete::Int(_, o)) => Some(s.cmp(o)), - (Concrete::DynBytes(b0), Concrete::DynBytes(b1)) => Some(b0.cmp(b1)), - _ => None, - } - } - } - } - - fn dependent_on(&self) -> Vec { - vec![] - } - fn update_deps(&mut self, _mapping: &BTreeMap) {} - - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - - fn maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - fn minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - - fn simplify_maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - fn simplify_minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - - fn cache_maximize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { - Ok(()) - } - - fn cache_minimize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { - Ok(()) - } - fn uncache(&mut self) {} -} - -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum MinMaxed { - Minimized(Box>), - Maximized(Box>), -} - -/// A range expression composed of other range [`Elem`] -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeExpr { - pub maximized: Option>, - pub minimized: Option>, - pub lhs: Box>, - pub op: RangeOp, - pub rhs: Box>, -} - -impl RangeExpr { - /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. - pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { - RangeExpr { - maximized: None, - minimized: None, - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - } - } - - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) - } -} - -impl RangeElem for RangeExpr { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn range_ord(&self, _other: &Self) -> Option { - todo!() - } - - fn dependent_on(&self) -> Vec { - let mut deps = self.lhs.dependent_on(); - deps.extend(self.rhs.dependent_on()); - deps - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - self.lhs.update_deps(mapping); - self.rhs.update_deps(mapping); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.lhs.filter_recursion(node_idx, new_idx); - self.rhs.filter_recursion(node_idx, new_idx); - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - Ok(*cached) - } else { - self.exec_op(true, analyzer) - } - } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - Ok(*cached) - } else { - self.exec_op(false, analyzer) - } - } - - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - self.simplify_exec_op(true, analyzer) - } - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - self.simplify_exec_op(false, analyzer) - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.cache_exec_op(true, g)?; - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.cache_exec_op(false, g)?; - } - Ok(()) - } - - fn uncache(&mut self) { - self.uncache_exec(); - } -} - -/// A core range element. -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum Elem { - /// A range element that is a reference to another node - Dynamic(Dynamic), - /// A concrete range element of type `T`. e.g.: some number like `10` - ConcreteDyn(Box>), - /// A concrete range element of type `T`. e.g.: some number like `10` - Concrete(RangeConcrete), - /// A range element that is an expression composed of other range elements - Expr(RangeExpr), - /// A null range element useful in range expressions that dont have a rhs - Null, -} - -impl std::fmt::Display for Elem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), - Elem::ConcreteDyn(..) => write!(f, "range_elem"), - Elem::Concrete(RangeConcrete { val, .. }) => { - write!(f, "{}", val.as_string()) - } - Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => { - write!(f, "({} {} {})", op.to_string(), lhs, rhs) - } - _ => write!(f, ""), - } - } -} - -impl From for Elem { - fn from(c: Concrete) -> Self { - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }) - } -} - -impl From for Elem { - fn from(c: ContextVarNode) -> Self { - Elem::Reference(Dynamic::new(c.into())) - } -} - -impl From for Elem { - fn from(idx: NodeIdx) -> Self { - Elem::Reference(Dynamic::new(idx)) - } -} - -impl Elem { - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - match self { - Self::Dynamic(d) => d.idx == node_idx, - Self::Concrete(_) => false, - Self::Expr(expr) => expr.contains_node(node_idx), - Self::ConcreteDyn(d) => d.contains_node(node_idx), - Self::Null => false, - } - } - - pub fn dyn_map(&self) -> Option<&BTreeMap> { - match self { - Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), - _ => None, - } - } - - pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { - match self { - Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), - _ => None, - } - } - - /// Creates a new range element that is a cast from one type to another - pub fn cast(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Cast, other); - Elem::Expr(expr) - } - - pub fn concat(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Concat, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the minimum of two range elements - pub fn min(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Min, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the maximum of two range elements - pub fn max(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Max, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of equality of two range elements - pub fn eq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Eq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of inequality of two range elements - pub fn neq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Neq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is one range element to the power of another - pub fn pow(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Exp, other); - Elem::Expr(expr) - } -} - -impl From for Elem { - fn from(dy: Dynamic) -> Self { - Elem::Reference(dy) - } -} - -impl From> for Elem { - fn from(c: RangeConcrete) -> Self { - Elem::Concrete(c) - } -} - -impl Elem { - pub fn node_idx(&self) -> Option { - match self { - Self::Dynamic(Reference { idx, .. }) => Some(*idx), - _ => None, - } - } - - pub fn concrete(&self) -> Option { - match self { - Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), - _ => None, - } - } - - pub fn is_negative( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result { - let res = match self { - Elem::Concrete(RangeConcrete { - val: Concrete::Int(_, val), - .. - }) if val < &I256::zero() => true, - Elem::Reference(dy) => { - if maximize { - dy.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - dy.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - Elem::Expr(expr) => { - if maximize { - expr.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - expr.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - _ => false, - }; - Ok(res) - } - - pub fn pre_evaled_is_negative(&self) -> bool { - matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) - } - - pub fn maybe_concrete(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } - } - - pub fn maybe_range_dyn(&self) -> Option> { - match self { - Elem::ConcreteDyn(a) => Some(*a.clone()), - _ => None, - } - } -} - -impl RangeElem for Elem { - fn range_eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), - _ => false, - } - } - - fn range_ord(&self, other: &Self) -> Option { - match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => { - let ord = a.range_ord(b); - if ord.is_none() { - println!("couldnt compare: {a:?} {b:?}"); - } - - ord - } - _ => None, - } - } - - fn dependent_on(&self) -> Vec { - match self { - Self::Dynamic(d) => d.dependent_on(), - Self::Concrete(_) => vec![], - Self::Expr(expr) => expr.dependent_on(), - Self::ConcreteDyn(d) => d.dependent_on(), - Self::Null => vec![], - } - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - match self { - Self::Dynamic(d) => d.update_deps(mapping), - Self::Concrete(_) => {} - Self::Expr(expr) => expr.update_deps(mapping), - Self::ConcreteDyn(d) => d.update_deps(mapping), - Self::Null => {} - } - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - match self { - Self::Dynamic(ref mut d) => { - if d.idx == node_idx { - d.idx = new_idx - } - } - Self::Concrete(_) => {} - Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx), - Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx), - Self::Null => {} - } - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Dynamic(dy) => dy.maximize(analyzer)?, - Concrete(inner) => inner.maximize(analyzer)?, - ConcreteDyn(inner) => inner.maximize(analyzer)?, - Expr(expr) => expr.maximize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Dynamic(dy) => dy.minimize(analyzer)?, - Concrete(inner) => inner.minimize(analyzer)?, - ConcreteDyn(inner) => inner.minimize(analyzer)?, - Expr(expr) => expr.minimize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn simplify_maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Dynamic(dy) => dy.simplify_maximize(analyzer)?, - Concrete(inner) => inner.simplify_maximize(analyzer)?, - ConcreteDyn(inner) => inner.simplify_maximize(analyzer)?, - Expr(expr) => expr.simplify_maximize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn simplify_minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Dynamic(dy) => dy.simplify_minimize(analyzer)?, - Concrete(inner) => inner.simplify_minimize(analyzer)?, - ConcreteDyn(inner) => inner.simplify_minimize(analyzer)?, - Expr(expr) => expr.simplify_minimize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - use Elem::*; - match self { - Dynamic(dy) => dy.cache_maximize(analyzer), - Concrete(inner) => inner.cache_maximize(analyzer), - ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => expr.cache_maximize(analyzer), - Null => Ok(()), - } - } - - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - use Elem::*; - match self { - Dynamic(dy) => dy.cache_minimize(analyzer), - Concrete(inner) => inner.cache_minimize(analyzer), - ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => expr.cache_minimize(analyzer), - Null => Ok(()), - } - } - fn uncache(&mut self) { - use Elem::*; - match self { - Dynamic(dy) => dy.uncache(), - Concrete(inner) => inner.uncache(), - ConcreteDyn(inner) => inner.uncache(), - Expr(expr) => expr.uncache(), - Null => {} - } - } -} - -impl Add for Elem { - type Output = Self; - - fn add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(false), other); - Self::Expr(expr) - } -} - -impl Sub for Elem { - type Output = Self; - - fn sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(false), other); - Self::Expr(expr) - } -} - -impl Mul for Elem { - type Output = Self; - - fn mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(false), other); - Self::Expr(expr) - } -} - -impl Div for Elem { - type Output = Self; - - fn div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(false), other); - Self::Expr(expr) - } -} - -impl Shl for Elem { - type Output = Self; - - fn shl(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shl, other); - Self::Expr(expr) - } -} - -impl Shr for Elem { - type Output = Self; - - fn shr(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shr, other); - Self::Expr(expr) - } -} - -impl Rem for Elem { - type Output = Self; - - fn rem(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mod, other); - Self::Expr(expr) - } -} - -impl BitAnd for Elem { - type Output = Self; - - fn bitand(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitAnd, other); - Self::Expr(expr) - } -} - -impl BitOr for Elem { - type Output = Self; - - fn bitor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitOr, other); - Self::Expr(expr) - } -} - -impl BitXor for Elem { - type Output = Self; - - fn bitxor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitXor, other); - Self::Expr(expr) - } -} - -impl Elem { - pub fn wrapping_add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(true), other); - Self::Expr(expr) - } - pub fn wrapping_sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(true), other); - Self::Expr(expr) - } - pub fn wrapping_mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(true), other); - Self::Expr(expr) - } - pub fn wrapping_div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(true), other); - Self::Expr(expr) - } - - /// Creates a logical AND of two range elements - pub fn and(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::And, other); - Self::Expr(expr) - } - - /// Creates a logical OR of two range elements - pub fn or(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Or, other); - Self::Expr(expr) - } - - pub fn maybe_elem_min(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::min(val)?)), - _ => None, - } - } - - pub fn maybe_elem_max(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::max(val)?)), - _ => None, - } - } -} - -/// For execution of operations to be performed on range expressions -pub trait ExecOp { - /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side - /// and right-hand-side - fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError> { - self.exec(self.spread(analyzer)?, maximize) - } - - fn exec( - &self, - parts: (Elem, Elem, Elem, Elem), - maximize: bool, - ) -> Result, GraphError>; - /// Cache execution - fn cache_exec_op( - &mut self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result<(), GraphError>; - - fn spread( - &self, - analyzer: &impl GraphLike, - ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; - - fn simplify_spread( - &self, - analyzer: &impl GraphLike, - ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; - - fn uncache_exec(&mut self); - - fn simplify_exec_op( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError>; - - /// Attempts to simplify an expression (i.e. just apply constant folding) - fn simplify_exec( - &self, - parts: (Elem, Elem, Elem, Elem), - maximize: bool, - ) -> Result, GraphError> { - self.exec(parts, maximize) - } -} - -impl ExecOp for RangeExpr { - fn cache_exec_op( - &mut self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result<(), GraphError> { - self.lhs.cache_minimize(analyzer)?; - self.lhs.cache_maximize(analyzer)?; - self.rhs.cache_minimize(analyzer)?; - self.rhs.cache_maximize(analyzer)?; - let res = self.exec_op(maximize, analyzer)?; - if maximize { - self.maximized = Some(MinMaxed::Maximized(Box::new(res))); - } else { - self.minimized = Some(MinMaxed::Minimized(Box::new(res))); - } - Ok(()) - } - - fn uncache_exec(&mut self) { - self.lhs.uncache(); - self.rhs.uncache(); - } - - fn simplify_exec_op( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let parts = self.simplify_spread(analyzer)?; - self.exec(parts, maximize) - } - - fn spread( - &self, - analyzer: &impl GraphLike, - ) -> Result< - ( - Elem, - Elem, - Elem, - Elem, - ), - GraphError, - > { - let lhs_min = self.lhs.minimize(analyzer)?; - let lhs_max = self.lhs.maximize(analyzer)?; - let rhs_min = self.rhs.minimize(analyzer)?; - let rhs_max = self.rhs.maximize(analyzer)?; - Ok((lhs_min, lhs_max, rhs_min, rhs_max)) - } - - fn simplify_spread( - &self, - analyzer: &impl GraphLike, - ) -> Result< - ( - Elem, - Elem, - Elem, - Elem, - ), - GraphError, - > { - let lhs_min = self.lhs.simplify_minimize(analyzer)?; - let lhs_max = self.lhs.simplify_maximize(analyzer)?; - let rhs_min = self.rhs.simplify_minimize(analyzer)?; - let rhs_max = self.rhs.simplify_maximize(analyzer)?; - Ok((lhs_min, lhs_max, rhs_min, rhs_max)) - } - - fn exec( - &self, - (lhs_min, lhs_max, rhs_min, rhs_max): ( - Elem, - Elem, - Elem, - Elem, - ), - maximize: bool, - ) -> Result, GraphError> { - tracing::trace!( - "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", - self.lhs, - self.op.to_string(), - self.rhs, - lhs_min, - lhs_max, - rhs_min, - rhs_max - ); - - let lhs_min_neg = lhs_min.pre_evaled_is_negative(); - let lhs_max_neg = lhs_max.pre_evaled_is_negative(); - let rhs_min_neg = rhs_min.pre_evaled_is_negative(); - let rhs_max_neg = rhs_max.pre_evaled_is_negative(); - - let res = match self.op { - RangeOp::Add(unchecked) => { - if unchecked { - let candidates = vec![ - lhs_min.range_wrapping_add(&rhs_min), - lhs_min.range_wrapping_add(&rhs_max), - lhs_max.range_wrapping_add(&rhs_min), - lhs_max.range_wrapping_add(&rhs_max), - lhs_max.range_add(&rhs_max), - lhs_min.range_add(&rhs_min), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value + the largest value - lhs_max - .range_add(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } else { - lhs_min - .range_add(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Sub(unchecked) => { - if unchecked { - let candidates = vec![ - lhs_min.range_wrapping_sub(&rhs_min), - lhs_min.range_wrapping_sub(&rhs_max), - lhs_max.range_wrapping_sub(&rhs_min), - lhs_max.range_wrapping_sub(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value - the smallest value - lhs_max - .range_sub(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } else { - // if we are minimizing, the smallest value will always be smallest value - largest value - lhs_min - .range_sub(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Mul(unchecked) => { - if unchecked { - let candidates = vec![ - lhs_min.range_wrapping_mul(&rhs_min), - lhs_min.range_wrapping_mul(&rhs_max), - lhs_max.range_wrapping_mul(&rhs_min), - lhs_max.range_wrapping_mul(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, and both mins are negative and both maxes are positive, - // we dont know which will be larger of the two (i.e. -1*2**255 * -1*2**255 > 100*100) - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (true, true, true, true) => { - // all negative, will be min * min because those are furthest from 0 resulting in the - // largest positive value - lhs_min - .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller - match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { - Some(std::cmp::Ordering::Less) => max_expr, - Some(std::cmp::Ordering::Greater) => min_expr, - _ => max_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => Elem::Expr(self.clone()), - } - } - (_, false, _, false) => { - // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value - lhs_max - .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - (false, false, true, true) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_min - .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - (true, true, false, false) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_max - .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - (true, _, true, _) => lhs_min - .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())), - (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") - } - } - } else { - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (false, false, false, false) => { - // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value - lhs_min - .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - (true, true, true, true) => { - // all negative, will be max * max because those are closest to 0 resulting in the - // smallest positive value - lhs_max - .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller - match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { - Some(std::cmp::Ordering::Less) => min_expr, - Some(std::cmp::Ordering::Greater) => max_expr, - _ => min_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => Elem::Expr(self.clone()), - } - } - (true, _, _, false) => { - // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value - lhs_min - .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - (_, false, _, true) => { - // just lhs has a positive value, most negative will be lhs_max, rhs_max - lhs_max - .range_mul(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - (false, false, true, false) => lhs_max - .range_mul(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())), - (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") - } - } - } - } - RangeOp::Div(_unchecked) => { - let mut candidates = vec![ - lhs_min.range_div(&rhs_min), - lhs_min.range_div(&rhs_max), - lhs_max.range_div(&rhs_min), - lhs_max.range_div(&rhs_max), - ]; - - let one = Elem::from(Concrete::from(U256::from(1))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&one)); - candidates.push(lhs_max.range_div(&one)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&negative_one)); - candidates.push(lhs_max.range_div(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger - // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // max_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // min_expr - // } - // _ => { - // max_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (false, false, true, true) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, false, false) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, false, _) => { - // // lhs is positive, rhs min is positive, guaranteed to give largest - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, false) => { - // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, true, _) => { - // // at this point, its either all trues, or a single false - // // given that, to maximize, the only way to get a positive value is to use the most negative values - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (false, false, false, false) => { - // // smallest number will be lhs_min / rhs_min since both are positive - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, true) => { - // // smallest number will be lhs_max / rhs_min since both are negative - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, false) => { - // // The way to maintain most negative value is lhs_min / rhs_max, all others would go - // // positive or guaranteed to be closer to 0 - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger - // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // min_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // max_expr - // } - // _ => { - // min_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (_, false, true, _) => { - // // We are going negative here, so it will be most positive / least negative - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, _) => { - // // We are going negative here, so it will be most negative / least positive - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - // RangeOp::Mod => { - // lhs.range_mod(&rhs).unwrap_or(Elem::Expr(self.clone())) - // } - RangeOp::Min => { - let candidates = vec![ - lhs_min.range_min(&rhs_min), - lhs_min.range_min(&rhs_max), - lhs_max.range_min(&rhs_min), - lhs_max.range_min(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // // counter-intuitively, we want the maximum value from a call to minimum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the minimum values but getting the larger of the minimum - // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Max => { - let candidates = vec![ - lhs_min.range_max(&rhs_min), - lhs_min.range_max(&rhs_max), - lhs_max.range_max(&rhs_min), - lhs_max.range_max(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (_, true, _, true) | (_, false, _, false) => { - // // counter-intuitively, we want the minimum value from a call to maximum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the maximum values but getting the smaller of the maximum - // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, true) => { - // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, _, false) => { - // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Gt => { - if maximize { - lhs_max - .range_gt(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } else { - lhs_min - .range_gt(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Lt => { - if maximize { - lhs_min - .range_lt(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } else { - lhs_max - .range_lt(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Gte => { - if maximize { - lhs_max - .range_gte(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } else { - lhs_min - .range_gte(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Lte => { - if maximize { - lhs_min - .range_lte(&rhs_max) - .unwrap_or(Elem::Expr(self.clone())) - } else { - lhs_max - .range_lte(&rhs_min) - .unwrap_or(Elem::Expr(self.clone())) - } - } - RangeOp::Eq => { - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - - if maximize { - // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); - - // if lhs max is less than the rhs min, it has to be false - if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // if lhs min is greater than the rhs max, it has to be false - if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // lhs_max >= rhs_min - // lhs_min <= rhs_max - // therefore its possible to set some value to true here - if lhs_max_rhs_min_ord.is_some() && lhs_min_rhs_max_ord.is_some() { - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }) - } else { - Elem::Expr(self.clone()) - } - } else { - // check if either lhs element is *not* contained by rhs - match ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }), - // if any of those are not equal, we can construct - // an element that is true - _ => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }), - } - } - } - RangeOp::Neq => { - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - if maximize { - // check if either lhs element is *not* contained by rhs - match ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }), - // if any of those are not equal, we can construct - // an element that is true - _ => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }), - } - } else { - // if they are constants and equal, we can stop here - // (rhs min == rhs max) == (lhs min == lhs max ) - if let ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) = ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // they aren't constants, check if there is any overlap - match ( - // check if lhs minimum is contained within the right hand side - // this means the values could be equal - // effectively: - // rhs min <= lhs min <= rhs max - lhs_min.range_ord(&rhs_min), - lhs_min.range_ord(&rhs_max), - ) { - (_, Some(std::cmp::Ordering::Equal)) - | (Some(std::cmp::Ordering::Equal), _) - | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })) - } - _ => {} - } - - match ( - // check if the lhs maximum is contained within the right hand side - // effectively: - // rhs min <= lhs max <= rhs max - lhs_max.range_ord(&rhs_min), - lhs_max.range_ord(&rhs_max), - ) { - (_, Some(std::cmp::Ordering::Equal)) - | (Some(std::cmp::Ordering::Equal), _) - | (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })) - } - _ => {} - } - - Elem::Expr(self.clone()) - } - } - RangeOp::Shl => { - let candidates = vec![ - lhs_min.range_shl(&rhs_min), - lhs_min.range_shl(&rhs_max), - lhs_max.range_shl(&rhs_min), - lhs_max.range_shl(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Shr => { - let candidates = vec![ - lhs_min.range_shr(&rhs_min), - lhs_min.range_shr(&rhs_max), - lhs_max.range_shr(&rhs_min), - lhs_max.range_shr(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::And => { - let candidates = vec![ - lhs_min.range_and(&rhs_min), - lhs_min.range_and(&rhs_max), - lhs_max.range_and(&rhs_min), - lhs_max.range_and(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Or => { - let candidates = vec![ - lhs_min.range_or(&rhs_min), - lhs_min.range_or(&rhs_max), - lhs_max.range_or(&rhs_min), - lhs_max.range_or(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Not => { - assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); - let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Cast => { - // the weird thing about cast is that we really dont know until after the cast due to sizing things - // so we should just try them all then compare - let candidates = vec![ - lhs_min.range_cast(&rhs_min), - lhs_min.range_cast(&rhs_max), - lhs_max.range_cast(&rhs_min), - lhs_max.range_cast(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Exp => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_exp(&rhs_min), - lhs_min.range_exp(&rhs_max), - lhs_max.range_exp(&rhs_min), - lhs_max.range_exp(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitAnd => { - let mut candidates = vec![ - lhs_min.range_bit_and(&rhs_min), - lhs_min.range_bit_and(&rhs_max), - lhs_max.range_bit_and(&rhs_min), - lhs_max.range_bit_and(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&zero)); - candidates.push(lhs_max.range_bit_and(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&negative_one)); - candidates.push(lhs_max.range_bit_and(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitOr => { - let mut candidates = vec![ - lhs_min.range_bit_or(&rhs_min), - lhs_min.range_bit_or(&rhs_max), - lhs_max.range_bit_or(&rhs_min), - lhs_max.range_bit_or(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&zero)); - candidates.push(lhs_max.range_bit_or(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&negative_one)); - candidates.push(lhs_max.range_bit_or(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitXor => { - let mut candidates = vec![ - lhs_min.range_bit_xor(&rhs_min), - lhs_min.range_bit_xor(&rhs_max), - lhs_max.range_bit_xor(&rhs_min), - lhs_max.range_bit_xor(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - // if the rhs contains zero, in xor, thats just itself - candidates.push(lhs_max.range_bit_xor(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_xor(&negative_one)); - candidates.push(lhs_max.range_bit_xor(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitNot => { - let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - - let min_contains = matches!( - lhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - lhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - match lhs_min { - Elem::Concrete( - r @ RangeConcrete { - val: Concrete::Uint(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), - Elem::Concrete( - r @ RangeConcrete { - val: Concrete::Int(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::min(&r.val).unwrap()))), - _ => {} - } - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Concat => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_concat(&rhs_min), - lhs_min.range_concat(&rhs_max), - lhs_max.range_concat(&rhs_min), - lhs_max.range_concat(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(Elem::Expr(self.clone())); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - _ => Elem::Expr(self.clone()), - }; - Ok(res) - } -} diff --git a/shared/src/range/mod.rs b/shared/src/range/mod.rs deleted file mode 100644 index 57f8526e..00000000 --- a/shared/src/range/mod.rs +++ /dev/null @@ -1,749 +0,0 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::context::ContextNode; -use crate::context::ContextVarNode; -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; - -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeConcrete; -use crate::range::elem_ty::RangeDyn; -use crate::range::range_string::ToRangeString; -use crate::Builtin; -use crate::Concrete; - -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::H256; -use ethers_core::types::I256; -use ethers_core::types::U256; -use std::collections::BTreeMap; - -use solang_parser::pt::Loc; - -pub mod elem; -pub mod elem_ty; -pub mod range_ops; -pub mod range_string; - -#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] -pub struct SolcRange { - pub min: Elem, - pub min_cached: Option>, - pub max: Elem, - pub max_cached: Option>, - pub exclusions: Vec>, -} - -impl AsDotStr for SolcRange { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { - format!( - "[{}, {}] excluding: [{}]", - self.evaled_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s, - self.evaled_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s, - self.exclusions - .iter() - .map(|excl| excl.to_range_string(false, analyzer).s) - .collect::>() - .join(", ") - ) - } -} - -impl From for SolcRange { - fn from(b: bool) -> Self { - let val = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(b), - loc: Loc::Implicit, - }); - Self::new(val.clone(), val, vec![]) - } -} - -impl SolcRange { - pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { - Self { - min, - min_cached: None, - max, - max_cached: None, - exclusions, - } - } - - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { - let min = self.evaled_range_min(analyzer)?; - let max = self.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max)) - } - - pub fn min_is_negative(&self, analyzer: &impl GraphLike) -> Result { - self.min.is_negative(false, analyzer) - } - - pub fn default_bool() -> Self { - let min = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: Loc::Implicit, - }); - let max = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: Loc::Implicit, - }); - Self::new(min, max, vec![]) - } - pub fn from(c: Concrete) -> Option { - match c { - c @ Concrete::Uint(_, _) - | c @ Concrete::Int(_, _) - | c @ Concrete::Bool(_) - | c @ Concrete::Address(_) - | c @ Concrete::Bytes(_, _) => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: c.clone(), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }), - vec![], - )), - Concrete::String(s) => { - let val = s - .chars() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let mut bytes = [0x00; 32]; - v.encode_utf8(&mut bytes[..]); - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(s.len()))), - val, - loc: Loc::Implicit, - })); - Some(SolcRange::new(r.clone(), r, vec![])) - } - Concrete::DynBytes(b) => { - let val = b - .iter() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let mut bytes = [0x00; 32]; - bytes[0] = *v; - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(b.len()))), - val, - loc: Loc::Implicit, - })); - Some(SolcRange::new(r.clone(), r, vec![])) - } - _e => None, - } - } - - pub fn try_from_builtin(builtin: &Builtin) -> Option { - match builtin { - Builtin::Uint(size) => { - if *size == 256 { - Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, 0.into()), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, U256::MAX), - loc: Loc::Implicit, - }), - vec![], - )) - } else { - Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, 0.into()), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, U256::from(2).pow(U256::from(*size)) - 1), - loc: Loc::Implicit, - }), - vec![], - )) - } - } - Builtin::Int(size) => { - if *size == 256 { - Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, I256::MIN), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, I256::MAX), - loc: Loc::Implicit, - }), - vec![], - )) - } else { - let max: I256 = - I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1); - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, min), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, max), - loc: Loc::Implicit, - }), - vec![], - )) - } - } - Builtin::Bool => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: Loc::Implicit, - }), - vec![], - )), - Builtin::Address | Builtin::Payable | Builtin::AddressPayable => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Address(Address::from_slice(&[0x00; 20])), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Address(Address::from_slice(&[0xff; 20])), - loc: Loc::Implicit, - }), - vec![], - )), - Builtin::Bytes(size) => { - let v: Vec<_> = (0..32u8) - .map(|i| if i < *size { 0xff } else { 0x00 }) - .collect(); - Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, H256::from_slice(&[0x00; 32])), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, H256::from_slice(&v[..])), - loc: Loc::Implicit, - }), - vec![], - )) - } - Builtin::DynamicBytes - | Builtin::String - | Builtin::Array(_) - | Builtin::Mapping(_, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::zero())), - val: Default::default(), - loc: Loc::Implicit, - })), - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::MAX)), - val: Default::default(), - loc: Loc::Implicit, - })), - vec![], - )), - Builtin::SizedArray(s, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })), - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })), - vec![], - )), - _ => None, - } - } - - pub fn lte_dyn(self, other: ContextVarNode) -> Self { - Self::new(self.min, self.max.min(Elem::from(other)), self.exclusions) - } - - pub fn gte_dyn(self, other: ContextVarNode) -> Self { - Self::new(self.min.max(Elem::from(other)), self.max, self.exclusions) - } - - pub fn lt_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min, - self.max.min( - Elem::from(other) - - Elem::Concrete(RangeConcrete { - val: U256::from(1).into(), - loc: Loc::Implicit, - }), - ), - self.exclusions, - ) - } - - pub fn gt_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.max( - Elem::from(other) - + Elem::Concrete(RangeConcrete { - val: U256::from(1).into(), - loc: Loc::Implicit, - }), - ), - self.max, - self.exclusions, - ) - } - - pub fn dyn_fn_from_op(op: RangeOp) -> &'static dyn Fn(SolcRange, ContextVarNode) -> SolcRange { - match op { - RangeOp::Add(false) => &Self::add_dyn, - RangeOp::Add(true) => &Self::wrapping_add_dyn, - RangeOp::Sub(false) => &Self::sub_dyn, - RangeOp::Sub(true) => &Self::wrapping_sub_dyn, - RangeOp::Mul(false) => &Self::mul_dyn, - RangeOp::Mul(true) => &Self::wrapping_mul_dyn, - RangeOp::Div(false) => &Self::div_dyn, - RangeOp::Div(true) => &Self::wrapping_mul_dyn, - RangeOp::Shr => &Self::shr_dyn, - RangeOp::Shl => &Self::shl_dyn, - RangeOp::Mod => &Self::mod_dyn, - RangeOp::Min => &Self::min_dyn, - RangeOp::Max => &Self::max_dyn, - RangeOp::Lt => &Self::lt_dyn, - RangeOp::Lte => &Self::lte_dyn, - RangeOp::Gt => &Self::gt_dyn, - RangeOp::Gte => &Self::gte_dyn, - RangeOp::Eq => &Self::eq_dyn, - RangeOp::Neq => &Self::neq_dyn, - RangeOp::Exp => &Self::exp_dyn, - RangeOp::BitAnd => &Self::bit_and_dyn, - RangeOp::BitOr => &Self::bit_or_dyn, - RangeOp::BitXor => &Self::bit_xor_dyn, - // RangeOp::And => ( - // &Self::and_dyn, - // (DynSide::Min, DynSide::Max), - // ), - // RangeOp::Or => ( - // &Self::or_dyn, - // (DynSide::Min, DynSide::Max), - // ), - e => unreachable!("Comparator operations shouldn't exist in a range: {:?}", e), - } - } - - pub fn add_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min + Elem::from(other), - self.max + Elem::from(other), - self.exclusions, - ) - } - - pub fn wrapping_add_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.wrapping_add(Elem::from(other)), - self.max.wrapping_add(Elem::from(other)), - self.exclusions, - ) - } - - pub fn sub_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min - Elem::from(other), - self.max - Elem::from(other), - self.exclusions, - ) - } - - pub fn wrapping_sub_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.wrapping_sub(Elem::from(other)), - self.max.wrapping_sub(Elem::from(other)), - self.exclusions, - ) - } - - pub fn mul_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min * Elem::from(other), - self.max * Elem::from(other), - self.exclusions, - ) - } - - pub fn wrapping_mul_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.wrapping_mul(Elem::from(other)), - self.max.wrapping_mul(Elem::from(other)), - self.exclusions, - ) - } - - pub fn exp_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.pow(Elem::from(other)), - self.max.pow(Elem::from(other)), - self.exclusions, - ) - } - - pub fn bit_and_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min & Elem::from(other), - self.max & Elem::from(other), - self.exclusions, - ) - } - - pub fn bit_or_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min | Elem::from(other), - self.max | Elem::from(other), - self.exclusions, - ) - } - - pub fn bit_xor_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min ^ Elem::from(other), - self.max ^ Elem::from(other), - self.exclusions, - ) - } - - pub fn div_dyn(self, other: ContextVarNode) -> Self { - let elem = Elem::from(other); - Self::new(self.min / elem.clone(), self.max / elem, self.exclusions) - } - - pub fn wrapping_div_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.wrapping_div(Elem::from(other)), - self.max.wrapping_div(Elem::from(other)), - self.exclusions, - ) - } - - pub fn shl_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min << Elem::from(other), - self.max << Elem::from(other), - self.exclusions, - ) - } - - pub fn shr_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min >> Elem::from(other), - self.max >> Elem::from(other), - self.exclusions, - ) - } - - pub fn mod_dyn(self, other: ContextVarNode) -> Self { - let elem = Elem::from(other); - Self::new( - Elem::from(Concrete::from(U256::zero())), - elem.clone() - Elem::from(Concrete::from(U256::from(1))).cast(elem), - self.exclusions, - ) - } - - pub fn min_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.min(Elem::from(other)), - self.max.min(Elem::from(other)), - self.exclusions, - ) - } - - pub fn max_dyn(self, other: ContextVarNode) -> Self { - Self::new( - self.min.max(Elem::from(other)), - self.max.max(Elem::from(other)), - self.exclusions, - ) - } - - pub fn eq_dyn(self, other: ContextVarNode) -> Self { - let min = self.min.eq(Elem::from(other)); - let max = self.max.eq(Elem::from(other)); - Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) - } - - pub fn neq_dyn(self, other: ContextVarNode) -> Self { - let min = self.min.neq(Elem::from(other)); - let max = self.max.neq(Elem::from(other)); - Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) - } -} - -impl Range for SolcRange { - type ElemTy = Elem; - fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy> { - std::borrow::Cow::Borrowed(&self.min) - } - fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy> { - std::borrow::Cow::Borrowed(&self.max) - } - fn range_min_mut(&mut self) -> &mut Self::ElemTy { - &mut self.min - } - fn range_max_mut(&mut self) -> &mut Self::ElemTy { - &mut self.max - } - - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - if self.min_cached.is_none() { - let min = self.range_min_mut(); - min.cache_minimize(analyzer)?; - self.min_cached = Some(self.range_min().minimize(analyzer)?); - } - if self.max_cached.is_none() { - let max = self.range_max_mut(); - max.cache_maximize(analyzer)?; - self.max_cached = Some(self.range_max().maximize(analyzer)?); - } - Ok(()) - } - - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result { - if let Some(cached) = &self.min_cached { - Ok(cached.clone()) - } else { - self.range_min().minimize(analyzer) - } - } - - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result { - if let Some(cached) = &self.max_cached { - Ok(cached.clone()) - } else { - self.range_max().maximize(analyzer) - } - } - - fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result { - println!("simplified range min"); - self.range_min().simplify_minimize(analyzer) - } - fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result { - println!("simplified range max"); - self.range_max().simplify_maximize(analyzer) - } - fn range_exclusions(&self) -> Vec { - self.exclusions.clone() - } - fn set_range_min(&mut self, new: Self::ElemTy) { - self.min_cached = None; - self.min = new; - } - fn set_range_max(&mut self, new: Self::ElemTy) { - self.max_cached = None; - self.max = new; - } - - fn add_range_exclusion(&mut self, new: Self::ElemTy) { - if !self.exclusions.contains(&new) { - self.exclusions.push(new); - } - } - fn set_range_exclusions(&mut self, new: Vec) { - self.exclusions = new; - } - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { - self.min.filter_recursion(self_idx, new_idx); - } - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { - self.max.filter_recursion(self_idx, new_idx); - } -} - -pub trait Range { - type ElemTy: RangeElem + Clone; - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; - fn simplified_range_min(&self, analyzer: &impl GraphLike) -> Result; - fn simplified_range_max(&self, analyzer: &impl GraphLike) -> Result; - fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; - fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy>; - fn uncache_range_min(&mut self) { - self.range_min_mut().uncache(); - } - fn uncache_range_max(&mut self) { - self.range_max_mut().uncache(); - } - fn range_min_mut(&mut self) -> &mut Self::ElemTy; - fn range_max_mut(&mut self) -> &mut Self::ElemTy; - fn range_exclusions(&self) -> Vec - where - Self: std::marker::Sized; - fn set_range_min(&mut self, new: Self::ElemTy); - fn set_range_max(&mut self, new: Self::ElemTy); - fn set_range_exclusions(&mut self, new: Vec) - where - Self: std::marker::Sized; - fn add_range_exclusion(&mut self, new: Self::ElemTy) - where - Self: std::marker::Sized; - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); - fn dependent_on(&self) -> Vec { - let mut deps = self.range_min().dependent_on(); - deps.extend(self.range_max().dependent_on()); - deps - } - - fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphLike) { - let deps = self.dependent_on(); - let mapping: BTreeMap = deps - .into_iter() - .filter(|dep| !dep.is_const(analyzer).unwrap()) - .map(|dep| { - let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); - if latest == node { - if let Some(prev) = latest.previous_version(analyzer) { - (dep, prev) - } else { - (dep, dep) - } - } else { - (dep, latest) - } - }) - .collect(); - - let mut min = self.range_min().into_owned(); - let mut max = self.range_max().into_owned(); - min.update_deps(&mapping); - max.update_deps(&mapping); - self.set_range_min(min); - self.set_range_max(max); - } -} - -pub trait RangeEval>: Range { - fn sat(&self, analyzer: &impl GraphLike) -> bool; - fn unsat(&self, analyzer: &impl GraphLike) -> bool { - !self.sat(analyzer) - } - fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool; - fn contains_elem(&self, other: &T, analyzer: &impl GraphLike) -> bool; - fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool; -} - -impl RangeEval> for SolcRange { - fn sat(&self, analyzer: &impl GraphLike) -> bool { - matches!( - self.evaled_range_min(analyzer) - .unwrap() - .range_ord(&self.evaled_range_max(analyzer).unwrap()), - None | Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ) - } - - fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool { - let min_contains = matches!( - self.evaled_range_min(analyzer) - .unwrap() - .range_ord(&other.evaled_range_min(analyzer).unwrap()), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - self.evaled_range_max(analyzer) - .unwrap() - .range_ord(&other.evaled_range_max(analyzer).unwrap()), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - min_contains && max_contains - } - - fn contains_elem(&self, other: &Elem, analyzer: &impl GraphLike) -> bool { - let min_contains = match self - .evaled_range_min(analyzer) - .unwrap() - .range_ord(&other.minimize(analyzer).unwrap()) - { - Some(std::cmp::Ordering::Less) => true, - Some(std::cmp::Ordering::Equal) => return true, - _ => false, - }; - - let max_contains = match self - .evaled_range_max(analyzer) - .unwrap() - .range_ord(&other.maximize(analyzer).unwrap()) - { - Some(std::cmp::Ordering::Greater) => true, - Some(std::cmp::Ordering::Equal) => return true, - _ => false, - }; - - min_contains && max_contains - } - - fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool { - let lhs_min = self.evaled_range_min(analyzer).unwrap(); - let rhs_max = other.evaled_range_max(analyzer).unwrap(); - - match lhs_min.range_ord(&rhs_max) { - Some(std::cmp::Ordering::Less) => { - // we know our min is less than the other max - // check that the max is greater than or eq their min - let lhs_max = self.evaled_range_max(analyzer).unwrap(); - let rhs_min = other.evaled_range_min(analyzer).unwrap(); - matches!( - lhs_max.range_ord(&rhs_min), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) - } - Some(std::cmp::Ordering::Equal) => true, - _ => false, - } - } -} diff --git a/shared/src/range/range_ops.rs b/shared/src/range/range_ops.rs deleted file mode 100644 index 4a2b4f40..00000000 --- a/shared/src/range/range_ops.rs +++ /dev/null @@ -1,1792 +0,0 @@ -use crate::range::Elem; -use crate::range::RangeConcrete; -use crate::range::RangeDyn; -use crate::Concrete; -use ethers_core::types::H256; -use ethers_core::types::I256; -use ethers_core::types::U256; -use std::collections::BTreeMap; - -pub trait RangeAdd { - /// Perform addition between two range elements - fn range_add(&self, other: &Rhs) -> Option>; - fn range_wrapping_add(&self, other: &Rhs) -> Option>; -} - -impl RangeAdd for RangeConcrete { - fn range_add(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - let max_uint = max.into_u256().unwrap(); - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(lhs_val.saturating_add(rhs_val).min(max_uint)), - loc: self.loc, - })) - } - _ => { - match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - // neg_v guaranteed to be negative here - if neg_v.into_raw() > *val { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_add(I256::from_raw(*val)), - ), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.saturating_sub(neg_v.into_raw())), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_add(*r).max(min)), - loc: self.loc, - })) - } - _ => None, - } - } - } - } - fn range_wrapping_add(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(lhs_val.overflowing_add(rhs_val).0), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(neg_v.into_raw().overflowing_add(*val).0), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_add(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeAdd for Elem { - fn range_add(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - _ => None, - } - } - fn range_wrapping_add(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - _ => None, - } - } -} - -pub trait RangeSub { - /// Perform subtraction between two range elements - fn range_sub(&self, other: &Rhs) -> Option>; - fn range_wrapping_sub(&self, other: &Rhs) -> Option>; -} - -impl RangeSub for RangeConcrete { - fn range_sub(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if lhs_val > rhs_val { - let val = lhs_val.saturating_sub(rhs_val); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } else { - match self.val { - Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(size, val.saturating_sub(I256::from_raw(rhs_val))), - loc: self.loc, - })), - _ => { - // TODO: this should cause a revert - let val = lhs_val.saturating_sub(rhs_val); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } - } - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - let max = if *lhs_size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(*lhs_size)) - 1 - }; - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.saturating_add(neg_v.into_raw()).min(max)), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - - let min = max * I256::from(-1i32) - I256::from(1i32); - - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_sub(I256::from_raw(*val).max(min)), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_sub(*r)), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_wrapping_sub(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if lhs_val > rhs_val { - let val = lhs_val.overflowing_sub(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } else { - match self.val { - Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - size, - val.overflowing_sub(I256::from_raw(rhs_val)).0, - ), - loc: self.loc, - })), - _ => { - let val = lhs_val.overflowing_sub(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } - } - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, val), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.overflowing_add(neg_v.into_raw()).0), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(neg_v.into_raw().overflowing_sub(*val).0), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_sub(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeSub for Elem { - fn range_sub(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - _ => None, - } - } - - fn range_wrapping_sub(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - _ => None, - } - } -} - -pub trait RangeMul { - /// Perform multiplication between two range elements - fn range_mul(&self, other: &Rhs) -> Option>; - fn range_wrapping_mul(&self, other: &Rhs) -> Option>; -} - -impl RangeMul for RangeConcrete { - fn range_mul(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - let res = lhs_val - .saturating_mul(rhs_val) - .min(max.into_u256().unwrap()); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(res), - loc: self.loc, - })) - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_mul(I256::from_raw(*val)).max(min), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_mul(*r).min(max)), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_wrapping_mul(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let _max = Concrete::max(&self.val).unwrap(); - let res = lhs_val.overflowing_mul(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(res), - loc: self.loc, - })) - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.overflowing_mul(I256::from_raw(*val)).0, - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_mul(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMul for Elem { - fn range_mul(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mul(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - _ => None, - } - } - - fn range_wrapping_mul(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_mul(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - _ => None, - } - } -} - -pub trait RangeExp { - /// Perform exponentiation between two range elements - fn range_exp(&self, other: &Rhs) -> Option>; -} - -impl RangeExp for RangeConcrete { - fn range_exp(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - if let Some(num) = lhs_val.checked_pow(rhs_val) { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(num.min(max.into_u256().unwrap())), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(max.into_u256().unwrap()), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let pow2 = val % U256::from(2) == 0.into(); - if val > &U256::from(u32::MAX) { - if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::max(&self.val).unwrap(), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::min(&self.val).unwrap(), - loc: self.loc, - })) - } - } else { - let min = Concrete::min(&self.val).unwrap().int_val().unwrap(); - let max = Concrete::max(&self.val).unwrap().int_val().unwrap(); - - if let Some(num) = neg_v.checked_pow(val.as_u32()) { - if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, num.min(max)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, num.max(min)), - loc: self.loc, - })) - } - } else if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::max(&self.val).unwrap(), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::min(&self.val).unwrap(), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } -} - -impl RangeExp for Elem { - fn range_exp(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_exp(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(Elem::from(Concrete::from(U256::from(1)))) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - _ => None, - } - } -} -pub trait RangeDiv { - /// Perform division between two range elements - fn range_div(&self, other: &Rhs) -> Option>; - - fn range_wrapping_div(&self, other: &Rhs) -> Option>; -} - -impl RangeDiv for RangeConcrete { - fn range_div(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val == 0.into() { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val / rhs_val), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - if neg_v == &I256::from(0) { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), - ), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::from(0) { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - if r == &I256::from(0) { - None - } else { - let (val, overflow) = l.overflowing_div(*r); - if overflow { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, val), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } - - fn range_wrapping_div(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val == 0.into() { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val / rhs_val), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - if neg_v == &I256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), - ), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - if r == &I256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - let (val, overflow) = l.overflowing_div(*r); - if overflow { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, val), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } -} - -impl RangeDiv for Elem { - fn range_div(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), - _ => None, - } - } - - fn range_wrapping_div(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), - _ => None, - } - } -} - -pub trait RangeMod { - /// Perform modulo between two range elements - fn range_mod(&self, other: &Rhs) -> Option>; -} - -impl RangeMod for RangeConcrete { - fn range_mod(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val % rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from_raw(*val) % *neg_v), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v % I256::from_raw(*val)), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l % *r), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMod for Elem { - fn range_mod(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mod(b), - _ => None, - } - } -} - -pub trait RangeMin { - /// Take the minimum of two range elements - fn range_min(&self, other: &Rhs) -> Option>; -} - -impl RangeMin for RangeConcrete { - fn range_min(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val.min(rhs_val)), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, _), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l.min(r)), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMin for Elem { - fn range_min(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_min(b), - _ => None, - } - } -} - -pub trait RangeMax { - /// Take the maximum of two range elements - fn range_max(&self, other: &Rhs) -> Option>; -} - -impl RangeMax for RangeConcrete { - fn range_max(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val.max(rhs_val)), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*lhs_size, *val), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, _), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*lhs_size, *val), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l.max(r)), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMax for Elem { - fn range_max(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_max(b), - _ => None, - } - } -} - -pub trait RangeOrd { - /// Perform a logical equality test - fn range_ord_eq(&self, other: &Rhs) -> Option>; - /// Perform a logical inequality test - fn range_neq(&self, other: &Rhs) -> Option>; - /// Perform a logical greater than test - fn range_gt(&self, other: &Rhs) -> Option>; - /// Perform a logical less than test - fn range_lt(&self, other: &Rhs) -> Option>; - /// Perform a logical greater than or equal test - fn range_gte(&self, other: &Rhs) -> Option>; - /// Perform a logical less than or equal test - fn range_lte(&self, other: &Rhs) -> Option>; -} - -impl RangeOrd for RangeConcrete { - fn range_ord_eq(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val == rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_, _), Concrete::Int(_, _)) - | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l == r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_neq(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val != rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_, _), Concrete::Int(_, _)) - | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l != r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_gt(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val > rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l > r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_lt(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val < rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l < r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_gte(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val >= rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l >= r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_lte(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val <= rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l <= r), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeOrd for Elem { - fn range_ord_eq(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_ord_eq(b), - _ => None, - } - } - fn range_neq(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_neq(b), - _ => None, - } - } - fn range_gt(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gt(b), - _ => None, - } - } - - fn range_lt(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lt(b), - _ => None, - } - } - - fn range_gte(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gte(b), - _ => None, - } - } - - fn range_lte(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lte(b), - _ => None, - } - } -} - -pub trait RangeShift { - /// Perform a bitwise shift left - fn range_shl(&self, other: &Rhs) -> Option>; - /// Perform a bitwise shift right - fn range_shr(&self, other: &Rhs) -> Option>; -} - -impl RangeShift for RangeConcrete { - fn range_shl(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val > 256.into() { - return Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })); - } - let max = Concrete::max(&self.val).unwrap().into_u256().unwrap(); - if self.val.int_val().is_some() { - // ints get weird treatment because they can push into the negatives - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - self.val.int_size().unwrap(), - I256::from_raw(lhs_val << rhs_val), - ), - loc: self.loc, - })) - } else if rhs_val > lhs_val.leading_zeros().into() { - Some(Elem::Concrete(RangeConcrete { - val: max.into(), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original((lhs_val << rhs_val).min(max)), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::zero() { - return Some(Elem::Concrete(self.clone())); - } - - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - - let min = max * I256::from(-1i32) - I256::from(1i32); - let (abs, is_min) = neg_v.overflowing_abs(); - if is_min { - if val > &U256::zero() { - Some(Elem::from(self.clone())) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::zero()), - loc: self.loc, - })) - } - } else if val > &U256::from(abs.leading_zeros()) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::zero()), - loc: self.loc, - })) - } else { - let raw = I256::from_raw(abs.into_raw() << val); - let as_int = if raw == I256::MIN { - raw - } else { - I256::from(-1i32) * raw - }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, as_int.max(min)), - loc: self.loc, - })) - } - } - _ => None, - }, - } - } - - fn range_shr(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val == U256::zero() { - Some(Elem::Concrete(self.clone())) - } else if rhs_val > U256::from(256) { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val >> rhs_val), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::zero() { - Some(Elem::Concrete(self.clone())) - } else if val > &U256::from(*lhs_size) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(-1i32)), - loc: self.loc, - })) - } else { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - - let (abs, is_min) = neg_v.overflowing_abs(); - let bits = if is_min { - 255 - } else { - 255 - abs.leading_zeros() - }; - - if val >= &U256::from(bits) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(-1i32)), - loc: self.loc, - })) - } else { - let shr_val = abs.into_raw() >> val; - let as_int = I256::from_raw(shr_val); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - (I256::from(-1i32) * as_int).max(min), - ), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } -} - -impl RangeShift for Elem { - fn range_shl(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_shl(b), - _ => None, - } - } - fn range_shr(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_shr(b), - _ => None, - } - } -} - -pub trait RangeUnary { - /// Perform a logical NOT - fn range_not(&self) -> Option>; - /// Perform a logical AND - fn range_and(&self, other: &Rhs) -> Option>; - /// Perform a logical OR - fn range_or(&self, other: &Rhs) -> Option>; -} - -impl RangeUnary for RangeConcrete { - fn range_not(&self) -> Option> { - match self.val { - Concrete::Bool(b) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(!b), - loc: self.loc, - })), - _ => None, - } - } - - fn range_and(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(*a && *b), - loc: self.loc, - })), - _ => None, - } - } - - fn range_or(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(*a || *b), - loc: self.loc, - })), - _ => None, - } - } -} - -impl RangeUnary for Elem { - fn range_not(&self) -> Option> { - match self { - Elem::Concrete(a) => a.range_not(), - _ => None, - } - } - fn range_and(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_and(b), - _ => None, - } - } - fn range_or(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_or(b), - _ => None, - } - } -} - -pub trait RangeCast { - /// Perform a cast on an element to the type of the right hand side - fn range_cast(&self, other: &Rhs) -> Option>; -} - -impl RangeCast for RangeConcrete { - fn range_cast(&self, other: &Self) -> Option> { - Some(Elem::Concrete(RangeConcrete { - val: self.val.clone().cast_from(&other.val)?, - loc: self.loc, - })) - } -} - -impl RangeCast>> for RangeConcrete { - fn range_cast(&self, other: &Box>) -> Option> { - match (self.val.clone(), other.val.iter().take(1).next()) { - ( - Concrete::Bytes(size, val), - Some(( - _, - Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), - )), - ) - | (Concrete::Bytes(size, val), None) => { - let mut existing = other.val.clone(); - let new = val - .0 - .iter() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let mut bytes = [0x00; 32]; - bytes[0] = *v; - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(size))), - val: existing, - loc: other.loc, - }))) - } - ( - Concrete::DynBytes(val), - Some(( - _, - Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), - )), - ) - | (Concrete::DynBytes(val), None) => { - let mut existing = other.val.clone(); - let new = val - .iter() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let mut bytes = [0x00; 32]; - bytes[0] = *v; - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) - } - ( - Concrete::String(val), - Some(( - _, - Elem::Concrete(Self { - val: Concrete::String(..), - .. - }), - )), - ) - | (Concrete::String(val), None) => { - let mut existing = other.val.clone(); - let new = val - .chars() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let mut bytes = [0x00; 32]; - v.encode_utf8(&mut bytes[..]); - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) - } - _e => None, - } - } -} - -impl RangeCast> for RangeDyn { - fn range_cast(&self, other: &Self) -> Option> { - let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); - let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); - match (val, o_val) { - ( - Some(( - _, - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - Some(( - _, - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - ) - | ( - Some(( - _, - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - ( - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - )), - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - )), - ) - | ( - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - )), - None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - ( - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - )), - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - )), - ) - | ( - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - )), - None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), - (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - _e => None, - } - } -} - -impl RangeCast> for RangeDyn { - fn range_cast(&self, other: &RangeConcrete) -> Option> { - let (_k, val): (_, &Elem) = self.val.iter().take(1).next()?; - let o_val = &other.val; - // println!("HERE {:?} {:?} {:?}", k, val, o_val); - match (val, o_val) { - ( - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(1, ..), - .. - }), - Concrete::Bytes(size, _), - ) => { - let mut h = H256::default(); - for (i, (_, val)) in self.val.iter().take(*size as usize).enumerate() { - match val { - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(1, v), - .. - }) => { - // consume as many as we can - h.0[i] = v.0[0]; - } - _ => break, - } - } - Some(Elem::Concrete(Concrete::Bytes(*size, h).into())) - } - _e => None, - } - } -} - -impl RangeCast for Elem { - fn range_cast(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_cast(b), - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { - // super dumb type stuff here that makes it so we have to specify - as RangeCast>::range_cast(a, b) - } - (Elem::ConcreteDyn(a), Elem::Concrete(b)) => a.range_cast(b), - (Elem::Concrete(a), Elem::ConcreteDyn(b)) => a.range_cast(b), - _e => None, - } - } -} - -pub trait RangeConcat { - /// Perform a cast on an element to the type of the right hand side - fn range_concat(&self, other: &Rhs) -> Option>; -} - -impl RangeConcat for RangeConcrete { - fn range_concat(&self, other: &Self) -> Option> { - Some(Elem::Concrete(RangeConcrete { - val: self.val.clone().concat(&other.val)?, - loc: self.loc, - })) - } -} - -impl RangeConcat> for RangeDyn { - fn range_concat(&self, other: &RangeConcrete) -> Option> { - match (other.val.clone(), self.val.iter().take(1).next()) { - ( - Concrete::DynBytes(val), - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - ) - | (Concrete::DynBytes(val), None) => { - let last = self.len.clone(); - let mut existing = self.val.clone(); - let new = val - .iter() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let idx = last.clone() + idx; - let mut bytes = [0x00; 32]; - bytes[0] = *v; - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) - } - ( - Concrete::String(val), - Some(( - _, - Elem::Concrete(RangeConcrete { - val: Concrete::String(..), - .. - }), - )), - ) - | (Concrete::String(val), None) => { - let last = self.len.clone(); - let mut existing = self.val.clone(); - let new = val - .chars() - .enumerate() - .map(|(i, v)| { - let idx = Elem::from(Concrete::from(U256::from(i))); - let idx = last.clone() + idx; - let mut bytes = [0x00; 32]; - v.encode_utf8(&mut bytes[..]); - let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) - }) - .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) - } - _e => None, - } - } -} - -impl RangeConcat> for RangeDyn { - fn range_concat(&self, other: &Self) -> Option> { - let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); - let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); - match (val, o_val) { - ( - Some(( - _, - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - Some(( - _, - &Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - )), - ) => { - let last = self.len.clone(); - let mut existing = self.val.clone(); - let other_vals = other - .val - .clone() - .into_iter() - .map(|(i, v)| (i + last.clone(), v)) - .collect::>(); - - existing.extend(other_vals); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: self.len.clone() + other.len.clone(), - val: existing, - loc: other.loc, - }))) - } - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), - (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - _e => None, - } - } -} - -impl RangeConcat for Elem { - fn range_concat(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_concat(b), - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_concat(&**b), - (Elem::Concrete(c), Elem::ConcreteDyn(d)) - | (Elem::ConcreteDyn(d), Elem::Concrete(c)) => d.range_concat(c), - _e => None, - } - } -} - -pub trait RangeBitwise { - /// Perform a bitwise AND - fn range_bit_and(&self, other: &Rhs) -> Option>; - /// Perform a bitwise OR - fn range_bit_or(&self, other: &Rhs) -> Option>; - /// Perform a bitwise XOR - fn range_bit_xor(&self, other: &Rhs) -> Option>; - /// Perform a bitwise NOT - fn range_bit_not(&self) -> Option>; -} - -impl RangeBitwise for RangeConcrete { - fn range_bit_and(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a & *b), - loc: self.loc, - })) - } - (Concrete::Int(s, a), Concrete::Int(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a & *b), - loc: self.loc, - })) - } - (Concrete::Uint(s, a), Concrete::Int(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a & b.into_raw()), - loc: self.loc, - })) - } - (Concrete::Int(s, a), Concrete::Uint(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, a.into_raw() & *b), - loc: self.loc, - })) - } - (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a & b), - loc: self.loc, - })) - } - _ => None, - } - } - - fn range_bit_or(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a | *b), - loc: self.loc, - })) - } - (Concrete::Int(s, a), Concrete::Int(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a | *b), - loc: self.loc, - })) - } - (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a | b), - loc: self.loc, - })) - } - _ => None, - } - } - - fn range_bit_xor(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a ^ *b), - loc: self.loc, - })) - } - (Concrete::Int(s, a), Concrete::Int(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a ^ *b), - loc: self.loc, - })) - } - (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a ^ b), - loc: self.loc, - })) - } - _ => None, - } - } - - fn range_bit_not(&self) -> Option> { - match &self.val { - Concrete::Uint(size, a) => { - let max = Concrete::max(&self.val).unwrap().uint_val().unwrap(); - let val = U256( - a.0.into_iter() - .map(|i| !i) - .collect::>() - .try_into() - .unwrap(), - ); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, val & max), - loc: self.loc, - })) - } - Concrete::Int(size, a) => { - let (val, _) = a.overflowing_neg(); - let (val, _) = val.overflowing_sub(1.into()); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, val), - loc: self.loc, - })) - } - Concrete::Bytes(s, a) => { - let mut h = H256::default(); - (0..*s).for_each(|i| { - h.0[i as usize] = !a.0[i as usize]; - }); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*s, h), - loc: self.loc, - })) - } - _ => None, - } - } -} - -impl RangeBitwise for Elem { - fn range_bit_and(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_and(b), - _ => None, - } - } - fn range_bit_or(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_or(b), - _ => None, - } - } - fn range_bit_xor(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_bit_xor(b), - _ => None, - } - } - - fn range_bit_not(&self) -> Option> { - match self { - Elem::Concrete(a) => a.range_bit_not(), - _ => None, - } - } -} diff --git a/shared/src/range/range_string.rs b/shared/src/range/range_string.rs deleted file mode 100644 index 05528fd5..00000000 --- a/shared/src/range/range_string.rs +++ /dev/null @@ -1,274 +0,0 @@ -use crate::analyzer::GraphLike; -use crate::context::ContextVarNode; -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; -use crate::range::elem_ty::Dynamic; -use crate::range::elem_ty::RangeExpr; -use crate::range::Elem; -use crate::range::RangeDyn; -use crate::Concrete; - -use std::collections::BTreeMap; - -use solang_parser::pt::Loc; - -/// A range element string consisting of a string and a location -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct RangeElemString { - pub s: String, - pub loc: Loc, -} - -impl RangeElemString { - /// Creates a new range element string from a string and a location - pub fn new(s: String, loc: Loc) -> Self { - Self { s, loc } - } -} - -/// A range string consisting of stringified range elements -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct RangeString { - pub min: RangeElemString, - pub max: RangeElemString, -} - -impl RangeString { - /// Creates a new range string from a min and max [`RangeElemString`] - pub fn new(min: RangeElemString, max: RangeElemString) -> Self { - Self { min, max } - } -} - -/// String related functions for ranges -pub trait ToRangeString { - /// Gets the definition string of the range element - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString; - /// Converts a range to a human string - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString; -} - -impl ToRangeString for Elem { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - match self { - Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { - let cvar = ContextVarNode::from(*idx) - .first_version(analyzer) - .underlying(analyzer) - .unwrap(); - RangeElemString::new(cvar.display_name.clone(), cvar.loc.unwrap_or(Loc::Implicit)) - } - Elem::ConcreteDyn(rd) => rd.def_string(analyzer), - Elem::Expr(expr) => expr.def_string(analyzer), - Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - } - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - match self { - Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { - let as_var = ContextVarNode::from(*idx); - let name = as_var.display_name(analyzer).unwrap(); - RangeElemString::new(name, as_var.loc(analyzer).unwrap()) - } - Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), - Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), - Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - } - } -} - -impl ToRangeString for RangeDyn { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - let displayed_vals = self - .val - .iter() - .take(20) - .map(|(key, val)| (key.minimize(analyzer).unwrap(), val)) - .collect::>(); - - let val_str = displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - - RangeElemString::new( - format!( - "{{len: {}, indices: [{}]}}", - self.len.to_range_string(false, analyzer).s, - val_str - ), - self.loc, - ) - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - let val_str = if self.val.len() > 10 { - let displayed_vals = self - .val - .iter() - .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - let val_str_head = displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - - let displayed_vals_tail = self - .val - .iter() - .rev() - .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - let val_str_tail = displayed_vals_tail - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - format!("{val_str_head} ... {val_str_tail}") - } else { - let displayed_vals = self - .val - .iter() - .take(10) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", ") - }; - - RangeElemString::new( - format!( - "{{len: {}, indices: {{{}}}}}", - self.len.to_range_string(maximize, analyzer).s, - val_str - ), - self.loc, - ) - } -} - -impl ToRangeString for RangeExpr { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - self.lhs.def_string(analyzer) - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); - let lhs_str = match *self.lhs { - Elem::Expr(_) => { - let new_str = format!("({})", lhs_r_str.s); - RangeElemString::new(new_str, lhs_r_str.loc) - } - _ => lhs_r_str, - }; - - let rhs_r_str = self.rhs.to_range_string(maximize, analyzer); - - let rhs_str = match *self.rhs { - Elem::Expr(_) => { - let new_str = format!("({})", rhs_r_str.s); - RangeElemString::new(new_str, rhs_r_str.loc) - } - _ => rhs_r_str, - }; - - if matches!(self.op, RangeOp::Min | RangeOp::Max) { - RangeElemString::new( - format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), - lhs_str.loc, - ) - } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { - let rhs = if maximize { - self.rhs.maximize(analyzer).unwrap() - } else { - self.rhs.minimize(analyzer).unwrap() - }; - - match rhs { - Elem::Concrete(c) => RangeElemString::new( - format!( - "{}({})", - c.val.as_builtin().as_string(analyzer).unwrap(), - lhs_str.s - ), - lhs_str.loc, - ), - _ => RangeElemString::new( - format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), - lhs_str.loc, - ), - } - } else if matches!(self.op, RangeOp::BitNot) { - let lhs = if maximize { - self.lhs.maximize(analyzer).unwrap() - } else { - self.lhs.minimize(analyzer).unwrap() - }; - - match lhs { - Elem::Concrete(_c) => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), - _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), - } - } else { - RangeElemString::new( - format!("{} {} {}", lhs_str.s, self.op.to_string(), rhs_str.s), - lhs_str.loc, - ) - } - } -} diff --git a/src/builtin_fns.rs b/src/builtin_fns.rs deleted file mode 100644 index f6832307..00000000 --- a/src/builtin_fns.rs +++ /dev/null @@ -1,816 +0,0 @@ -use crate::Builtin; -use crate::{Function, FunctionParam, FunctionReturn}; -use shared::analyzer::{AnalyzerLike, GraphLike}; -use solang_parser::pt::{FunctionAttribute, Identifier, Loc, StorageLocation, Visibility}; -use std::collections::HashMap; - -macro_rules! builtin_fn { - ($($field:ident : $value:expr),* $(,)?) => { - Function { - $( - $field: $value, - )* - ..Default::default() - } - } -} - -// A list of all Solidity builtins functions -pub fn builtin_fns() -> HashMap { - let funcs = [ - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "wrap".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "unwrap".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "concat".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "addmod".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "mulmod".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "balance".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "code".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "push".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "pop".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "ecrecover".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "type".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "assert".to_string(), - }), - name_loc: Loc::Builtin, - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "require".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "require_str".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "revert".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "revert_str".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "selfdestruct".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "keccak256".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "ripemd160".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "sha256".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "gasleft".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "blockhash".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.decode".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.encode".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.encodePacked".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.encodeWithSelector".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.encodeWithSignature".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "abi.encodeCall".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::Internal(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "delegatecall".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "call".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "staticcall".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "transfer".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - builtin_fn!( - name: Some(Identifier { - loc: Loc::Builtin, - name: "send".to_string(), - }), - attributes: vec![FunctionAttribute::Visibility(Visibility::External(Some( - Loc::Builtin, - )))], - ), - ]; - funcs - .into_iter() - .map(|func| (func.name.clone().expect("").name, func)) - .collect() -} - -pub fn builtin_fns_inputs( - analyzer: &mut (impl GraphLike + AnalyzerLike), -) -> HashMap, Vec)> { - let funcs = [ - ("wrap", vec![], vec![]), - ("unwrap", vec![], vec![]), - ( - "addmod", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - storage: None, - name: None, - }], - ), - ( - "mulmod", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 0, - storage: None, - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - storage: None, - name: None, - }], - ), - ( - "balance", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - storage: None, - name: None, - }], - ), - ( - "code", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: None, - name: None, - }], - ), - ( - "codehash", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: None, - name: None, - }], - ), - ("concat", vec![], vec![]), - ("push", vec![], vec![]), - ("pop", vec![], vec![]), - ( - "ecrecover", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - order: 1, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - order: 2, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(8)), - order: 3, - storage: None, - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - storage: None, - name: None, - }], - ), - ("type", vec![], vec![]), - ( - "assert", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bool), - order: 0, - storage: None, - name: None, - }], - vec![], - ), - ( - "require", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bool), - order: 0, - storage: None, - name: None, - }], - vec![], - ), - ( - "require_str", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bool), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::String), - order: 1, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }, - ], - vec![], - ), - ("revert", vec![], vec![]), - ( - "revert_str", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::String), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![], - ), - ( - "selfdestruct", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }], - vec![], - ), - ( - "keccak256", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - storage: None, - name: None, - }], - ), - ( - "ripemd160", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(20)), - storage: None, - name: None, - }], - ), - ( - "sha256", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - storage: None, - name: None, - }], - ), - ( - "gasleft", - vec![], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(64)), - storage: None, - name: None, - }], - ), - ( - "blockhash", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(64)), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(32)), - storage: None, - name: None, - }], - ), - ( - "abi.decode", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 0, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - vec![], - ), - ( - "abi.encode", - vec![], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "abi.encodePacked", - vec![], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "abi.encodeWithSelector", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bytes(4)), - order: 0, - storage: None, - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "abi.encodeWithSignature", - vec![FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::String), - order: 0, - storage: None, - name: None, - }], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ("abi.encodeCall", vec![], vec![]), - ( - "delegatecall", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 1, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "call", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 1, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "staticcall", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - order: 1, - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::DynamicBytes), - storage: Some(StorageLocation::Memory(Loc::Implicit)), - name: None, - }], - ), - ( - "transfer", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 1, - storage: None, - name: None, - }, - ], - vec![], - ), - ( - "send", - vec![ - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Address), - order: 0, - storage: None, - name: None, - }, - FunctionParam { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Uint(256)), - order: 1, - storage: None, - name: None, - }, - ], - vec![FunctionReturn { - loc: Loc::Builtin, - ty: analyzer.builtin_or_add(Builtin::Bool), - storage: None, - name: None, - }], - ), - ]; - - funcs - .into_iter() - .map(|(name, inputs, outputs)| (name.to_string(), (inputs, outputs))) - .collect() -} diff --git a/src/context/analyzers/bounds.rs b/src/context/analyzers/bounds.rs deleted file mode 100644 index 2ea3d72a..00000000 --- a/src/context/analyzers/bounds.rs +++ /dev/null @@ -1,318 +0,0 @@ -use crate::analyzers::FunctionVarsBoundAnalysis; -use crate::analyzers::VarBoundAnalysis; - -use crate::analyzers::LocSpan; -use crate::analyzers::{LocStrSpan, ReportConfig}; - -use shared::analyzer::GraphLike; -use shared::{ - context::*, - range::{range_string::*, Range, RangeEval, SolcRange}, -}; - -use ariadne::{Color, Fmt, Label, Span}; -use solang_parser::pt::StorageLocation; -use std::collections::{BTreeMap, BTreeSet}; - -pub static MIN_COLOR: Color = Color::Fixed(111); -pub static MAX_COLOR: Color = Color::Fixed(106); - -#[derive(PartialEq, Eq, Clone)] -pub struct AnalysisItem { - pub init: bool, - pub order: i32, - pub name: String, - pub loc: LocStrSpan, - pub storage: Option, - pub ctx: ContextNode, - pub ctx_conditionals: Vec<(String, Vec)>, - pub parts: Vec, - pub unsat: bool, -} - -#[derive(PartialEq, Eq, Clone, Debug, Hash)] -pub struct StrippedAnalysisItem { - pub init: bool, - pub order: i32, - pub name: String, - pub loc: LocSpan, - // pub storage: Option, - pub ctx: ContextNode, - pub ctx_conditionals: Vec<(String, Vec)>, - pub parts: Vec, - pub unsat: bool, -} - -impl From for StrippedAnalysisItem { - fn from(ai: AnalysisItem) -> Self { - Self { - init: ai.init, - order: ai.order, - name: ai.name, - loc: LocSpan(ai.loc.1), - // storage: ai.storage, - ctx: ai.ctx, - ctx_conditionals: ai.ctx_conditionals, - parts: ai.parts, - unsat: ai.unsat, - } - } -} - -impl PartialOrd for StrippedAnalysisItem { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for StrippedAnalysisItem { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.loc.0.cmp(&other.loc.0) - } -} - -#[derive(Default, Clone, Debug, Hash)] -pub struct OrderedAnalysis { - pub analyses: BTreeMap>, -} - -impl OrderedAnalysis { - pub fn from_bound_analysis(ba: VarBoundAnalysis, analyzer: &impl GraphLike) -> Self { - let mut analyses: BTreeMap> = Default::default(); - if let Some(init) = ba.init_item(analyzer) { - let source: usize = *LocSpan(init.loc.1).source(); - let mut set = BTreeSet::new(); - set.insert(init.into()); - analyses.insert(source, set); - } - ba.bound_changes - .iter() - .enumerate() - .for_each(|(i, bound_change)| { - let (parts, unsat) = range_parts(analyzer, &ba.report_config, &bound_change.1); - let item = StrippedAnalysisItem { - init: false, - name: ba.var_display_name.clone(), - loc: LocSpan(bound_change.0 .1), - order: i as i32, - // storage: ba.storage.clone(), - ctx: ba.ctx, - ctx_conditionals: ba.conditionals(analyzer), - parts, - unsat, - }; - - let entry = analyses - .entry(*LocSpan(bound_change.0 .1).source()) - .or_default(); - entry.insert(item); - }); - Self { analyses } - } - - pub fn from_func_analysis(fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphLike) -> Self { - let mut analyses = Self::default(); - fvba.vars_by_ctx.iter().for_each(|(_ctx, bas)| { - bas.iter().for_each(|ba| { - analyses.extend(Self::from_bound_analysis(ba.clone(), analyzer)); - }) - }); - analyses - } - - pub fn extend(&mut self, other: Self) { - other.analyses.into_iter().for_each(|(key, set)| { - let entry = self.analyses.entry(key).or_default(); - entry.extend(set); - }); - } -} - -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Hash)] -pub enum RangePart { - Equal(String), - Inclusion(String, String), - Exclusion(Vec), -} - -impl RangePart { - pub fn to_cli_string(self) -> String { - match self { - RangePart::Equal(val) => format!(" == {}", val), - RangePart::Inclusion(min, max) => { - format!(" ∈ [ {}, {} ]", min.fg(MIN_COLOR), max.fg(MAX_COLOR)) - } - RangePart::Exclusion(parts) => format!( - "&& ∉ {{{}}}", - parts - .into_iter() - .map(|p| p.to_cli_string()) - .collect::>() - .join(", ") - ) - .fg(Color::Red) - .to_string(), - } - } - - pub fn to_normal_string(&self) -> String { - match self { - e @ RangePart::Equal(_) => format!(" == {}", e.to_string()), - e @ RangePart::Inclusion(..) => format!(" ∈ {}", e.to_string()), - e @ RangePart::Exclusion(_) => format!("&& ∉ {{{}}}", e.to_string()), - } - } -} - -impl Into> for AnalysisItem { - fn into(self) -> ariadne::Label { - let (color, order, priority) = if self.init { - (Color::Magenta, self.order, -1) - } else { - ( - match self.storage { - Some(StorageLocation::Memory(..)) => Color::Blue, - Some(StorageLocation::Storage(..)) => Color::Green, - Some(StorageLocation::Calldata(..)) => Color::White, - None => Color::Cyan, - }, - self.order, - 0, - ) - }; - - Label::new(self.loc) - .with_message(format!( - "{}\"{}\"{}{}", - match self.storage { - Some(StorageLocation::Memory(..)) => "Memory var ", - Some(StorageLocation::Storage(..)) => "Storage var ", - Some(StorageLocation::Calldata(..)) => "Calldata var ", - None => "", - }, - self.name, - self.parts - .into_iter() - .map(|part| part.to_cli_string()) - .collect::>() - .join(" "), - if self.unsat { - " - unsatisfiable range, unreachable".fg(Color::Red) - } else { - "".fg(Color::Red) - } - )) - .with_color(color) - .with_order(order) - .with_priority(priority) - } -} - -impl ToString for StrippedAnalysisItem { - fn to_string(&self) -> String { - format!( - "{}{}{}", - // match self.storage { - // Some(StorageLocation::Memory(..)) => "Memory var ", - // Some(StorageLocation::Storage(..)) => "Storage var ", - // Some(StorageLocation::Calldata(..)) => "Calldata var ", - // None => "", - // }, - self.name, - self.parts - .iter() - .map(|part| part.to_normal_string()) - .collect::>() - .join(" "), - if self.unsat { - " - unsatisfiable range, unreachable" - } else { - "" - } - ) - } -} - -impl ToString for RangePart { - fn to_string(&self) -> String { - match self { - RangePart::Equal(inner) => inner.to_string(), - RangePart::Inclusion(min, max) => format!("[ {}, {} ]", min, max), - RangePart::Exclusion(inner) => format!( - "{{{}}}", - inner - .iter() - .map(|part| part.to_string()) - .collect::>() - .join(", ") - ), - } - } -} - -/// Creates an Vec<[RangePart]> from a range based on the current [ReportConfig] -pub fn range_parts( - analyzer: &impl GraphLike, - report_config: &ReportConfig, - range: &SolcRange, -) -> (Vec, bool) { - let mut parts = vec![]; - let min = if report_config.eval_bounds { - range - .evaled_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else if report_config.simplify_bounds { - range - .simplified_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else { - range.range_min().to_range_string(false, analyzer).s - }; - let max = if report_config.eval_bounds { - range - .evaled_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else if report_config.simplify_bounds { - range - .simplified_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else { - range.range_max().to_range_string(true, analyzer).s - }; - - if min == max { - parts.push(RangePart::Equal(min)); - } else { - parts.push(RangePart::Inclusion(min, max)); - } - - let range_excl = range.range_exclusions(); - if !range_excl.is_empty() { - parts.push(RangePart::Exclusion({ - let mut excls = range_excl - .iter() - .map(|range| { - let min = range.to_range_string(false, analyzer).s; - let max = range.to_range_string(true, analyzer).s; - if min == max { - RangePart::Equal(min) - } else { - RangePart::Inclusion(min, max) - } - }) - .collect::>(); - excls.dedup(); - excls - })); - } - let unsat = range.unsat(analyzer); - (parts, unsat) -} diff --git a/src/context/analyzers/func_analyzer/mod.rs b/src/context/analyzers/func_analyzer/mod.rs deleted file mode 100644 index 3ff556b1..00000000 --- a/src/context/analyzers/func_analyzer/mod.rs +++ /dev/null @@ -1,378 +0,0 @@ -use crate::analyzers::range_parts; -use crate::analyzers::VarBoundAnalysis; -use crate::analyzers::VarBoundAnalyzer; - -use crate::analyzers::{LocStrSpan, ReportConfig, ReportDisplay}; -use ariadne::ReportKind; -use std::collections::BTreeSet; - -use shared::analyzer::GraphLike; -use shared::{ - analyzer::{AnalyzerLike, Search}, - context::*, -}; - -use ariadne::{Color, Config, Fmt, Label, Report, Span}; -use solang_parser::pt::CodeLocation; -use std::collections::BTreeMap; - -mod report_display; -pub use report_display::*; - -#[derive(Debug, Clone)] -pub struct FunctionVarsBoundAnalysis { - /// Entry context location string span - pub ctx_loc: LocStrSpan, - /// Entry context - pub ctx: ContextNode, - /// If the context was killed (i.e. a `return` or `revert` of some kind), the location string span - pub ctx_killed: Option<(LocStrSpan, KilledKind)>, - /// The report configuration - pub report_config: ReportConfig, - /// Mapping of context node (i.e. for the lineage of the entry context) to a vector of bound analyses - pub vars_by_ctx: BTreeMap>, -} - -impl<'a> FunctionVarsBoundAnalysis { - pub fn as_cli_compat( - self, - file_mapping: &'a BTreeMap, - ) -> CLIFunctionVarsBoundAnalysis<'a> { - CLIFunctionVarsBoundAnalysis::new(file_mapping, self) - } - - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Bounds", Color::Cyan) - } - - pub fn reports_for_forks( - &self, - file_mapping: &'a BTreeMap, - analyzer: &impl GraphLike, - ) -> Vec> { - let mut handled_ctx_switches = BTreeSet::default(); - let reports = self - .vars_by_ctx - .iter() - .map(|(ctx, analyses)| { - // sort by display name instead of normal name - let deps = ctx.ctx_deps(analyzer).unwrap(); - let deps = deps - .values() - .map(|var| (var.display_name(analyzer).unwrap(), var)) - .collect::>(); - // create the bound strings - let bounds_string = deps - .iter() - .enumerate() - .filter_map(|(i, (name, cvar))| { - let range = cvar.ref_range(analyzer).unwrap()?; - let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); - let ret = parts.into_iter().fold( - format!("{}. {name}", i + 1), - |mut acc, part| { - acc = format!("{acc}{}", part.to_cli_string()); - acc - }, - ); - Some(format!("{ret}\n")) - }) - .collect::>() - .join(""); - let mut report = Report::build( - self.report_kind(), - self.ctx_loc.source(), - self.ctx_loc.start(), - ) - .with_message(format!( - "Bounds for subcontext: {}{}{}, killed: {:?}", - ctx.path(analyzer).fg(Color::Cyan), - if bounds_string.is_empty() { - "" - } else { - " where:\n" - }, - bounds_string.fg(Color::Yellow), - ctx.underlying(analyzer).unwrap().killed - )) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4) - .with_multiline_arrows(false), - ); - - let mut self_handled = false; - let mut added_bodies = vec![]; - let mut labels: Vec<_> = analyses - .iter() - .flat_map(|analysis| { - let mut labels = analysis.labels(analyzer); - labels.extend( - analysis - .spanned_ctx_info - .clone() - .into_iter() - .filter_map(|ctx_switch| { - let mut is_self = false; - if ctx_switch.ctx == *ctx - || ctx_switch.ctx.underlying(analyzer).unwrap().depth == 0 - { - self_handled = true; - is_self = true; - } - - if let Some(body) = ctx_switch.func_body_span { - if added_bodies.contains(&body) { - return None; - } - added_bodies.push(body.clone()); - if is_self { - Some( - Label::new(body) - .with_message("Entry function call") - .with_color(Color::White) - .with_priority(-2) - .with_order(-2), - ) - } else { - Some( - Label::new(body) - .with_message("Function call") - .with_color(Color::Fixed(140)) - .with_priority(-2) - .with_order(-2), - ) - } - } else { - if added_bodies.contains(&ctx_switch.func_span) { - return None; - } - added_bodies.push(ctx_switch.func_span.clone()); - if is_self { - Some( - Label::new(ctx_switch.func_span) - .with_message("Entry function call") - .with_color(Color::White) - .with_priority(-2) - .with_order(-2), - ) - } else { - Some( - Label::new(ctx_switch.func_span) - .with_message("Function call") - .with_color(Color::Fixed(140)) - .with_priority(-2) - .with_order(-2), - ) - } - } - }) - .collect::>(), - ); - - analysis.spanned_ctx_info.iter().for_each(|ctx_switch| { - if !handled_ctx_switches.contains(ctx_switch) { - handled_ctx_switches.insert(ctx_switch); - if ctx_switch.ctx != *ctx { - labels.extend( - ctx_switch - .ctx - .return_nodes(analyzer) - .unwrap() - .into_iter() - .filter_map(|(loc, var)| { - let range = var.ref_range(analyzer).unwrap()?; - let (parts, _unsat) = range_parts( - analyzer, - &self.report_config, - &range, - ); - Some( - Label::new(LocStrSpan::new(file_mapping, loc)) - .with_message( - format!( - "returns: \"{}\"{}", - var.display_name(analyzer).unwrap(), - parts - .into_iter() - .map(|i| i.to_cli_string()) - .collect::>() - .join(", ") - ) - .fg(Color::Yellow), - ) - .with_color(Color::Yellow) - .with_order(50), - ) - }) - .collect::>(), - ); - } - if ctx_switch.ctx == *ctx { - if let Some((killed_loc, kind)) = &ctx_switch.killed_loc { - labels.push( - Label::new(killed_loc.clone()) - .with_message(kind.analysis_str()) - .with_color(Color::Red) - .with_priority(10), - ); - } - self_handled = true; - } - } - }); - labels - }) - .collect(); - - if let Some((killed_span, kind)) = &self.ctx_killed { - if !self_handled { - labels.push( - Label::new(killed_span.clone()) - .with_message(kind.analysis_str().fg(Color::Red)) - .with_color(Color::Red), - ); - } - } - - labels.extend( - ctx.return_nodes(analyzer) - .unwrap() - .into_iter() - .filter_map(|(loc, var)| { - let range = var.ref_range(analyzer).unwrap()?; - let (parts, _unsat) = - range_parts(analyzer, &self.report_config, &range); - Some( - Label::new(LocStrSpan::new(file_mapping, loc)) - .with_message( - format!( - "returns: \"{}\"{}", - var.display_name(analyzer).unwrap(), - parts - .into_iter() - .map(|i| i.to_cli_string()) - .collect::>() - .join(", ") - ) - .fg(Color::Yellow), - ) - .with_color(Color::Yellow) - .with_order(50), - ) - }) - .collect::>(), - ); - if !self_handled { - if let Some(body) = ctx - .associated_fn(analyzer) - .unwrap() - .underlying(analyzer) - .unwrap() - .body - .as_ref() - { - report.add_label( - Label::new(LocStrSpan::new(file_mapping, body.loc())) - .with_message("Entry function call") - .with_priority(-2) - .with_order(-2), - ); - } - } - - report.add_labels(labels); - report.finish() - }) - .collect::>>(); - reports - } -} - -impl FunctionVarsBoundAnalyzer for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - fn bounds_for_all<'a>( - &'a self, - file_mapping: &'a BTreeMap, - ctx: ContextNode, - report_config: ReportConfig, - ) -> FunctionVarsBoundAnalysis { - let mut edges = ctx.all_edges(self).unwrap(); - if edges.is_empty() { - edges.push(ctx); - } - let lineage_analyses = edges - .iter() - .filter_map(|fork| { - if !report_config.show_unreachables - && matches!( - fork.underlying(self).unwrap().killed, - Some((_, KilledKind::Unreachable)) - ) - { - return None; - } - if !report_config.show_nonreverts - && matches!(fork.underlying(self).unwrap().killed, None) - { - return None; - } - if !report_config.show_reverts - && matches!( - fork.underlying(self).unwrap().killed, - Some((_, KilledKind::Revert)) - ) - { - return None; - } - let mut parents = fork.parent_list(self).unwrap(); - parents.reverse(); - parents.push(*fork); - let mut vars = ctx.vars(self).values().collect::>(); - vars.extend( - parents - .iter() - .flat_map(|parent| parent.vars(self).values().collect::>()) - .collect::>(), - ); - vars.sort_by_key(|a| a.name(self)); - vars.dedup_by(|a, b| a.name(self) == b.name(self)); - Some(( - *fork, - vars.iter() - .filter_map(|var| { - let is_ret = var.is_return_node_in_any(&parents, self); - if is_ret - | report_config.show_tmps - | (report_config.show_consts && var.is_const(self).unwrap()) - | (report_config.show_symbolics && var.is_symbolic(self).unwrap()) - { - Some(self.bounds_for_var_in_family_tree( - file_mapping, - parents.clone(), - var.name(self).unwrap(), - report_config, - )) - } else { - None - } - }) - .collect::>(), - )) - }) - .collect::>>(); - - FunctionVarsBoundAnalysis { - ctx_loc: LocStrSpan::new(file_mapping, ctx.underlying(self).unwrap().loc), - ctx, - ctx_killed: ctx - .killed_loc(self) - .unwrap() - .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), - vars_by_ctx: lineage_analyses, - report_config, - } - } -} diff --git a/src/context/analyzers/func_analyzer/report_display.rs b/src/context/analyzers/func_analyzer/report_display.rs deleted file mode 100644 index 0f54d0c1..00000000 --- a/src/context/analyzers/func_analyzer/report_display.rs +++ /dev/null @@ -1,92 +0,0 @@ -use crate::analyzers::func_analyzer::*; -use crate::analyzers::{LocStrSpan, ReportDisplay}; -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use shared::analyzer::GraphLike; -use std::collections::BTreeMap; - -pub struct CLIFunctionVarsBoundAnalysis<'a> { - pub file_mapping: &'a BTreeMap, - pub func_var_bound_analysis: FunctionVarsBoundAnalysis, -} - -impl<'a> CLIFunctionVarsBoundAnalysis<'a> { - pub fn new( - file_mapping: &'a BTreeMap, - func_var_bound_analysis: FunctionVarsBoundAnalysis, - ) -> Self { - Self { - file_mapping, - func_var_bound_analysis, - } - } -} - -impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Bounds", Color::Cyan) - } - fn msg(&self, analyzer: &impl GraphLike) -> String { - format!( - "Bounds for function: {}", - format!( - "function {}", - self.func_var_bound_analysis - .ctx - .associated_fn_name(analyzer) - .unwrap() - ) - .fg(Color::Cyan) - ) - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let mut report = Report::build( - self.report_kind(), - self.func_var_bound_analysis.ctx_loc.source(), - self.func_var_bound_analysis.ctx_loc.start(), - ) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - - report.add_labels(self.labels(analyzer)); - if let Some((killed_span, kind)) = &self.func_var_bound_analysis.ctx_killed { - report = report.with_label( - Label::new(killed_span.clone()) - .with_message(kind.analysis_str().fg(Color::Red)) - .with_color(Color::Red), - ); - } - - let mut reports = vec![report.finish()]; - - reports.extend( - self.func_var_bound_analysis - .reports_for_forks(self.file_mapping, analyzer), - ); - - reports - } - - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} diff --git a/src/context/analyzers/mod.rs b/src/context/analyzers/mod.rs deleted file mode 100644 index 9414cbc3..00000000 --- a/src/context/analyzers/mod.rs +++ /dev/null @@ -1,176 +0,0 @@ -pub mod bounds; - -use crate::AnalyzerLike; -use crate::GraphLike; -use ariadne::{Cache, Label, Report, ReportKind, Span}; -use bounds::*; -use shared::analyzer::Search; -use solang_parser::pt::Loc; -use std::collections::BTreeMap; - -mod func_analyzer; -pub use func_analyzer::*; -mod var_analyzer; -pub use var_analyzer::*; - -pub trait ContextAnalyzer: - AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer -{ -} -impl ContextAnalyzer for T where - T: AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer -{ -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct LocSpan(pub Loc); - -impl Default for LocSpan { - fn default() -> Self { - LocSpan(Loc::Implicit) - } -} - -impl Span for LocSpan { - type SourceId = usize; - fn source(&self) -> &Self::SourceId { - match self.0 { - Loc::File(ref f, _, _) => f, - Loc::Implicit => &0, - _ => todo!("handle non file loc"), - } - } - - fn start(&self) -> usize { - match self.0 { - Loc::File(_, start, _) => start, - Loc::Implicit => 0, - _ => todo!("handle non file loc"), - } - } - - fn end(&self) -> usize { - match self.0 { - Loc::File(_, _, end) => end, - Loc::Implicit => 0, - _ => todo!("handle non file loc"), - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct LocStrSpan(pub String, pub Loc); - -impl Default for LocStrSpan { - fn default() -> Self { - LocStrSpan("".to_string(), Loc::Implicit) - } -} - -impl LocStrSpan { - pub fn new(file_mapping: &BTreeMap, loc: Loc) -> Self { - let source = match loc { - Loc::File(ref f, _, _) => f, - Loc::Implicit => &0, - _ => todo!("handle non file loc"), - }; - LocStrSpan( - file_mapping - .get(source) - .expect("No file for num") - .to_string(), - loc, - ) - } -} - -impl Span for LocStrSpan { - type SourceId = String; - fn source(&self) -> &Self::SourceId { - &self.0 - } - - fn start(&self) -> usize { - match self.1 { - Loc::File(_, start, _) => start, - Loc::Implicit => 0, - _ => todo!("handle non file loc"), - } - } - - fn end(&self) -> usize { - match self.1 { - Loc::File(_, _, end) => end, - Loc::Implicit => 0, - _ => todo!("handle non file loc"), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub struct ReportConfig { - pub eval_bounds: bool, - pub simplify_bounds: bool, - pub show_tmps: bool, - pub show_consts: bool, - pub show_symbolics: bool, - pub show_initial_bounds: bool, - pub show_all_lines: bool, - pub show_reverts: bool, - pub show_unreachables: bool, - pub show_nonreverts: bool, -} - -impl ReportConfig { - pub fn new( - eval_bounds: bool, - simplify_bounds: bool, - show_tmps: bool, - show_consts: bool, - show_symbolics: bool, - show_initial_bounds: bool, - show_all_lines: bool, - show_reverts: bool, - show_unreachables: bool, - show_nonreverts: bool, - ) -> Self { - Self { - eval_bounds, - simplify_bounds, - show_tmps, - show_consts, - show_symbolics, - show_initial_bounds, - show_all_lines, - show_reverts, - show_unreachables, - show_nonreverts, - } - } -} - -impl Default for ReportConfig { - fn default() -> Self { - Self { - eval_bounds: true, - simplify_bounds: false, - show_tmps: false, - show_consts: false, - show_symbolics: true, - show_initial_bounds: false, - show_all_lines: false, - show_reverts: false, - show_unreachables: false, - show_nonreverts: true, - } - } -} - -pub trait ReportDisplay { - fn report_kind(&self) -> ReportKind; - fn msg(&self, analyzer: &impl GraphLike) -> String; - fn labels(&self, analyzer: &impl GraphLike) -> Vec>; - fn reports(&self, analyzer: &impl GraphLike) -> Vec>; - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); - fn eprint_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); -} diff --git a/src/context/analyzers/var_analyzer/mod.rs b/src/context/analyzers/var_analyzer/mod.rs deleted file mode 100644 index 0f0fb23f..00000000 --- a/src/context/analyzers/var_analyzer/mod.rs +++ /dev/null @@ -1,266 +0,0 @@ -use crate::analyzers::range_parts; -use crate::analyzers::AnalysisItem; -use crate::analyzers::RangePart; -use crate::analyzers::{LocStrSpan, ReportConfig}; -use shared::analyzer::GraphLike; -use shared::{ - analyzer::{AnalyzerLike, Search}, - context::*, - range::{Range, SolcRange}, -}; -use std::collections::BTreeSet; - -use solang_parser::pt::{CodeLocation, StorageLocation}; -use std::collections::BTreeMap; - -mod report_display; -pub use report_display::*; - -#[derive(PartialOrd, Eq, PartialEq, Ord, Clone, Debug)] -pub struct CtxSwitch { - pub ctx: ContextNode, - pub func_span: LocStrSpan, - pub func_body_span: Option, - pub killed_loc: Option<(LocStrSpan, KilledKind)>, -} - -#[derive(Debug, Clone)] -pub struct VarBoundAnalysis { - /// The context to analyze - pub ctx: ContextNode, - /// The variable's name - pub var_name: String, - /// The variable's display name - pub var_display_name: String, - /// The variable definition and optionally it's initial range - pub var_def: (LocStrSpan, Option), - /// The function defintion - pub func_span: LocStrSpan, - /// Storage type of the variable - pub storage: Option, - /// Vector of bound changes and their location - pub bound_changes: Vec<(LocStrSpan, SolcRange)>, - /// Report configuration - pub report_config: ReportConfig, - /// Spanned (context nodes, function name span, return spans) - pub spanned_ctx_info: BTreeSet, - /// Location where context was killed - pub ctx_killed: Option<(LocStrSpan, KilledKind)>, -} - -impl Default for VarBoundAnalysis { - fn default() -> Self { - Self { - ctx: ContextNode(0), - var_name: Default::default(), - var_display_name: Default::default(), - var_def: Default::default(), - func_span: Default::default(), - bound_changes: Default::default(), - report_config: Default::default(), - storage: None, - ctx_killed: None, - spanned_ctx_info: Default::default(), - } - } -} - -impl VarBoundAnalysis { - pub fn conditionals(&self, analyzer: &impl GraphLike) -> Vec<(String, Vec)> { - let deps = self.ctx.ctx_deps(analyzer).unwrap(); - let deps = deps - .values() - .map(|var| (var.display_name(analyzer).unwrap(), var)) - .collect::>(); - // create the bound strings - deps.iter() - .enumerate() - .filter_map(|(_i, (_name, cvar))| { - let range = cvar.ref_range(analyzer).unwrap()?; - let parts = range_parts(analyzer, &self.report_config, &range).0; - Some((cvar.display_name(analyzer).unwrap(), parts)) - }) - .collect() - } - - /// Creates an [AnalysisItem] if there is a initial bound for a variable - pub fn init_item(&self, analyzer: &impl GraphLike) -> Option { - let mut parts = vec![]; - let mut unsat = false; - if let Some(init_range) = &self.var_def.1 { - (parts, unsat) = range_parts(analyzer, &self.report_config, init_range) - } - if parts.is_empty() { - None - } else { - Some(AnalysisItem { - init: true, - order: -1, - name: self.var_display_name.clone(), - loc: self.var_def.0.clone(), - storage: self.storage.clone(), - ctx: self.ctx, - ctx_conditionals: self.conditionals(analyzer), - parts, - unsat, - }) - } - } -} - -impl VarBoundAnalyzer for T where T: Search + AnalyzerLike + Sized {} -pub trait VarBoundAnalyzer: Search + AnalyzerLike + Sized { - /// Given a lineage of a context (first element being the youngest, last element being the oldest), - /// generate a bound analysis for a variable throughout the lineage - fn bounds_for_var_in_family_tree( - &self, - file_mapping: &'_ BTreeMap, - ordered_ctxs: Vec, - var_name: String, - report_config: ReportConfig, - ) -> VarBoundAnalysis { - let mut inherited = None; - ordered_ctxs - .into_iter() - .filter_map(|ctx| Some((ctx, ctx.var_by_name(self, &var_name)?))) - .for_each(|(_ctx, cvar)| { - let analysis = self.bounds_for_var_node( - &inherited, - file_mapping, - &var_name, - cvar, - report_config, - inherited.is_some(), - ); - inherited = Some(analysis); - }); - inherited.unwrap_or_default() - } - - /// Analyzes the bounds for a variable up to the provided node - fn bounds_for_var_node( - &self, - inherited: &Option, - file_mapping: &'_ BTreeMap, - var_name: &str, - cvar: ContextVarNode, - report_config: ReportConfig, - is_subctx: bool, - ) -> VarBoundAnalysis { - let mut curr = cvar.first_version(self); - - let ctx = cvar.ctx(self); - let (func_span, func_body_span) = - if let Some(fn_call) = ctx.underlying(self).unwrap().fn_call { - ( - LocStrSpan::new(file_mapping, fn_call.underlying(self).unwrap().loc), - fn_call - .underlying(self) - .unwrap() - .body - .as_ref() - .map(|body| LocStrSpan::new(file_mapping, body.loc())), - ) - } else if let Some(ext_fn_call) = ctx.underlying(self).unwrap().ext_fn_call { - ( - LocStrSpan::new(file_mapping, ext_fn_call.underlying(self).unwrap().loc), - ext_fn_call - .underlying(self) - .unwrap() - .body - .as_ref() - .map(|body| LocStrSpan::new(file_mapping, body.loc())), - ) - } else { - let fn_call = ctx.associated_fn(self).unwrap(); - ( - LocStrSpan::new(file_mapping, fn_call.underlying(self).unwrap().loc), - fn_call - .underlying(self) - .unwrap() - .body - .as_ref() - .map(|body| LocStrSpan::new(file_mapping, body.loc())), - ) - }; - - let mut ba: VarBoundAnalysis = if let Some(inherited) = inherited { - let mut new_ba = inherited.clone(); - let ctx_switch = CtxSwitch { - ctx, - func_span, - func_body_span, - killed_loc: ctx - .killed_loc(self) - .unwrap() - .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), - }; - - new_ba.spanned_ctx_info.insert(ctx_switch); - - new_ba - } else { - VarBoundAnalysis { - ctx, - var_name: var_name.to_string(), - var_display_name: cvar.display_name(self).unwrap(), - func_span, - var_def: ( - LocStrSpan::new(file_mapping, curr.loc(self).unwrap()), - if !is_subctx { - curr.range(self).unwrap() - } else { - None - }, - ), - bound_changes: vec![], - report_config, - storage: curr.underlying(self).unwrap().storage.clone(), - ctx_killed: ctx - .killed_loc(self) - .unwrap() - .map(|(loc, kind)| (LocStrSpan::new(file_mapping, loc), kind)), - ..Default::default() - } - }; - - if let Some(curr_range) = curr.ref_range(self).unwrap() { - let mut cr_min = curr_range.evaled_range_min(self).unwrap(); - let mut cr_max = curr_range.evaled_range_max(self).unwrap(); - let mut cr_excl = curr_range.range_exclusions(); - while let Some(next) = curr.next_version(self) { - if let Some(next_range) = next.ref_range(self).unwrap() { - let nr_min = next_range.evaled_range_min(self).unwrap(); - let nr_max = next_range.evaled_range_max(self).unwrap(); - let nr_excl = &next_range.exclusions; - - // check if there was a bound change - if report_config.show_all_lines - || nr_min != cr_min - || nr_max != cr_max - || nr_excl != &cr_excl - { - cr_min = nr_min; - cr_max = nr_max; - cr_excl = nr_excl.to_vec(); - let new = ( - LocStrSpan::new(file_mapping, next.loc(self).unwrap()), - next_range.into_owned(), - ); - if !ba.bound_changes.contains(&new) { - ba.bound_changes.push(new); - } - } - } - - if next == cvar { - break; - } else { - curr = next; - } - } - } - - ba - } -} diff --git a/src/context/analyzers/var_analyzer/report_display.rs b/src/context/analyzers/var_analyzer/report_display.rs deleted file mode 100644 index 66210180..00000000 --- a/src/context/analyzers/var_analyzer/report_display.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::analyzers::{LocStrSpan, ReportDisplay}; -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use shared::analyzer::GraphLike; - -use crate::analyzers::var_analyzer::*; - -impl ReportDisplay for VarBoundAnalysis { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Bounds", Color::Cyan) - } - fn msg(&self, analyzer: &impl GraphLike) -> String { - format!( - "Bounds for {} in {}:", - self.var_display_name, - self.ctx.underlying(analyzer).unwrap().path - ) - } - fn labels(&self, analyzer: &impl GraphLike) -> Vec> { - let mut labels = if self.report_config.show_initial_bounds { - if let Some(init_item) = self.init_item(analyzer) { - vec![init_item.into()] - } else { - vec![] - } - } else { - vec![] - }; - - labels.extend( - self.bound_changes - .iter() - .enumerate() - .map(|(i, bound_change)| { - let (parts, unsat) = - range_parts(analyzer, &self.report_config, &bound_change.1); - AnalysisItem { - init: false, - name: self.var_display_name.clone(), - loc: bound_change.0.clone(), - order: i as i32, - storage: self.storage.clone(), - ctx: self.ctx, - ctx_conditionals: self.conditionals(analyzer), - parts, - unsat, - } - .into() - }) - .collect::>(), - ); - - labels - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let mut report = Report::build( - self.report_kind(), - self.var_def.0.source(), - self.var_def.0.start(), - ) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - - report.add_labels(self.labels(analyzer)); - - if let Some((killed_span, kind)) = &self.ctx_killed { - report = report.with_label( - Label::new(killed_span.clone()) - .with_message(kind.analysis_str().fg(Color::Red)) - .with_color(Color::Red), - ); - } - - let reports = vec![report.finish()]; - - // if self.report_config.show_subctxs { - // reports.extend( - // self.sub_ctxs - // .iter() - // .flat_map(|analysis| analysis.reports(analyzer)) - // .collect::>(), - // ); - // } - - reports - } - - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = self.reports(analyzer); - reports.into_iter().for_each(|report| { - report.print(&mut src).unwrap(); - }); - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = self.reports(analyzer); - reports.into_iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} diff --git a/src/context/exprs/array.rs b/src/context/exprs/array.rs deleted file mode 100644 index 2acc730b..00000000 --- a/src/context/exprs/array.rs +++ /dev/null @@ -1,183 +0,0 @@ -use crate::context::ExprErr; -use crate::context::IntoExprErr; -use crate::{ - context::exprs::{member_access::MemberAccess, require::Require}, - Builtin, ContextBuilder, Edge, Node, VarType, -}; -use shared::{analyzer::AnalyzerLike, context::*, range::elem::RangeOp}; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::{Expression, Loc}; - -impl Array for T where T: AnalyzerLike + Sized {} -pub trait Array: AnalyzerLike + Sized { - /// Gets the array type - #[tracing::instrument(level = "trace", skip_all)] - fn array_ty(&mut self, ty_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - self.parse_ctx_expr(ty_expr, ctx)?; - self.apply_to_edges(ctx, ty_expr.loc(), &|analyzer, ctx, loc| { - if let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_ty(ctx, ty_expr, ret) - } else { - Err(ExprErr::NoLhs( - loc, - "No array specified for getting array type".to_string(), - )) - } - }) - } - - fn match_ty( - &mut self, - ctx: ContextNode, - ty_expr: &Expression, - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(inner_ty) | ExprRet::SingleLiteral(inner_ty) => { - if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { - let dyn_b = Builtin::Array(var_type); - if let Some(idx) = self.builtins().get(&dyn_b) { - ctx.push_expr(ExprRet::Single(*idx), self) - .into_expr_err(ty_expr.loc())?; - } else { - let idx = self.add_node(Node::Builtin(dyn_b.clone())); - self.builtins_mut().insert(dyn_b, idx); - ctx.push_expr(ExprRet::Single(idx), self) - .into_expr_err(ty_expr.loc())?; - } - Ok(()) - } else { - Err(ExprErr::ArrayTy(ty_expr.loc(), "Expected to be able to convert to a var type from an index to determine array type. This is a bug. Please report it at github.com/nascentxyz/pyrometer.".to_string())) - } - } - ExprRet::Multi(inner) => { - inner - .into_iter() - .map(|i| self.match_ty(ctx, ty_expr, i)) - .collect::, ExprErr>>()?; - Ok(()) - } - ExprRet::CtxKilled(kind) => { - ctx.kill(self, ty_expr.loc(), kind) - .into_expr_err(ty_expr.loc())?; - Ok(()) - } - ExprRet::Null => Ok(()), - } - } - - /// Indexes into an array - #[tracing::instrument(level = "trace", skip_all)] - fn index_into_array( - &mut self, - loc: Loc, - ty_expr: &Expression, - index_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!("Indexing into array"); - self.parse_ctx_expr(index_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(index_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Could not find the index variable".to_string())) - }; - if matches!(index_tys, ExprRet::CtxKilled(_)) { - ctx.push_expr(index_tys, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(ty_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(inner_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Could not find the array".to_string())) - }; - if matches!(inner_tys, ExprRet::CtxKilled(_)) { - ctx.push_expr(inner_tys, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.index_into_array_inner( - ctx, - loc, - inner_tys.flatten(), - index_tys.clone().flatten(), - ) - }) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn index_into_array_inner( - &mut self, - ctx: ContextNode, - loc: Loc, - inner_paths: ExprRet, - index_paths: ExprRet, - ) -> Result<(), ExprErr> { - match (inner_paths, index_paths) { - (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), - (_, ExprRet::CtxKilled(kind)) => { - ctx.kill(self, loc, kind).into_expr_err(loc) - } - (ExprRet::CtxKilled(kind), _) => { - ctx.kill(self, loc, kind).into_expr_err(loc) - } - (ExprRet::Single(parent), ExprRet::Single(index)) | (ExprRet::Single(parent), ExprRet::SingleLiteral(index)) => { - let index = ContextVarNode::from(index).latest_version(self); - let parent = ContextVarNode::from(parent).latest_version(self); - let idx = self.advance_var_in_ctx(index, loc, ctx)?; - if !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { - let len_var = self.tmp_length(parent, ctx, loc).latest_version(self); - self.handle_require_inner( - ctx, - loc, - &ExprRet::Single(len_var.latest_version(self).into()), - &ExprRet::Single(idx.latest_version(self).into()), - RangeOp::Gt, - RangeOp::Lt, - (RangeOp::Lte, RangeOp::Gte), - )?; - } - - let name = format!("{}[{}]", parent.name(self).into_expr_err(loc)?, index.name(self).into_expr_err(loc)?); - - if let Some(index_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - let index_var = index_var.latest_version(self); - let index_var = self.advance_var_in_ctx(index_var, loc, ctx)?; - ctx.push_expr(ExprRet::Single(index_var.into()), self).into_expr_err(loc)?; - Ok(()) - } else { - let ty = parent.ty(self).into_expr_err(loc)?.clone(); - let ty = ty.get_index_dynamic_ty(index, self).into_expr_err(loc)?; - let index_var = ContextVar { - loc: Some(loc), - name: name.clone(), - display_name: format!( - "{}[{}]", - parent.display_name(self).into_expr_err(loc)?, - index.display_name(self).into_expr_err(loc)? - ), - storage: parent.storage(self).into_expr_err(loc)?.clone(), - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - }; - - let idx_node = self.add_node(Node::ContextVar(index_var)); - self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); - self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; - self.add_edge(index, idx_node, Edge::Context(ContextEdge::Index)); - - ctx.push_expr(ExprRet::Single(idx_node), self).into_expr_err(loc)?; - Ok(()) - } - } - e => Err(ExprErr::ArrayIndex(loc, format!("Expected single expr evaluation of index expression, but was: {e:?}. This is a bug. Please report it at github.com/nascentxyz/pyrometer."))), - } - } -} diff --git a/src/context/exprs/bin_op.rs b/src/context/exprs/bin_op.rs deleted file mode 100644 index 22804398..00000000 --- a/src/context/exprs/bin_op.rs +++ /dev/null @@ -1,797 +0,0 @@ -use crate::context::exprs::require::Require; -use crate::context::exprs::IntoExprErr; -use crate::context::{ContextBuilder, ExprErr}; -use ethers_core::types::{I256, U256}; - -use shared::range::elem::RangeElem; -use shared::range::elem_ty::RangeExpr; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::{BuiltInNode, Builtin, Concrete, VarType}, - range::{ - elem::RangeOp, - elem_ty::{Dynamic, Elem}, - Range, RangeEval, SolcRange, - }, - Edge, Node, -}; - -use solang_parser::pt::{Expression, Loc}; - -impl BinOp for T where T: AnalyzerLike + Sized {} -pub trait BinOp: AnalyzerLike + Sized { - /// Evaluate and execute a binary operation expression - #[tracing::instrument(level = "trace", skip_all)] - fn op_expr( - &mut self, - loc: Loc, - lhs_expr: &Expression, - rhs_expr: &Expression, - ctx: ContextNode, - op: RangeOp, - assign: bool, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(rhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Binary operation had no right hand side".to_string())) - }; - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let rhs_paths = rhs_paths.flatten(); - let rhs_ctx = ctx; - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, format!("Binary operation had no left hand side, Expr: {lhs_expr:#?}, rhs ctx: {}, curr ctx: {}", rhs_ctx.path(analyzer), ctx.path(analyzer)))) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let lhs_paths = lhs_paths.flatten(); - analyzer.op_match(ctx, loc, &lhs_paths, &rhs_paths, op, assign) - }) - }) - } - - fn op_match( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: &ExprRet, - op: RangeOp, - assign: bool, - ) -> Result<(), ExprErr> { - match (lhs_paths, rhs_paths) { - (ExprRet::Null, _) => Err(ExprErr::NoLhs( - loc, - "No left hand side provided for binary operation".to_string(), - )), - (_, ExprRet::Null) => Err(ExprErr::NoRhs( - loc, - "No right hand side provided for binary operation".to_string(), - )), - (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - lhs_cvar.try_increase_size(self).into_expr_err(loc)?; - rhs_cvar.try_increase_size(self).into_expr_err(loc)?; - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { - ContextVarNode::from(*lhs) - .cast_from(&ContextVarNode::from(*rhs), self) - .into_expr_err(loc)?; - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { - ContextVarNode::from(*rhs) - .cast_from(&ContextVarNode::from(*lhs), self) - .into_expr_err(loc)?; - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (lhs @ ExprRet::Single(..), ExprRet::Multi(rhs_sides)) => { - rhs_sides - .iter() - .map(|expr_ret| self.op_match(ctx, loc, lhs, expr_ret, op, assign)) - .collect::, ExprErr>>()?; - Ok(()) - } - (ExprRet::Multi(lhs_sides), rhs @ ExprRet::Single(..)) => { - lhs_sides - .iter() - .map(|expr_ret| self.op_match(ctx, loc, expr_ret, rhs, op, assign)) - .collect::, ExprErr>>()?; - Ok(()) - } - (_, ExprRet::CtxKilled(kind)) => ctx.kill(self, loc, *kind).into_expr_err(loc), - (ExprRet::CtxKilled(kind), _) => ctx.kill(self, loc, *kind).into_expr_err(loc), - (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled combination in binop: {lhs_sides:?} {rhs_sides:?}"), - )), - (l, r) => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled combination in binop: {l:?} {r:?}"), - )), - } - } - - /// Execute a binary operation after parsing the expressions - #[tracing::instrument(level = "trace", skip_all)] - fn op( - &mut self, - loc: Loc, - lhs_cvar: ContextVarNode, - rhs_cvar: ContextVarNode, - ctx: ContextNode, - op: RangeOp, - assign: bool, - ) -> Result { - tracing::trace!( - "binary op: {} {} {}, assign: {}", - lhs_cvar.display_name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.display_name(self).into_expr_err(loc)?, - assign - ); - - let unchecked = match op { - RangeOp::Add(u) | RangeOp::Sub(u) | RangeOp::Mul(u) | RangeOp::Div(u) => u, - _ => false, - }; - - let new_lhs = if assign { - self.advance_var_in_ctx(lhs_cvar, loc, ctx)? - } else { - let mut new_lhs_underlying = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} {} {})", - ctx.new_tmp(self).into_expr_err(loc)?, - lhs_cvar.name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.name(self).into_expr_err(loc)? - ), - display_name: format!( - "({} {} {})", - lhs_cvar.display_name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.display_name(self).into_expr_err(loc)? - ), - storage: None, - is_tmp: true, - is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)? - || rhs_cvar.is_symbolic(self).into_expr_err(loc)?, - is_return: false, - tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), - ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), - }; - - // will potentially mutate the ty from concrete to builtin with a concrete range - new_lhs_underlying - .ty - .concrete_to_builtin(self) - .into_expr_err(loc)?; - - let new_var = self.add_node(Node::ContextVar(new_lhs_underlying)); - ctx.add_var(new_var.into(), self).into_expr_err(loc)?; - self.add_edge(new_var, ctx, Edge::Context(ContextEdge::Variable)); - ContextVarNode::from(new_var) - }; - - let mut new_rhs = rhs_cvar.latest_version(self); - - let expr = Elem::Expr(RangeExpr::::new( - Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), - op, - Elem::from(Dynamic::new(rhs_cvar.latest_version(self).into())), - )); - - // TODO: change to only hit this path if !uncheck - - // TODO: If one of lhs_cvar OR rhs_cvar are not symbolic, - // apply the requirement on the symbolic expression side instead of - // ignoring the case where - - // if lhs_cvar.is_symbolic(self) && new_rhs.is_symbolic(self) { - if !unchecked { - match op { - RangeOp::Div(..) | RangeOp::Mod => { - if new_rhs.is_const(self).into_expr_err(loc)? { - if new_rhs - .evaled_range_min(self) - .into_expr_err(loc)? - .expect("No range?") - .range_eq(&Elem::from(Concrete::from(U256::zero()))) - { - let res = ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc); - let _ = self.add_if_err(res); - - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { - let tmp_rhs = self.advance_var_in_ctx(new_rhs, loc, ctx)?; - let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); - let var = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero_node.into(), - self, - ); - let zero_node = self.add_node(Node::ContextVar(var.into_expr_err(loc)?)); - - if self - .require( - tmp_rhs, - zero_node.into(), - ctx, - loc, - RangeOp::Neq, - RangeOp::Eq, - (RangeOp::Eq, RangeOp::Neq), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} != 0)", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} != 0)", - tmp_rhs.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - new_lhs, - RangeOp::Gt, - Some(zero_node.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - - let range = tmp_rhs - .ref_range(self) - .into_expr_err(loc)? - .expect("No range?"); - if range.min_is_negative(self).into_expr_err(loc)? { - let mut range_excls = range.range_exclusions(); - let excl = Elem::from(Concrete::from(I256::zero())); - if !range_excls.contains(&excl) { - range_excls.push(excl); - } - tmp_rhs - .set_range_exclusions(self, range_excls) - .into_expr_err(loc)?; - } else { - // the new min is max(1, rhs.min) - let min = Elem::max( - Elem::from(Dynamic::new(new_rhs.into())), - // tmp_rhs - // .range_min(self) - // .into_expr_err(loc)? - // .unwrap_or_else(|| { - // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) - // }), - Elem::from(Concrete::from(U256::from(1))).cast( - Elem::from(Dynamic::new(tmp_rhs.into())), // .range_min(self) - // .into_expr_err(loc)? - // .expect("No range minimum?"), - ), - ); - - tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; - new_rhs = tmp_rhs; - } - } - } - RangeOp::Sub(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_const(self).into_expr_err(loc)? { - if !lhs_cvar.is_int(self).into_expr_err(loc)? { - if let (Some(lmax), Some(rmin)) = ( - lhs_cvar.evaled_range_max(self).into_expr_err(loc)?, - rhs_cvar.evaled_range_min(self).into_expr_err(loc)?, - ) { - if matches!( - lmax.range_ord(&rmin), - Some(std::cmp::Ordering::Less) - | Some(std::cmp::Ordering::Equal) - ) { - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } - } - } else if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - if self - .require( - tmp_lhs, - new_rhs, - ctx, - loc, - RangeOp::Gte, - RangeOp::Lte, - (RangeOp::Lte, RangeOp::Gte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - // the new min is max(lhs.min, rhs.min) - let min = Elem::max( - Elem::from(Dynamic::new(lhs_cvar.into())), - // .range_min(self) - // .into_expr_err(loc)? - // .unwrap_or_else(|| { - // panic!( - // "No range minimum: {:?}", - // tmp_lhs.ty(self).unwrap().as_dot_str(self) - // ) - // }), - Elem::from(rhs_cvar), - ); - tmp_lhs.set_range_min(self, min).into_expr_err(loc)?; - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} >= {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} >= {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Gte, - Some(new_rhs), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - } - } - RangeOp::Add(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - - // the new max is min(lhs.max, (2**256 - rhs.min)) - let max = Elem::min( - Elem::from(Dynamic::new(lhs_cvar.into())), - // .range_max(self) - // .into_expr_err(loc)? - // .expect("No range max?"), - Elem::from(Concrete::from(U256::MAX)) - Elem::from(rhs_cvar), - ); - - tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; - - let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); - let tmp_max = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - max_node.into(), - self, - ); - let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); - - let tmp_rhs = self.op( - loc, - max_node.into(), - new_rhs, - ctx, - RangeOp::Sub(false), - false, - )?; - - if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { - return Ok(tmp_rhs); - } - - let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; - - if self - .require( - tmp_lhs, - tmp_rhs.into(), - ctx, - loc, - RangeOp::Lte, - RangeOp::Gte, - (RangeOp::Gte, RangeOp::Lte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} <= 2**256 - 1 - {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} <= 2**256 - 1 - {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Lte, - Some(tmp_rhs.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - } - } - RangeOp::Mul(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - - // the new max is min(lhs.max, (2**256 / max(1, rhs.min))) - let max = Elem::min( - Elem::from(Dynamic::new(lhs_cvar.into())), - // .range_max(self) - // .into_expr_err(loc)? - // .expect("No range max?"), - Elem::from(Concrete::from(U256::MAX)) - / Elem::max( - Elem::from(Concrete::from(U256::from(1))), - Elem::from(rhs_cvar), - ), - ); - - tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; - - let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); - let tmp_max = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - max_node.into(), - self, - ); - let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); - - let tmp_rhs = - self.op(loc, max_node.into(), new_rhs, ctx, RangeOp::Div(true), true)?; - - if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { - return Ok(tmp_rhs); - } - - let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; - - if self - .require( - tmp_lhs, - tmp_rhs.into(), - ctx, - loc, - RangeOp::Lte, - RangeOp::Gte, - (RangeOp::Gte, RangeOp::Lte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} <= (2**256 - 1) / {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} <= (2**256 - 1) / {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Lte, - Some(tmp_rhs.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - } - } - RangeOp::Exp => { - if new_rhs.is_const(self).into_expr_err(loc)? { - if matches!( - new_rhs - .evaled_range_min(self) - .into_expr_err(loc)? - .expect("No range") - .range_ord(&Elem::from(Concrete::from(U256::zero()))), - Some(std::cmp::Ordering::Less) - ) { - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { - let tmp_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; - // the new min is max(lhs.min, rhs.min) - let min = Elem::max( - Elem::from(Dynamic::new(rhs_cvar.into())), - // .range_min(self) - // .into_expr_err(loc)? - // .expect("No range minimum?"), - Elem::from(Concrete::from(U256::zero())), - ); - - tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; - - let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); - let tmp_zero = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero_node.into(), - self, - ); - let zero_node = - self.add_node(Node::ContextVar(tmp_zero.into_expr_err(loc)?)); - - if self - .require( - tmp_rhs, - zero_node.into(), - ctx, - loc, - RangeOp::Gte, - RangeOp::Lte, - (RangeOp::Lte, RangeOp::Gte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} >= 0)", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} >= 0)", - tmp_rhs.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_rhs, - RangeOp::Gte, - Some(zero_node.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - new_rhs = tmp_rhs; - } - } - _ => {} - } - } - - // let lhs_range = if let Some(lhs_range) = new_lhs.range(self).into_expr_err(loc)? { - // lhs_range - // } else { - // new_rhs - // .range(self) - // .into_expr_err(loc)? - // .expect("Neither lhs nor rhs had a usable range") - // }; - - // let func = SolcRange::dyn_fn_from_op(op); - // let new_range = func(lhs_range, new_rhs); - new_lhs - .set_range_min(self, expr.clone()) - .into_expr_err(loc)?; - new_lhs.set_range_max(self, expr).into_expr_err(loc)?; - - // last ditch effort to prevent exponentiation from having a minimum of 1 instead of 0. - // if the lhs is 0 check if the rhs is also 0, otherwise set minimum to 0. - if matches!(op, RangeOp::Exp) { - if let (Some(old_lhs_range), Some(rhs_range)) = ( - lhs_cvar - .latest_version(self) - .ref_range(self) - .into_expr_err(loc)?, - new_rhs.ref_range(self).into_expr_err(loc)?, - ) { - let zero = Elem::from(Concrete::from(U256::zero())); - let zero_range = SolcRange::new(zero.clone(), zero.clone(), vec![]); - // We have to check if the the lhs and the right hand side contain the zero range. - // If they both do, we have to set the minimum to zero due to 0**0 = 1, but 0**x = 0. - // This is technically a slight widening of the interval and could be improved. - if old_lhs_range.contains(&zero_range, self) - && rhs_range.contains(&zero_range, self) - { - new_lhs.set_range_min(self, zero).into_expr_err(loc)?; - } - } - } - Ok(ExprRet::Single(new_lhs.into())) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn bit_not( - &mut self, - loc: Loc, - lhs_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(lhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) - }; - - if matches!(lhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.bit_not_inner(ctx, loc, lhs.flatten()) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn bit_not_inner( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_expr: ExprRet, - ) -> Result<(), ExprErr> { - match lhs_expr { - ExprRet::CtxKilled(kind) => { - ctx.kill(self, loc, kind).into_expr_err(loc)?; - ctx.push_expr(lhs_expr, self).into_expr_err(loc)?; - Ok(()) - } - ExprRet::SingleLiteral(lhs) => { - // TODO: try to pop from the stack and if there is a single element there - // use it as a type hint, then place it back on the stack - ContextVarNode::from(lhs) - .try_increase_size(self) - .into_expr_err(loc)?; - self.bit_not_inner(ctx, loc, ExprRet::Single(lhs))?; - Ok(()) - } - ExprRet::Single(lhs) => { - let lhs_cvar = ContextVarNode::from(lhs); - tracing::trace!( - "bitwise not: {}", - lhs_cvar.display_name(self).into_expr_err(loc)? - ); - let out_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}(~{})", - ctx.new_tmp(self).into_expr_err(loc)?, - lhs_cvar.name(self).into_expr_err(loc)?, - ), - display_name: format!("~{}", lhs_cvar.display_name(self).into_expr_err(loc)?,), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::BitNot, None)), - is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, - is_return: false, - ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), - }; - - let expr = Elem::Expr(RangeExpr::::new( - Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), - RangeOp::BitNot, - Elem::Null, - )); - - let out_var = ContextVarNode::from(self.add_node(Node::ContextVar(out_var))); - - out_var - .set_range_min(self, expr.clone()) - .into_expr_err(loc)?; - out_var.set_range_max(self, expr).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(out_var.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(f) => Err(ExprErr::MultiNot( - loc, - format!("Multiple elements in bitwise not expression: {f:?}"), - )), - ExprRet::Null => Err(ExprErr::NoRhs( - loc, - "No right hand side in `not` expression".to_string(), - )), - } - } -} diff --git a/src/context/exprs/cmp.rs b/src/context/exprs/cmp.rs deleted file mode 100644 index f7fe03a1..00000000 --- a/src/context/exprs/cmp.rs +++ /dev/null @@ -1,469 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::ContextBuilder; -use shared::analyzer::GraphError; - -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::*, - range::{ - elem::{RangeElem, RangeOp}, - elem_ty::{Elem, RangeConcrete, RangeExpr}, - Range, SolcRange, - }, - Node, -}; - -use solang_parser::pt::{Expression, Loc}; -use std::cmp::Ordering; - -impl Cmp for T where T: AnalyzerLike + Sized {} -pub trait Cmp: AnalyzerLike + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn not(&mut self, loc: Loc, lhs_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - self.parse_ctx_expr(lhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) - }; - - if matches!(lhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.not_inner(ctx, loc, lhs.flatten()) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn not_inner(&mut self, ctx: ContextNode, loc: Loc, lhs_expr: ExprRet) -> Result<(), ExprErr> { - match lhs_expr { - ExprRet::CtxKilled(kind) => { - ctx.kill(self, loc, kind).into_expr_err(loc)?; - ctx.push_expr(lhs_expr, self).into_expr_err(loc)?; - Ok(()) - } - ExprRet::Single(lhs) | ExprRet::SingleLiteral(lhs) => { - let lhs_cvar = ContextVarNode::from(lhs); - tracing::trace!("not: {}", lhs_cvar.display_name(self).into_expr_err(loc)?); - let range = self.not_eval(ctx, loc, lhs_cvar)?; - let out_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}(!{})", - ctx.new_tmp(self).into_expr_err(loc)?, - lhs_cvar.name(self).into_expr_err(loc)?, - ), - display_name: format!("!{}", lhs_cvar.display_name(self).into_expr_err(loc)?,), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Not, None)), - is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - Some(range), - ), - }; - - ctx.push_expr( - ExprRet::Single(self.add_node(Node::ContextVar(out_var))), - self, - ) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(f) => Err(ExprErr::MultiNot( - loc, - format!("Multiple elements in not expression: {f:?}"), - )), - ExprRet::Null => Err(ExprErr::NoRhs( - loc, - "No right hand side in `not` expression".to_string(), - )), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn cmp( - &mut self, - loc: Loc, - lhs_expr: &Expression, - op: RangeOp, - rhs_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.parse_ctx_expr(rhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Cmp operation had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Cmp operation had no left hand side".to_string())) - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.cmp_inner(ctx, loc, &lhs_paths.flatten(), op, &rhs_paths) - }) - }) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn cmp_inner( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_paths: &ExprRet, - op: RangeOp, - rhs_paths: &ExprRet, - ) -> Result<(), ExprErr> { - match (lhs_paths, rhs_paths) { - (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), - (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { - ContextVarNode::from(*lhs) - .literal_cast_from(&ContextVarNode::from(*rhs), self) - .into_expr_err(loc)?; - self.cmp_inner(ctx, loc, &ExprRet::Single(*rhs), op, rhs_paths) - } - (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - lhs_cvar.try_increase_size(self).into_expr_err(loc)?; - rhs_cvar.try_increase_size(self).into_expr_err(loc)?; - self.cmp_inner( - ctx, - loc, - &ExprRet::Single(lhs_cvar.into()), - op, - &ExprRet::Single(rhs_cvar.into()), - ) - } - (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { - ContextVarNode::from(*rhs) - .literal_cast_from(&ContextVarNode::from(*lhs), self) - .into_expr_err(loc)?; - self.cmp_inner(ctx, loc, lhs_paths, op, &ExprRet::Single(*rhs)) - } - (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs); - let rhs_cvar = ContextVarNode::from(*rhs); - tracing::trace!( - "cmp: {} {} {}", - lhs_cvar.display_name(self).unwrap(), - op.to_string(), - rhs_cvar.display_name(self).unwrap() - ); - let range = { - let elem = Elem::Expr(RangeExpr { - minimized: None, - maximized: None, - lhs: Box::new(Elem::from(lhs_cvar)), - op, - rhs: Box::new(Elem::from(rhs_cvar)), - }); - - let exclusions = lhs_cvar - .ref_range(self) - .into_expr_err(loc)? - .expect("No lhs range") - .range_exclusions(); - SolcRange::new(elem.clone(), elem, exclusions) - }; - // println!("{:?}", range.evaled_range_max(self)); - // println!("{:?}", range.evaled_range_min(self)); - - // println!( - // "cmp: {} {} {}, [{}, {}], [{}, {}] ", - // lhs_cvar.name(self).into_expr_err(loc)?, - // op.to_string(), - // rhs_cvar.name(self).into_expr_err(loc)?, - // lhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, - // lhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s, - // rhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, - // rhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s - // ); - - let out_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} {} {})", - ctx.new_tmp(self).into_expr_err(loc)?, - lhs_cvar.name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "{} {} {}", - lhs_cvar.display_name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - is_symbolic: ContextVarNode::from(*lhs) - .is_symbolic(self) - .into_expr_err(loc)? - || ContextVarNode::from(*rhs) - .is_symbolic(self) - .into_expr_err(loc)?, - is_return: false, - tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - Some(range), - ), - }; - - ctx.push_expr( - ExprRet::Single(self.add_node(Node::ContextVar(out_var))), - self, - ) - .into_expr_err(loc) - } - (l @ ExprRet::Single(_lhs), ExprRet::Multi(rhs_sides)) => { - rhs_sides - .iter() - .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, l, op, expr_ret))?; - Ok(()) - } - (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_)) => { - lhs_sides - .iter() - .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, expr_ret, op, r))?; - Ok(()) - } - (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( - |(lhs_expr_ret, rhs_expr_ret)| { - self.cmp_inner(ctx, loc, lhs_expr_ret, op, rhs_expr_ret) - }, - )?; - Ok(()) - } else { - rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.cmp_inner(ctx, loc, lhs_paths, op, rhs_expr_ret) - })?; - Ok(()) - } - } - (e, f) => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled combination in `cmp`: {e:?} {f:?}"), - )), - } - } - - fn not_eval( - &self, - _ctx: ContextNode, - loc: Loc, - lhs_cvar: ContextVarNode, - ) -> Result { - if let Some(lhs_range) = lhs_cvar.range(self).into_expr_err(loc)? { - let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; - - // invert - if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?) { - let val = Elem::Expr(RangeExpr { - minimized: None, - maximized: None, - lhs: Box::new(lhs_range.range_min().into_owned()), - op: RangeOp::Not, - rhs: Box::new(Elem::Null), - }); - - return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions)); - } - } - - let min = RangeConcrete { - val: Concrete::Bool(false), - loc, - }; - - let max = RangeConcrete { - val: Concrete::Bool(true), - loc, - }; - Ok(SolcRange::new( - Elem::Concrete(min), - Elem::Concrete(max), - vec![], - )) - } - - fn range_eval( - &self, - _ctx: ContextNode, - lhs_cvar: ContextVarNode, - rhs_cvar: ContextVarNode, - op: RangeOp, - ) -> Result { - if let Some(lhs_range) = lhs_cvar.ref_range(self)? { - if let Some(rhs_range) = rhs_cvar.ref_range(self)? { - match op { - RangeOp::Lt => { - // if lhs_max < rhs_min, we know this cmp will evaluate to - // true - - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { - return Ok(true.into()); - } - - // Similarly if lhs_min >= rhs_max, we know this cmp will evaluate to - // false - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max) { - Some(Ordering::Greater) => { - return Ok(false.into()); - } - Some(Ordering::Equal) => { - return Ok(false.into()); - } - _ => {} - } - } - RangeOp::Gt => { - // if lhs_min > rhs_max, we know this cmp will evaluate to - // true - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { - return Ok(true.into()); - } - - // if lhs_max <= rhs_min, we know this cmp will evaluate to - // false - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min) { - Some(Ordering::Less) => { - return Ok(false.into()); - } - Some(Ordering::Equal) => { - return Ok(false.into()); - } - _ => {} - } - } - RangeOp::Lte => { - // if lhs_max <= rhs_min, we know this cmp will evaluate to - // true - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min) { - Some(Ordering::Less) => { - return Ok(true.into()); - } - Some(Ordering::Equal) => { - return Ok(true.into()); - } - _ => {} - } - - // Similarly if lhs_min > rhs_max, we know this cmp will evaluate to - // false - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { - return Ok(false.into()); - } - } - RangeOp::Gte => { - // if lhs_min >= rhs_max, we know this cmp will evaluate to - // true - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max) { - Some(Ordering::Greater) => { - return Ok(true.into()); - } - Some(Ordering::Equal) => { - return Ok(true.into()); - } - _ => {} - } - - // if lhs_max < rhs_min, we know this cmp will evaluate to - // false - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { - return Ok(false.into()); - } - } - RangeOp::Eq => { - // if all elems are equal we know its true - // we dont know anything else - let lhs_min = lhs_range.evaled_range_min(self)?; - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let ( - Some(Ordering::Equal), - Some(Ordering::Equal), - Some(Ordering::Equal), - ) = ( - // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max), - // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min), - // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max), - ) { - return Ok(true.into()); - } - } - RangeOp::Neq => { - // if all elems are equal we know its true - // we dont know anything else - let lhs_min = lhs_range.evaled_range_min(self)?; - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let ( - Some(Ordering::Equal), - Some(Ordering::Equal), - Some(Ordering::Equal), - ) = ( - // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max), - // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min), - // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max), - ) { - return Ok(false.into()); - } - } - e => unreachable!("Cmp with strange op: {:?}", e), - } - Ok(SolcRange::default_bool()) - } else { - Ok(SolcRange::default_bool()) - } - } else { - Ok(SolcRange::default_bool()) - } - } -} diff --git a/src/context/exprs/cond_op.rs b/src/context/exprs/cond_op.rs deleted file mode 100644 index 3938a0d3..00000000 --- a/src/context/exprs/cond_op.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{exprs::Require, AnalyzerLike, ContextBuilder}; -use shared::{context::*, Edge, Node, NodeIdx}; - -use solang_parser::pt::CodeLocation; -use solang_parser::pt::{Expression, Loc, Statement}; - -impl CondOp for T where T: AnalyzerLike + Require + Sized {} -pub trait CondOp: AnalyzerLike + Require + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn cond_op_stmt( - &mut self, - loc: Loc, - if_expr: &Expression, - true_stmt: &Statement, - false_stmt: &Option>, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let tctx = - Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) - .into_expr_err(loc)?; - let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); - let fctx = - Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) - .into_expr_err(loc)?; - let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); - ctx.set_child_fork(true_subctx, false_subctx, analyzer) - .into_expr_err(loc)?; - let ctx_fork = analyzer.add_node(Node::ContextFork); - analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); - analyzer.add_edge( - NodeIdx::from(true_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - NodeIdx::from(false_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - - // we want to check if the true branch is possible to take - analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; - let mut true_killed = false; - if true_subctx.is_killed(analyzer).into_expr_err(loc)? { - // it was killed, therefore true branch is unreachable. - // since it is unreachable, we want to not create - // unnecessary subcontexts - true_killed = true; - } - - // we want to check if the false branch is possible to take - analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; - let mut false_killed = false; - if false_subctx.is_killed(analyzer).into_expr_err(loc)? { - // it was killed, therefore true branch is unreachable. - // since it is unreachable, we want to not create - // unnecessary subcontexts - false_killed = true; - } - - match (true_killed, false_killed) { - (true, true) => { - // both have been killed, delete the child and dont process the bodies - ctx.delete_child(analyzer).into_expr_err(loc)?; - } - (true, false) => { - // the true context has been killed, delete child, process the false fork expression - // in the parent context and parse the false body - ctx.delete_child(analyzer).into_expr_err(loc)?; - analyzer.false_fork_if_cvar(if_expr.clone(), ctx)?; - if let Some(false_stmt) = false_stmt { - return analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); - Ok(()) - }); - } - } - (false, true) => { - // the false context has been killed, delete child, process the true fork expression - // in the parent context and parse the true body - ctx.delete_child(analyzer).into_expr_err(loc)?; - analyzer.true_fork_if_cvar(if_expr.clone(), ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement( - true_stmt, - ctx.unchecked(analyzer).into_expr_err(loc)?, - Some(ctx), - ); - Ok(()) - })?; - } - (false, false) => { - // both branches are reachable. process each body - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement( - true_stmt, - ctx.unchecked(analyzer).into_expr_err(loc)?, - Some(ctx), - ); - Ok(()) - })?; - if let Some(false_stmt) = false_stmt { - return analyzer.apply_to_edges( - false_subctx, - loc, - &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); - Ok(()) - }, - ); - } - } - } - Ok(()) - }) - } - - /// When we have a conditional operator, we create a fork in the context. One side of the fork is - /// if the expression is true, the other is if it is false. - #[tracing::instrument(level = "trace", skip_all)] - fn cond_op_expr( - &mut self, - loc: Loc, - if_expr: &Expression, - true_expr: &Expression, - false_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!("conditional operator"); - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let tctx = - Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) - .into_expr_err(loc)?; - let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); - let fctx = - Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) - .into_expr_err(loc)?; - let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); - ctx.set_child_fork(true_subctx, false_subctx, analyzer) - .into_expr_err(loc)?; - let ctx_fork = analyzer.add_node(Node::ContextFork); - analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); - analyzer.add_edge( - NodeIdx::from(true_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - NodeIdx::from(false_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - - analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_expr(true_expr, ctx) - })?; - - analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_expr(false_expr, ctx) - }) - }) - } - - /// Creates the true_fork cvar (updates bounds assuming its true) - fn true_fork_if_cvar( - &mut self, - if_expr: Expression, - true_fork_ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.apply_to_edges(true_fork_ctx, if_expr.loc(), &|analyzer, ctx, _loc| { - analyzer.handle_require(&[if_expr.clone()], ctx)?; - Ok(()) - }) - } - - /// Creates the false_fork cvar (inverts the expression and sets the bounds assuming its false) - fn false_fork_if_cvar( - &mut self, - if_expr: Expression, - false_fork_ctx: ContextNode, - ) -> Result<(), ExprErr> { - let loc = if_expr.loc(); - let inv_if_expr = self.inverse_expr(if_expr); - self.apply_to_edges(false_fork_ctx, loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(&[inv_if_expr.clone()], ctx)?; - Ok(()) - }) - } -} diff --git a/src/context/exprs/env.rs b/src/context/exprs/env.rs deleted file mode 100644 index ba36b1c2..00000000 --- a/src/context/exprs/env.rs +++ /dev/null @@ -1,449 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::FuncCaller; -use crate::context::ExprErr; -use crate::{context::ContextNode, AnalyzerLike}; -use shared::context::ExprRet; -use shared::context::{ContextEdge, ContextVar}; -use shared::nodes::Builtin; -use shared::nodes::Concrete; -use shared::Edge; -use shared::Node; -use solang_parser::pt::Expression; -use solang_parser::pt::Loc; - -use solang_parser::pt::Identifier; - -impl Env for T where T: AnalyzerLike + Sized {} -pub trait Env: AnalyzerLike + Sized { - fn env_variable( - &mut self, - ident: &Identifier, - ctx: ContextNode, - ) -> Result, ExprErr> { - match &*ident.name { - "msg" | "tx" => { - ctx.push_expr(ExprRet::Single(self.msg().into()), self) - .into_expr_err(ident.loc)?; - Ok(Some(())) - } - "block" => { - ctx.push_expr(ExprRet::Single(self.block().into()), self) - .into_expr_err(ident.loc)?; - Ok(Some(())) - } - "abi" => Ok(Some(())), - "_" => { - #[allow(clippy::manual_map)] - if let Some(mod_state) = &ctx - .underlying(self) - .into_expr_err(ident.loc)? - .modifier_state - .clone() - { - self.resume_from_modifier(ctx, mod_state.clone())?; - self.modifier_inherit_return(ctx, mod_state.parent_ctx); - Ok(Some(())) - } else { - Ok(None) - } - } - _e => Ok(None), - } - } - - fn block_access( - &mut self, - loc: Loc, - ctx: ContextNode, - ident_name: &str, - ) -> Result { - let name = format!("block.{}", ident_name); - tracing::trace!("Block Env member access: {}", name); - if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - Ok(ExprRet::Single(attr_var.latest_version(self).into())) - } else { - let (node, name) = match ident_name { - "hash" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.hash { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.blockhash".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Bytes(32)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.blockhash".to_string(); - var.display_name = "block.blockhash".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "basefee" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.basefee { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.basefee".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.basefee".to_string(); - var.display_name = "block.basefee".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "chainid" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.chainid { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.chainid".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.chainid".to_string(); - var.display_name = "block.chainid".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "coinbase" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.coinbase { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.coinbase".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Address); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.coinbase".to_string(); - var.display_name = "block.coinbase".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "difficulty" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.difficulty { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.difficulty".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.difficulty".to_string(); - var.display_name = "block.difficulty".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "gaslimit" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.gaslimit { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.gaslimit".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.gaslimit".to_string(); - var.display_name = "block.gaslimit".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "number" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.number { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.number".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.number".to_string(); - var.display_name = "block.number".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "prevrandao" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.prevrandao { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.prevrandao".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.prevrandao".to_string(); - var.display_name = "block.prevrandao".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "timestamp" => { - if let Some(d) = self.block().underlying(self).into_expr_err(loc)?.timestamp { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "block.timestamp".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "block.timestamp".to_string(); - var.display_name = "block.timestamp".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - e => { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!("Unknown member access on block: {e:?}"), - )) - } - }; - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; - var.name = name.clone(); - var.display_name = name; - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - } - - fn msg_access( - &mut self, - loc: Loc, - ctx: ContextNode, - ident_name: &str, - ) -> Result { - let name = format!("msg.{}", ident_name); - tracing::trace!("Msg Env member access: {}", name); - - if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - Ok(ExprRet::Single(attr_var.latest_version(self).into())) - } else { - let (node, name) = match ident_name { - "data" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.data.clone() { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "msg.data".to_string(), - ) - } else { - let b = Builtin::DynamicBytes; - let node = self.builtin_or_add(b); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "msg.data".to_string(); - var.display_name = "msg.data".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "sender" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.sender { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "msg.sender".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Address); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "msg.sender".to_string(); - var.display_name = "msg.sender".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "sig" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.sig { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "msg.sig".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Bytes(4)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "msg.sig".to_string(); - var.display_name = "msg.sig".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "value" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.value { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "msg.value".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(256)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "msg.value".to_string(); - var.display_name = "msg.value".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "origin" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.origin { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "tx.origin".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Address); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "tx.origin".to_string(); - var.display_name = "tx.origin".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "gasprice" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.gasprice { - let c = Concrete::from(d); - ( - self.add_node(Node::Concrete(c)).into(), - "tx.gasprice".to_string(), - ) - } else { - let node = self.builtin_or_add(Builtin::Uint(64)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.name = "tx.gasprice".to_string(); - var.display_name = "tx.gasprice".to_string(); - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - "gaslimit" => { - if let Some(d) = self.msg().underlying(self).into_expr_err(loc)?.gaslimit { - let c = Concrete::from(d); - (self.add_node(Node::Concrete(c)).into(), "".to_string()) - } else { - let node = self.builtin_or_add(Builtin::Uint(64)); - let mut var = ContextVar::new_from_builtin(loc, node.into(), self) - .into_expr_err(loc)?; - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(cvar)); - } - } - e => { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!("Unknown member access on msg: {e:?}"), - )) - } - }; - - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; - var.name = name.clone(); - var.display_name = name; - var.is_tmp = false; - var.is_symbolic = true; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - } -} diff --git a/src/context/exprs/list.rs b/src/context/exprs/list.rs deleted file mode 100644 index a5fae6e1..00000000 --- a/src/context/exprs/list.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use shared::{analyzer::AnalyzerLike, context::*, nodes::*, Edge, Node}; -use solang_parser::pt::Expression; - -use solang_parser::pt::{Parameter, ParameterList}; - -use solang_parser::pt::Loc; - -impl List for T where T: AnalyzerLike + Sized {} - -pub trait List: AnalyzerLike + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { - params - .iter() - .try_for_each(|(loc, input)| { - if let Some(input) = input { - self.parse_ctx_expr(&input.ty, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - ctx.append_tmp_expr(analyzer.match_ty(ctx, &loc, &ret, input)?, analyzer).into_expr_err(loc) - }) - } else { - // create a dummy var - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.append_tmp_expr(ExprRet::Null, analyzer).into_expr_err(loc) - }) - } - })?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); - }; - ctx.push_expr(ret, analyzer).into_expr_err(loc) - }) - } - - fn match_ty( - &mut self, - ctx: ContextNode, - loc: &Loc, - ty_ret: &ExprRet, - input: &Parameter, - ) -> Result { - match ty_ret { - ExprRet::Null => Ok(ExprRet::Null), - ExprRet::Single(ty) | ExprRet::SingleLiteral(ty) => { - if let Some(input_name) = &input.name { - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let var = ContextVar { - loc: Some(*loc), - name: input_name.to_string(), - display_name: input_name.to_string(), - storage: input.storage.clone(), - is_tmp: false, - is_symbolic: false, - tmp_of: None, - is_return: false, - ty, - }; - let input_node = self.add_node(Node::ContextVar(var)); - ctx.add_var(input_node.into(), self).into_expr_err(*loc)?; - self.add_edge(input_node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(input_node)) - } else { - match self.node(*ty) { - Node::ContextVar(_var) => { - // reference the variable directly, don't create a temporary variable - Ok(ExprRet::Single(*ty)) - } - _ => { - // create a tmp - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let tmp_num = ctx.new_tmp(self).into_expr_err(*loc)?; - let new_lhs_underlying = ContextVar { - loc: Some(*loc), - name: format!("tmp{tmp_num}"), - display_name: format!("tmp{tmp_num}"), - storage: input.storage.clone(), - is_tmp: true, - is_symbolic: false, - tmp_of: None, - is_return: false, - ty, - }; - let input_node = self.add_node(Node::ContextVar(new_lhs_underlying)); - ctx.add_var(input_node.into(), self).into_expr_err(*loc)?; - self.add_edge(input_node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(input_node)) - } - } - } - } - ExprRet::Multi(inner) => Ok(ExprRet::Multi( - inner - .iter() - .map(|i| self.match_ty(ctx, loc, i, input)) - .collect::>()?, - )), - ExprRet::CtxKilled(kind) => Ok(ExprRet::CtxKilled(*kind)), - } - } -} diff --git a/src/context/exprs/literal.rs b/src/context/exprs/literal.rs deleted file mode 100644 index ec8c4b8f..00000000 --- a/src/context/exprs/literal.rs +++ /dev/null @@ -1,226 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::ExprErr; -use ethers_core::types::H256; -use ethers_core::types::I256; -use shared::context::ExprRet; -use shared::nodes::Builtin; -use shared::range::elem_ty::Elem; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::{Concrete, ConcreteNode}, - Edge, Node, -}; -use solang_parser::pt::HexLiteral; -use solang_parser::pt::Identifier; - -use ethers_core::types::{Address, U256}; -use solang_parser::pt::Loc; -use std::str::FromStr; - -impl Literal for T where T: AnalyzerLike + Sized {} - -pub trait Literal: AnalyzerLike + Sized { - fn number_literal( - &mut self, - ctx: ContextNode, - loc: Loc, - integer: &str, - exponent: &str, - negative: bool, - ) -> Result<(), ExprErr> { - let int = U256::from_dec_str(integer).unwrap(); - let val = if !exponent.is_empty() { - let exp = U256::from_dec_str(exponent).unwrap(); - int * U256::from(10).pow(exp) - } else { - int - }; - - let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; - let concrete_node = if negative { - let val = if val == U256::from(2).pow(255.into()) { - // no need to set upper bit - I256::from_raw(val) - } else { - I256::from(-1i32) * I256::from_raw(val) - }; - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Int(size, val)))) - } else { - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Uint(size, val)))) - }; - - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } - - fn rational_number_literal( - &mut self, - ctx: ContextNode, - loc: Loc, - integer: &str, - fraction: &str, - exponent: &str, - _unit: &Option, - ) -> Result<(), ExprErr> { - let int = U256::from_dec_str(integer).unwrap(); - let exp = if !exponent.is_empty() { - U256::from_dec_str(exponent).unwrap() - } else { - U256::from(0) - }; - let fraction_len = fraction.len(); - let fraction_denom = U256::from(10).pow(fraction_len.into()); - let fraction = U256::from_dec_str(fraction).unwrap(); - - let int_elem = Elem::min( - Elem::from(Concrete::from(int)), - Elem::from(Concrete::from(U256::from(1))), - ); - let exp_elem = Elem::from(Concrete::from(exp)); - let rational_range = (Elem::from(Concrete::from(fraction)) - + int_elem * Elem::from(Concrete::from(fraction_denom))) - * Elem::from(Concrete::from(U256::from(10))).pow(exp_elem); - let cvar = - ContextVar::new_from_builtin(loc, self.builtin_or_add(Builtin::Uint(256)).into(), self) - .into_expr_err(loc)?; - let node = ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); - node.set_range_max(self, rational_range.clone()) - .into_expr_err(loc)?; - node.set_range_min(self, rational_range) - .into_expr_err(loc)?; - - ctx.add_var(node, self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - - fn hex_num_literal( - &mut self, - ctx: ContextNode, - loc: Loc, - integer: &str, - negative: bool, - ) -> Result<(), ExprErr> { - let integer: String = integer.chars().filter(|c| *c != '_').collect(); - let val = U256::from_str_radix(&integer, 16).unwrap(); - let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; - let concrete_node = if negative { - let val = I256::from(-1i32) * I256::from_raw(val); - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Int(size, val)))) - } else { - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Uint(size, val)))) - }; - - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } - - fn hex_literals(&mut self, ctx: ContextNode, hexes: &[HexLiteral]) -> Result<(), ExprErr> { - if hexes.len() == 1 { - let mut h = H256::default(); - let mut max = 0; - if let Ok(hex_val) = hex::decode(&hexes[0].hex) { - hex_val.iter().enumerate().for_each(|(i, hex_byte)| { - if *hex_byte != 0x00u8 { - max = i as u8; - } - h.0[i] = *hex_byte; - }); - } - - let concrete_node = - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Bytes(max + 1, h)))); - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(hexes[0].loc, ctx, concrete_node, self) - .into_expr_err(hexes[0].loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(hexes[0].loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(hexes[0].loc)?; - Ok(()) - } else { - let mut h = vec![]; - hexes.iter().for_each(|sub_hex| { - if let Ok(hex_val) = hex::decode(&sub_hex.hex) { - h.extend(hex_val) - } - }); - - let mut loc = hexes[0].loc; - loc.use_end_from(&hexes[hexes.len() - 1].loc); - let concrete_node = - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::DynBytes(h)))); - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } - } - - fn address_literal(&mut self, ctx: ContextNode, loc: Loc, addr: &str) -> Result<(), ExprErr> { - let addr = Address::from_str(addr).unwrap(); - - let concrete_node = - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Address(addr)))); - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } - - fn string_literal(&mut self, ctx: ContextNode, loc: Loc, s: &str) -> Result<(), ExprErr> { - let concrete_node = - ConcreteNode::from(self.add_node(Node::Concrete(Concrete::String(s.to_string())))); - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } - - fn bool_literal(&mut self, ctx: ContextNode, loc: Loc, b: bool) -> Result<(), ExprErr> { - let concrete_node = ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Bool(b)))); - let ccvar = Node::ContextVar( - ContextVar::new_from_concrete(loc, ctx, concrete_node, self).into_expr_err(loc)?, - ); - let node = self.add_node(ccvar); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::SingleLiteral(node), self) - .into_expr_err(loc)?; - Ok(()) - } -} diff --git a/src/context/exprs/member_access.rs b/src/context/exprs/member_access.rs deleted file mode 100644 index b3b68111..00000000 --- a/src/context/exprs/member_access.rs +++ /dev/null @@ -1,1092 +0,0 @@ -use crate::context::exprs::env::Env; -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{context::exprs::variable::Variable, ContextBuilder, NodeIdx}; -use petgraph::{visit::EdgeRef, Direction}; -use shared::range::elem_ty::Elem; -use shared::range::Range; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::*, - range::SolcRange, - {Edge, Node}, -}; -use std::collections::BTreeSet; - -use ethers_core::types::{I256, U256}; - -use solang_parser::pt::{Expression, Identifier, Loc}; - -impl MemberAccess for T where T: AnalyzerLike + Sized {} -pub trait MemberAccess: AnalyzerLike + Sized { - fn visible_member_funcs( - &mut self, - ctx: ContextNode, - loc: Loc, - member_idx: NodeIdx, - ) -> Result, ExprErr> { - let res = match self.node(member_idx) { - Node::ContextVar(cvar) => match &cvar.ty { - VarType::User(TypeNode::Contract(con_node), _) => { - let mut funcs = con_node.linearized_functions(self); - self - .possible_library_funcs(ctx, con_node.0.into()) - .into_iter() - .for_each(|func| { - let name = func.name(self).unwrap(); - funcs.entry(name).or_insert(func); - }); - funcs.values().copied().collect() - }, - VarType::BuiltIn(bn, _) => self - .possible_library_funcs(ctx, bn.0.into()) - .into_iter() - .collect::>(), - VarType::Concrete(cnode) => { - let b = cnode.underlying(self).unwrap().as_builtin(); - let bn = self.builtin_or_add(b); - self.possible_library_funcs(ctx, bn) - .into_iter() - .collect::>() - } - VarType::User(TypeNode::Struct(sn), _) => self - .possible_library_funcs(ctx, sn.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Enum(en), _) => self - .possible_library_funcs(ctx, en.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Ty(ty), _) => self - .possible_library_funcs(ctx, ty.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Func(func_node), _) => self - .possible_library_funcs(ctx, func_node.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Unresolved(n), _) => { - match self.node(*n) { - Node::Unresolved(ident) => { - return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) - } - _ => unreachable!() - } - } - }, - Node::Contract(_) => ContractNode::from(member_idx).funcs(self), - Node::Concrete(_) - | Node::Ty(_) - | Node::Struct(_) - | Node::Function(_) - | Node::Enum(_) - | Node::Builtin(_) => self - .possible_library_funcs(ctx, member_idx) - .into_iter() - .collect::>(), - e => { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!("This type cannot have member functions: {:?}", e), - )) - } - }; - Ok(res) - } - - /// Gets the array type - #[tracing::instrument(level = "trace", skip_all)] - fn member_access( - &mut self, - loc: Loc, - member_expr: &Expression, - ident: &Identifier, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - // TODO: this is wrong as it overwrites a function call of the form elem.length(...) i believe - if ident.name == "length" { - return self.length(loc, member_expr, ctx); - } - - self.parse_ctx_expr(member_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_member(ctx, loc, ident, ret) - }) - } - - fn match_member( - &mut self, - ctx: ContextNode, - loc: Loc, - ident: &Identifier, - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { - ctx.push_expr(self.member_access_inner(loc, idx, ident, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|ret| self.match_member(ctx, loc, ident, ret)), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Null => Ok(()), - } - } - - fn member_access_var_ty( - &mut self, - cvar: ContextVar, - loc: Loc, - member_idx: NodeIdx, - ident: &Identifier, - ctx: ContextNode, - ) -> Result { - match &cvar.ty { - VarType::User(TypeNode::Struct(struct_node), _) => { - self.struct_member_access(member_idx, *struct_node, ident, ctx, loc, Some(cvar)) - } - VarType::User(TypeNode::Enum(enum_node), _) => { - self.enum_member_access(member_idx, *enum_node, ident, ctx, loc) - } - VarType::User(TypeNode::Ty(ty_node), _) => { - self.ty_member_access(member_idx, *ty_node, ident, ctx, loc, Some(cvar)) - } - VarType::User(TypeNode::Contract(con_node), _) => { - self.contract_member_access(member_idx, *con_node, ident, ctx, loc, Some(cvar)) - } - VarType::BuiltIn(bn, _) => self.builtin_member_access( - loc, - ctx, - *bn, - ContextVarNode::from(member_idx) - .is_storage(self) - .into_expr_err(loc)?, - ident, - ), - VarType::Concrete(cn) => { - let builtin = cn.underlying(self).into_expr_err(loc)?.as_builtin(); - let bn = self.builtin_or_add(builtin).into(); - self.builtin_member_access( - loc, - ctx, - bn, - ContextVarNode::from(member_idx) - .is_storage(self) - .into_expr_err(loc)?, - ident, - ) - } - e => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled member access: {:?}, {:?}", e, ident), - )), - } - } - - fn struct_member_access( - &mut self, - member_idx: NodeIdx, - struct_node: StructNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - maybe_parent: Option, - ) -> Result { - let name = format!( - "{}.{}", - struct_node.name(self).into_expr_err(loc)?, - ident.name - ); - tracing::trace!("Struct member access: {}", name); - if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - Ok(ExprRet::Single(attr_var.latest_version(self).into())) - } else if let Some(field) = struct_node.find_field(self, ident) { - let cvar = if let Some(parent) = maybe_parent { - parent - } else { - ContextVar::maybe_from_user_ty(self, loc, struct_node.into()).unwrap() - }; - if let Some(field_cvar) = ContextVar::maybe_new_from_field( - self, - loc, - &cvar, - field.underlying(self).unwrap().clone(), - ) { - let fc_node = self.add_node(Node::ContextVar(field_cvar)); - self.add_edge( - fc_node, - ContextVarNode::from(member_idx).first_version(self), - Edge::Context(ContextEdge::AttrAccess), - ); - ctx.add_var(fc_node.into(), self).into_expr_err(loc)?; - self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(fc_node)) - } else { - panic!("Couldn't create field variable"); - } - } else if let Some(func) = self.library_func_search(ctx, struct_node.0.into(), ident) { - Ok(func) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on struct \"{}\"", - ident.name, - struct_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn enum_member_access( - &mut self, - _member_idx: NodeIdx, - enum_node: EnumNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - ) -> Result { - tracing::trace!("Enum member access: {}", ident.name); - - if let Some(variant) = enum_node - .variants(self) - .into_expr_err(loc)? - .iter() - .find(|variant| **variant == ident.name) - { - let var = - ContextVar::new_from_enum_variant(self, ctx, loc, enum_node, variant.to_string()) - .into_expr_err(loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } else if let Some(ret) = self.library_func_search(ctx, enum_node.0.into(), ident) { - Ok(ret) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on enum \"{}\"", - ident.name, - enum_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn contract_member_access( - &mut self, - member_idx: NodeIdx, - con_node: ContractNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - maybe_parent: Option, - ) -> Result { - tracing::trace!( - "Contract member access: {}.{}", - con_node - .maybe_name(self) - .into_expr_err(loc)? - .unwrap_or_else(|| "interface".to_string()), - ident.name - ); - - if let Some(func) = con_node - .funcs(self) - .into_iter() - .find(|func_node| func_node.name(self).unwrap() == ident.name) - { - if let Some(func_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { - let fn_node = self.add_node(Node::ContextVar(func_cvar)); - // this prevents attaching a dummy node to the parent which could cause a cycle in the graph - if maybe_parent.is_some() { - self.add_edge(fn_node, member_idx, Edge::Context(ContextEdge::FuncAccess)); - } - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unable to construct the function \"{}\" in contract \"{}\"", - ident.name, - con_node.name(self).into_expr_err(loc)? - ), - )) - } - } else if let Some(func) = con_node - .structs(self) - .into_iter() - .find(|struct_node| struct_node.name(self).unwrap() == ident.name) - { - if let Some(struct_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { - let struct_node = self.add_node(Node::ContextVar(struct_cvar)); - // this prevents attaching a dummy node to the parent which could cause a cycle in the graph - if maybe_parent.is_some() { - self.add_edge( - struct_node, - member_idx, - Edge::Context(ContextEdge::StructAccess), - ); - } - return Ok(ExprRet::Single(struct_node)); - } else { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unable to construct the struct \"{}\" in contract \"{}\"", - ident.name, - con_node.name(self).into_expr_err(loc)? - ), - )); - } - } else { - match &*ident.name { - "name" => { - let c = Concrete::from(con_node.name(self).unwrap()); - let cnode = self.add_node(Node::Concrete(c)); - let cvar = ContextVar::new_from_concrete(loc, ctx, cnode.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - "creationCode" | "runtimeCode" => { - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = - ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - "interfaceId" => { - // TODO: actually calculate this - let bn = self.builtin_or_add(Builtin::Bytes(4)); - let cvar = - ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - _ => { - return Err(ExprErr::ContractFunctionNotFound( - loc, - format!( - "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", - ident.name, - con_node.name(self).unwrap(), - con_node - .funcs(self) - .iter() - .map(|func| func.name(self).unwrap()) - .collect::>() - ), - )) - } - } - } - } - - fn ty_member_access( - &mut self, - _member_idx: NodeIdx, - ty_node: TyNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - _maybe_parent: Option, - ) -> Result { - let name = ident.name.split('(').collect::>()[0]; - if let Some(func) = self.library_func_search(ctx, ty_node.0.into(), ident) { - Ok(func) - } else if let Some(func) = self.builtin_fn_or_maybe_add(name) { - Ok(ExprRet::Single(func)) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on struct \"{}\"", - ident.name, - ty_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn member_access_inner( - &mut self, - loc: Loc, - member_idx: NodeIdx, - ident: &Identifier, - ctx: ContextNode, - ) -> Result { - match self.node(member_idx) { - Node::ContextVar(cvar) => { - self.member_access_var_ty(cvar.clone(), loc, member_idx, ident, ctx) - } - Node::Contract(_c) => self.contract_member_access( - member_idx, - ContractNode::from(member_idx), - ident, - ctx, - loc, - None, - ), - Node::Struct(_c) => self.struct_member_access( - member_idx, - StructNode::from(member_idx), - ident, - ctx, - loc, - None, - ), - Node::Enum(_c) => { - self.enum_member_access(member_idx, EnumNode::from(member_idx), ident, ctx, loc) - } - Node::Ty(_ty) => { - self.ty_member_access(member_idx, TyNode::from(member_idx), ident, ctx, loc, None) - } - Node::Msg(_msg) => self.msg_access(loc, ctx, &ident.name), - Node::Block(_b) => self.block_access(loc, ctx, &ident.name), - Node::Builtin(ref _b) => { - self.builtin_member_access(loc, ctx, BuiltInNode::from(member_idx), false, ident) - } - e => Err(ExprErr::Todo( - loc, - format!("Member access on type: {e:?} is not yet supported"), - )), - } - } - - fn builtin_member_access( - &mut self, - loc: Loc, - ctx: ContextNode, - node: BuiltInNode, - is_storage: bool, - ident: &Identifier, - ) -> Result { - tracing::trace!("Looking for builtin member function"); - if let Some(ret) = self.library_func_search(ctx, node.0.into(), ident) { - Ok(ret) - } else { - match node.underlying(self).into_expr_err(loc)?.clone() { - Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { - match &*ident.name { - "delegatecall" - | "call" - | "staticcall" - | "delegatecall(address, bytes)" - | "call(address, bytes)" - | "staticcall(address, bytes)" => { - // TODO: check if the address is known to be a certain type and the function signature is known - // and call into the function - let builtin_name = ident.name.split('(').collect::>()[0]; - let func_node = self.builtin_fn_or_maybe_add(builtin_name).unwrap(); - Ok(ExprRet::Single(func_node)) - } - "code" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - "codehash" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Bytes(32)); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - "balance" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Uint(256)); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - _ if ident.name.starts_with("send") => { - let bn = self.builtin_or_add(Builtin::Bool); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - _ if ident.name.starts_with("transfer") => Ok(ExprRet::Multi(vec![])), - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on address: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - } - } - Builtin::Bool => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on bool: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::String => match ident.name.split('(').collect::>()[0] { - "concat" => { - let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); - Ok(ExprRet::Single(fn_node)) - } - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on string: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - }, - Builtin::Bytes(size) => Err(ExprErr::MemberAccessNotFound( - loc, - format!("Unknown member access on bytes{}: {:?}", size, ident.name), - )), - Builtin::Rational => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on rational: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::DynamicBytes => match ident.name.split('(').collect::>()[0] { - "concat" => { - let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); - Ok(ExprRet::Single(fn_node)) - } - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on bytes: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - }, - Builtin::Array(_) => { - if ident.name.starts_with("push") { - if is_storage { - let fn_node = self.builtin_fn_or_maybe_add("push").unwrap(); - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::NonStoragePush( - loc, - "Trying to push to nonstorage array is not supported".to_string(), - )) - } - } else if ident.name.starts_with("pop") { - if is_storage { - let fn_node = self.builtin_fn_or_maybe_add("pop").unwrap(); - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::NonStoragePush( - loc, - "Trying to pop from nonstorage array is not supported".to_string(), - )) - } - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on array[]: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )) - } - } - Builtin::SizedArray(s, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on array[{s}]: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Mapping(_, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on mapping: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Func(_, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on func: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Int(size) => { - let max = if size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1) - }; - match &*ident.name { - "max" => { - let c = Concrete::Int(size, max); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.max"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - "min" => { - let min = max * I256::from(-1i32) - I256::from(1i32); - let c = Concrete::Int(size, min); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.min"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - e => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown type attribute on int{size}: {e:?}, ctx: {}", - ctx.path(self) - ), - )), - } - } - Builtin::Uint(size) => match &*ident.name { - "max" => { - let size = size; - let max = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(size)) - 1 - }; - let c = Concrete::Uint(size, max); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("uint{size}.max"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - "min" => { - let min = U256::zero(); - let c = Concrete::from(min); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.min"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - e => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown type attribute on uint{size}: {e:?}, ctx: {}", - ctx.path(self) - ), - )), - }, - } - } - } - - fn library_func_search( - &mut self, - ctx: ContextNode, - ty: NodeIdx, - ident: &Identifier, - ) -> Option { - self.possible_library_funcs(ctx, ty) - .iter() - .filter_map(|func| { - if let Ok(name) = func.name(self) { - Some((name, func)) - } else { - None - } - }) - .find_map(|(name, func)| { - if name == ident.name { - Some(ExprRet::Single((*func).into())) - } else { - None - } - }) - } - - fn possible_library_funcs(&mut self, ctx: ContextNode, ty: NodeIdx) -> BTreeSet { - let mut funcs: BTreeSet = BTreeSet::new(); - if let Some(associated_contract) = ctx.maybe_associated_contract(self).unwrap() { - // search for contract scoped `using` statements - funcs.extend( - self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { - matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == associated_contract.into()) - }).map(|edge| edge.target().into()).collect::>() - ); - } - - // Search for global `using` funcs - if let Some(source) = ctx.maybe_associated_source(self) { - funcs.extend( - self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { - matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source) - }).map(|edge| edge.target().into()).collect::>() - ); - } - - funcs - } - - #[tracing::instrument(level = "trace", skip_all)] - fn index_access( - &mut self, - loc: Loc, - parent: NodeIdx, - dyn_builtin: BuiltInNode, - ident: &Identifier, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.variable(ident, ctx, None)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())) - }; - - if matches!(index_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(index_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_index_access(&index_paths, loc, parent.into(), dyn_builtin, ctx) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn match_index_access( - &mut self, - index_paths: &ExprRet, - loc: Loc, - parent: ContextVarNode, - dyn_builtin: BuiltInNode, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - match index_paths { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc), - ExprRet::Single(idx) => { - let parent = parent.first_version(self); - let parent_name = parent.name(self).into_expr_err(loc)?; - let parent_display_name = parent.display_name(self).unwrap(); - - tracing::trace!( - "Index access: {}[{}]", - parent_display_name, - ContextVarNode::from(*idx) - .display_name(self) - .into_expr_err(loc)? - ); - let parent_ty = dyn_builtin; - let parent_stor = parent - .storage(self) - .into_expr_err(loc)? - .as_ref() - .expect("parent didnt have a storage location?"); - let indexed_var = ContextVar::new_from_index( - self, - loc, - parent_name, - parent_display_name, - parent_stor.clone(), - &parent_ty, - ContextVarNode::from(*idx), - ) - .into_expr_err(loc)?; - - let idx_node = self.add_node(Node::ContextVar(indexed_var)); - self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); - self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; - self.add_edge(*idx, idx_node, Edge::Context(ContextEdge::Index)); - ctx.push_expr(ExprRet::Single(idx_node), self) - .into_expr_err(loc)?; - Ok(()) - } - e => Err(ExprErr::UnhandledExprRet( - loc, - format!("Unhandled expression return in index access: {e:?}"), - )), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn length( - &mut self, - loc: Loc, - input_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(input_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_length(ctx, loc, ret, true) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn tmp_length( - &mut self, - arr: ContextVarNode, - array_ctx: ContextNode, - loc: Loc, - ) -> ContextVarNode { - let arr = arr.first_version(self); - let name = format!("{}.length", arr.name(self).unwrap()); - tracing::trace!("Length access: {}", name); - if let Some(attr_var) = array_ctx.var_by_name_or_recurse(self, &name).unwrap() { - attr_var.latest_version(self) - } else { - let range = if let Ok(Some(size)) = arr.ty(self).unwrap().maybe_array_size(self) { - SolcRange::from(Concrete::from(size)) - } else { - SolcRange::try_from_builtin(&Builtin::Uint(256)) - }; - - let len_var = ContextVar { - loc: Some(loc), - name: arr.name(self).unwrap() + ".length", - display_name: arr.display_name(self).unwrap() + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - range, - ), - }; - let len_node = self.add_node(Node::ContextVar(len_var)); - - let next_arr = self - .advance_var_in_ctx(arr.latest_version(self), loc, array_ctx) - .unwrap(); - if next_arr - .underlying(self) - .unwrap() - .ty - .is_dyn_builtin(self) - .unwrap() - { - if let Some(r) = next_arr.ref_range(self).unwrap() { - let min = r.evaled_range_min(self).unwrap(); - let max = r.evaled_range_max(self).unwrap(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); - array_ctx.add_var(len_node.into(), self).unwrap(); - len_node.into() - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn match_length( - &mut self, - ctx: ContextNode, - loc: Loc, - elem_path: ExprRet, - update_len_bound: bool, - ) -> Result<(), ExprErr> { - match elem_path { - ExprRet::Null => { - ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; - Ok(()) - } - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Single(arr) => { - let next_arr = self.advance_var_in_ctx( - ContextVarNode::from(arr).latest_version(self), - loc, - ctx, - )?; - let arr = ContextVarNode::from(arr).first_version(self); - let name = format!("{}.length", arr.name(self).into_expr_err(loc)?); - tracing::trace!("Length access: {}", name); - if let Some(len_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - let len_var = len_var.latest_version(self); - let new_len = self.advance_var_in_ctx(len_var, loc, ctx)?; - if update_len_bound - && next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - ctx.push_expr(ExprRet::Single(new_len.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let range = if let Ok(Some(size)) = - arr.ty(self).into_expr_err(loc)?.maybe_array_size(self) - { - SolcRange::from(Concrete::from(size)) - } else { - SolcRange::try_from_builtin(&Builtin::Uint(256)) - }; - - let len_var = ContextVar { - loc: Some(loc), - name, - display_name: arr.display_name(self).into_expr_err(loc)? + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - range, - ), - }; - let len_node = self.add_node(Node::ContextVar(len_var)); - - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_node.into(), self).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(len_node), self) - .into_expr_err(loc)?; - Ok(()) - } - } - e => todo!("here: {e:?}"), - } - } -} diff --git a/src/context/exprs/mod.rs b/src/context/exprs/mod.rs deleted file mode 100644 index e3d2c8eb..00000000 --- a/src/context/exprs/mod.rs +++ /dev/null @@ -1,184 +0,0 @@ -use shared::analyzer::GraphError; -use solang_parser::pt::Loc; - -mod array; -mod bin_op; -mod cmp; -mod cond_op; -mod env; -mod list; -mod literal; -mod member_access; -mod require; -mod variable; - -pub use array::*; -pub use bin_op::*; -pub use cmp::*; -pub use cond_op::*; -pub use env::*; -pub use list::*; -pub use literal::*; -pub use member_access::*; -pub use require::*; -pub use variable::*; - -pub trait ExprParser: - BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env -{ -} -impl ExprParser for T where - T: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env -{ -} - -pub trait IntoExprErr { - fn into_expr_err(self, loc: Loc) -> Result; -} - -impl IntoExprErr for Result { - fn into_expr_err(self, loc: Loc) -> Result { - match self { - Ok(v) => Ok(v), - Err(e) => Err(ExprErr::from_graph_err(loc, e)), - } - } -} - -#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] -pub enum ExprErr { - ParseError(Loc, String), - NoLhs(Loc, String), - NoRhs(Loc, String), - NoReturn(Loc, String), - ArrayTy(Loc, String), - ArrayIndex(Loc, String), - UnhandledCombo(Loc, String), - UnhandledExprRet(Loc, String), - MultiNot(Loc, String), - VarBadType(Loc, String), - Todo(Loc, String), - BadRange(Loc, String), - ContractFunctionNotFound(Loc, String), - MemberAccessNotFound(Loc, String), - FunctionNotFound(Loc, String), - - FunctionCallBlockTodo(Loc, String), - - NonStoragePush(Loc, String), - IntrinsicNamedArgs(Loc, String), - InvalidFunctionInput(Loc, String), - TakeFromFork(Loc, String), - GraphError(Loc, GraphError), - Unresolved(Loc, String), -} - -impl ExprErr { - pub fn from_graph_err(loc: Loc, graph_err: GraphError) -> Self { - Self::GraphError(loc, graph_err) - } -} - -impl ExprErr { - pub fn loc(&self) -> Loc { - use ExprErr::*; - match self { - ParseError(loc, ..) => *loc, - NoLhs(loc, ..) => *loc, - NoRhs(loc, ..) => *loc, - NoReturn(loc, ..) => *loc, - ArrayTy(loc, ..) => *loc, - ArrayIndex(loc, ..) => *loc, - UnhandledCombo(loc, ..) => *loc, - UnhandledExprRet(loc, ..) => *loc, - MultiNot(loc, ..) => *loc, - VarBadType(loc, ..) => *loc, - Todo(loc, ..) => *loc, - FunctionCallBlockTodo(loc, ..) => *loc, - BadRange(loc, ..) => *loc, - ContractFunctionNotFound(loc, ..) => *loc, - MemberAccessNotFound(loc, ..) => *loc, - FunctionNotFound(loc, ..) => *loc, - NonStoragePush(loc, ..) => *loc, - IntrinsicNamedArgs(loc, ..) => *loc, - InvalidFunctionInput(loc, ..) => *loc, - TakeFromFork(loc, ..) => *loc, - GraphError(loc, ..) => *loc, - Unresolved(loc, ..) => *loc, - } - } - - pub fn msg(&self) -> &str { - use ExprErr::*; - match self { - ParseError(_, msg, ..) => msg, - NoLhs(_, msg, ..) => msg, - NoRhs(_, msg, ..) => msg, - NoReturn(_, msg, ..) => msg, - ArrayTy(_, msg, ..) => msg, - ArrayIndex(_, msg, ..) => msg, - UnhandledCombo(_, msg, ..) => msg, - UnhandledExprRet(_, msg, ..) => msg, - MultiNot(_, msg, ..) => msg, - VarBadType(_, msg, ..) => msg, - Todo(_, msg, ..) => msg, - FunctionCallBlockTodo(_, msg, ..) => msg, - BadRange(_, msg, ..) => msg, - ContractFunctionNotFound(_, msg, ..) => msg, - MemberAccessNotFound(_, msg, ..) => msg, - FunctionNotFound(_, msg, ..) => msg, - NonStoragePush(_, msg, ..) => msg, - IntrinsicNamedArgs(_, msg, ..) => msg, - InvalidFunctionInput(_, msg, ..) => msg, - TakeFromFork(_, msg, ..) => msg, - Unresolved(_, msg, ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(msg), ..) => { - msg - } - GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(msg), ..) => msg, - } - } - - pub fn report_msg(&self) -> &str { - use ExprErr::*; - match self { - ParseError(..) => "Could not parse this", - NoLhs(..) => "No left-hand side passed to expression", - NoRhs(..) => "No right-hand side passed to expression", - NoReturn(..) => "No returned element from expression", - ArrayTy(..) => "Unexpected type as array element", - ArrayIndex(..) => "Unexpected type as array index", - UnhandledCombo(..) => "Unhandled ExprRet variant combination", - UnhandledExprRet(..) => "Unhandled ExprRet variant", - MultiNot(..) => "Expected a single ExprRet in Not statement, got ExprRet::Multi", - VarBadType(..) => "This type cannot be made into a variable", - Todo(..) => "TODO", - FunctionCallBlockTodo(..) => "TODO", - Unresolved(..) => "Unresolved type: This is likely a bug. Please report it at https://github.com/nascentxyz/pyrometer", - BadRange(..) => "Expected a range for a variable but there was none", - ContractFunctionNotFound(..) => "Contract function could not be Found", - MemberAccessNotFound(..) => "Member element could not be found", - FunctionNotFound(..) => "Function could not be found", - NonStoragePush(..) => "Pushing on non-storage based array is unsupported", - IntrinsicNamedArgs(..) => "Arguments in calls to intrinsic functions cannot be named", - InvalidFunctionInput(..) => "Arguments to this function call do not match required types", - TakeFromFork(..) => "IR Error: Tried to take from an child context that ended up forking", - GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(_), ..) => "Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(_), ..) => "Max call depth reached - either recursion or loop", - GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(_), ..) => "TODO: Max fork width reached - Need to widen variables and remove contexts", - GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(_), ..) => "Graph IR Error: Child redefintion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(_), ..) => "Graph IR Error: Detached Variable. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(_), ..) => "Graph IR Error: Variable update in an old context. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(_), ..) => "Graph IR Error: Expecting single expression return, got multiple. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(_), ..) => "Graph IR Error: Expected a particular number of elements on the context stack but found a different amount. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(_), ..) => "Graph IR Error: Unbreakable recursion in variable range. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - } - } -} diff --git a/src/context/exprs/require.rs b/src/context/exprs/require.rs deleted file mode 100644 index 0852ad30..00000000 --- a/src/context/exprs/require.rs +++ /dev/null @@ -1,1503 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{ - exprs::{BinOp, Variable}, - AnalyzerLike, Concrete, ConcreteNode, ContextBuilder, Node, -}; -use shared::range::elem_ty::RangeExpr; -use shared::range::range_string::ToRangeString; - -use shared::{ - context::*, - nodes::{BuiltInNode, Builtin, VarType}, - range::{ - elem::{RangeElem, RangeOp}, - elem_ty::{Elem, RangeConcrete}, - Range, RangeEval, SolcRange, - }, - Edge, -}; -use solang_parser::helpers::CodeLocation; - -use ethers_core::types::I256; -use solang_parser::pt::{Expression, Loc}; -use std::cmp::Ordering; - -impl Require for T where T: Variable + BinOp + Sized + AnalyzerLike {} -pub trait Require: AnalyzerLike + Variable + BinOp + Sized { - /// Inverts a comparator expression - fn inverse_expr(&self, expr: Expression) -> Expression { - match expr { - Expression::Equal(loc, lhs, rhs) => Expression::NotEqual(loc, lhs, rhs), - Expression::NotEqual(loc, lhs, rhs) => Expression::Equal(loc, lhs, rhs), - Expression::Less(loc, lhs, rhs) => Expression::MoreEqual(loc, lhs, rhs), - Expression::More(loc, lhs, rhs) => Expression::LessEqual(loc, lhs, rhs), - Expression::MoreEqual(loc, lhs, rhs) => Expression::Less(loc, lhs, rhs), - Expression::LessEqual(loc, lhs, rhs) => Expression::More(loc, lhs, rhs), - // Expression::And(loc, lhs, rhs) => { - // Expression::Or(loc, Box::new(self.inverse_expr(*lhs)), Box::new(self.inverse_expr(*rhs))) - // } - // Expression::Not(loc, lhs) => { - // Expression::Equal(loc, lhs, Box::new(Expression::BoolLiteral(loc, true))) - // } - e => Expression::Not(e.loc(), Box::new(e)), - } - } - - /// Handles a require expression - #[tracing::instrument(level = "trace", skip_all)] - fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { - match inputs.get(0).expect("No lhs input for require statement") { - Expression::Equal(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `==` had no right hand side".to_string())) - }; - - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `==` had no left hand side".to_string())) - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - ) - }) - }) - } - Expression::NotEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `!=` had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `!=` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Neq, - RangeOp::Eq, - (RangeOp::Eq, RangeOp::Neq), - ) - }) - }) - } - Expression::Less(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `<` had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `<` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Lt, - RangeOp::Gt, - (RangeOp::Gt, RangeOp::Lt), - ) - }) - }) - } - Expression::More(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `>` had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `>` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Gt, - RangeOp::Lt, - (RangeOp::Lt, RangeOp::Gt), - ) - }) - }) - } - Expression::MoreEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `>=` had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `>=` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Gte, - RangeOp::Lte, - (RangeOp::Lte, RangeOp::Gte), - ) - }) - }) - } - Expression::LessEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `<=` had no right hand side".to_string())) - }; - let rhs_paths = rhs_paths.flatten(); - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `<=` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths.flatten(), - &rhs_paths, - RangeOp::Lte, - RangeOp::Gte, - (RangeOp::Gte, RangeOp::Lte), - ) - }) - }) - } - Expression::Not(loc, lhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `NOT` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let cnode = - ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(false)))); - let tmp_false = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) - .into_expr_err(loc)?, - ); - let rhs_paths = - ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_false)).into()); - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths, - &rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - ) - }) - } - Expression::And(loc, lhs, rhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(rhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) - .into_expr_err(loc)?, - ); - let node = analyzer.add_node(tmp_true); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - let tmp_rhs_paths = ExprRet::Single(node); - - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths, - &tmp_rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - )?; - - analyzer.handle_require_inner( - ctx, - loc, - &rhs_paths, - &tmp_rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - )?; - - - // update the part's bounds - let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - let underlying = lhs_cvar.underlying(analyzer).into_expr_err(loc)?; - if let Some(tmp) = underlying.tmp_of { - if let Some((op, inv_op, pair)) = tmp.op.require_parts() { - analyzer.handle_require_inner( - ctx, - loc, - &ExprRet::Single(tmp.lhs.into()), - &ExprRet::Single(tmp.rhs.unwrap().into()), - op, - inv_op, - pair, - )?; - } - } - - // update the part's bounds - let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); - let underlying = rhs_cvar.underlying(analyzer).into_expr_err(loc)?; - if let Some(tmp) = underlying.tmp_of { - if let Some((op, inv_op, pair)) = tmp.op.require_parts() { - analyzer.handle_require_inner( - ctx, - loc, - &ExprRet::Single(tmp.lhs.into()), - &ExprRet::Single(tmp.rhs.unwrap().into()), - op, - inv_op, - pair, - )?; - } - } - Ok(()) - }) - }) - } - Expression::Or(loc, lhs, rhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(rhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); - - let elem = Elem::Expr(RangeExpr::new(lhs_cvar.into(), RangeOp::Or, rhs_cvar.into())); - let range = SolcRange::new(elem.clone(), elem, vec![]); - - let new_lhs_underlying = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} {} {})", - ctx.new_tmp(analyzer).into_expr_err(loc)?, - lhs_cvar.name(analyzer).into_expr_err(loc)?, - RangeOp::Or.to_string(), - rhs_cvar.name(analyzer).into_expr_err(loc)? - ), - display_name: format!( - "({} {} {})", - lhs_cvar.display_name(analyzer).into_expr_err(loc)?, - RangeOp::Or.to_string(), - rhs_cvar.display_name(analyzer).into_expr_err(loc)? - ), - storage: None, - is_tmp: true, - is_symbolic: lhs_cvar.is_symbolic(analyzer).into_expr_err(loc)? - || rhs_cvar.is_symbolic(analyzer).into_expr_err(loc)?, - is_return: false, - tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Or, Some(rhs_cvar))), - ty: VarType::BuiltIn(analyzer.builtin_or_add(Builtin::Bool).into(), Some(range)) - }; - let or_var = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_lhs_underlying))); - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) - .into_expr_err(loc)?, - ); - let node = analyzer.add_node(tmp_true); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - let rhs_paths = ExprRet::Single(node); - analyzer.handle_require_inner( - ctx, - loc, - &ExprRet::Single(or_var.into()), - &rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - ) - }) - }) - } - other => { - self.parse_ctx_expr(other, ctx)?; - self.apply_to_edges(ctx, other.loc(), &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) - .into_expr_err(other.loc())?, - ); - let rhs_paths = - ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths, - &rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - ) - }) - } - } - } - - fn handle_require_inner( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: &ExprRet, - op: RangeOp, - rhs_op: RangeOp, - recursion_ops: (RangeOp, RangeOp), - ) -> Result<(), ExprErr> { - match (lhs_paths, rhs_paths) { - (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), - (_, ExprRet::CtxKilled(..)) | (ExprRet::CtxKilled(..), _) => Ok(()), - (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { - ContextVarNode::from(*lhs) - .cast_from(&ContextVarNode::from(*rhs), self) - .into_expr_err(loc)?; - self.handle_require_inner( - ctx, - loc, - &ExprRet::Single(*lhs), - rhs_paths, - op, - rhs_op, - recursion_ops, - ) - } - (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { - ContextVarNode::from(*rhs) - .cast_from(&ContextVarNode::from(*lhs), self) - .into_expr_err(loc)?; - self.handle_require_inner( - ctx, - loc, - lhs_paths, - &ExprRet::Single(*rhs), - op, - rhs_op, - recursion_ops, - ) - } - (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let new_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let new_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; - - self.require(new_lhs, new_rhs, ctx, loc, op, rhs_op, recursion_ops)?; - Ok(()) - } - (l @ ExprRet::Single(_) | l @ ExprRet::SingleLiteral(_), ExprRet::Multi(rhs_sides)) => { - rhs_sides.iter().try_for_each(|expr_ret| { - self.handle_require_inner(ctx, loc, l, expr_ret, op, rhs_op, recursion_ops) - }) - } - (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { - lhs_sides.iter().try_for_each(|expr_ret| { - self.handle_require_inner(ctx, loc, expr_ret, r, op, rhs_op, recursion_ops) - }) - } - (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( - |(lhs_expr_ret, rhs_expr_ret)| { - self.handle_require_inner( - ctx, - loc, - lhs_expr_ret, - rhs_expr_ret, - op, - rhs_op, - recursion_ops, - ) - }, - ) - } else { - rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.handle_require_inner( - ctx, - loc, - lhs_paths, - rhs_expr_ret, - op, - rhs_op, - recursion_ops, - ) - }) - } - } - (e, f) => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled combination in require: {:?} {:?}", e, f), - )), - } - } - - /// Updates the range bounds for the variables passed into the require function. If the lefthand side is a temporary value, - /// it will recursively update the range bounds for the underlying variable - #[allow(clippy::too_many_arguments)] - #[tracing::instrument(level = "trace", skip_all)] - fn require( - &mut self, - mut new_lhs: ContextVarNode, - mut new_rhs: ContextVarNode, - ctx: ContextNode, - loc: Loc, - op: RangeOp, - rhs_op: RangeOp, - recursion_ops: (RangeOp, RangeOp), - ) -> Result, ExprErr> { - tracing::trace!( - "require: {} {} {}", - new_lhs.display_name(self).into_expr_err(loc)?, - op.to_string(), - new_rhs.display_name(self).into_expr_err(loc)? - ); - let mut any_unsat = false; - let mut tmp_cvar = None; - - if let Some(lhs_range) = new_lhs - .underlying(self) - .into_expr_err(loc)? - .ty - .range(self) - .into_expr_err(loc)? - { - let lhs_range_fn = SolcRange::dyn_fn_from_op(op); - // lhs_range.update_deps(new_lhs, ctx, self); - let mut new_var_range = lhs_range_fn(lhs_range.clone(), new_rhs); - - if let Some(rhs_range) = new_rhs.range(self).into_expr_err(loc)? { - let lhs_is_const = new_lhs.is_const(self).into_expr_err(loc)?; - // println!("is const: {lhs_is_const},[{}, {}]", new_lhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_lhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); - let rhs_is_const = new_rhs.is_const(self).into_expr_err(loc)?; - // println!("is const: {rhs_is_const}, [{}, {}]", new_rhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_rhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); - match (lhs_is_const, rhs_is_const) { - (true, true) => { - if self.const_killable(op, lhs_range, rhs_range) { - tracing::trace!("const killable"); - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(None); - } - } - (true, false) => { - // flip the new range around to be in terms of rhs - let rhs_range_fn = SolcRange::dyn_fn_from_op(rhs_op); - new_var_range = rhs_range_fn(rhs_range.clone(), new_lhs); - if self - .update_nonconst_from_const(loc, rhs_op, new_lhs, new_rhs, rhs_range)? - { - tracing::trace!("half-const killable"); - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(None); - } - } - (false, true) => { - if self.update_nonconst_from_const(loc, op, new_rhs, new_lhs, lhs_range)? { - tracing::trace!("half-const killable"); - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(None); - } - } - (false, false) => { - if self.update_nonconst_from_nonconst( - loc, op, new_lhs, new_rhs, lhs_range, rhs_range, - )? { - tracing::trace!("nonconst killable"); - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(None); - } - } - } - } else { - return Err(ExprErr::BadRange( - loc, - format!( - "Require: right hand side didnt have a range, likely invalid solidity - {:?}", - new_rhs.underlying(self).into_expr_err(loc)? - ) - )); - } - - if let Some(backing_arr) = new_lhs.len_var_to_array(self).into_expr_err(loc)? { - if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { - let min = r.range_min().into_owned(); - let max = r.range_max().into_owned(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } else if let Some(arr) = new_lhs.index_to_array(self) { - if let Some(index) = new_lhs.index_access_to_index(self) { - let next_arr = self.advance_var_in_ctx(arr.latest_version(self), loc, ctx)?; - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(new_rhs)); - next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(new_rhs)); - next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } - } - } - - if let Some(backing_arr) = new_rhs.len_var_to_array(self).into_expr_err(loc)? { - if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { - let min = r.range_min().into_owned(); - let max = r.range_max().into_owned(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} {} {})", - ctx.new_tmp(self).into_expr_err(loc)?, - new_lhs.name(self).into_expr_err(loc)?, - op.to_string(), - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} {} {})", - new_lhs.display_name(self).into_expr_err(loc)?, - op.to_string(), - new_rhs.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new(new_lhs, op, Some(new_rhs))), - is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? - || new_rhs.is_symbolic(self).into_expr_err(loc)?, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_var(cvar, self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - - tmp_cvar = Some(cvar); - - any_unsat |= new_var_range.unsat(self); - if any_unsat { - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(None); - } - - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - } - - new_lhs.update_deps(ctx, self).into_expr_err(loc)?; - new_rhs.update_deps(ctx, self).into_expr_err(loc)?; - tracing::trace!( - "{} is tmp: {}", - new_lhs.display_name(self).unwrap(), - new_lhs.is_tmp(self).unwrap() - ); - if let Some(tmp) = new_lhs.tmp_of(self).into_expr_err(loc)? { - if tmp.op.inverse().is_some() && !matches!(op, RangeOp::Eq | RangeOp::Neq) { - self.range_recursion(tmp, recursion_ops, new_rhs, ctx, loc, &mut any_unsat)?; - } else { - match tmp.op { - RangeOp::Not => {} - _ => { - self.uninvertable_range_recursion(tmp, new_lhs, new_rhs, loc, ctx); - } - } - } - } - - Ok(tmp_cvar) - } - - /// Checks and returns whether the require statement is killable (i.e. impossible) - fn const_killable(&mut self, op: RangeOp, lhs_range: SolcRange, rhs_range: SolcRange) -> bool { - // check that the op is satisfied, return it as a bool - match op { - RangeOp::Eq => !lhs_range - .evaled_range_min(self) - .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap()), - RangeOp::Neq => lhs_range - .evaled_range_min(self) - .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap()), - RangeOp::Gt => { - matches!( - lhs_range - .evaled_range_min(self) - .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), - Some(Ordering::Equal) | Some(Ordering::Less) - ) - } - RangeOp::Gte => { - matches!( - lhs_range - .evaled_range_min(self) - .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), - Some(Ordering::Less) - ) - } - RangeOp::Lt => { - matches!( - lhs_range - .evaled_range_min(self) - .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), - Some(Ordering::Equal) | Some(Ordering::Greater) - ) - } - RangeOp::Lte => { - matches!( - lhs_range - .evaled_range_min(self) - .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), - Some(Ordering::Greater) - ) - } - e => todo!("Non-comparator in require, {e:?}"), - } - } - - /// Given a const var and a nonconst range, update the range based on the op - #[tracing::instrument(level = "trace", skip_all)] - fn update_nonconst_from_const( - &mut self, - loc: Loc, - op: RangeOp, - const_var: ContextVarNode, - nonconst_var: ContextVarNode, - mut nonconst_range: SolcRange, - ) -> Result { - tracing::trace!("Setting range for nonconst from const"); - match op { - RangeOp::Eq => { - // check that the constant is contained in the nonconst var range - let elem = Elem::from(const_var.latest_version(self)); - let evaled_min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; - if evaled_min.maybe_concrete().is_none() { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", evaled_min.to_range_string(false, self).s))); - } - - if !nonconst_range.contains_elem(&elem, self) { - return Ok(true); - } - // if its contained, we can set the min & max to it - nonconst_var - .set_range_min(self, elem.clone()) - .into_expr_err(loc)?; - nonconst_var.set_range_max(self, elem).into_expr_err(loc)?; - Ok(false) - } - RangeOp::Neq => { - // check if contains - let elem = Elem::from(const_var.latest_version(self)); - - // potentially add the const var as a range exclusion - if let Some(Ordering::Equal) = nonconst_range - .evaled_range_min(self) - .into_expr_err(loc)? - .range_ord(&elem) - { - // mins are equivalent, add 1 instead of adding an exclusion - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; - let Some(min) = min - .maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); - }; - let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); - let min = nonconst_range.range_min().into_owned() + Elem::from(one); - nonconst_var.set_range_min(self, min).into_expr_err(loc)?; - } else if let Some(std::cmp::Ordering::Equal) = nonconst_range - .evaled_range_max(self) - .into_expr_err(loc)? - .range_ord(&elem) - { - // maxs are equivalent, subtract 1 instead of adding an exclusion - let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; - - let Some(max) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); - }; - let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); - let max = nonconst_range.range_max().into_owned() - Elem::from(one); - nonconst_var.set_range_max(self, max).into_expr_err(loc)?; - } else { - // just add as an exclusion - nonconst_range.add_range_exclusion(elem); - nonconst_var - .set_range_exclusions(self, nonconst_range.exclusions) - .into_expr_err(loc)?; - } - - Ok(false) - } - RangeOp::Gt => { - let elem = Elem::from(const_var.latest_version(self)); - - // if nonconst max is <= const, we can't make this true - let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; - if matches!( - max.range_ord(&elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Less) | Some(Ordering::Equal) - ) { - return Ok(true); - } - - // we add one to the element because its strict > - let Some(max_conc) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); - }; - let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); - nonconst_var - .set_range_min( - self, - (elem + one.into()).max(nonconst_range.range_min().into_owned()), - ) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Gte => { - let elem = Elem::from(const_var.latest_version(self)); - - // if nonconst max is < const, we can't make this true - if matches!( - nonconst_range - .evaled_range_max(self) - .into_expr_err(loc)? - .range_ord(&elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Less) - ) { - return Ok(true); - } - - nonconst_var - .set_range_min(self, elem.max(nonconst_range.range_min().into_owned())) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Lt => { - let elem = Elem::from(const_var.latest_version(self)); - - // if nonconst min is >= const, we can't make this true - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; - if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Greater) | Some(Ordering::Equal) - ) { - return Ok(true); - } - - // we add one to the element because its strict > - - let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(true, self).s))); - }; - let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); - - nonconst_var - .set_range_max( - self, - (elem - one.into()).min(nonconst_range.range_max().into_owned()), - ) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Lte => { - let elem = Elem::from(const_var.latest_version(self)); - - // if nonconst min is > const, we can't make this true - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; - if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Greater) - ) { - return Ok(true); - } - - nonconst_var - .set_range_max(self, elem.min(nonconst_range.range_max().into_owned())) - .into_expr_err(loc)?; - Ok(false) - } - e => todo!("Non-comparator in require, {e:?}"), - } - } - - /// Given a const var and a nonconst range, update the range based on the op. Returns whether its impossible - fn update_nonconst_from_nonconst( - &mut self, - loc: Loc, - op: RangeOp, - new_lhs: ContextVarNode, - new_rhs: ContextVarNode, - mut lhs_range: SolcRange, - mut rhs_range: SolcRange, - ) -> Result { - tracing::trace!("Setting range for nonconst from nonconst"); - match op { - RangeOp::Eq => { - // check that there is overlap in the ranges - if !lhs_range.overlaps(&rhs_range, self) { - return Ok(true); - } - - // take the tighest range - match lhs_range - .evaled_range_min(self) - .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_min(self).into_expr_err(loc)?) - { - Some(Ordering::Greater) => { - // take lhs range min as its tigher - new_rhs - .set_range_min(self, Elem::from(new_rhs)) - .into_expr_err(loc)?; - } - Some(Ordering::Less) => { - // take rhs range min as its tigher - new_lhs - .set_range_min(self, rhs_range.range_min().into_owned()) - .into_expr_err(loc)?; - } - _ => { - // equal or not comparable - both keep their minimums - } - } - - // take the tighest range - match lhs_range - .evaled_range_max(self) - .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_max(self).into_expr_err(loc)?) - { - Some(Ordering::Less) => { - // take lhs range min as its tigher - new_rhs - .set_range_max(self, lhs_range.range_max().into_owned()) - .into_expr_err(loc)?; - } - Some(Ordering::Greater) => { - // take rhs range min as its tigher - new_lhs - .set_range_max(self, rhs_range.range_max().into_owned()) - .into_expr_err(loc)?; - } - _ => { - // equal or not comparable - both keep their maximums - } - } - - Ok(false) - } - RangeOp::Neq => { - let rhs_elem = Elem::from(new_rhs.latest_version(self)); - // just add as an exclusion - lhs_range.add_range_exclusion(rhs_elem); - new_lhs - .set_range_exclusions(self, lhs_range.exclusions) - .into_expr_err(loc)?; - - let lhs_elem = Elem::from(new_lhs.latest_version(self)); - // just add as an exclusion - rhs_range.add_range_exclusion(lhs_elem); - new_rhs - .set_range_exclusions(self, rhs_range.exclusions) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Gt => { - let rhs_elem = Elem::from(new_rhs.latest_version(self)); - let lhs_elem = Elem::from(new_lhs.latest_version(self)); - - // if lhs.max is <= rhs.min, we can't make this true - let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; - if matches!( - max.range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Less) | Some(Ordering::Equal) - ) { - return Ok(true); - } - - let Some(max_conc) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); - }; - - let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); - - // we add/sub one to the element because its strict > - new_lhs - .set_range_min( - self, - (rhs_elem + one.clone().into()).max(lhs_range.range_min().into_owned()), - ) - .into_expr_err(loc)?; - new_rhs - .set_range_max( - self, - (lhs_elem - one.into()).min(rhs_range.range_max().into_owned()), - ) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Gte => { - let rhs_elem = Elem::from(new_rhs.latest_version(self)); - let lhs_elem = Elem::from(new_lhs.latest_version(self)); - - // if lhs.max is < rhs.min, we can't make this true - if matches!( - lhs_range - .evaled_range_max(self) - .into_expr_err(loc)? - .range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Less) - ) { - return Ok(true); - } - - new_lhs - .set_range_min(self, rhs_elem.max(lhs_range.range_min().into_owned())) - .into_expr_err(loc)?; - new_rhs - .set_range_max(self, lhs_elem.min(rhs_range.range_max().into_owned())) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Lt => { - let rhs_elem = Elem::from(new_rhs.latest_version(self)); - let lhs_elem = Elem::from(new_lhs.latest_version(self)); - - // if lhs min is >= rhs.max, we can't make this true - let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; - if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), - Some(Ordering::Greater) | Some(Ordering::Equal) - ) { - return Ok(true); - } - - // we add/sub one to the element because its strict > - let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); - }; - - let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); - - new_lhs - .set_range_max( - self, - (rhs_elem - one.clone().into()).min(lhs_range.range_max().into_owned()), - ) - .into_expr_err(loc)?; - new_rhs - .set_range_min( - self, - (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), - ) - .into_expr_err(loc)?; - Ok(false) - } - RangeOp::Lte => { - let rhs_elem = Elem::from(new_rhs.latest_version(self)); - let lhs_elem = Elem::from(new_lhs.latest_version(self)); - - // if nonconst min is > const, we can't make this true - let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; - if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), - Some(Ordering::Greater) - ) { - return Ok(true); - } - - new_lhs - .set_range_max(self, rhs_elem.min(lhs_range.range_max().into_owned())) - .into_expr_err(loc)?; - new_rhs - .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) - .into_expr_err(loc)?; - Ok(false) - } - e => todo!("Non-comparator in require, {e:?}"), - } - } - - fn uninvertable_range_recursion( - &mut self, - tmp_construction: TmpConstruction, - _new_lhs_core: ContextVarNode, - _rhs_cvar: ContextVarNode, - loc: Loc, - ctx: ContextNode, - ) { - if !tmp_construction.lhs.is_const(self).unwrap() { - // widen to maximum range :( - let new_underlying_lhs = self - .advance_var_in_ctx(tmp_construction.lhs.latest_version(self), loc, ctx) - .unwrap(); - if let Some(lhs_range) = tmp_construction.lhs.ref_range(self).unwrap() { - if let Elem::Concrete(c) = lhs_range.evaled_range_min(self).unwrap() { - new_underlying_lhs - .set_range_min( - self, - Elem::Concrete(RangeConcrete { - val: Concrete::min(&c.val).unwrap_or_else(|| c.val.clone()), - loc, - }), - ) - .unwrap(); - new_underlying_lhs - .set_range_max( - self, - Elem::Concrete(RangeConcrete { - val: Concrete::max(&c.val).unwrap_or(c.val), - loc, - }), - ) - .unwrap(); - } - } - } - } - - /// Recursively updates the range for a - fn range_recursion( - &mut self, - tmp_construction: TmpConstruction, - (flip_op, no_flip_op): (RangeOp, RangeOp), - rhs_cvar: ContextVarNode, - ctx: ContextNode, - loc: Loc, - any_unsat: &mut bool, - ) -> Result<(), ExprErr> { - tracing::trace!("Recursing through range"); - // handle lhs - let Some(inverse) = tmp_construction - .op - .inverse() else { - return Ok(()); - }; - - if !tmp_construction.lhs.is_const(self).into_expr_err(loc)? { - tracing::trace!("handling lhs range recursion"); - let adjusted_gt_rhs = ContextVarNode::from({ - let tmp = self.op( - loc, - rhs_cvar, - tmp_construction.rhs.expect("No rhs in tmp_construction"), - ctx, - inverse, - false, - )?; - if matches!(tmp, ExprRet::CtxKilled(_)) { - ctx.push_expr(tmp, self).into_expr_err(loc)?; - return Ok(()); - } - tmp.expect_single().into_expr_err(loc)? - }); - let new_underlying_lhs = - self.advance_var_in_curr_ctx(tmp_construction.lhs.latest_version(self), loc)?; - if let Some(lhs_range) = new_underlying_lhs - .underlying(self) - .into_expr_err(loc)? - .ty - .range(self) - .into_expr_err(loc)? - { - if let Some(_rhs_range) = adjusted_gt_rhs - .underlying(self) - .into_expr_err(loc)? - .ty - .ref_range(self) - .into_expr_err(loc)? - { - let lhs_range_fn = SolcRange::dyn_fn_from_op(no_flip_op); - let new_lhs_range = lhs_range_fn(lhs_range, adjusted_gt_rhs); - - new_underlying_lhs - .set_range_min(self, new_lhs_range.range_min().into_owned()) - .into_expr_err(loc)?; - new_underlying_lhs - .set_range_max(self, new_lhs_range.range_max().into_owned()) - .into_expr_err(loc)?; - - if new_lhs_range.unsat(self) { - *any_unsat = true; - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(()); - } - if let Some(tmp) = new_underlying_lhs.tmp_of(self).into_expr_err(loc)? { - self.range_recursion( - tmp, - (flip_op, no_flip_op), - adjusted_gt_rhs, - ctx, - loc, - any_unsat, - )?; - } - } - } - } - - // handle rhs - if let Some(rhs) = tmp_construction.rhs { - if !rhs.is_const(self).into_expr_err(loc)? { - tracing::trace!("handling rhs range recursion"); - let (needs_inverse, adjusted_gt_rhs) = match tmp_construction.op { - RangeOp::Sub(..) => { - let concrete = ConcreteNode( - self.add_node(Node::Concrete(Concrete::Int(256, I256::from(-1i32)))) - .index(), - ); - let lhs_cvar = ContextVar::new_from_concrete(loc, ctx, concrete, self) - .into_expr_err(loc)?; - let tmp_lhs = - ContextVarNode::from(self.add_node(Node::ContextVar(lhs_cvar))); - - // tmp_rhs = rhs_cvar * -1 - let tmp_rhs = - self.op(loc, rhs_cvar, tmp_lhs, ctx, RangeOp::Mul(false), false)?; - if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(tmp_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let tmp_rhs = - ContextVarNode::from(tmp_rhs.expect_single().into_expr_err(loc)?); - - // new_rhs = (rhs_cvar * -1) + tmp_construction.lhs - let new_rhs = - self.op(loc, tmp_rhs, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (true, new_rhs) - } - RangeOp::Add(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Mul(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Div(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Shl => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Shr => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Eq => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - RangeOp::Neq => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; - if matches!(new_rhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_rhs, self).into_expr_err(loc)?; - return Ok(()); - } - let new_rhs = - ContextVarNode::from(new_rhs.expect_single().into_expr_err(loc)?); - (false, new_rhs) - } - e => panic!("here {e:?}"), - }; - - let new_underlying_rhs = - self.advance_var_in_curr_ctx(rhs.latest_version(self), loc)?; - if let Some(lhs_range) = new_underlying_rhs - .underlying(self) - .into_expr_err(loc)? - .ty - .range(self) - .into_expr_err(loc)? - { - if let Some(_rhs_range) = adjusted_gt_rhs - .underlying(self) - .into_expr_err(loc)? - .ty - .ref_range(self) - .into_expr_err(loc)? - { - let new_lhs_range = if needs_inverse { - let lhs_range_fn = SolcRange::dyn_fn_from_op(flip_op); - lhs_range_fn(lhs_range, adjusted_gt_rhs) - } else { - let lhs_range_fn = SolcRange::dyn_fn_from_op(no_flip_op); - lhs_range_fn(lhs_range, adjusted_gt_rhs) - }; - - new_underlying_rhs - .set_range_min(self, new_lhs_range.range_min().into_owned()) - .into_expr_err(loc)?; - new_underlying_rhs - .set_range_max(self, new_lhs_range.range_max().into_owned()) - .into_expr_err(loc)?; - - if new_lhs_range.unsat(self) { - *any_unsat = true; - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(()); - } - - if let Some(tmp) = new_underlying_rhs.tmp_of(self).into_expr_err(loc)? { - self.range_recursion( - tmp, - (flip_op, no_flip_op), - adjusted_gt_rhs, - ctx, - loc, - any_unsat, - )?; - } - } - } - } - } - - Ok(()) - } -} diff --git a/src/context/exprs/variable.rs b/src/context/exprs/variable.rs deleted file mode 100644 index d77dc4a2..00000000 --- a/src/context/exprs/variable.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::context::{exprs::env::Env, ContextBuilder}; -use shared::nodes::VarNode; -use shared::{analyzer::AnalyzerLike, context::*, Edge, Node}; -use solang_parser::pt::Expression; - -use solang_parser::pt::Identifier; - -impl Variable for T where T: AnalyzerLike + Sized {} - -pub trait Variable: AnalyzerLike + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn variable( - &mut self, - ident: &Identifier, - ctx: ContextNode, - recursion_target: Option, - ) -> Result<(), ExprErr> { - tracing::trace!( - "Getting variable: {}, loc: {:?}, ctx: {}", - &ident.name, - ident.loc, - ctx.path(self) - ); - let target_ctx = if let Some(recursion_target) = recursion_target { - recursion_target - } else { - ctx - }; - - // solang doesnt have `super` as a keyword - if let Some(cvar) = ctx.var_by_name(self, &ident.name) { - let cvar = cvar.latest_version(self); - self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { - let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; - edge_ctx - .push_expr(ExprRet::Single(var.into()), analyzer) - .into_expr_err(ident.loc) - }) - } else if ident.name == "_" { - self.env_variable(ident, target_ctx)?; - Ok(()) - } else if let Some(cvar) = ctx - .var_by_name_or_recurse(self, &ident.name) - .into_expr_err(ident.loc)? - { - // check if we can inherit it - let cvar = cvar.latest_version(self); - self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { - let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; - edge_ctx - .push_expr(ExprRet::Single(var.into()), analyzer) - .into_expr_err(ident.loc) - }) - // if let Some(recursion_target) = recursion_target { - // self.variable(ident, parent_ctx, Some(recursion_target)) - // } else { - // self.variable(ident, parent_ctx, Some(target_ctx)) - // } - } else if (self.env_variable(ident, target_ctx)?).is_some() { - Ok(()) - } else if let Some(idx) = self.user_types().get(&ident.name).cloned() { - let const_var = if let Node::Var(_v) = self.node(idx) { - VarNode::from(idx) - .const_value(ident.loc, self) - .into_expr_err(ident.loc)? - } else { - None - }; - - let var = if let Some(con) = const_var { - con - } else { - match self.node(idx) { - Node::Var(_) | Node::Enum(_) => { - match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { - Some(v) => v, - None => { - return Err(ExprErr::VarBadType( - ident.loc, - format!( - "Could not create context variable from user type: {:?}", - self.node(idx) - ), - )) - } - } - } - _ => { - return target_ctx - .push_expr(ExprRet::Single(idx), self) - .into_expr_err(ident.loc) - } - } - }; - - let new_cvarnode = self.add_node(Node::ContextVar(var)); - - ctx.add_var(new_cvarnode.into(), self) - .into_expr_err(ident.loc)?; - self.add_edge( - new_cvarnode, - target_ctx, - Edge::Context(ContextEdge::Variable), - ); - target_ctx - .push_expr(ExprRet::Single(new_cvarnode), self) - .into_expr_err(ident.loc)?; - Ok(()) - } else if let Some(func_node) = self.builtin_fn_or_maybe_add(&ident.name) { - target_ctx - .push_expr(ExprRet::Single(func_node), self) - .into_expr_err(ident.loc)?; - Ok(()) - } else if let Some(_func) = target_ctx - .visible_funcs(self) - .into_expr_err(ident.loc)? - .iter() - .find(|func| func.name(self).unwrap() == ident.name) - { - Err(ExprErr::Todo( - ident.loc, - "Function as variables has limited support".to_string(), - )) - } else { - let node = self.add_node(Node::Unresolved(ident.clone())); - self.user_types_mut().insert(ident.name.clone(), node); - target_ctx - .push_expr(ExprRet::Single(node), self) - .into_expr_err(ident.loc)?; - Ok(()) - } - } -} diff --git a/src/context/func_call/internal_call.rs b/src/context/func_call/internal_call.rs deleted file mode 100644 index 9f32b079..00000000 --- a/src/context/func_call/internal_call.rs +++ /dev/null @@ -1,287 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{func_call::FuncCaller, ContextBuilder}; -use shared::context::ExprRet; -use shared::nodes::{Builtin, Concrete, VarType}; -use shared::{ - analyzer::{AnalyzerLike, GraphLike}, - context::{ContextEdge, ContextNode, ContextVar, ContextVarNode}, - Edge, Node, -}; -use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; - -impl InternalFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike -{ -} -pub trait InternalFuncCaller: - AnalyzerLike + Sized + GraphLike -{ - #[tracing::instrument(level = "trace", skip_all)] - fn call_internal_named_func( - &mut self, - ctx: ContextNode, - loc: &Loc, - ident: &Identifier, - // _func_expr: &Expression, - input_args: &[NamedArgument], - ) -> Result<(), ExprErr> { - // It is a function call, check if we have the ident in scope - let funcs = ctx.visible_funcs(self).into_expr_err(*loc)?; - // filter down all funcs to those that match - let possible_funcs = funcs - .iter() - .filter(|func| { - let named_correctly = func - .name(self) - .unwrap() - .starts_with(&format!("{}(", ident.name)); - if !named_correctly { - false - } else { - // filter by params - let params = func.params(self); - if params.len() != input_args.len() { - false - } else { - params.iter().all(|param| { - input_args - .iter() - .any(|input| input.name.name == param.name(self).unwrap()) - }) - } - } - }) - .copied() - .collect::>(); - - if possible_funcs.is_empty() { - // check structs - let structs = ctx.visible_structs(self); - let possible_structs = structs - .iter() - .filter(|strukt| { - let named_correctly = strukt - .name(self) - .unwrap() - .starts_with(&ident.name.to_string()); - if !named_correctly { - false - } else { - // filter by params - let fields = strukt.fields(self); - if fields.len() != input_args.len() { - false - } else { - fields.iter().all(|field| { - input_args - .iter() - .any(|input| input.name.name == field.name(self).unwrap()) - }) - } - } - }) - .copied() - .collect::>(); - if possible_structs.is_empty() { - Err(ExprErr::FunctionNotFound( - *loc, - format!( - "No functions or structs found for named function call: {:?}", - ident.name - ), - )) - } else if possible_structs.len() == 1 { - let strukt = possible_structs[0]; - let var = - ContextVar::new_from_struct(*loc, strukt, ctx, self).into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - - strukt.fields(self).iter().try_for_each(|field| { - let field_cvar = ContextVar::maybe_new_from_field( - self, - *loc, - ContextVarNode::from(cvar) - .underlying(self) - .into_expr_err(*loc)?, - field.underlying(self).unwrap().clone(), - ) - .expect("Invalid struct field"); - - let fc_node = self.add_node(Node::ContextVar(field_cvar)); - self.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(fc_node.into(), self).into_expr_err(*loc)?; - let field_as_ret = ExprRet::Single(fc_node); - let input = input_args - .iter() - .find(|arg| arg.name.name == field.name(self).unwrap()) - .expect("No field in struct in struct construction"); - self.parse_ctx_expr(&input.expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(assignment) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) - }; - - if matches!(assignment, ExprRet::CtxKilled(_)) { - ctx.push_expr(assignment, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &assignment)?; - let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - Ok(()) - }) - })?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(*loc)?; - Ok(()) - })?; - Ok(()) - } else { - Err(ExprErr::Todo( - *loc, - "Disambiguation of struct construction not currently supported".to_string(), - )) - } - } else if possible_funcs.len() == 1 { - let func = possible_funcs[0]; - let params = func.params(self); - let inputs: Vec<_> = params - .iter() - .map(|param| { - let input = input_args - .iter() - .find(|arg| arg.name.name == param.name(self).unwrap()) - .expect( - "No parameter with named provided in named parameter function call", - ); - input.expr.clone() - }) - .collect(); - self.parse_inputs(ctx, *loc, &inputs[..])?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) - }) - } else { - todo!("Disambiguate named function call"); - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn call_internal_func( - &mut self, - ctx: ContextNode, - loc: &Loc, - ident: &Identifier, - func_expr: &Expression, - input_exprs: &[Expression], - ) -> Result<(), ExprErr> { - tracing::trace!("function call: {}(..)", ident.name); - // It is a function call, check if we have the ident in scope - let funcs = ctx.visible_funcs(self).into_expr_err(*loc)?; - // println!("visible funcs: {:#?}", funcs.iter().map(|f| f.name(self).unwrap()).collect::>()); - // filter down all funcs to those that match - let possible_funcs = funcs - .iter() - .filter(|func| { - func.name(self) - .unwrap() - .starts_with(&format!("{}(", ident.name)) - }) - .copied() - .collect::>(); - - if possible_funcs.is_empty() { - // this is a builtin, cast, or unknown function? - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let ret = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let ret = ret.flatten(); - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) - }) - } else if possible_funcs.len() == 1 { - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let inputs = inputs.flatten(); - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.setup_fn_call(&ident.loc, &inputs, (possible_funcs[0]).into(), ctx, None) - }) - } else { - // this is the annoying case due to function overloading & type inference on number literals - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let inputs = inputs.flatten(); - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let resizeables: Vec<_> = inputs.as_flat_vec() - .iter() - .map(|idx| { - match VarType::try_from_idx(analyzer, *idx) { - Some(VarType::BuiltIn(bn, _)) => { - matches!(analyzer.node(bn), Node::Builtin(Builtin::Uint(_)) | Node::Builtin(Builtin::Int(_)) | Node::Builtin(Builtin::Bytes(_))) - // match analyzer.node(bn) { - // Node::Builtin(Builtin::Uint(s)) if s < &256 => true, - // Node::Builtin(Builtin::Int(s)) if s < &256 => true, - // Node::Builtin(Builtin::Bytes(s)) if s < &32 => true, - // _ => false - // } - } - Some(VarType::Concrete(c)) => { - matches!(analyzer.node(c), Node::Concrete(Concrete::Uint(_, _)) | Node::Concrete(Concrete::Int(_, _)) | Node::Concrete(Concrete::Bytes(_, _))) - } - _ => false - } - }) - .collect(); - if let Some(func) = analyzer.disambiguate_fn_call( - &ident.name, - resizeables, - &inputs, - &possible_funcs, - ) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) - } else { - Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not disambiguate function, default input types: {}, possible functions: {:#?}", - inputs.try_as_func_input_str(analyzer), - possible_funcs - .iter() - .map(|i| i.name(analyzer).unwrap()) - .collect::>() - ), - )) - } - }) - } - } -} diff --git a/src/context/func_call/intrinsic_call.rs b/src/context/func_call/intrinsic_call.rs deleted file mode 100644 index 0804f6b5..00000000 --- a/src/context/func_call/intrinsic_call.rs +++ /dev/null @@ -1,1060 +0,0 @@ -use crate::context::func_call::FuncCaller; -use crate::context::{ - exprs::{Array, MemberAccess, Require}, - ContextBuilder, -}; -use crate::context::{ExprErr, IntoExprErr}; -use ethers_core::types::U256; -use shared::nodes::BuiltInNode; -use shared::nodes::StructNode; -use shared::nodes::TyNode; - -use shared::analyzer::Search; -use shared::analyzer::{AnalyzerLike, GraphLike}; -use shared::nodes::Concrete; - -use shared::{ - context::*, - nodes::{Builtin, VarType}, - range::{ - elem::RangeOp, - elem_ty::{Elem, RangeExpr}, - Range, SolcRange, - }, - Edge, Node, NodeIdx, -}; - -use solang_parser::pt::{Expression, Loc}; - -impl IntrinsicFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + Search -{ -} -pub trait IntrinsicFuncCaller: - AnalyzerLike + Sized + GraphLike + Search -{ - /// Calls an intrinsic/builtin function call (casts, require, etc.) - #[tracing::instrument(level = "trace", skip_all)] - fn intrinsic_func_call( - &mut self, - loc: &Loc, - input_exprs: &[Expression], - func_idx: NodeIdx, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - match self.node(func_idx) { - Node::Function(underlying) => { - if let Some(func_name) = &underlying.name { - match &*func_name.name { - "abi.decode" => { - // we skip the first because that is what is being decoded. - // TODO: check if we have a concrete bytes value - fn match_decode( - ctx: ContextNode, - loc: &Loc, - ret: ExprRet, - analyzer: &mut impl AnalyzerLike, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(expect_builtin) => { - match analyzer.node(expect_builtin) { - Node::Builtin(_) => { - let var = ContextVar::new_from_builtin( - *loc, - expect_builtin.into(), - analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - Node::ContextVar(cvar) => { - let bn = analyzer - .builtin_or_add( - cvar.ty - .as_builtin(analyzer) - .into_expr_err(*loc)?, - ) - .into(); - let var = ContextVar::new_from_builtin( - *loc, bn, analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - e => todo!("Unhandled type in abi.decode: {e:?}"), - } - } - ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { - match_decode(ctx, loc, i.clone(), analyzer) - }), - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) - } - e => panic!("This is invalid solidity: {:?}", e), - } - } - self.parse_ctx_expr(&input_exprs[1], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - match_decode(ctx, &loc, ret, analyzer) - }) - } - "abi.encode" - | "abi.encodePacked" - | "abi.encodeCall" - | "abi.encodeWithSignature" - | "abi.encodeWithSelector" => { - // currently we dont support concrete abi encoding, TODO - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "delegatecall" | "staticcall" | "call" => { - ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; - // TODO: try to be smarter based on the address input - let booln = self.builtin_or_add(Builtin::Bool); - let bool_cvar = ContextVar::new_from_builtin(*loc, booln.into(), self) - .into_expr_err(*loc)?; - let bool_node = self.add_node(Node::ContextVar(bool_cvar)); - ctx.add_var(bool_node.into(), self).into_expr_err(*loc)?; - self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); - - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr( - ExprRet::Multi(vec![ - ExprRet::Single(bool_node), - ExprRet::Single(node), - ]), - self, - ) - .into_expr_err(*loc)?; - Ok(()) - } - "code" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "balance" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Uint(256)); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "require" | "assert" => { - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(input_exprs, ctx) - }) - } - "type" => self.parse_ctx_expr(&input_exprs[0], ctx), - "push" => { - assert!(input_exprs.len() == 2); - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].push(..) was not an array to push to".to_string())) - }; - if matches!(array, ExprRet::CtxKilled(_)) { - ctx.push_expr(array, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "array[].push(..) was not given an element to push".to_string())) - }; - - if matches!(new_elem, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let arr = array.expect_single().into_expr_err(loc)?; - let arr = ContextVarNode::from(arr).latest_version(analyzer); - // get length - let len = analyzer.tmp_length(arr, ctx, loc); - - let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; - // set length as index - analyzer.index_into_array_inner( - ctx, - loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(len_as_idx.latest_version(analyzer).into()), - )?; - let index = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?.unwrap(); - if matches!(index, ExprRet::CtxKilled(_)) { - ctx.push_expr(index, analyzer).into_expr_err(loc)?; - return Ok(()); - } - // assign index to new_elem - analyzer.match_assign_sides(ctx, loc, &index, &new_elem) - }) - }) - } - "pop" => { - assert!(input_exprs.len() == 1); - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) - }; - if matches!(array, ExprRet::CtxKilled(_)) { - ctx.push_expr(array, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - // get the array - let arr = array.expect_single().into_expr_err(loc)?; - let arr = ContextVarNode::from(arr).latest_version(analyzer); - - // get length - analyzer.match_length(ctx, loc, array, false)?; - let Some(len) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) - }; - let len = len.expect_single().into_expr_err(loc)?; - let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; - next_len.set_range_min(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; - next_len.set_range_max(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; - - // set length as index - analyzer.index_into_array_inner( - ctx, - loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(next_len.latest_version(analyzer).into()), - ) - }) - } - "concat" => self.concat(loc, input_exprs, ctx), - "keccak256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) - }; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; - Ok(()) - }) - } - "sha256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; - Ok(()) - }) - } - "ripemd160" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; - Ok(()) - }) - } - "blockhash" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "blockhash function was not provided a block number".to_string())) - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; - Ok(()) - }) - } - "gasleft" => { - let var = ContextVar::new_from_builtin( - *loc, - self.builtin_or_add(Builtin::Uint(64)).into(), - self, - ) - .into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), self) - .into_expr_err(*loc)?; - Ok(()) - } - "ecrecover" => { - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let cctx = Context::new_subctx( - ctx, - None, - loc, - None, - Some(func_idx.into()), - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let call_ctx = analyzer.add_node(Node::Context( - cctx - )); - ctx.set_child_call(call_ctx.into(), analyzer) - .into_expr_err(loc)?; - let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); - analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); - analyzer.add_edge( - call_ctx, - call_node, - Edge::Context(ContextEdge::Subcontext), - ); - - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) - }; - - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let mut inner_vals = vec![]; - match input { - ExprRet::Single(var) - | ExprRet::SingleLiteral(var) => { - inner_vals.push( - ContextVarNode::from(var).display_name(analyzer).unwrap(), - ); - } - _ => inner_vals.push("".to_string()), - } - let inner_name = inner_vals.into_iter().collect::>().join(", "); - let mut var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Address).into(), - analyzer, - ) - .into_expr_err(loc)?; - var.display_name = format!("ecrecover({})", inner_name); - var.is_symbolic = true; - var.is_return = true; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); - ContextNode::from(call_ctx) - .add_return_node(loc, cvar.into(), analyzer) - .into_expr_err(loc)?; - - let rctx = Context::new_subctx( - call_ctx.into(), - Some(ctx), - loc, - None, - None, - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let ret_ctx = analyzer.add_node(Node::Context( - rctx - )); - ContextNode::from(call_ctx) - .set_child_call(ret_ctx.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge(ret_ctx, call_ctx, Edge::Context(ContextEdge::Continue)); - - let tmp_ret = ContextVarNode::from(cvar) - .as_tmp( - ContextNode::from(call_ctx).underlying(analyzer).unwrap().loc, - ret_ctx.into(), - analyzer, - ) - .unwrap(); - tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; - tmp_ret.underlying_mut(analyzer).unwrap().display_name = - format!("ecrecover({}).return", inner_name); - ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); - - ContextNode::from(ret_ctx).push_expr(ExprRet::Single(tmp_ret.into()), analyzer).into_expr_err(loc)?; - Ok(()) - }) - } - "addmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "mulmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "wrap" => { - if input_exprs.len() != 2 { - return Err(ExprErr::InvalidFunctionInput(*loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); - } - - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) - }; - input.expect_length(2).into_expr_err(loc)?; - let ret = input.as_vec(); - let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; - let var = ContextVar::new_from_ty( - loc, - TyNode::from(wrapping_ty), - ctx, - analyzer, - ) - .into_expr_err(loc)?; - let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_wrapped), RangeOp::Cast, Elem::from(cvar))); - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - "unwrap" => { - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) - }; - input.expect_length(2).into_expr_err(loc)?; - let ret = input.as_vec(); - let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; - let mut var = ContextVar::new_from_builtin( - loc, - BuiltInNode::from(TyNode::from(wrapping_ty).underlying(analyzer).into_expr_err(loc)?.ty), - analyzer, - ) - .into_expr_err(loc)?; - let to_be_unwrapped = ret[1].expect_single().into_expr_err(loc)?; - var.display_name = format!("{}.unwrap({})", - TyNode::from(wrapping_ty).name(analyzer).into_expr_err(loc)?, - ContextVarNode::from(to_be_unwrapped).display_name(analyzer).into_expr_err(loc)? - ); - - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_unwrapped), RangeOp::Cast, Elem::from(cvar))); - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; - - cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; - cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - e => Err(ExprErr::Todo( - *loc, - format!("builtin function: {e:?} doesn't exist or isn't implemented"), - )), - } - } else { - panic!("unnamed builtin?") - } - } - Node::Builtin(Builtin::Array(_)) => { - // create a new list - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) - }; - - if matches!(len_var, ExprRet::CtxKilled(_)) { - ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let len_cvar = len_var.expect_single().into_expr_err(loc)?; - - let ty = VarType::try_from_idx(analyzer, func_idx); - - let new_arr = ContextVar { - loc: Some(loc), - name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), - display_name: "arr".to_string(), - storage: None, - is_tmp: true, - is_symbolic: false, - is_return: false, - tmp_of: None, - ty: ty.expect("No type for node"), - }; - - let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); - - let len_var = ContextVar { - loc: Some(loc), - name: arr.name(analyzer).into_expr_err(loc)? + ".length", - display_name: arr.display_name(analyzer).unwrap() + ".length", - storage: None, - is_tmp: true, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: ContextVarNode::from(len_cvar) - .underlying(analyzer) - .into_expr_err(loc)? - .ty - .clone(), - }; - - let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); - analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(arr, analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); - - // update the length - if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { - let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; - let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - - ctx.push_expr(ExprRet::Single(arr.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - Node::Builtin(ty) => { - // it is a cast - let ty = ty.clone(); - fn cast_match( - ctx: ContextNode, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ty: &Builtin, - ret: ExprRet, - func_idx: NodeIdx, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, loc, kind).into_expr_err(loc) - } - ExprRet::Null => Ok(()), - ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { - let new_var = ContextVarNode::from(cvar) - .as_cast_tmp(loc, ctx, ty.clone(), analyzer) - .into_expr_err(loc)?; - - new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = - VarType::try_from_idx(analyzer, func_idx).expect(""); - // cast the ranges - if let Some(r) = ContextVarNode::from(cvar) - .range(analyzer) - .into_expr_err(loc)? - { - let curr_range = - SolcRange::try_from_builtin(ty).expect("No default range"); - let min = r - .range_min() - .into_owned() - .cast(curr_range.range_min().into_owned()); - let max = r - .range_max() - .into_owned() - .cast(curr_range.range_max().into_owned()); - new_var.set_range_min(analyzer, min).into_expr_err(loc)?; - new_var.set_range_max(analyzer, max).into_expr_err(loc)?; - // cast the range exclusions - TODO: verify this is correct - let mut exclusions = r.range_exclusions(); - exclusions.iter_mut().for_each(|range| { - *range = - range.clone().cast(curr_range.range_min().into_owned()); - }); - new_var - .set_range_exclusions(analyzer, exclusions) - .into_expr_err(loc)?; - } - - ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| cast_match(ctx, loc, analyzer, ty, i, func_idx)), - } - } - - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - cast_match(ctx, loc, analyzer, &ty, ret, func_idx) - }) - } - Node::ContextVar(_c) => { - // its a user type - // TODO: figure out if we actually need to do anything? - // input_exprs - // .iter() - // .try_for_each(|expr| self.parse_ctx_expr(expr, ctx))?; - - // self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - // }) - - ctx.push_expr(ExprRet::Single(func_idx), self) - .into_expr_err(*loc)?; - Ok(()) - } - Node::Contract(_) => { - if input_exprs.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - "Invalid number of inputs to a contract instantiation".to_string(), - )); - } - - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { - Some(v) => v, - None => { - return Err(ExprErr::VarBadType( - loc, - format!( - "Could not create context variable from user type: {:?}", - analyzer.node(func_idx) - ), - )) - } - }; - let idx = ret.expect_single().into_expr_err(loc)?; - let contract_cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - contract_cvar - .set_range_min(analyzer, Elem::from(idx)) - .into_expr_err(loc)?; - contract_cvar - .set_range_max(analyzer, Elem::from(idx)) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - Node::Unresolved(_) => { - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Function call failed".to_string())) - }; - - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let visible_funcs = ctx.visible_funcs(analyzer).into_expr_err(loc)? - .iter() - .map(|func| func.name(analyzer).unwrap()) - .collect::>(); - - if let Node::Unresolved(ident) = analyzer.node(func_idx) { - Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not find function: \"{}{}\", context: {}, visible functions: {:#?}", - ident.name, - inputs.try_as_func_input_str(analyzer), - ctx.path(analyzer), - visible_funcs - ) - )) - } else { - unreachable!() - } - }) - } - Node::Struct(_) => { - // struct construction - let strukt = StructNode::from(func_idx); - let var = - ContextVar::new_from_struct(*loc, strukt, ctx, self).into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Struct Function call failed".to_string())) - }; - - let inputs = inputs.as_vec(); - // set struct fields - strukt - .fields(analyzer) - .iter() - .zip(inputs) - .try_for_each(|(field, input)| { - let field_cvar = ContextVar::maybe_new_from_field( - analyzer, - loc, - ContextVarNode::from(cvar) - .underlying(analyzer) - .into_expr_err(loc)?, - field.underlying(analyzer).unwrap().clone(), - ) - .expect("Invalid struct field"); - - let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); - analyzer.add_edge( - fc_node, - cvar, - Edge::Context(ContextEdge::AttrAccess), - ); - analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; - let field_as_ret = ExprRet::Single(fc_node); - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; - let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - Ok(()) - })?; - - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc) - }) - } - e => Err(ExprErr::FunctionNotFound(*loc, format!("{e:?}"))), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn concat( - &mut self, - loc: &Loc, - input_exprs: &[Expression], - ctx: ContextNode, - ) -> Result<(), ExprErr> { - input_exprs[1..].iter().try_for_each(|expr| { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let input = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or(ExprRet::Null); - ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) - }) - })?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())) - }; - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let inputs = inputs.as_vec(); - if inputs.is_empty() { - ctx.push_expr(ExprRet::Multi(vec![]), analyzer) - .into_expr_err(loc)?; - Ok(()) - } else { - let start = &inputs[0]; - if inputs.len() > 1 { - analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) - } else { - analyzer.match_concat(ctx, loc, start.clone(), &[], None) - } - } - }) - } - - fn match_concat( - &mut self, - ctx: ContextNode, - loc: Loc, - curr: ExprRet, - inputs: &[ExprRet], - accum_node: Option, - ) -> Result<(), ExprErr> { - if let Some(accum_node) = accum_node { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => { - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } else { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - let acc = ContextVarNode::from(var) - .as_tmp(loc, ctx, self) - .into_expr_err(loc)?; - inputs - .iter() - .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) - .collect::, ExprErr>>()?; - ctx.push_expr(ExprRet::Single(acc.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => Err(ExprErr::NoRhs( - loc, - "No input provided to concat function".to_string(), - )), - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } - } - - fn concat_inner( - &mut self, - loc: Loc, - accum: ContextVarNode, - right: ContextVarNode, - ) -> Result<(), ExprErr> { - match ( - accum.ty(self).into_expr_err(loc)?, - right.ty(self).into_expr_err(loc)?, - ) { - (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { - let new_ty = match ( - accum_cnode.underlying(self).into_expr_err(loc)?, - right_cnode.underlying(self).into_expr_err(loc)?, - ) { - (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (a, b) => { - // Invalid solidity - return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); - } - }; - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { - let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; - // let val = match underlying { - // Concrete::String(val) => { - // val - // .chars() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // v.encode_utf8(&mut bytes[..]); - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // Concrete::DynBytes(val) => { - // val - // .iter() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // bytes[0] = *v; - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) - // }; - // TODO: Extend with bn - - let range = SolcRange::from(underlying.clone()).unwrap(); - let min = range.min.clone().concat(r2.min.clone()); - let max = range.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; - - let new_ty = - VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { - // TODO: improve length calculation here - let min = r.min.clone().concat(r2.min.clone()); - let max = r.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; - Ok(()) - } - (_, _) => Ok(()), - } - } -} diff --git a/src/context/func_call/mod.rs b/src/context/func_call/mod.rs deleted file mode 100644 index 897feec9..00000000 --- a/src/context/func_call/mod.rs +++ /dev/null @@ -1,1174 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::{ - internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, - namespaced_call::NameSpaceFuncCaller, -}; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use std::cell::RefCell; -use std::rc::Rc; - -use shared::analyzer::GraphLike; -use shared::context::ExprRet; -use shared::context::*; -use solang_parser::helpers::CodeLocation; -use std::collections::BTreeMap; - -use shared::range::Range; -use solang_parser::pt::{Expression, Loc, NamedArgument, StorageLocation}; - -use crate::VarType; - -use shared::{analyzer::AnalyzerLike, nodes::*, Edge, Node, NodeIdx}; - -pub mod internal_call; -pub mod intrinsic_call; -pub mod modifier; -pub mod namespaced_call; - -impl FuncCaller for T where - T: AnalyzerLike + Sized + GraphLike -{ -} -pub trait FuncCaller: - GraphLike + AnalyzerLike + Sized -{ - #[tracing::instrument(level = "trace", skip_all)] - fn named_fn_call_expr( - &mut self, - ctx: ContextNode, - loc: &Loc, - func_expr: &Expression, - input_exprs: &[NamedArgument], - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_named_func(ctx, loc, member_expr, ident, input_exprs) - } - Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), - e => Err(ExprErr::IntrinsicNamedArgs( - *loc, - format!("Cannot call intrinsic functions with named arguments. Call: {e:?}"), - )), - } - } - #[tracing::instrument(level = "trace", skip_all)] - fn fn_call_expr( - &mut self, - ctx: ContextNode, - loc: &Loc, - func_expr: &Expression, - input_exprs: &[Expression], - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_func(ctx, loc, member_expr, ident, input_exprs) - } - Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, input_exprs), - _ => { - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Function call to nonexistent function".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) - }) - } - } - } - - fn match_intrinsic_fallback( - &mut self, - ctx: ContextNode, - loc: &Loc, - input_exprs: &[Expression], - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(func_idx) | ExprRet::SingleLiteral(func_idx) => { - self.intrinsic_func_call(loc, input_exprs, func_idx, ctx) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|ret| self.match_intrinsic_fallback(ctx, loc, input_exprs, ret)), - ExprRet::CtxKilled(kind) => ctx.kill(self, *loc, kind).into_expr_err(*loc), - ExprRet::Null => Ok(()), - } - } - - /// Disambiguates a function call by their inputs (length & type) - fn disambiguate_fn_call( - &mut self, - fn_name: &str, - literals: Vec, - input_paths: &ExprRet, - funcs: &[FunctionNode], - ) -> Option { - let input_paths = input_paths.clone().flatten(); - // try to find the function based on naive signature - // This doesnt do type inference on NumberLiterals (i.e. 100 could be uintX or intX, and there could - // be a function that takes an int256 but we evaled as uint256) - let fn_sig = format!("{}{}", fn_name, input_paths.try_as_func_input_str(self)); - if let Some(func) = funcs.iter().find(|func| func.name(self).unwrap() == fn_sig) { - return Some(*func); - } - - // filter by input len - let inputs = input_paths.as_flat_vec(); - let funcs: Vec<&FunctionNode> = funcs - .iter() - .filter(|func| func.params(self).len() == inputs.len()) - .collect(); - - if funcs.len() == 1 { - return Some(*funcs[0]); - } - - if !literals.iter().any(|i| *i) { - None - } else { - let funcs = funcs - .iter() - .filter(|func| { - let params = func.params(self); - params - .iter() - .zip(&inputs) - .enumerate() - .all(|(i, (param, input))| { - let param_ty = VarType::try_from_idx(self, (*param).into()).unwrap(); - let input_ty = ContextVarNode::from(*input).ty(self).unwrap(); - if param_ty.ty_eq(input_ty, self).unwrap() { - true - } else if literals[i] { - let possibilities = ContextVarNode::from(*input) - .ty(self) - .unwrap() - .possible_builtins_from_ty_inf(self); - let param_ty = param.ty(self).unwrap(); - match self.node(param_ty) { - Node::Builtin(b) => possibilities.contains(b), - _ => false, - } - } else { - false - } - }) - }) - .collect::>(); - if funcs.len() == 1 { - Some(**funcs[0]) - } else { - // this would be invalid solidity, likely the user needs to perform a cast - None - } - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_inputs( - &mut self, - ctx: ContextNode, - loc: Loc, - inputs: &[Expression], - ) -> Result<(), ExprErr> { - let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { - Rc::new(RefCell::new(true)) - } else { - Rc::new(RefCell::new(false)) - }; - - inputs - .iter() - .try_for_each(|input| { - self.parse_ctx_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) - })?; - if !inputs.is_empty() { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - ctx.push_expr(ret, analyzer).into_expr_err(loc) - }) - } else { - Ok(()) - } - } - - /// Setups up storage variables for a function call and calls it - fn setup_fn_call( - &mut self, - loc: &Loc, - inputs: &ExprRet, - func_idx: NodeIdx, - ctx: ContextNode, - func_call_str: Option<&str>, - ) -> Result<(), ExprErr> { - // if we have a single match thats our function - let var = match ContextVar::maybe_from_user_ty(self, *loc, func_idx) { - Some(v) => v, - None => panic!( - "Could not create context variable from user type: {:?}", - self.node(func_idx) - ), - }; - - let new_cvarnode = self.add_node(Node::ContextVar(var)); - ctx.add_var(new_cvarnode.into(), self).into_expr_err(*loc)?; - self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); - if let Some(func_node) = ContextVarNode::from(new_cvarnode) - .ty(self) - .into_expr_err(*loc)? - .func_node(self) - { - self.func_call(ctx, *loc, inputs, func_node, func_call_str, None) - } else { - unreachable!() - } - } - - /// Matches the input kinds and performs the call - fn func_call( - &mut self, - ctx: ContextNode, - loc: Loc, - input_paths: &ExprRet, - func: FunctionNode, - func_call_str: Option<&str>, - modifier_state: Option, - ) -> Result<(), ExprErr> { - let params = func.params(self); - let input_paths = input_paths.clone().flatten(); - if input_paths.has_killed() { - return ctx - .kill(self, loc, input_paths.killed_kind().unwrap()) - .into_expr_err(loc); - } - match input_paths { - ExprRet::Single(input_var) | ExprRet::SingleLiteral(input_var) => { - // if we get a single var, we expect the func to only take a single - // variable - self.func_call_inner( - false, - ctx, - func, - loc, - vec![ContextVarNode::from(input_var).latest_version(self)], - params, - func_call_str, - modifier_state, - ) - } - ExprRet::Multi(ref inputs) => { - if ExprRet::Multi(inputs.to_vec()).flatten().has_killed() { - return ctx - .kill( - self, - loc, - ExprRet::Multi(inputs.to_vec()).killed_kind().unwrap(), - ) - .into_expr_err(loc); - } - // check if the inputs length matchs func params length - // if they do, check that none are forks - if inputs.len() == params.len() { - let input_vars = inputs - .iter() - .map(|expr_ret| { - let var = expr_ret.expect_single().into_expr_err(loc)?; - Ok(ContextVarNode::from(var).latest_version(self)) - }) - .collect::, ExprErr>>()?; - self.func_call_inner( - false, - ctx, - func, - loc, - input_vars, - params, - func_call_str, - modifier_state, - ) - } else { - Err(ExprErr::InvalidFunctionInput( - loc, - format!( - "Length mismatch: {inputs:?} {params:?}, inputs as vars: {}, ctx: {}", - ExprRet::Multi(inputs.to_vec()).debug_str(self), - ctx.path(self) - ), - )) - } - } - e => todo!("here: {:?}", e), - } - } - - fn create_call_ctx( - &mut self, - curr_ctx: ContextNode, - loc: Loc, - func_node: FunctionNode, - modifier_state: Option, - ) -> Result { - let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; - let ctx = Context::new_subctx( - curr_ctx, - None, - loc, - None, - Some(func_node), - fn_ext, - self, - modifier_state, - ) - .into_expr_err(loc)?; - let callee_ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - curr_ctx - .set_child_call(callee_ctx, self) - .into_expr_err(loc)?; - let ctx_fork = self.add_node(Node::FunctionCall); - self.add_edge(ctx_fork, curr_ctx, Edge::Context(ContextEdge::Subcontext)); - self.add_edge(ctx_fork, func_node, Edge::Context(ContextEdge::Call)); - self.add_edge( - NodeIdx::from(callee_ctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - Ok(callee_ctx) - } - - /// Maps inputs to function parameters such that if there is a renaming i.e. `a(uint256 x)` is called via `a(y)`, - /// we map `y -> x` for future lookups - fn map_inputs_to_params( - &mut self, - loc: Loc, - entry_call: bool, - params: Vec, - inputs: Vec, - callee_ctx: ContextNode, - ) -> Result, ExprErr> { - Ok(params - .iter() - .zip(inputs.iter()) - .filter_map(|(param, input)| { - if !entry_call { - if let Some(name) = - self.add_if_err(param.maybe_name(self).into_expr_err(loc))? - { - let res = input - .latest_version(self) - .underlying(self) - .into_expr_err(loc) - .cloned(); - let mut new_cvar = self.add_if_err(res)?; - new_cvar.loc = Some(param.loc(self).unwrap()); - new_cvar.name = name.clone(); - new_cvar.display_name = name; - new_cvar.is_tmp = false; - new_cvar.storage = if let Some(StorageLocation::Storage(_)) = - param.underlying(self).unwrap().storage - { - new_cvar.storage - } else { - None - }; - - if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) - { - let ty = new_cvar.ty.clone(); - if !ty.ty_eq(¶m_ty, self).unwrap() { - if let Some(new_ty) = ty.try_cast(¶m_ty, self).unwrap() { - new_cvar.ty = new_ty; - } - } - } - - let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); - self.add_edge( - node, - input.latest_version(self), - Edge::Context(ContextEdge::InputVariable), - ); - - if let (Some(r), Some(r2)) = - (node.range(self).unwrap(), param.range(self).unwrap()) - { - let new_min = - r.range_min().into_owned().cast(r2.range_min().into_owned()); - let new_max = - r.range_max().into_owned().cast(r2.range_max().into_owned()); - let res = node.try_set_range_min(self, new_min).into_expr_err(loc); - self.add_if_err(res); - let res = node.try_set_range_max(self, new_max).into_expr_err(loc); - self.add_if_err(res); - let res = node - .try_set_range_exclusions(self, r.exclusions) - .into_expr_err(loc); - self.add_if_err(res); - } - callee_ctx.add_var(node, self).unwrap(); - self.add_edge(node, callee_ctx, Edge::Context(ContextEdge::Variable)); - Some((*input, node)) - } else { - None - } - } else { - None - } - }) - .collect::>()) - } - - /// Checks if there are any modifiers and executes them prior to executing the function - #[tracing::instrument(level = "trace", skip_all)] - fn func_call_inner( - &mut self, - entry_call: bool, - ctx: ContextNode, - func_node: FunctionNode, - loc: Loc, - inputs: Vec, - params: Vec, - func_call_str: Option<&str>, - modifier_state: Option, - ) -> Result<(), ExprErr> { - // pseudocode: - // 1. Create context for the call - // 2. Check for modifiers - // 3. Call modifier 0, then 1, then 2, ... then N. - // 4. Call this function - // 5. Finish modifier N.. then 2, then 1, then 0 - let callee_ctx = if entry_call { - ctx - } else { - self.create_call_ctx(ctx, loc, func_node, modifier_state)? - }; - - // TODO: implement joining - // if !entry_call { - // let mapping = params - // .iter() - // .zip(inputs.iter()) - // .map(|(param, input)| (*input, *param)) - // .collect::>(); - // ctx.join(func_node, &mapping, self); - // } - - // handle remapping of variable names and bringing variables into the new context - let renamed_inputs = - self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; - - // begin modifier handling by making sure modifiers were set - if !func_node.modifiers_set(self).into_expr_err(loc)? { - self.set_modifiers(func_node, ctx)?; - } - - // get modifiers - let mods = func_node.modifiers(self); - self.apply_to_edges(callee_ctx, loc, &|analyzer, callee_ctx, loc| { - if let Some(mod_state) = &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state { - // we are iterating through modifiers - if mod_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = mod_state.clone(); - mstate.num += 1; - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, mstate) - } else { - // out of modifiers, execute the actual function call - analyzer.execute_call_inner( - loc, - ctx, - callee_ctx, - func_node, - &renamed_inputs, - func_call_str, - ) - } - } else if !mods.is_empty() { - // we have modifiers and havent executed them, start the process of executing them - let state = - ModifierState::new(0, loc, func_node, callee_ctx, ctx, renamed_inputs.clone()); - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, state) - } else { - // no modifiers, just execute the function - analyzer.execute_call_inner( - loc, - ctx, - callee_ctx, - func_node, - &renamed_inputs, - func_call_str, - ) - } - }) - } - - /// Actually executes the function - #[tracing::instrument(level = "trace", skip_all)] - fn execute_call_inner( - &mut self, - loc: Loc, - caller_ctx: ContextNode, - callee_ctx: ContextNode, - func_node: FunctionNode, - _renamed_inputs: &BTreeMap, - func_call_str: Option<&str>, - ) -> Result<(), ExprErr> { - if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { - // add return nodes into the subctx - func_node - .returns(self) - .collect::>() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - callee_ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); - } - }); - - self.parse_ctx_statement(&body, false, Some(callee_ctx)); - self.ctx_rets(loc, caller_ctx, callee_ctx) - } else { - let ret_ctx = Context::new_subctx( - callee_ctx, - Some(caller_ctx), - loc, - None, - None, - false, - self, - caller_ctx - .underlying(self) - .into_expr_err(loc)? - .modifier_state - .clone(), - ) - .unwrap(); - let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); - - let res = callee_ctx - .set_child_call(ret_subctx, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { - func_node - .returns(analyzer) - .collect::>() - .into_iter() - .try_for_each(|ret| { - let underlying = ret.underlying(analyzer).unwrap(); - let mut var = - ContextVar::new_from_func_ret(ctx, analyzer, underlying.clone()) - .unwrap() - .expect("No type for return variable?"); - if let Some(func_call) = &func_call_str { - var.name = - format!("{}_{}", func_call, callee_ctx.new_tmp(analyzer).unwrap()); - var.display_name = func_call.to_string(); - } - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - }) - } - } - - fn ctx_rets( - &mut self, - loc: Loc, - caller_ctx: ContextNode, - callee_ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!( - "Handling function call return for: {}, {}, depth: {:?}, {:?}", - caller_ctx.path(self), - callee_ctx.path(self), - caller_ctx.depth(self), - callee_ctx.depth(self), - ); - match callee_ctx.underlying(self).into_expr_err(loc)?.child { - Some(CallFork::Fork(w1, w2)) => { - self.ctx_rets(loc, caller_ctx, w1)?; - self.ctx_rets(loc, caller_ctx, w2)?; - Ok(()) - } - Some(CallFork::Call(c)) - if c.underlying(self).into_expr_err(loc)?.depth - >= caller_ctx.underlying(self).into_expr_err(loc)?.depth => - { - // follow rabbit hole - self.ctx_rets(loc, caller_ctx, c)?; - Ok(()) - } - _ => { - if callee_ctx.is_killed(self).into_expr_err(loc)? { - return Ok(()); - } - let callee_depth = callee_ctx.underlying(self).into_expr_err(loc)?.depth; - let caller_depth = caller_ctx.underlying(self).into_expr_err(loc)?.depth; - if callee_depth != caller_depth { - let ctx = Context::new_subctx( - callee_ctx, - Some(caller_ctx), - loc, - None, - None, - false, - self, - caller_ctx - .underlying(self) - .into_expr_err(loc)? - .modifier_state - .clone(), - ) - .unwrap(); - let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); - - let res = callee_ctx - .set_child_call(ret_subctx, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); - - if rets.is_empty() { - let func_rets: Vec = callee_ctx - .associated_fn(self) - .into_expr_err(loc)? - .returns(self) - .collect(); - func_rets - .iter() - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) - .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; - - // add unnamed rets - func_rets - .into_iter() - .filter(|ret| ret.maybe_name(self).unwrap().is_none()) - .collect::>() - .iter() - .try_for_each(|ret| { - let ret_loc = ret.loc(self).into_expr_err(loc)?; - let cvar = ContextVar::new_from_func_ret( - callee_ctx, - self, - ret.underlying(self).into_expr_err(loc)?.clone(), - ) - .into_expr_err(loc)? - .unwrap(); - let cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); - callee_ctx.add_var(cvar, self).into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Variable), - ); - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } - let ret = rets - .into_iter() - .enumerate() - .map(|(i, (_, node))| { - let tmp_ret = node - .as_tmp(callee_ctx.underlying(self).unwrap().loc, ret_subctx, self) - .unwrap(); - tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; - tmp_ret - .underlying_mut(self) - .into_expr_err(loc)? - .display_name = - format!("{}.{}", callee_ctx.associated_fn_name(self).unwrap(), i); - ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; - self.add_edge( - tmp_ret, - ret_subctx, - Edge::Context(ContextEdge::Variable), - ); - Ok(ExprRet::Single(tmp_ret.into())) - }) - .collect::>()?; - ret_subctx - .push_expr(ExprRet::Multi(ret), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); - - if rets.is_empty() { - callee_ctx - .associated_fn(self) - .into_expr_err(loc)? - .returns(self) - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) - .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } - callee_ctx - .push_expr( - ExprRet::Multi( - rets.iter() - .map(|(_, node)| ExprRet::Single((*node).into())) - .collect(), - ), - self, - ) - .into_expr_err(loc) - } - } - } - } - - /// Calls a modifier for a function - #[tracing::instrument(level = "trace", skip_all)] - fn call_modifier_for_fn( - &mut self, - loc: Loc, - func_ctx: ContextNode, - func_node: FunctionNode, - mod_state: ModifierState, - ) -> Result<(), ExprErr> { - let mod_node = func_node.modifiers(self)[mod_state.num]; - tracing::trace!( - "calling modifier {} for func {}", - mod_node.name(self).into_expr_err(loc)?, - func_node.name(self).into_expr_err(loc)? - ); - - let input_exprs = func_node - .modifier_input_vars(mod_state.num, self) - .into_expr_err(loc)?; - - input_exprs - .iter() - .try_for_each(|expr| self.parse_ctx_expr(expr, func_ctx))?; - self.apply_to_edges(func_ctx, loc, &|analyzer, ctx, loc| { - let input_paths = if input_exprs.is_empty() { - ExprRet::Multi(vec![]) - } else { - let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, format!("No inputs to modifier, expected: {}", input_exprs.len()))) - }; - - if matches!(input_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(input_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - input_paths - }; - - analyzer.func_call( - ctx, - loc, - &input_paths, - mod_node, - None, - Some(mod_state.clone()), - ) - }) - } - - /// Resumes the parent function of a modifier - #[tracing::instrument(level = "trace", skip_all)] - fn resume_from_modifier( - &mut self, - ctx: ContextNode, - modifier_state: ModifierState, - ) -> Result<(), ExprErr> { - tracing::trace!( - "resuming from modifier: {}", - ctx.associated_fn_name(self) - .into_expr_err(modifier_state.loc)? - ); - - let mods = modifier_state.parent_fn.modifiers(self); - self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { - if modifier_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = modifier_state.clone(); - mstate.num += 1; - - let loc = mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc; - - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - loc, - None, - None, - false, - analyzer, - Some(modifier_state.clone()), - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; - - analyzer.call_modifier_for_fn( - mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc, - new_parent_subctx, - mstate.parent_fn, - mstate, - )?; - Ok(()) - } else { - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - modifier_state.loc, - None, - None, - false, - analyzer, - None, - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; - - // actually execute the parent function - analyzer.execute_call_inner( - modifier_state.loc, - ctx, - new_parent_subctx, - modifier_state.parent_fn, - &modifier_state.renamed_inputs, - None, - )?; - - fn inherit_return_from_call( - analyzer: &mut (impl GraphLike + AnalyzerLike), - loc: Loc, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - let mctx = - Context::new_subctx(ctx, Some(ctx), loc, None, None, false, analyzer, None) - .unwrap(); - let modifier_after_subctx = - ContextNode::from(analyzer.add_node(Node::Context(mctx))); - - ctx.set_child_call(modifier_after_subctx, analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - modifier_after_subctx, - ctx, - Edge::Context(ContextEdge::Continue), - ); - - let ret = ctx.underlying(analyzer).unwrap().ret.clone(); - modifier_after_subctx.underlying_mut(analyzer).unwrap().ret = ret; - Ok(()) - } - - analyzer.apply_to_edges(new_parent_subctx, loc, &|analyzer, ctx, _loc| { - inherit_return_from_call(analyzer, modifier_state.loc, ctx) - }) - - // if edges.is_empty() { - // inherit_return_from_call(analyzer, modifier_state.loc, new_parent_subctx)?; - // } else { - // edges.iter().try_for_each(|i| { - // inherit_return_from_call(analyzer, modifier_state.loc, *i)?; - // Ok(()) - // })?; - // } - // Ok(()) - } - }) - } - - /// Inherit the input changes from a function call - fn inherit_input_changes( - &mut self, - loc: Loc, - to_ctx: ContextNode, - from_ctx: ContextNode, - renamed_inputs: &BTreeMap, - ) -> Result<(), ExprErr> { - if to_ctx != from_ctx { - self.apply_to_edges(to_ctx, loc, &|analyzer, to_ctx, loc| { - renamed_inputs - .iter() - .try_for_each(|(input_var, updated_var)| { - let new_input = analyzer.advance_var_in_ctx( - input_var.latest_version(analyzer), - loc, - to_ctx, - )?; - let latest_updated = updated_var.latest_version(analyzer); - if let Some(updated_var_range) = - latest_updated.range(analyzer).into_expr_err(loc)? - { - let res = new_input - .set_range_min(analyzer, updated_var_range.range_min().into_owned()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_input - .set_range_max(analyzer, updated_var_range.range_max().into_owned()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_input - .set_range_exclusions( - analyzer, - updated_var_range.range_exclusions(), - ) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - } - Ok(()) - }) - })?; - } - Ok(()) - } - - /// Inherit the input changes from a function call - fn modifier_inherit_return(&mut self, mod_ctx: ContextNode, fn_ctx: ContextNode) { - let ret = fn_ctx.underlying(self).unwrap().ret.clone(); - mod_ctx.underlying_mut(self).unwrap().ret = ret; - } - - /// Inherit the storage changes from a function call - fn inherit_storage_changes( - &mut self, - loc: Loc, - inheritor_ctx: ContextNode, - grantor_ctx: ContextNode, - ) -> Result<(), ExprErr> { - if inheritor_ctx != grantor_ctx { - return self.apply_to_edges(inheritor_ctx, loc, &|analyzer, inheritor_ctx, loc| { - let vars = grantor_ctx.local_vars(analyzer).clone(); - vars.iter().try_for_each(|(name, old_var)| { - let var = old_var.latest_version(analyzer); - let underlying = var.underlying(analyzer).into_expr_err(loc)?; - if var.is_storage(analyzer).into_expr_err(loc)? { - if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { - let new_inheritor_var = analyzer - .advance_var_in_ctx( - inheritor_var, - underlying.loc.expect("No loc for val change"), - inheritor_ctx, - ) - .unwrap(); - let _ = new_inheritor_var - .set_range_min(analyzer, r.range_min().into_owned()); - let _ = new_inheritor_var - .set_range_max(analyzer, r.range_max().into_owned()); - let _ = new_inheritor_var - .set_range_exclusions(analyzer, r.range_exclusions()); - } - } else { - let new_in_inheritor = - analyzer.add_node(Node::ContextVar(underlying.clone())); - inheritor_ctx - .add_var(new_in_inheritor.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - new_in_inheritor, - inheritor_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - new_in_inheritor, - var, - Edge::Context(ContextEdge::InheritedVariable), - ); - } - } - Ok(()) - }) - }); - } - Ok(()) - } - - fn modifiers( - &mut self, - ctx: ContextNode, - func: FunctionNode, - ) -> Result, ExprErr> { - use std::fmt::Write; - let binding = func.underlying(self).unwrap().clone(); - let modifiers = binding.modifiers_as_base(); - if modifiers.is_empty() { - Ok(vec![]) - } else { - let res = modifiers - .iter() - .map(|modifier| { - assert_eq!(modifier.name.identifiers.len(), 1); - // construct arg string for function selector - let mut mod_name = format!("{}", modifier.name.identifiers[0]); - if let Some(args) = &modifier.args { - let args_str = args - .iter() - .map(|expr| { - let mctx = Context::new_subctx( - ctx, - None, - Loc::Implicit, - None, - None, - false, - self, - None, - ) - .into_expr_err(Loc::Implicit)?; - let callee_ctx = - ContextNode::from(self.add_node(Node::Context(mctx))); - let _res = ctx.set_child_call(callee_ctx, self); - self.parse_ctx_expr(expr, callee_ctx)?; - let f: Vec = - self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { - let ret = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap(); - Ok(ret.try_as_func_input_str(analyzer)) - })?; - - ctx.delete_child(self).into_expr_err(expr.loc())?; - Ok(f.first().unwrap().clone()) - }) - .collect::, ExprErr>>()? - .join(", "); - let _ = write!(mod_name, "{args_str}"); - } else { - let _ = write!(mod_name, "()"); - } - let _ = write!(mod_name, ""); - let found: Option = ctx - .visible_modifiers(self) - .unwrap() - .iter() - .find(|modifier| modifier.name(self).unwrap() == mod_name) - .copied(); - Ok(found) - }) - .collect::>, ExprErr>>()? - .into_iter() - .flatten() - .collect::>(); - Ok(res) - } - } - - fn set_modifiers(&mut self, func: FunctionNode, ctx: ContextNode) -> Result<(), ExprErr> { - let modifiers = self.modifiers(ctx, func)?; - modifiers - .iter() - .enumerate() - .for_each(|(i, modifier)| self.add_edge(*modifier, func, Edge::FuncModifier(i))); - func.underlying_mut(self).unwrap().modifiers_set = true; - Ok(()) - } -} diff --git a/src/context/func_call/modifier.rs b/src/context/func_call/modifier.rs deleted file mode 100644 index a62adda5..00000000 --- a/src/context/func_call/modifier.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::FuncCaller; - -use crate::context::ExprErr; - -use shared::analyzer::GraphLike; -use shared::context::*; - -use solang_parser::pt::{Expression, Loc}; - -use shared::{analyzer::AnalyzerLike, nodes::*}; - -impl ModifierCaller for T where - T: AnalyzerLike + Sized + GraphLike -{ -} -pub trait ModifierCaller: - GraphLike + AnalyzerLike + Sized -{ - fn handle_modifiers( - &mut self, - ctx: ContextNode, - loc: Loc, - _input_paths: &ExprRet, - func: FunctionNode, - _func_call_str: Option, - ) -> Result { - if !func.modifiers_set(self).into_expr_err(loc)? { - self.set_modifiers(func, ctx)?; - } - - todo!() - } -} diff --git a/src/context/func_call/namespaced_call.rs b/src/context/func_call/namespaced_call.rs deleted file mode 100644 index 9a4118d2..00000000 --- a/src/context/func_call/namespaced_call.rs +++ /dev/null @@ -1,372 +0,0 @@ -use crate::context::{ - exprs::{IntoExprErr, MemberAccess}, - func_call::intrinsic_call::IntrinsicFuncCaller, - func_call::FuncCaller, - ContextBuilder, ExprErr, -}; -use shared::nodes::BuiltInNode; -use shared::{ - analyzer::{AnalyzerLike, GraphLike}, - context::{ContextNode, ContextVarNode, ExprRet}, - nodes::FunctionNode, - Node, NodeIdx, -}; -use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; - -impl NameSpaceFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike -{ -} -pub trait NameSpaceFuncCaller: - AnalyzerLike + Sized + GraphLike -{ - #[tracing::instrument(level = "trace", skip_all)] - fn call_name_spaced_named_func( - &mut self, - ctx: ContextNode, - _loc: &Loc, - member_expr: &Expression, - _ident: &Identifier, - _input_args: &[NamedArgument], - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(member_expr, ctx)?; - todo!("here"); - } - - #[tracing::instrument(level = "trace", skip_all)] - fn call_name_spaced_func( - &mut self, - ctx: ContextNode, - loc: &Loc, - member_expr: &Expression, - ident: &Identifier, - input_exprs: &[Expression], - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - tracing::trace!("Calling name spaced function"); - if let Variable(Identifier { name, .. }) = member_expr { - if name == "abi" { - let func_name = format!("abi.{}", ident.name); - let fn_node = self - .builtin_fn_or_maybe_add(&func_name) - .unwrap_or_else(|| panic!("No builtin function with name {func_name}")); - return self.intrinsic_func_call(loc, input_exprs, fn_node, ctx); - } else if name == "super" { - if let Some(contract) = ctx.maybe_associated_contract(self).into_expr_err(*loc)? { - let supers = contract.super_contracts(self); - let possible_funcs: Vec<_> = supers - .iter() - .filter_map(|con_node| { - con_node - .linearized_functions(self) - .into_iter() - .find(|(func_name, _func_node)| func_name.starts_with(&ident.name)) - .map(|(_, node)| node) - }) - .collect(); - - if possible_funcs.is_empty() { - return Err(ExprErr::FunctionNotFound( - *loc, - "Could not find function in super".to_string(), - )); - } - self.parse_inputs(ctx, *loc, input_exprs)?; - return self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = if let Some(inputs) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - { - inputs - } else { - ExprRet::Multi(vec![]) - }; - if possible_funcs.len() == 1 { - let mut inputs = inputs.as_vec(); - let func = possible_funcs[0]; - if func.params(analyzer).len() < inputs.len() { - inputs = inputs[1..].to_vec(); - } - let inputs = ExprRet::Multi(inputs); - if inputs.has_killed() { - return ctx - .kill(analyzer, loc, inputs.killed_kind().unwrap()) - .into_expr_err(loc); - } - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) - } else { - // this is the annoying case due to function overloading & type inference on number literals - let mut lits = vec![false]; - lits.extend( - input_exprs - .iter() - .map(|expr| { - match expr { - Negate(_, expr) => { - // negative number potentially - matches!(**expr, NumberLiteral(..) | HexLiteral(..)) - } - NumberLiteral(..) | HexLiteral(..) => true, - _ => false, - } - }) - .collect::>(), - ); - - if inputs.has_killed() { - return ctx - .kill(analyzer, loc, inputs.killed_kind().unwrap()) - .into_expr_err(loc); - } - if let Some(func) = analyzer.disambiguate_fn_call( - &ident.name, - lits, - &inputs, - &possible_funcs, - ) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) - } else { - Err(ExprErr::FunctionNotFound( - loc, - "Could not find function in super".to_string(), - )) - } - } - }); - } - } - } - - self.parse_ctx_expr(member_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Namespace function call had no namespace".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) - }) - } - - fn match_namespaced_member( - &mut self, - ctx: ContextNode, - loc: Loc, - member_expr: &Expression, - ident: &Identifier, - input_exprs: &[Expression], - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { - self.call_name_spaced_func_inner(ctx, loc, member_expr, ident, input_exprs, inner) - } - ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { - self.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) - }), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Null => Err(ExprErr::NoLhs( - loc, - "No function found due to null".to_string(), - )), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn call_name_spaced_func_inner( - &mut self, - ctx: ContextNode, - loc: Loc, - member_expr: &Expression, - ident: &Identifier, - input_exprs: &[Expression], - member: NodeIdx, - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - tracing::trace!( - "namespaced function call: {:?}.{:?}(..)", - ContextVarNode::from(member).display_name(self), - ident.name - ); - - let funcs = self.visible_member_funcs(ctx, loc, member)?; - // filter down all funcs to those that match - let possible_funcs = funcs - .iter() - .filter(|func| { - func.name(self) - .unwrap() - .starts_with(&format!("{}(", ident.name)) - }) - .copied() - .collect::>(); - - ctx.push_expr(ExprRet::Single(member), self) - .into_expr_err(loc)?; - - self.parse_inputs(ctx, loc, input_exprs)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Namespace function call had no inputs".to_string())) - }; - - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if possible_funcs.is_empty() { - // TODO: this is extremely ugly. - if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); - } - let mut inputs = inputs.as_vec(); - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } - let inputs = ExprRet::Multi(inputs); - - let as_input_str = inputs.try_as_func_input_str(analyzer); - - let lits = inputs.literals_list().into_expr_err(loc)?; - if lits.iter().any(|i| *i) { - // try to disambiguate - if lits[0] { - Err(ExprErr::Todo(loc, "First element in function call was literal".to_string())) - } else { - let ty = if let Node::ContextVar(cvar) = analyzer.node(member) { - cvar.ty.ty_idx() - } else { - member - }; - - let possible_builtins: Vec<_> = analyzer.builtin_fn_inputs().iter().filter_map(|(func_name, (inputs, _))| { - if func_name.starts_with(&ident.name) { - if let Some(input) = inputs.first() { - let Ok(implicitly_castable) = BuiltInNode::from(ty).implicitly_castable_to(&BuiltInNode::from(input.ty), analyzer) else { - return None - }; - if implicitly_castable { - Some(func_name.clone()) - } else { - None - } - } else { - None - } - } else { - None - } - }).collect::>(); - let possible_builtins: Vec<_> = possible_builtins.into_iter().filter_map(|name| { - analyzer.builtin_fn_or_maybe_add(&name).map(FunctionNode::from) - }).collect(); - if let Some(func) = - analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_builtins) - { - let expr = &MemberAccess( - loc, - Box::new(member_expr.clone()), - Identifier { - loc: ident.loc, - name: func.name(analyzer).into_expr_err(loc)?.split('(').collect::>()[0].to_string(), - }, - ); - analyzer.parse_ctx_expr(expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let mut modifier_input_exprs = vec![member_expr.clone()]; - modifier_input_exprs.extend(input_exprs.to_vec()); - analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) - }) - } else { - // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) - Err(ExprErr::FunctionNotFound( - loc, - format!("Could not disambiguate function, possible functions: {:#?}", possible_builtins.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) - )) - } - } - } else { - let expr = &MemberAccess( - loc, - Box::new(member_expr.clone()), - Identifier { - loc: ident.loc, - name: format!("{}{}", ident.name, as_input_str), - }, - ); - analyzer.parse_ctx_expr(expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let mut modifier_input_exprs = vec![member_expr.clone()]; - modifier_input_exprs.extend(input_exprs.to_vec()); - analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) - }) - } - } else if possible_funcs.len() == 1 { - let mut inputs = inputs.as_vec(); - let func = possible_funcs[0]; - if func.params(analyzer).len() > inputs.len() { - // Add the member back in if its a context variable - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } - } - let inputs = ExprRet::Multi(inputs); - if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); - } - - - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) - } else { - // Add the member back in if its a context variable - let mut inputs = inputs.as_vec(); - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } - let inputs = ExprRet::Multi(inputs); - // this is the annoying case due to function overloading & type inference on number literals - let mut lits = vec![false]; - lits.extend( - input_exprs - .iter() - .map(|expr| { - match expr { - Negate(_, expr) => { - // negative number potentially - matches!(**expr, NumberLiteral(..) | HexLiteral(..)) - } - NumberLiteral(..) | HexLiteral(..) => true, - _ => false, - } - }) - .collect::>(), - ); - - if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); - } - if let Some(func) = - analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_funcs) - { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) - } else { - Err(ExprErr::FunctionNotFound( - loc, - format!("Could not disambiguate function, possible functions: {:#?}", possible_funcs.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) - )) - } - } - }) - } -} diff --git a/src/context/loops.rs b/src/context/loops.rs deleted file mode 100644 index 449b4d6e..00000000 --- a/src/context/loops.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::ExprErr; -use solang_parser::pt::Loc; -use solang_parser::pt::Statement; - -use crate::context::ContextBuilder; -use shared::analyzer::GraphLike; -use shared::context::*; -use shared::{analyzer::AnalyzerLike, Node}; -use solang_parser::pt::Expression; - -impl Looper for T where T: AnalyzerLike + Sized + GraphLike {} -pub trait Looper: GraphLike + AnalyzerLike + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn for_loop( - &mut self, - loc: Loc, - ctx: ContextNode, - maybe_init: &Option>, - _maybe_limiter: &Option>, - _maybe_post: &Option>, - maybe_body: &Option>, - ) -> Result<(), ExprErr> { - // TODO: improve this - if let Some(initer) = maybe_init { - self.parse_ctx_statement(initer, false, Some(ctx)); - } - - if let Some(body) = maybe_body { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.reset_vars(loc, ctx, body) - }) - } else { - Ok(()) - } - } - - fn reset_vars(&mut self, loc: Loc, ctx: ContextNode, body: &Statement) -> Result<(), ExprErr> { - let og_ctx = ctx; - let sctx = Context::new_subctx(ctx, None, loc, None, None, false, self, None) - .into_expr_err(loc)?; - let subctx = ContextNode::from(self.add_node(Node::Context(sctx))); - ctx.set_child_call(subctx, self).into_expr_err(loc)?; - self.parse_ctx_statement(body, false, Some(subctx)); - self.apply_to_edges(subctx, loc, &|analyzer, ctx, loc| { - let vars = subctx.local_vars(analyzer).clone(); - vars.iter().for_each(|(name, var)| { - // widen to max range - if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = var - .underlying(analyzer) - .unwrap() - .ty - .default_range(analyzer) - .unwrap() - { - let new_inheritor_var = analyzer - .advance_var_in_ctx(inheritor_var, loc, ctx) - .unwrap(); - let res = new_inheritor_var - .set_range_min(analyzer, r.min) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_inheritor_var - .set_range_max(analyzer, r.max) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - } - } - }); - - let sctx = - Context::new_subctx(ctx, Some(og_ctx), loc, None, None, false, analyzer, None) - .into_expr_err(loc)?; - let sctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); - ctx.set_child_call(sctx, analyzer).into_expr_err(loc) - }) - } - - fn while_loop( - &mut self, - loc: Loc, - ctx: ContextNode, - _limiter: &Expression, - body: &Statement, - ) -> Result<(), ExprErr> { - // TODO: improve this - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.reset_vars(loc, ctx, body) - }) - } -} diff --git a/src/context/mod.rs b/src/context/mod.rs deleted file mode 100644 index d2b35d2b..00000000 --- a/src/context/mod.rs +++ /dev/null @@ -1,1537 +0,0 @@ -use crate::context::yul::YulBuilder; -use ethers_core::types::I256; - -use ethers_core::types::U256; - -use shared::analyzer::GraphError; -use shared::analyzer::GraphLike; -use shared::context::*; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::YulStatement; - -use shared::range::elem_ty::Elem; -use shared::range::Range; -use solang_parser::pt::VariableDeclaration; - -use crate::VarType; -use petgraph::{visit::EdgeRef, Direction}; -use shared::{analyzer::AnalyzerLike, nodes::*, range::elem::RangeOp, Edge, Node, NodeIdx}; -use solang_parser::pt::{Expression, Loc, Statement}; - -// pub mod func; -// use func::*; -pub mod func_call; -use func_call::*; - -pub mod loops; -use loops::*; - -pub mod exprs; -use exprs::*; - -pub mod analyzers; -pub mod queries; - -pub mod yul; - -impl ContextBuilder for T where - T: AnalyzerLike + Sized + ExprParser -{ -} - -pub trait ContextBuilder: - AnalyzerLike + Sized + ExprParser -{ - fn parse_ctx_statement( - &mut self, - stmt: &Statement, - unchecked: bool, - parent_ctx: Option + Clone + Copy>, - ) where - Self: Sized, - { - if let Some(parent) = parent_ctx { - match self.node(parent) { - Node::Context(_) => { - let ctx = ContextNode::from(parent.into()); - if !ctx.killed_or_ret(self).unwrap() { - if let Some(live_edges) = - self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) - { - if live_edges.is_empty() { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) - } else { - live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_stmt_inner(stmt, unchecked, Some(*fork_ctx)); - }); - } - } - } - } - _ => self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx), - } - } else { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_ctx_stmt_inner( - &mut self, - stmt: &Statement, - unchecked: bool, - parent_ctx: Option + Clone + Copy>, - ) where - Self: Sized, - { - use Statement::*; - // println!("stmt: {:#?}, node: {:#?}", stmt, if let Some(node) = parent_ctx { Some(self.node(node.into())) } else { None}); - // if let Some(ctx) = parent_ctx { - // if let Node::Context(_) = self.node(ctx) { - // println!("ctx: {}, {:#?}", ContextNode::from(ctx.into()).path(self), stmt); - // } - // } - - // at the end of a statement we shouldn't have anything in the stack? - if let Some(ctx) = parent_ctx { - if let Node::Context(_) = self.node(ctx) { - let c = ContextNode::from(ctx.into()); - let _ = c.pop_expr_latest(stmt.loc(), self); - if unchecked { - let _ = c.set_unchecked(self); - } else { - let _ = c.unset_unchecked(self); - } - - if c.killed_or_ret(self).unwrap() { - return; - } - } - } - - match stmt { - Block { - loc, - unchecked, - statements, - } => { - tracing::trace!("parsing block"); - let parent = parent_ctx.expect("Free floating contexts shouldn't happen"); - let mut entry_loc = None; - let mut mods_set = false; - let ctx_node = match self.node(parent) { - Node::Function(fn_node) => { - mods_set = fn_node.modifiers_set; - entry_loc = Some(fn_node.loc); - let ctx = Context::new( - FunctionNode::from(parent.into()), - self.add_if_err( - FunctionNode::from(parent.into()) - .name(self) - .into_expr_err(stmt.loc()), - ) - .unwrap(), - *loc, - ); - let ctx_node = self.add_node(Node::Context(ctx)); - self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Context)); - - ctx_node - } - Node::Context(_) => { - // let ctx = Context::new_subctx( - // ContextNode::from(parent.into()), - // *loc, - // false, - // self, - // ); - // let ctx_node = self.add_node(Node::Context(ctx)); - // self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Subcontext)); - // ctx_node - parent.into() - } - e => todo!( - "Expected a context to be created by a function or context but got: {:?}", - e - ), - }; - - // optionally add named input and named outputs into context - let (params, inputs): (Vec<_>, Vec<_>) = self - .graph() - .edges_directed(parent.into(), Direction::Incoming) - .filter(|edge| *edge.weight() == Edge::FunctionParam) - .map(|edge| FunctionParamNode::from(edge.source())) - .collect::>() - .into_iter() - .filter_map(|param_node| { - let res = param_node - .underlying(self) - .into_expr_err(stmt.loc()) - .cloned(); - let func_param = self.add_if_err(res)?; - if let Some(cvar) = ContextVar::maybe_new_from_func_param(self, func_param) - { - let cvar_node = self.add_node(Node::ContextVar(cvar)); - ContextNode::from(ctx_node) - .add_var(cvar_node.into(), self) - .unwrap(); - self.add_edge( - cvar_node, - ctx_node, - Edge::Context(ContextEdge::Variable), - ); - - Some((param_node, ContextVarNode::from(cvar_node))) - } else { - None - } - }) - .unzip(); - - self.graph() - .edges_directed(parent.into(), Direction::Incoming) - .filter(|edge| *edge.weight() == Edge::FunctionReturn) - .map(|edge| FunctionReturnNode::from(edge.source())) - .collect::>() - .iter() - .for_each(|ret_node| { - let res = ret_node.underlying(self).into_expr_err(stmt.loc()).cloned(); - let func_ret = self.add_if_err(res).unwrap(); - if let Some(cvar) = ContextVar::maybe_new_from_func_ret(self, func_ret) { - let cvar_node = self.add_node(Node::ContextVar(cvar)); - ContextNode::from(ctx_node) - .add_var(cvar_node.into(), self) - .unwrap(); - self.add_edge( - cvar_node, - ctx_node, - Edge::Context(ContextEdge::Variable), - ); - } - }); - - if let Some(fn_loc) = entry_loc { - if !mods_set { - let parent = FunctionNode::from(parent.into()); - let _ = self - .set_modifiers(parent, ctx_node.into()) - .map_err(|e| self.add_expr_err(e)); - } - - let res = self.func_call_inner( - true, - ctx_node.into(), - parent.into().into(), - fn_loc, - inputs, - params, - None, - None, - ); - if self.widen_if_limit_hit(ctx_node.into(), res) { - return; - } - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad funciton call"); - let res = ContextNode::from(ctx_node) - .kill( - analyzer, - fn_loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(fn_loc); - let _ = analyzer.add_if_err(res); - } - Ok(()) - }); - - if self.widen_if_limit_hit(ctx_node.into(), res) { - return; - } - - return; - } - - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, _loc| { - statements - .iter() - .for_each(|stmt| analyzer.parse_ctx_statement(stmt, *unchecked, Some(ctx))); - Ok(()) - }); - if self.widen_if_limit_hit(ctx_node.into(), res) {} - } - VariableDefinition(loc, var_decl, maybe_expr) => { - let ctx = ContextNode::from( - parent_ctx - .expect("No context for variable definition?") - .into(), - ); - tracing::trace!( - "parsing variable definition, {:?} {var_decl:?}", - ctx.path(self) - ); - - if let Some(rhs) = maybe_expr { - match self.parse_ctx_expr(rhs, ctx) { - Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, format!("Variable definition had no right hand side, {}", ctx.path(analyzer)))) - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(&var_decl.ty, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Variable definition had no left hand side".to_string())) - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, Some(&rhs_paths))?; - Ok(()) - }) - } else { - Ok(()) - } - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - ret => { - let _ = self.widen_if_limit_hit(ctx, ret); - } - } - } else { - let res = self.parse_ctx_expr(&var_decl.ty, ctx); - if self.widen_if_limit_hit(ctx, res) { - return; - } - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Variable definition had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, None)?; - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - } - Args(_loc, _args) => { - tracing::trace!("parsing args, {_args:?}"); - } - If(loc, if_expr, true_expr, maybe_false_expr) => { - tracing::trace!("parsing if, {if_expr:?}"); - let ctx = ContextNode::from(parent_ctx.expect("Dangling if statement").into()); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.cond_op_stmt(loc, if_expr, true_expr, maybe_false_expr, ctx) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - While(loc, cond, body) => { - tracing::trace!("parsing while, {cond:?}"); - if let Some(parent) = parent_ctx { - let res = self.apply_to_edges( - ContextNode::from(parent.into()), - *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, cond, body), - ); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - Expression(loc, expr) => { - tracing::trace!("parsing expr, {expr:?}"); - if let Some(parent) = parent_ctx { - let ctx = parent.into().into(); - match self.parse_ctx_expr(expr, ctx) { - Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad expr"); - ContextNode::from(parent.into()) - .kill( - analyzer, - loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(loc)?; - } - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - e => { - let _ = self.widen_if_limit_hit(ctx, e); - } - } - } - } - For(loc, maybe_for_start, maybe_for_middle, maybe_for_end, maybe_for_body) => { - tracing::trace!("parsing for loop"); - if let Some(parent) = parent_ctx { - let res = - self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { - analyzer.for_loop( - loc, - ctx, - maybe_for_start, - maybe_for_middle, - maybe_for_end, - maybe_for_body, - ) - }); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - DoWhile(loc, while_stmt, while_expr) => { - tracing::trace!("parsing `do while`, {while_expr:?}"); - if let Some(parent) = parent_ctx { - let res = self.apply_to_edges( - ContextNode::from(parent.into()), - *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, while_expr, while_stmt), - ); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - Continue(_loc) => { - tracing::trace!("parsing continue"); - // TODO: We cheat in loops by just widening so continues dont matter yet - } - Break(_loc) => { - tracing::trace!("parsing break"); - // TODO: We cheat in loops by just widening so breaks dont matter yet - } - Assembly { - loc, - dialect: _, - flags: _, - block: yul_block, - } => { - tracing::trace!("parsing assembly"); - let ctx = ContextNode::from( - parent_ctx - .expect("No context for variable definition?") - .into(), - ); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(&YulStatement::Block(yul_block.clone()), ctx); - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - Return(loc, maybe_ret_expr) => { - tracing::trace!("parsing return"); - if let Some(ret_expr) = maybe_ret_expr { - if let Some(parent) = parent_ctx { - let res = self.parse_ctx_expr(ret_expr, parent.into().into()); - if self.widen_if_limit_hit(parent.into().into(), res) { - return; - } - let res = self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { - let Ok(Some(ret)) = ctx.pop_expr_latest(loc, analyzer) else { - return Err(ExprErr::NoLhs(loc, "Return did not have a associated expression".to_string())); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let paths = ret.flatten(); - if paths.is_killed() { - tracing::trace!("killing due to bad return"); - let res = ContextNode::from(parent.into()) - .kill(analyzer, loc, paths.killed_kind().unwrap()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - return Ok(()); - } - analyzer.return_match(ctx, &loc, &paths); - Ok(()) - }); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - } - Revert(loc, _maybe_err_path, _exprs) => { - tracing::trace!("parsing revert"); - if let Some(parent) = parent_ctx { - let parent = ContextNode::from(parent.into()); - let res = self.apply_to_edges(parent, *loc, &|analyzer, ctx, loc| { - let res = ctx - .kill(analyzer, loc, KilledKind::Revert) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - Ok(()) - }); - let _ = self.add_if_err(res); - } - } - RevertNamedArgs(_loc, _maybe_err_path, _named_args) => { - tracing::trace!("parsing named revert"); - todo!("revert named args") - } - Emit(_loc, _emit_expr) => {} - Try(_loc, _try_expr, _maybe_returns, _clauses) => {} - Error(_loc) => {} - } - } - - fn widen_if_limit_hit(&mut self, ctx: ContextNode, maybe_err: Result<(), ExprErr>) -> bool { - match maybe_err { - Err(ExprErr::FunctionCallBlockTodo(_, _s)) => { - // dont kill for this one - false - } - Err(e @ ExprErr::GraphError(_, GraphError::MaxStackWidthReached(..), ..)) => { - // TODO: we should ideally peak at each if statement body and only widen variables referenced in there - // but for now we just delete the forks, and reset all local variables - self.add_expr_err(e); - true - } - Err(e) => { - let res = ctx - .kill(self, e.loc(), KilledKind::ParseError) - .into_expr_err(e.loc()); - let _ = self.add_if_err(res); - self.add_expr_err(e); - false - } - _ => false, - } - } - - fn return_match(&mut self, ctx: ContextNode, loc: &Loc, paths: &ExprRet) { - match paths { - ExprRet::CtxKilled(kind) => { - let _ = ctx.kill(self, *loc, *kind); - } - ExprRet::Single(expr) | ExprRet::SingleLiteral(expr) => { - let latest = ContextVarNode::from(*expr).latest_version(self); - // let ret = self.advance_var_in_ctx(latest, *loc, *ctx); - let path = ctx.path(self); - let res = latest.underlying_mut(self).into_expr_err(*loc); - match res { - Ok(var) => { - tracing::trace!("Returning: {}, {}", path, var.display_name); - var.is_return = true; - - self.add_edge(latest, ctx, Edge::Context(ContextEdge::Return)); - - let res = ctx.add_return_node(*loc, latest, self).into_expr_err(*loc); - // ctx.kill(self, *loc, KilledKind::Ended); - let _ = self.add_if_err(res); - } - Err(e) => self.add_expr_err(e), - } - } - ExprRet::Multi(rets) => { - rets.iter().for_each(|expr_ret| { - self.return_match(ctx, loc, expr_ret); - }); - } - ExprRet::Null => {} - } - } - - fn match_var_def( - &mut self, - ctx: ContextNode, - var_decl: &VariableDeclaration, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: Option<&ExprRet>, - ) -> Result { - match (lhs_paths, rhs_paths) { - (ExprRet::CtxKilled(kind), _) | (_, Some(ExprRet::CtxKilled(kind))) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(true) - } - (ExprRet::Single(ty), Some(ExprRet::SingleLiteral(rhs))) => { - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let res = rhs_cvar.literal_cast_from_ty(ty, self).into_expr_err(loc); - let _ = self.add_if_err(res); - self.match_var_def( - ctx, - var_decl, - loc, - lhs_paths, - Some(&ExprRet::Single(rhs_cvar.into())), - ) - } - (ExprRet::Single(ty), Some(ExprRet::Single(rhs))) => { - let name = var_decl.name.clone().expect("Variable wasn't named"); - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let var = ContextVar { - loc: Some(loc), - name: name.to_string(), - display_name: name.to_string(), - storage: var_decl.storage.clone(), - is_tmp: false, - is_symbolic: true, - tmp_of: None, - is_return: false, - ty, - }; - let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); - ctx.add_var(lhs, self).into_expr_err(loc)?; - self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); - let rhs = ContextVarNode::from(*rhs); - - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let _ = analyzer.assign(loc, lhs, rhs, ctx)?; - // match_assign_ret(analyzer, ctx, ret); - Ok(()) - })?; - - Ok(false) - } - (ExprRet::Single(ty), None) => { - let name = var_decl.name.clone().expect("Variable wasn't named"); - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let var = ContextVar { - loc: Some(loc), - name: name.to_string(), - display_name: name.to_string(), - storage: var_decl.storage.clone(), - is_tmp: false, - is_symbolic: true, - tmp_of: None, - is_return: false, - ty, - }; - let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); - ctx.add_var(lhs, self).into_expr_err(loc)?; - self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); - Ok(false) - } - (l @ ExprRet::Single(_lhs), Some(ExprRet::Multi(rhs_sides))) => Ok(rhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, l, Some(expr_ret))) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), r @ Some(ExprRet::Single(_))) => Ok(lhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, r)) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), None) => Ok(lhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, None)) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), Some(ExprRet::Multi(rhs_sides))) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - Ok(lhs_sides - .iter() - .zip(rhs_sides.iter()) - .map(|(lhs_expr_ret, rhs_expr_ret)| { - self.match_var_def(ctx, var_decl, loc, lhs_expr_ret, Some(rhs_expr_ret)) - }) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)) - } else { - Ok(rhs_sides - .iter() - .map(|rhs_expr_ret| { - self.match_var_def(ctx, var_decl, loc, lhs_paths, Some(rhs_expr_ret)) - }) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)) - } - } - (_e, _f) => Err(ExprErr::Todo( - loc, - "Unhandled ExprRet combination in `match_var_def`".to_string(), - )), - } - } - - fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - if !ctx.killed_or_ret(self).unwrap() { - let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; - if edges.is_empty() { - self.parse_ctx_expr_inner(expr, ctx) - } else { - edges - .iter() - .try_for_each(|fork_ctx| self.parse_ctx_expr(expr, *fork_ctx))?; - Ok(()) - } - } else { - Ok(()) - } - } - - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - use Expression::*; - // println!( - // "ctx: {}, current stack: {:?}, \nexpr: {:?}\n", - // ctx.underlying(self).unwrap().path, - // ctx.underlying(self) - // .unwrap() - // .expr_ret_stack - // .iter() - // .map(|i| i.debug_str(self)) - // .collect::>(), - // expr - // ); - match expr { - // literals - NumberLiteral(loc, int, exp, _unit) => self.number_literal(ctx, *loc, int, exp, false), - AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), - StringLiteral(lits) => lits - .iter() - .try_for_each(|lit| self.string_literal(ctx, lit.loc, &lit.string)), - BoolLiteral(loc, b) => self.bool_literal(ctx, *loc, *b), - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), - HexLiteral(hexes) => self.hex_literals(ctx, hexes), - RationalNumberLiteral(loc, integer, fraction, exp, unit) => { - self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) - } - Negate(_loc, expr) => match &**expr { - NumberLiteral(loc, int, exp, _unit) => { - self.number_literal(ctx, *loc, int, exp, true) - } - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), - e => { - self.parse_ctx_expr(e, ctx)?; - self.apply_to_edges(ctx, e.loc(), &|analyzer, ctx, loc| { - tracing::trace!("Negate variable pop"); - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No variable present to negate".to_string())) - }; - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - // Solidity is dumb and used to allow negation of unsigned integers. - // That means we have to cast this as a int256. - let var = rhs_paths.expect_single().into_expr_err(loc)?; - - let zero = analyzer.add_node(Node::Concrete(Concrete::from(I256::from(0i32)))); - let zero = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero.into(), - analyzer, - ).into_expr_err(loc)?; - let zero = analyzer.add_node(Node::ContextVar(zero)); - let new_underlying = ContextVarNode::from(var) - .underlying(analyzer).into_expr_err(loc)? - .clone() - .as_cast_tmp(loc, ctx, Builtin::Int(256), analyzer).into_expr_err(loc)?; - let node = analyzer.add_node(Node::ContextVar(new_underlying)); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - - ContextVarNode::from(node).cast_from( - &ContextVarNode::from(zero), - analyzer - ).into_expr_err(loc)?; - - let lhs_paths = ExprRet::Single(zero); - analyzer.op_match( - ctx, - loc, - &lhs_paths, - &ExprRet::Single(ContextVarNode::from(node).latest_version(analyzer).into()), - RangeOp::Sub(true), - false, - ) - }) - } // e => todo!("UnaryMinus unexpected rhs: {e:?}"), - }, - UnaryPlus(_loc, e) => todo!("UnaryPlus unexpected rhs: {e:?}"), - - // Binary ops - Power(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) - } - Add(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignAdd(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Subtract(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignSubtract(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Multiply(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignMultiply(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Divide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), false) - } - AssignDivide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), true) - } - Modulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) - } - AssignModulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) - } - ShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) - } - AssignShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) - } - ShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) - } - AssignShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) - } - ConditionalOperator(loc, if_expr, true_expr, false_expr) => { - self.cond_op_expr(*loc, if_expr, true_expr, false_expr, ctx) - } - - // Bitwise ops - BitwiseAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) - } - AssignAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) - } - BitwiseXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) - } - AssignXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) - } - BitwiseOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) - } - AssignOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) - } - BitwiseNot(loc, lhs_expr) => self.bit_not(*loc, lhs_expr, ctx), - - // assign - Assign(loc, lhs_expr, rhs_expr) => self.assign_exprs(*loc, lhs_expr, rhs_expr, ctx), - List(loc, params) => self.list(ctx, *loc, params), - // array - ArraySubscript(_loc, ty_expr, None) => self.array_ty(ty_expr, ctx), - ArraySubscript(loc, ty_expr, Some(index_expr)) => { - self.index_into_array(*loc, ty_expr, index_expr, ctx) - } - ArraySlice(loc, _lhs_expr, _maybe_middle_expr, _maybe_rhs) => Err(ExprErr::Todo( - *loc, - "Array slicing not currently supported".to_string(), - )), - ArrayLiteral(loc, _) => Err(ExprErr::Todo( - *loc, - "Array literal not currently supported".to_string(), - )), - - // Comparator - Equal(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Eq, rhs, ctx), - NotEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Neq, rhs, ctx), - Less(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lt, rhs, ctx), - More(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gt, rhs, ctx), - LessEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lte, rhs, ctx), - MoreEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gte, rhs, ctx), - - // Logical - Not(loc, expr) => self.not(*loc, expr, ctx), - And(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::And, rhs, ctx), - Or(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Or, rhs, ctx), - - // Function calls - FunctionCallBlock(loc, _func_expr, _input_exprs) => { - // TODO: update msg node - Err(ExprErr::Todo( - *loc, - "Function call block is unsupported. We shouldn't have hit this code path" - .to_string(), - )) - } - NamedFunctionCall(loc, func_expr, input_args) => { - self.named_fn_call_expr(ctx, loc, func_expr, input_args) - } - FunctionCall(loc, func_expr, input_exprs) => { - let updated_func_expr = match **func_expr { - FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { - // we dont currently handle the `{value: .. gas: ..}` msg updating - self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take affect".to_string())); - inner_func_expr.clone() - } - _ => func_expr.clone(), - }; - - self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) - } - // member - New(_loc, expr) => self.parse_ctx_expr(expr, ctx), - This(loc) => { - let var = ContextVar::new_from_contract( - *loc, - ctx.associated_contract(self).into_expr_err(*loc)?, - self, - ) - .into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(cvar), self) - .into_expr_err(*loc)?; - Ok(()) - } - MemberAccess(loc, member_expr, ident) => { - self.member_access(*loc, member_expr, ident, ctx) - } - - Delete(loc, expr) => { - fn delete_match( - ctx: ContextNode, - loc: &Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ret: ExprRet, - ) { - match ret { - ExprRet::CtxKilled(kind) => { - let _ = ctx.kill(analyzer, *loc, kind); - } - ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { - let mut new_var = - analyzer.advance_var_in_ctx(cvar.into(), *loc, ctx).unwrap(); - let res = new_var.sol_delete_range(analyzer).into_expr_err(*loc); - let _ = analyzer.add_if_err(res); - } - ExprRet::Multi(inner) => { - inner - .iter() - .for_each(|i| delete_match(ctx, loc, analyzer, i.clone())); - } - ExprRet::Null => {} - } - } - - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("Delete variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Delete operation had no right hand side".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - delete_match(ctx, &loc, analyzer, ret); - Ok(()) - }) - } - - // de/increment stuff - PreIncrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PreIncrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "PreIncrement operation had no right hand side".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, true, true, loc, &ret) - }) - } - PostIncrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PostIncrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "PostIncrement operation had no right hand side".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, false, true, loc, &ret) - }) - } - PreDecrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PreDecrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "PreDecrement operation had no right hand side".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, true, false, loc, &ret) - }) - } - PostDecrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PostDecrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "PostDecrement operation had no right hand side".to_string())) - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, false, false, loc, &ret) - }) - } - - // Misc. - Variable(ident) => self.variable(ident, ctx, None), - Type(loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { - if let Some(idx) = self.builtins().get(&builtin) { - ctx.push_expr(ExprRet::Single(*idx), self) - .into_expr_err(*loc)?; - Ok(()) - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins_mut().insert(builtin, idx); - ctx.push_expr(ExprRet::Single(idx), self) - .into_expr_err(*loc)?; - Ok(()) - } - } else { - ctx.push_expr(ExprRet::Null, self).into_expr_err(*loc)?; - Ok(()) - } - } - Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), - } - } - - fn match_in_de_crement( - &mut self, - ctx: ContextNode, - pre: bool, - increment: bool, - loc: Loc, - rhs: &ExprRet, - ) -> Result<(), ExprErr> { - match rhs { - ExprRet::CtxKilled(kind) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(()) - } - ExprRet::SingleLiteral(var) => { - let res = ContextVarNode::from(*var) - .try_increase_size(self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) - } - ExprRet::Single(var) => { - let cvar = ContextVarNode::from(*var); - let elem = Elem::from(cvar); - let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); - // if let Some(r) = cvar.range(self).into_expr_err(loc)? { - if increment { - if pre { - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() + one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - let res = new_cvar.set_range_max(self, elem + one).into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() + one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem + one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(dup.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - } else if pre { - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem - one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem - one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(dup.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - // } else { - // panic!("No range in post-increment") - // } - } - ExprRet::Multi(inner) => inner - .iter() - .try_for_each(|expr| self.match_in_de_crement(ctx, pre, increment, loc, expr)), - ExprRet::Null => Ok(()), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn assign_exprs( - &mut self, - loc: Loc, - lhs_expr: &Expression, - rhs_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(rhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Assign operation had no right hand side".to_string())) - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Assign operation had no left hand side".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_assign_sides(ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; - Ok(()) - }) - }) - } - - fn match_assign_sides( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: &ExprRet, - ) -> Result<(), ExprErr> { - match (lhs_paths, rhs_paths) { - (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), - (ExprRet::CtxKilled(kind), _) | (_, ExprRet::CtxKilled(kind)) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let res = rhs_cvar - .literal_cast_from(&lhs_cvar, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (l @ ExprRet::Single(_), ExprRet::Multi(rhs_sides)) => rhs_sides - .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, l, expr_ret)), - (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { - lhs_sides - .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, expr_ret, r)) - } - (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( - |(lhs_expr_ret, rhs_expr_ret)| { - self.match_assign_sides(ctx, loc, lhs_expr_ret, rhs_expr_ret) - }, - ) - } else { - rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.match_assign_sides(ctx, loc, lhs_paths, rhs_expr_ret) - }) - } - } - (e, f) => todo!("any: {:?} {:?}", e, f), - } - } - - fn assign( - &mut self, - loc: Loc, - lhs_cvar: ContextVarNode, - rhs_cvar: ContextVarNode, - ctx: ContextNode, - ) -> Result { - tracing::trace!( - "assigning: {} to {}", - lhs_cvar.display_name(self).unwrap(), - rhs_cvar.display_name(self).unwrap() - ); - let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( - Elem::from(rhs_cvar.latest_version(self)), - Elem::from(rhs_cvar.latest_version(self)), - ); - - let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; - if rhs_cvar.underlying(self).into_expr_err(loc)?.is_return { - if let Some(rhs_ctx) = rhs_cvar.maybe_ctx(self) { - self.add_edge( - rhs_cvar, - new_lhs, - Edge::Context(ContextEdge::ReturnAssign( - rhs_ctx.underlying(self).unwrap().ext_fn_call.is_some(), - )), - ); - } else { - return Err(ExprErr::GraphError( - loc, - GraphError::DetachedVariable(format!( - "No context for variable: {}, node idx: {}, curr ctx: {}, lhs ctx: {}", - rhs_cvar.display_name(self).unwrap(), - rhs_cvar.0, - ctx.path(self), - lhs_cvar.ctx(self).path(self) - )), - )); - } - } - if !lhs_cvar.ty_eq(&rhs_cvar, self).into_expr_err(loc)? { - let cast_to_min = match lhs_cvar.range_min(self).into_expr_err(loc)? { - Some(v) => v, - None => { - return Err(ExprErr::BadRange( - loc, - format!( - "No range during cast? {:?}, {:?}", - lhs_cvar.underlying(self).unwrap(), - rhs_cvar.underlying(self).unwrap(), - ), - )) - } - }; - - let cast_to_max = match lhs_cvar.range_max(self).into_expr_err(loc)? { - Some(v) => v, - None => { - return Err(ExprErr::BadRange( - loc, - format!( - "No range during cast? {:?}, {:?}", - lhs_cvar.underlying(self).unwrap(), - rhs_cvar.underlying(self).unwrap(), - ), - )) - } - }; - - let _ = new_lhs.try_set_range_min(self, new_lower_bound.cast(cast_to_min)); - let _ = new_lhs.try_set_range_max(self, new_upper_bound.cast(cast_to_max)); - } else { - let _ = new_lhs.try_set_range_min(self, new_lower_bound); - let _ = new_lhs.try_set_range_max(self, new_upper_bound); - } - if let Some(rhs_range) = rhs_cvar.ref_range(self).into_expr_err(loc)? { - let res = new_lhs - .try_set_range_exclusions(self, rhs_range.exclusions.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(arr) = lhs_cvar.index_to_array(self) { - if let Some(index) = lhs_cvar.index_access_to_index(self) { - let next_arr = self.advance_var_in_ctx(arr, loc, ctx)?; - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - } - } - - Ok(ExprRet::Single(new_lhs.into())) - } - - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - fn advance_var_in_ctx( - &mut self, - cvar_node: ContextVarNode, - loc: Loc, - ctx: ContextNode, - ) -> Result { - tracing::trace!( - "advancing variable: {}", - cvar_node.display_name(self).into_expr_err(loc)? - ); - if let Some(cvar) = cvar_node.next_version(self) { - panic!( - "Not latest version of: {}", - cvar.display_name(self).unwrap() - ); - } - if let Some(child) = ctx.underlying(self).into_expr_err(loc)?.child { - return Err(ExprErr::GraphError( - loc, - GraphError::VariableUpdateInOldContext(format!( - "Variable update of {} in old context: parent: {}, child: {:#?}", - cvar_node.display_name(self).unwrap(), - ctx.path(self), - child - )), - )); - } - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - // get the old context - let new_cvarnode; - - 'a: { - if let Some(old_ctx) = cvar_node.maybe_ctx(self) { - // get the previous version to remove and prevent spurious nodes - if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { - let prev_version = prev.underlying(self).into_expr_err(loc)?; - // check if there was no change between the previous version and the latest version - if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { - // there was no change in the current context, just give them the current variable - new_cvarnode = cvar_node.into(); - break 'a; - } - } - - new_cvar.loc = Some(loc); - new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - if old_ctx != ctx { - ctx.add_var(new_cvarnode.into(), self).into_expr_err(loc)?; - self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); - self.add_edge( - new_cvarnode, - cvar_node.0, - Edge::Context(ContextEdge::InheritedVariable), - ); - } else { - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - } - } else { - new_cvar.loc = Some(loc); - new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - } - } - - Ok(ContextVarNode::from(new_cvarnode)) - } - - fn advance_var_in_curr_ctx( - &mut self, - cvar_node: ContextVarNode, - loc: Loc, - ) -> Result { - tracing::trace!( - "advancing variable: {}", - cvar_node.display_name(self).into_expr_err(loc)? - ); - if let Some(cvar) = cvar_node.next_version(self) { - panic!( - "Not latest version of: {}", - cvar.display_name(self).unwrap() - ); - } - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - new_cvar.loc = Some(loc); - - let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - - Ok(ContextVarNode::from(new_cvarnode)) - } - - fn advance_var_underlying(&mut self, cvar_node: ContextVarNode, loc: Loc) -> &mut ContextVar { - assert_eq!(None, cvar_node.next_version(self)); - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .unwrap() - .clone(); - new_cvar.loc = Some(loc); - let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - ContextVarNode::from(new_cvarnode) - .underlying_mut(self) - .unwrap() - } - - fn apply_to_edges( - &mut self, - ctx: ContextNode, - loc: Loc, - closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result<(), ExprErr>, - ) -> Result<(), ExprErr> { - let live_edges = ctx.live_edges(self).into_expr_err(loc)?; - tracing::trace!( - "Applying to live edges of: {}. edges: {:#?}", - ctx.path(self), - live_edges.iter().map(|i| i.path(self)).collect::>(), - ); - if !ctx.killed_or_ret(self).into_expr_err(loc)? { - if ctx.underlying(self).into_expr_err(loc)?.child.is_some() { - if live_edges.is_empty() { - Ok(()) - } else { - live_edges - .iter() - .try_for_each(|ctx| closure(self, *ctx, loc)) - } - } else if live_edges.is_empty() { - closure(self, ctx, loc) - } else { - live_edges - .iter() - .try_for_each(|ctx| closure(self, *ctx, loc)) - } - } else { - Ok(()) - } - } - - fn take_from_edge( - &mut self, - ctx: ContextNode, - loc: Loc, - closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result, - ) -> Result, ExprErr> { - let live_edges = ctx.live_edges(self).into_expr_err(loc)?; - tracing::trace!( - "Taking from live edges of: {}. edges: {:#?}", - ctx.path(self), - live_edges.iter().map(|i| i.path(self)).collect::>(), - ); - - if live_edges.is_empty() { - Ok(vec![closure(self, ctx, loc)?]) - } else { - live_edges - .iter() - .map(|ctx| closure(self, *ctx, loc)) - .collect::, ExprErr>>() - } - } -} diff --git a/src/context/queries/mod.rs b/src/context/queries/mod.rs deleted file mode 100644 index 18fde10f..00000000 --- a/src/context/queries/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod storage_write; -pub mod taint; diff --git a/src/context/queries/storage_write/access.rs b/src/context/queries/storage_write/access.rs deleted file mode 100644 index 86efab45..00000000 --- a/src/context/queries/storage_write/access.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::{ - analyzer::*, - context::ContextNode, - nodes::{TypeNode, VarType}, - NodeIdx, -}; - -use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; -use std::collections::BTreeMap; - -#[derive(Debug, Clone)] -pub struct AccessStorageWriteReport { - pub msgs: Vec, -} - -impl AccessStorageWriteReport { - pub fn new(msgs: Vec) -> Self { - Self { msgs } - } -} - -impl ReportDisplay for AccessStorageWriteReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Access Analysis", Color::Green) - } - fn msg(&self, _analyzer: &impl GraphLike) -> String { - self.msgs.join(";\n") - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let report = Report::build(self.report_kind(), "".to_string(), 0) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - vec![report.finish()] - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl AccessStorageWriteQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait AccessStorageWriteQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn access_query( - &self, - _entry: NodeIdx, - _file_mapping: &'_ BTreeMap, - _report_config: ReportConfig, - _contract_name: String, - _storage_var_name: String, - ) -> AccessStorageWriteReport { - todo!() - } - - fn recurse(&self, ctx: ContextNode, storage_var_name: String) -> Vec { - if let Some(cvar) = ctx.var_by_name(self, &storage_var_name) { - match cvar.ty(self).unwrap() { - VarType::User(TypeNode::Struct(s_node), _) => { - let fields = s_node - .fields(self) - .iter() - .map(|field| format!("{}.{}", storage_var_name, field.name(self).unwrap())) - .collect(); - fields - } - _ => vec![storage_var_name], - } - } else { - vec![storage_var_name] - } - } -} diff --git a/src/context/queries/storage_write/mod.rs b/src/context/queries/storage_write/mod.rs deleted file mode 100644 index 17f8adc3..00000000 --- a/src/context/queries/storage_write/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod access; -pub use access::*; - -mod target; -pub use target::*; diff --git a/src/context/queries/storage_write/target.rs b/src/context/queries/storage_write/target.rs deleted file mode 100644 index d244f04d..00000000 --- a/src/context/queries/storage_write/target.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::{ - analyzer::*, - range::{range_string::ToRangeString, Range, SolcRange}, - NodeIdx, -}; - -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use std::collections::BTreeMap; - -#[derive(Debug, Clone)] -pub struct StorageRangeReport { - pub target: SolcRange, - pub write_loc: Option, - pub analysis: VarBoundAnalysis, -} - -impl ReportDisplay for StorageRangeReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Storage Write Query", Color::Green) - } - fn msg(&self, analyzer: &impl GraphLike) -> String { - let bounds_string = self - .analysis - .ctx - .ctx_deps(analyzer) - .unwrap() - .iter() - .filter_map(|(_name, cvar)| { - let min = if self.analysis.report_config.eval_bounds { - cvar.range(analyzer) - .unwrap()? - .evaled_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else if self.analysis.report_config.simplify_bounds { - cvar.range(analyzer) - .unwrap()? - .simplified_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else { - cvar.range(analyzer) - .unwrap()? - .range_min() - .to_range_string(false, analyzer) - .s - }; - - let max = if self.analysis.report_config.eval_bounds { - cvar.range(analyzer) - .unwrap()? - .evaled_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else if self.analysis.report_config.simplify_bounds { - cvar.range(analyzer) - .unwrap()? - .simplified_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else { - cvar.range(analyzer) - .unwrap()? - .range_max() - .to_range_string(true, analyzer) - .s - }; - - Some(format!( - "\"{}\" ∈ {{{}, {}}}", - cvar.display_name(analyzer).unwrap(), - min, - max, - )) - }) - .collect::>() - .join(" ∧ "); - format!( - "Found storage write that could lead to target value in ctx {}: \"{}\" ∈ {{{}, {}}}{}{} ", - self.analysis.ctx.path(analyzer), - self.analysis.var_name, - self.target - .evaled_range_min(analyzer).unwrap() .to_range_string(false, analyzer) - .s, - self.target - .evaled_range_max(analyzer).unwrap() .to_range_string(true, analyzer) - .s, - if bounds_string.is_empty() { - "" - } else { - ", where " - }, - bounds_string.fg(Color::Yellow) - ) - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let mut report = Report::build( - self.analysis.report_kind(), - self.analysis.var_def.0.source(), - self.analysis.var_def.0.start(), - ) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - - report.add_labels(self.analysis.labels(analyzer)); - - let reports = vec![report.finish()]; - reports - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl StorageRangeQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait StorageRangeQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn func_query( - &mut self, - _entry: NodeIdx, - _file_mapping: &'_ BTreeMap, - _report_config: ReportConfig, - _contract_name: String, - _func_name: String, - _storage_var_name: String, - _target: SolcRange, - ) -> Option { - todo!() - } -} diff --git a/src/context/queries/taint.rs b/src/context/queries/taint.rs deleted file mode 100644 index 83d03571..00000000 --- a/src/context/queries/taint.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::context::CallFork; - -use shared::{analyzer::*, NodeIdx}; - -use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; - -#[derive(Debug, Clone)] -pub struct TaintReport { - pub msgs: Vec, -} - -impl TaintReport { - pub fn new(msgs: Vec) -> Self { - Self { msgs } - } -} - -impl ReportDisplay for TaintReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Taint Analysis", Color::Green) - } - fn msg(&self, _analyzer: &impl GraphLike) -> String { - self.msgs.join(";\n") - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let report = Report::build(self.report_kind(), "".to_string(), 0) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - vec![report.finish()] - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl TaintQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait TaintQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn taint_query(&self, _entry: NodeIdx, _contract_name: String) { - todo!() - } - - fn recurse_children(&self, _child: CallFork) { - todo!() - } -} diff --git a/src/context/yul/mod.rs b/src/context/yul/mod.rs deleted file mode 100644 index 223167de..00000000 --- a/src/context/yul/mod.rs +++ /dev/null @@ -1,343 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ContextBuilder; -use crate::context::ExprParser; -use crate::AnalyzerLike; -use crate::ExprErr; -use shared::context::Context; -use shared::context::ContextVar; -use shared::context::ContextVarNode; -use shared::context::ExprRet; -use shared::nodes::Builtin; -use shared::nodes::VarType; -use shared::{ - context::{ContextEdge, ContextNode}, - Edge, Node, -}; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::Expression; -use solang_parser::pt::Loc; - -use solang_parser::pt::{YulExpression, YulFor, YulStatement, YulSwitch}; - -mod yul_cond_op; -pub use yul_cond_op::*; - -mod yul_funcs; -pub use yul_funcs::*; - -impl YulBuilder for T where - T: AnalyzerLike + Sized + ExprParser -{ -} -pub trait YulBuilder: - AnalyzerLike + Sized + ExprParser -{ - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) - where - Self: Sized, - { - if let Some(true) = self.add_if_err(ctx.is_ended(self).into_expr_err(stmt.loc())) { - return; - } - if let Some(live_edges) = self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { - if live_edges.is_empty() { - self.parse_ctx_yul_stmt_inner(stmt, ctx) - } else { - live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_yul_stmt_inner(stmt, *fork_ctx); - }); - } - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_ctx_yul_stmt_inner(&mut self, stmt: &YulStatement, ctx: ContextNode) - where - Self: Sized, - { - use YulStatement::*; - // println!("ctx: {}, yul stmt: {:?}", ctx.path(self), stmt); - - let res = ctx - .pop_expr_latest(stmt.loc(), self) - .into_expr_err(stmt.loc()); - let _ = self.add_if_err(res); - - if ctx.is_killed(self).unwrap() { - return; - } - let ret = self.apply_to_edges(ctx, stmt.loc(), &|analyzer, ctx, _loc| { - match stmt { - Assign(loc, yul_exprs, yul_expr) => { - match yul_exprs - .iter() - .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) - { - Ok(()) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "No left hand side assignments in yul block".to_string())) - }; - if matches!(lhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) - }; - - if matches!(rhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_sides( - ctx, - loc, - &lhs_side, - &rhs_side, - ) - }) - }) - } - Err(e) => Err(e), - } - } - VariableDeclaration(loc, yul_idents, maybe_yul_expr) => { - let nodes = yul_idents - .iter() - .map(|ident| { - let b_ty = analyzer.builtin_or_add(Builtin::Uint(256)); - let var = ContextVar { - loc: Some(ident.loc), - name: ident.id.name.clone(), - display_name: ident.id.name.clone(), - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), - }; - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - ctx.add_var(cvar, analyzer).unwrap(); - analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - analyzer.advance_var_in_ctx(cvar, *loc, ctx).unwrap() - }) - .collect::>(); - - if let Some(yul_expr) = maybe_yul_expr { - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_yul(ctx, loc, &nodes, ret) - - }) - } else { - Ok(()) - } - } - If(loc, yul_expr, yul_block) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let ret = analyzer.yul_cond_op_stmt(loc, yul_expr, yul_block, ctx); - let _ = analyzer.add_if_err(ret); - Ok(()) - }) - } - For(YulFor { - loc, - init_block: _, - condition: _, - post_block: _, - execution_block: _, - }) => { - let sctx = Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) - .into_expr_err(*loc)?; - let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); - ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; - analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { - let vars = subctx.local_vars(analyzer).clone(); - vars.iter().for_each(|(name, var)| { - // widen to max range - if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = var - .underlying(analyzer) - .unwrap() - .ty - .default_range(analyzer) - .unwrap() - { - let new_inheritor_var = analyzer - .advance_var_in_ctx(inheritor_var, loc, ctx) - .unwrap(); - let res = new_inheritor_var - .set_range_min(analyzer, r.min) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_inheritor_var - .set_range_max(analyzer, r.max) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - } - } - }); - Ok(()) - }) - } - Switch(YulSwitch { - loc, - condition, - cases, - default, - }) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.yul_switch_stmt(loc, condition.clone(), cases.to_vec(), default.clone(), ctx) - }) - } - Leave(loc) => { - Err(ExprErr::Todo(*loc, "Yul `leave` statements are not currently supported".to_string())) - } - Break(loc) => { - Err(ExprErr::Todo(*loc, "Yul `break` statements are not currently supported".to_string())) - } - Continue(loc) => { - Err(ExprErr::Todo(*loc, "Yul `continue` statements are not currently supported".to_string())) - } - Block(yul_block) => { - yul_block - .statements - .iter() - .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); - Ok(()) - } - FunctionDefinition(yul_func_def) => { - Err(ExprErr::Todo(yul_func_def.loc(), "Yul `function` defintions are not currently supported".to_string())) - } - FunctionCall(yul_func_call) => { - analyzer.yul_func_call(yul_func_call, ctx) - } - Error(loc) => { - Err(ExprErr::ParseError(*loc, "Could not parse this yul statement".to_string())) - } - } - }); - let _ = self.add_if_err(ret); - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_ctx_yul_expr( - &mut self, - expr: &YulExpression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!("Parsing yul expression: {expr:?}"); - - let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; - if edges.is_empty() { - self.parse_ctx_yul_expr_inner(expr, ctx) - } else { - edges - .iter() - .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(expr, *fork_ctx))?; - Ok(()) - } - } - - fn parse_ctx_yul_expr_inner( - &mut self, - expr: &YulExpression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - use YulExpression::*; - match expr { - BoolLiteral(loc, b, _) => self.bool_literal(ctx, *loc, *b), - NumberLiteral(loc, int, expr, _unit) => { - self.number_literal(ctx, *loc, int, expr, false) - } - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), - HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), - StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), - Variable(ident) => self.variable(ident, ctx, None), - FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), - SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( - expr.loc(), - "Yul member access not yet supported".to_string(), - )), - } - } - - fn match_assign_yul( - &mut self, - _ctx: ContextNode, - loc: Loc, - nodes: &[ContextVarNode], - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => { - self.match_assign_yul_inner(loc, &nodes[0], s)?; - } - ExprRet::Multi(inner) => { - if inner.len() == nodes.len() { - inner - .into_iter() - .zip(nodes.iter()) - .map(|(ret, node)| self.match_assign_yul_inner(loc, node, ret)) - .collect::, ExprErr>>()?; - } else { - return Err(ExprErr::Todo( - loc, - format!("Differing number of assignees and assignors in yul expression, assignors: {}, assignees: {}", nodes.len(), inner.len()), - )); - }; - } - ExprRet::CtxKilled(_kind) => {} - ExprRet::Null => {} - } - - Ok(()) - } - - fn match_assign_yul_inner( - &mut self, - loc: Loc, - node: &ContextVarNode, - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret.flatten() { - ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { - let assign = ContextVarNode::from(idx); - let assign_ty = assign.underlying(self).into_expr_err(loc)?.ty.clone(); - if assign_ty.is_dyn(self).into_expr_err(loc)? { - let b_ty = self.builtin_or_add(Builtin::Bytes(32)); - node.underlying_mut(self).into_expr_err(loc)?.ty = - VarType::try_from_idx(self, b_ty).unwrap(); - } else { - node.underlying_mut(self).into_expr_err(loc)?.ty = assign_ty; - } - } - ExprRet::Multi(_inner) => { - return Err(ExprErr::Todo( - loc, - "Multi in single assignment yul expression is unhandled".to_string(), - )) - } - ExprRet::CtxKilled(..) => {} - ExprRet::Null => {} - } - Ok(()) - } -} diff --git a/src/context/yul/yul_cond_op.rs b/src/context/yul/yul_cond_op.rs deleted file mode 100644 index 59d35621..00000000 --- a/src/context/yul/yul_cond_op.rs +++ /dev/null @@ -1,365 +0,0 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::yul::YulBuilder; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use crate::Concrete; -use crate::ConcreteNode; -use crate::{exprs::Require, AnalyzerLike}; -use ethers_core::types::U256; -use shared::context::ExprRet; -use shared::range::elem::RangeOp; -use shared::{context::*, Edge, Node, NodeIdx}; -use solang_parser::pt::Identifier; -use solang_parser::pt::YulBlock; -use solang_parser::pt::YulFunctionCall; -use solang_parser::pt::YulSwitchOptions; - -use solang_parser::pt::CodeLocation; -use solang_parser::pt::{Expression, Loc}; -use solang_parser::pt::{YulExpression, YulStatement}; - -impl YulCondOp for T where T: AnalyzerLike + Require + Sized -{} -pub trait YulCondOp: AnalyzerLike + Require + Sized { - #[tracing::instrument(level = "trace", skip_all)] - fn yul_cond_op_stmt( - &mut self, - loc: Loc, - if_expr: &YulExpression, - true_stmt: &YulBlock, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let tctx = - Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) - .into_expr_err(loc)?; - let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); - let fctx = - Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) - .into_expr_err(loc)?; - let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); - ctx.set_child_fork(true_subctx, false_subctx, analyzer) - .into_expr_err(loc)?; - let ctx_fork = analyzer.add_node(Node::ContextFork); - analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); - analyzer.add_edge( - NodeIdx::from(true_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - NodeIdx::from(false_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - - analyzer.parse_ctx_yul_expr(if_expr, true_subctx)?; - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "True conditional had no lhs".to_string())); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_yul_true(ctx, if_expr.loc(), &ret) - })?; - - analyzer.parse_ctx_yul_statement(&YulStatement::Block(true_stmt.clone()), true_subctx); - // let false_expr = YulExpression::FunctionCall(Box::new(YulFunctionCall { - // loc, - // id: Identifier { - // loc, - // name: "iszero".to_string(), - // }, - // arguments: vec![if_expr.clone()], - // })); - analyzer.parse_ctx_yul_expr(if_expr, false_subctx)?; - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "False conditional had no lhs".to_string())); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_yul_false(ctx, if_expr.loc(), &ret) - }) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn yul_if_else( - &mut self, - loc: Loc, - if_else_chain: &IfElseChain, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) - .into_expr_err(loc)?; - let true_subctx = ContextNode::from( - analyzer.add_node(Node::Context( - tctx - )), - ); - let fctx = Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) - .into_expr_err(loc)?; - let false_subctx = ContextNode::from( - analyzer.add_node(Node::Context( - fctx - )), - ); - ctx.set_child_fork(true_subctx, false_subctx, analyzer) - .into_expr_err(loc)?; - let ctx_fork = analyzer.add_node(Node::ContextFork); - analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); - analyzer.add_edge( - NodeIdx::from(true_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - NodeIdx::from(false_subctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - - - let if_expr_loc = if_else_chain.if_expr.loc(); - analyzer.apply_to_edges(true_subctx, if_expr_loc, &|analyzer, ctx, loc| { - analyzer.parse_ctx_yul_expr(&if_else_chain.if_expr, true_subctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - let Some(true_vars) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul switch statement was missing a case discriminator".to_string())) - }; - - if matches!(true_vars, ExprRet::CtxKilled(_)) { - ctx.push_expr(true_vars, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_yul_true(ctx, loc, &true_vars)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(&if_else_chain.true_stmt, ctx); - Ok(()) - }) - }) - })?; - - - if let Some(next) = &if_else_chain.next { - match next { - ElseOrDefault::Default(default) => { - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(default, ctx); - Ok(()) - }) - } - ElseOrDefault::Else(iec) => { - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { - analyzer.yul_if_else(loc, iec, ctx) - }) - } - } - } else { - Ok(()) - } - }) - } - - fn match_yul_true( - &mut self, - ctx: ContextNode, - loc: Loc, - true_cvars: &ExprRet, - ) -> Result<(), ExprErr> { - match true_cvars { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc)?, - ExprRet::Single(_true_cvar) | ExprRet::SingleLiteral(_true_cvar) => { - let cnode = ConcreteNode::from( - self.add_node(Node::Concrete(Concrete::Uint(1, U256::from(0)))), - ); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, self) - .into_expr_err(loc)?, - ); - let rhs_paths = - ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); - - self.handle_require_inner( - ctx, - loc, - true_cvars, - &rhs_paths, - RangeOp::Gt, - RangeOp::Lt, - (RangeOp::Lt, RangeOp::Gt), - )?; - } - ExprRet::Multi(ref true_paths) => { - // TODO: validate this - // we only take one because we just need the context out of the return - true_paths - .iter() - .take(1) - .try_for_each(|expr_ret| self.match_yul_true(ctx, loc, expr_ret))?; - } - ExprRet::Null => {} - } - Ok(()) - } - - fn match_yul_false( - &mut self, - ctx: ContextNode, - loc: Loc, - false_cvars: &ExprRet, - ) -> Result<(), ExprErr> { - match false_cvars { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc)?, - ExprRet::Single(_false_cvar) | ExprRet::SingleLiteral(_false_cvar) => { - let cnode = ConcreteNode::from( - self.add_node(Node::Concrete(Concrete::Uint(1, U256::from(0)))), - ); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, self) - .into_expr_err(loc)?, - ); - let rhs_paths = - ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); - - self.handle_require_inner( - ctx, - loc, - false_cvars, - &rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - )?; - } - ExprRet::Multi(ref false_paths) => { - // TODO: validate this - // we only take one because we just need the context out of the return - false_paths - .iter() - .take(1) - .try_for_each(|expr_ret| self.match_yul_false(ctx, loc, expr_ret))?; - } - ExprRet::Null => {} - } - - Ok(()) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn yul_switch_stmt( - &mut self, - loc: Loc, - condition: YulExpression, - cases: Vec, - default: Option, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - let iec = IfElseChain::from(loc, (condition, cases, default))?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.yul_if_else(loc, &iec, ctx) - }) - } -} - -#[derive(Clone, Debug)] -pub struct IfElseChain { - pub if_expr: YulExpression, - pub true_stmt: YulStatement, - pub next: Option, -} - -#[derive(Clone, Debug)] -pub enum ElseOrDefault { - Else(Box), - Default(YulStatement), -} - -impl From for ElseOrDefault { - fn from(iec: IfElseChain) -> Self { - Self::Else(Box::new(iec)) - } -} - -impl IfElseChain { - pub fn from_child(ed: ElseOrDefault) -> Option { - match ed { - ElseOrDefault::Else(iec) => Some(*iec), - _ => None, - } - } -} - -impl From for ElseOrDefault { - fn from(default: YulSwitchOptions) -> Self { - match default { - YulSwitchOptions::Default(_loc, block) => { - ElseOrDefault::Default(YulStatement::Block(block)) - } - _ => unreachable!("case as default"), - } - } -} - -pub type SwitchInfo = ( - YulExpression, - Vec, - Option, -); - -impl IfElseChain { - pub fn from(loc: Loc, (condition, cases, default): SwitchInfo) -> Result { - let mut child: Option = default.map(|default| default.into()); - - cases.into_iter().rev().for_each(|case| { - let mut chain_part: IfElseChain = From::from((condition.clone(), case)); - if let Some(c) = child.take() { - chain_part.next = c.into(); - } - child = Some(chain_part.into()); - }); - let Some(child) = child else { - return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) - }; - - let Some(iec) = IfElseChain::from_child(child) else { - return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) - }; - Ok(iec) - } -} - -impl From<(YulExpression, YulSwitchOptions)> for IfElseChain { - fn from((condition, case): (YulExpression, YulSwitchOptions)) -> Self { - match case { - YulSwitchOptions::Case(loc, expr, stmt) => { - let if_expr = YulExpression::FunctionCall(Box::new(YulFunctionCall { - loc, - id: Identifier { - loc, - name: "eq".to_string(), - }, - arguments: vec![condition, expr], - })); - IfElseChain { - if_expr, - true_stmt: YulStatement::Block(stmt), - next: None, - } - } - YulSwitchOptions::Default(_loc, _block) => { - unreachable!("We shouldn't have a `default` case in cases - only in the `default` input parameter") - } - } - } -} diff --git a/src/context/yul/yul_funcs.rs b/src/context/yul/yul_funcs.rs deleted file mode 100644 index 5f151e5f..00000000 --- a/src/context/yul/yul_funcs.rs +++ /dev/null @@ -1,656 +0,0 @@ -use crate::context::exprs::BinOp; -use crate::context::exprs::Cmp; -use crate::context::exprs::Env; -use crate::context::exprs::IntoExprErr; -use crate::context::yul::YulBuilder; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use crate::Concrete; -use crate::ConcreteNode; -use crate::Node; -use ethers_core::types::U256; -use shared::analyzer::AnalyzerLike; -use shared::analyzer::GraphLike; -use shared::context::ExprRet; -use shared::nodes::VarType; -use shared::range::elem_ty::RangeExpr; - -use solang_parser::pt::YulExpression; -use std::cell::RefCell; -use std::rc::Rc; - -use shared::range::{elem_ty::Elem, SolcRange}; -use shared::{context::ContextEdge, nodes::Builtin, Edge}; -use shared::{context::*, range::elem::RangeOp}; -use solang_parser::pt::YulFunctionCall; -use solang_parser::pt::{Expression, Loc, StorageLocation}; - -impl YulFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike -{ -} -pub trait YulFuncCaller: - GraphLike + AnalyzerLike + Sized -{ - fn yul_func_call( - &mut self, - func_call: &YulFunctionCall, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - let YulFunctionCall { loc, id, arguments } = func_call; - - match &*id.name { - "caller" => { - let t = self.msg_access(*loc, ctx, "sender")?; - ctx.push_expr(t, self).into_expr_err(*loc) - } - "origin" => { - let t = self.msg_access(*loc, ctx, "origin")?; - ctx.push_expr(t, self).into_expr_err(*loc) - } - "gasprice" => { - let t = self.msg_access(*loc, ctx, "gasprice")?; - ctx.push_expr(t, self).into_expr_err(*loc) - } - "callvalue" => { - let t = self.msg_access(*loc, ctx, "value")?; - ctx.push_expr(t, self).into_expr_err(*loc) - } - "pop" => { - let _ = ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; - Ok(()) - } - "hash" | "basefee" | "chainid" | "coinbase" | "difficulty" | "gaslimit" | "number" - | "prevrandao" | "timestamp" => { - let t = self.block_access(*loc, ctx, &id.name)?; - ctx.push_expr(t, self).into_expr_err(*loc) - } - "log0" | "log1" | "log2" | "log3" | "log4" => { - ctx.push_expr(ExprRet::Multi(vec![]), self) - .into_expr_err(*loc)?; - Ok(()) - } - "stop" | "revert" | "selfdestruct" | "invalid" => { - ctx.kill(self, *loc, KilledKind::Revert).into_expr_err(*loc) - } - "return" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(offset) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Return had no offset".to_string())) - }; - if matches!(offset, ExprRet::CtxKilled(_)) { - ctx.push_expr(offset, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(size) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Return had no size".to_string())) - }; - if matches!(size, ExprRet::CtxKilled(_)) { - ctx.push_expr(size, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.return_yul(ctx, loc, size)?; - ctx.kill(analyzer, loc, KilledKind::Ended) - .into_expr_err(loc)?; - // ctx.push_expr(ExprRet::CtxKilled(KilledKind::Ended), analyzer) - // .into_expr_err(loc)?; - Ok(()) - }) - }) - } - "not" => { - if arguments.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `not` expected 1 argument found: {:?}", - arguments.len() - ), - )); - } - - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) - }; - - if matches!(lhs, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.bit_not_inner(ctx, loc, lhs.flatten()) - }) - } - "add" | "sub" | "mul" | "div" | "sdiv" | "mod" | "smod" | "exp" | "and" | "or" - | "xor" | "shl" | "shr" | "sar" => { - let op = match &*id.name { - "add" => RangeOp::Add(true), - "sub" => RangeOp::Sub(true), - "mul" => RangeOp::Mul(true), - "div" | "sdiv" => RangeOp::Div(true), - "mod" | "smod" => RangeOp::Mod, - "exp" => RangeOp::Exp, - "and" => RangeOp::BitAnd, - "or" => RangeOp::BitOr, - "xor" => RangeOp::BitXor, - "shl" => RangeOp::Shl, - "shr" | "sar" => RangeOp::Shr, - _ => unreachable!(), - }; - - if arguments.len() != 2 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `{}` expects 2 arguments found: {:?}", - id.name, - arguments.len() - ), - )); - } - - let inputs: Vec = if matches!(&*id.name, "shl" | "shr" | "sar") { - // yul shifts are super dumb and are reversed. - vec![arguments[1].clone(), arguments[0].clone()] - } else { - vec![arguments[0].clone(), arguments[1].clone()] - }; - - self.parse_inputs(ctx, *loc, &inputs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no inputs".to_string())) - }; - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - inputs.expect_length(2).into_expr_err(loc)?; - let inputs = inputs.as_vec(); - - // we have to cast the inputs into an EVM word, which is effectively a u256. - let word_ty = analyzer.builtin_or_add(Builtin::Uint(256)); - let cast_ty = VarType::try_from_idx(analyzer, word_ty).unwrap(); - let lhs_paths = ContextVarNode::from(inputs[0].expect_single().into_expr_err(loc)?); - lhs_paths.cast_from_ty(cast_ty.clone(), analyzer).into_expr_err(loc)?; - let rhs_paths = ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); - rhs_paths.cast_from_ty(cast_ty, analyzer).into_expr_err(loc)?; - - analyzer.op_match(ctx, loc, &ExprRet::Single(lhs_paths.into()), &ExprRet::Single(rhs_paths.into()), op, false) - }) - } - "lt" | "gt" | "slt" | "sgt" | "eq" => { - let op = match &*id.name { - "lt" | "slt" => RangeOp::Lt, - "gt" | "sgt" => RangeOp::Gt, - "eq" => RangeOp::Eq, - _ => unreachable!(), - }; - - if arguments.len() != 2 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `{}` expects 2 arguments found: {:?}", - id.name, - arguments.len() - ), - )); - } - - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no right hand side".to_string())) - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no left hand side".to_string())) - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.cmp_inner(ctx, loc, &lhs_paths, op, &rhs_paths)?; - let Some(result) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no return".to_string())) - }; - - let res = ContextVarNode::from(result.expect_single().into_expr_err(loc)?); - let next = analyzer.advance_var_in_ctx(res, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new( - Elem::from(res), - RangeOp::Cast, - Elem::from(Concrete::Uint(1, U256::zero())) - )); - - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; - ctx.push_expr( - ExprRet::Single(next.into()), - analyzer, - ) - .into_expr_err(loc) - }) - }) - } - "iszero" => { - if arguments.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `iszero` expects 1 arguments found: {:?}", - arguments.len() - ), - )); - } - - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `iszero` operation had no input".to_string())) - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let cnode = ConcreteNode::from( - analyzer.add_node(Node::Concrete(Concrete::from(U256::from(0)))), - ); - let tmp_true = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) - .into_expr_err(loc)?, - ); - let rhs_paths = - ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); - - analyzer.cmp_inner(ctx, loc, &lhs_paths, RangeOp::Eq, &rhs_paths) - }) - } - "addmod" | "mulmod" => { - let b = Builtin::Uint(256); - let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "msize" | "pc" | "mload" | "sload" | "gas" | "returndatasize" => { - // TODO: actually handle this. @MemoryModel - let b = Builtin::Uint(256); - let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "calldatacopy" => { - // TODO: actually handle this. @MemoryModel - Ok(()) - } - "calldataload" => { - if arguments.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `calldataload` expects 1 arguments found: {:?}", - arguments.len() - ), - )); - } - - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `calldataload` operation had no input".to_string())) - }; - // TODO: check const version - let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; - let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("calldata[{}:{}+32]", elem.display_name(analyzer).into_expr_err(loc)?, elem.display_name(analyzer).into_expr_err(loc)?); - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc) - }) - } - "keccak256" => { - let b = Builtin::Bytes(32); - let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "call" | "delegatecall" | "callcode" | "staticcall" => { - let b = Builtin::Uint(256); - let mut var = - ContextVar::new_from_builtin(*loc, self.builtin_or_add(b.clone()).into(), self) - .into_expr_err(*loc)?; - var.display_name = format!("{id}_success"); - let mut range = SolcRange::try_from_builtin(&b).unwrap(); - range.min = Elem::from(Concrete::from(U256::from(0))); - range.max = Elem::from(Concrete::from(U256::from(1))); - var.ty.set_range(range).into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "create" | "create2" => { - let b = Builtin::Address; - let mut var = - ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - var.display_name = format!("{id}_success"); - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "returndatacopy" => { - ctx.push_expr(ExprRet::Multi(vec![]), self) - .into_expr_err(*loc)?; - Ok(()) - } - "byte" => { - let b = Builtin::Uint(8); - let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "mstore" | "mstore8" => { - // TODO: improve this. Right now we are extremely pessimistic and just say we know nothing about memory variables anymore. - // We should check if the location is a reference to an existing var and update based on that - // @MemoryModel - let vars = ctx.local_vars(self).clone(); - vars.into_iter().try_for_each(|(_name, var)| { - // widen to any max range - let latest_var = var.latest_version(self); - if matches!( - latest_var.underlying(self).into_expr_err(*loc)?.storage, - Some(StorageLocation::Memory(_)) - ) { - let res = latest_var.ty(self).into_expr_err(*loc)?; - if let Some(r) = res.default_range(self).unwrap() { - let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); - let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); - let _ = self.add_if_err(res); - let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); - let _ = self.add_if_err(res); - } - } - Ok(()) - })?; - ctx.push_expr(ExprRet::Multi(vec![]), self) - .into_expr_err(*loc)?; - Ok(()) - } - "sstore" => { - // TODO: improve this. Right now we are extremely pessimistic and just say we know nothing about storage variables anymore. - // We should check if the location is a reference to an existing var and update based on that - let vars = ctx.local_vars(self).clone(); - vars.iter().try_for_each(|(_name, var)| { - // widen to any max range - let latest_var = var.latest_version(self); - if matches!( - latest_var.underlying(self).into_expr_err(*loc)?.storage, - Some(StorageLocation::Storage(_)) - ) { - let res = latest_var.ty(self).into_expr_err(*loc)?; - if let Some(r) = res.default_range(self).unwrap() { - let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); - let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); - let _ = self.add_if_err(res); - let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); - let _ = self.add_if_err(res); - } - } - Ok(()) - })?; - ctx.push_expr(ExprRet::Multi(vec![]), self) - .into_expr_err(*loc)?; - Ok(()) - } - "balance" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `balance` operation had no input".to_string())) - }; - - let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; - let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("balance({})", elem.display_name(analyzer).into_expr_err(loc)?); - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc) - }) - } - "selfbalance" => { - let b = Builtin::Uint(256); - let mut var = - ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - var.display_name = "selfbalance()".to_string(); - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc) - } - "address" => { - let b = Builtin::Address; - let mut var = - ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - var.display_name = "address()".to_string(); - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc) - } - "extcodesize" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) - }; - - let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; - let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("extcodesize({})", elem.display_name(analyzer).into_expr_err(loc)?); - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc) - }) - } - "codesize" => { - let b = Builtin::Uint(256); - let mut var = - ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) - .into_expr_err(*loc)?; - var.display_name = "codesize()".to_string(); - let node = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc) - } - "codecopy" => { - if arguments.len() != 3 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `{}` expects 3 arguments found: {:?}", - id.name, - arguments.len() - ), - )); - } - - self.parse_inputs(ctx, *loc, arguments)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `codecopy` operation had no input".to_string())) - }; - ctx.push_expr(ExprRet::Multi(vec![]), analyzer) - .into_expr_err(loc) - }) - } - "extcodecopy" => { - if arguments.len() != 4 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "Yul function: `{}` expects 4 arguments found: {:?}", - id.name, - arguments.len() - ), - )); - } - - self.parse_inputs(ctx, *loc, arguments)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodecopy` operation had no input".to_string())) - }; - ctx.push_expr(ExprRet::Multi(vec![]), analyzer) - .into_expr_err(loc) - }) - } - "extcodehash" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) - }; - - let b = Builtin::Bytes(32); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; - let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("extcodehash({})", elem.display_name(analyzer).into_expr_err(loc)?); - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc) - }) - } - _ => Err(ExprErr::Todo( - *loc, - format!("Unhandled builtin yul function: {id:?}"), - )), - } - } - - fn return_yul(&mut self, ctx: ContextNode, loc: Loc, size: ExprRet) -> Result<(), ExprErr> { - match size { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Single(size) | ExprRet::SingleLiteral(size) => { - let b = Builtin::DynamicBytes; - let mut var = - ContextVar::new_from_builtin(loc, self.builtin_or_add(b.clone()).into(), self) - .into_expr_err(loc)?; - let mut range = SolcRange::try_from_builtin(&b).unwrap(); - match &mut range.min { - Elem::ConcreteDyn(ref mut r) => r.set_len(Elem::from(size)), - _ => unreachable!(), - } - match range.max { - Elem::ConcreteDyn(ref mut r) => r.set_len(Elem::from(size)), - _ => unreachable!(), - } - var.is_return = true; - var.ty.set_range(range).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(var)); - self.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); - ctx.add_return_node(loc, ContextVarNode::from(node).latest_version(self), self) - .into_expr_err(loc) - } - ExprRet::Multi(sizes) => { - sizes - .into_iter() - .try_for_each(|size| self.return_yul(ctx, loc, size))?; - Ok(()) - } - ExprRet::Null => Ok(()), - } - } - - // fn byte_index(&mut self, var: ExprRet, index: ExprRet) -> Result { - // match (var, index) { - // (ExprRet::Single(var_idx) - // | ExprRet::Single(var_idx), - // ExprRet::Single(index_idx) - // | ExprRet::Single(index_idx), - // ) => { - - // } - // } - // } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_inputs( - &mut self, - ctx: ContextNode, - loc: Loc, - inputs: &[YulExpression], - ) -> Result<(), ExprErr> { - let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { - Rc::new(RefCell::new(true)) - } else { - Rc::new(RefCell::new(false)) - }; - - inputs - .iter() - .try_for_each(|input| { - self.parse_ctx_yul_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) - })?; - if !inputs.is_empty() { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - ctx.push_expr(ret, analyzer).into_expr_err(loc) - }) - } else { - Ok(()) - } - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 3d67b73b..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,1134 +0,0 @@ -use crate::analyzers::LocStrSpan; -use crate::context::exprs::IntoExprErr; -use crate::exprs::ExprErr; -use ariadne::Source; -use ethers_core::types::U256; -use shared::analyzer::*; -use shared::context::ContextNode; -use shared::context::ExprRet; -use shared::context::{Context, ContextEdge}; -use shared::nodes::*; -use shared::{Edge, Node, NodeIdx}; -use solang_parser::diagnostics::Diagnostic; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::Identifier; -use solang_parser::pt::Import; -use std::collections::BTreeMap; - -use std::ffi::OsString; -use std::path::Path; - -use solang_parser::pt::{ - ContractDefinition, ContractPart, EnumDefinition, ErrorDefinition, Expression, - FunctionDefinition, FunctionTy, SourceUnit, SourceUnitPart, StructDefinition, TypeDefinition, - Using, UsingList, VariableDefinition, -}; -use std::path::PathBuf; -use std::{collections::HashMap, fs}; - -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use petgraph::{graph::*, Directed}; - -mod builtin_fns; - -pub mod context; -// pub mod range; -use context::*; -pub use shared; - -#[derive(Debug, Clone, Default)] -pub struct FinalPassItem { - pub funcs: Vec, - pub usings: Vec<(Using, NodeIdx)>, - pub inherits: Vec<(ContractNode, Vec)>, - pub vars: Vec<(VarNode, NodeIdx)>, -} -impl FinalPassItem { - pub fn new( - funcs: Vec, - usings: Vec<(Using, NodeIdx)>, - inherits: Vec<(ContractNode, Vec)>, - vars: Vec<(VarNode, NodeIdx)>, - ) -> Self { - Self { - funcs, - usings, - inherits, - vars, - } - } -} - -#[derive(Debug, Clone)] -pub struct Analyzer { - /// The root path of the contract to be analyzed - pub root: PathBuf, - /// Solidity remappings - as would be passed into the solidity compiler - pub remappings: Vec<(String, String)>, - /// Imported sources - the canonicalized string to the entry source element index - pub imported_srcs: BTreeMap>, - /// Since we use a staged approach to analysis, we analyze all user types first then go through and patch up any missing or unresolved - /// parts of a contract (i.e. we parsed a struct which is used as an input to a function signature, we have to know about the struct) - pub final_pass_items: Vec, - /// The next file number to use when parsing a new file - pub file_no: usize, - /// The index of the current `msg` node - pub msg: MsgNode, - /// The index of the current `block` node - pub block: BlockNode, - /// The underlying graph holding all of the elements of the contracts - pub graph: Graph, - /// The entry node - this is the root of the dag, all relevant things should eventually point back to this (otherwise can be discarded) - pub entry: NodeIdx, - /// A mapping of a solidity builtin to the index in the graph - pub builtins: HashMap, - /// A mapping of a user type's name to the index in the graph (i.e. `struct A` would mapped `A` -> index) - pub user_types: HashMap, - /// A mapping of solidity builtin function to a [Function] struct, i.e. `ecrecover` -> `Function { name: "ecrecover", ..}` - pub builtin_fns: HashMap, - /// A mapping of solidity builtin functions to their indices in the graph - pub builtin_fn_nodes: HashMap, - /// A mapping of solidity builtin function names to their parameters and returns, i.e. `ecrecover` -> `([hash, r, s, v], [signer])` - pub builtin_fn_inputs: HashMap, Vec)>, - /// Accumulated errors that happened while analyzing - pub expr_errs: Vec, - /// The maximum depth to analyze to (i.e. call depth) - pub max_depth: usize, - /// The maximum number of forks throughout the lifetime of the analysis. - pub max_width: usize, - /// Dummy function used during parsing to attach contexts to for more complex first-pass parsing (i.e. before `final_pass`) - pub parse_fn: FunctionNode, -} - -impl Default for Analyzer { - fn default() -> Self { - let mut a = Self { - root: Default::default(), - remappings: Default::default(), - imported_srcs: Default::default(), - final_pass_items: Default::default(), - file_no: 0, - msg: MsgNode(0), - block: BlockNode(0), - graph: Default::default(), - entry: NodeIndex::from(0), - builtins: Default::default(), - user_types: Default::default(), - builtin_fns: builtin_fns::builtin_fns(), - builtin_fn_nodes: Default::default(), - builtin_fn_inputs: Default::default(), - expr_errs: Default::default(), - max_depth: 1024, - max_width: 2_i32.pow(14) as usize, - parse_fn: NodeIdx::from(0).into(), - }; - a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); - - let msg = Msg::default(); - let block = Block::default(); - let msg = a.graph.add_node(Node::Msg(msg)).into(); - let block = a.graph.add_node(Node::Block(block)).into(); - a.msg = msg; - a.block = block; - a.entry = a.add_node(Node::Entry); - let pf = Function { - name: Some(Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".into(), - }), - ..Default::default() - }; - let parser_fn = FunctionNode::from(a.add_node(pf)); - a.add_edge(parser_fn, a.entry, Edge::Func); - a.parse_fn = parser_fn; - a - } -} - -impl GraphLike for Analyzer { - fn graph_mut(&mut self) -> &mut Graph { - &mut self.graph - } - - fn graph(&self) -> &Graph { - &self.graph - } -} - -impl AnalyzerLike for Analyzer { - type Expr = Expression; - type ExprErr = ExprErr; - - fn builtin_fn_nodes(&self) -> &HashMap { - &self.builtin_fn_nodes - } - - fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap { - &mut self.builtin_fn_nodes - } - - fn max_depth(&self) -> usize { - self.max_depth - } - - fn max_width(&self) -> usize { - self.max_width - } - - fn add_expr_err(&mut self, err: ExprErr) { - if !self.expr_errs.contains(&err) { - self.expr_errs.push(err); - } - } - - fn expr_errs(&self) -> Vec { - self.expr_errs.clone() - } - - fn entry(&self) -> NodeIdx { - self.entry - } - - fn msg(&mut self) -> MsgNode { - self.msg - } - - fn block(&mut self) -> BlockNode { - self.block - } - - fn builtin_fns(&self) -> &HashMap { - &self.builtin_fns - } - - fn builtin_fn_inputs(&self) -> &HashMap, Vec)> { - &self.builtin_fn_inputs - } - - fn builtins(&self) -> &HashMap { - &self.builtins - } - fn builtins_mut(&mut self) -> &mut HashMap { - &mut self.builtins - } - fn user_types(&self) -> &HashMap { - &self.user_types - } - fn user_types_mut(&mut self) -> &mut HashMap { - &mut self.user_types - } - - fn parse_expr(&mut self, expr: &Expression, parent: Option) -> NodeIdx { - use Expression::*; - match expr { - Type(_loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { - if let Some(idx) = self.builtins.get(&builtin) { - *idx - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins.insert(builtin, idx); - idx - } - } else if let Some(idx) = self.complicated_parse(expr, parent) { - self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) - .unwrap_or(0.into()) - } else { - 0.into() - } - } - Variable(ident) => { - if let Some(idx) = self.user_types.get(&ident.name) { - *idx - } else { - let node = self.add_node(Node::Unresolved(ident.clone())); - self.user_types.insert(ident.name.clone(), node); - node - } - } - ArraySubscript(_loc, ty_expr, None) => { - let inner_ty = self.parse_expr(ty_expr, parent); - if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { - let dyn_b = Builtin::Array(var_type); - if let Some(idx) = self.builtins.get(&dyn_b) { - *idx - } else { - let idx = self.add_node(Node::Builtin(dyn_b.clone())); - self.builtins.insert(dyn_b, idx); - idx - } - } else { - inner_ty - } - } - ArraySubscript(loc, ty_expr, Some(idx_expr)) => { - let inner_ty = self.parse_expr(ty_expr, parent); - let idx = self.parse_expr(idx_expr, parent); - if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { - let res = ConcreteNode::from(idx) - .underlying(self) - .into_expr_err(*loc) - .cloned(); - if let Some(concrete) = self.add_if_err(res) { - if let Some(size) = concrete.uint_val() { - let dyn_b = Builtin::SizedArray(size, var_type); - if let Some(idx) = self.builtins.get(&dyn_b) { - *idx - } else { - let idx = self.add_node(Node::Builtin(dyn_b.clone())); - self.builtins.insert(dyn_b, idx); - idx - } - } else { - inner_ty - } - } else { - inner_ty - } - } else { - inner_ty - } - } - NumberLiteral(_loc, integer, exponent, _unit) => { - let int = U256::from_dec_str(integer).unwrap(); - let val = if !exponent.is_empty() { - let exp = U256::from_dec_str(exponent).unwrap(); - int * U256::from(10).pow(exp) - } else { - int - }; - - self.add_node(Node::Concrete(Concrete::Uint(256, val))) - } - _ => { - if let Some(idx) = self.complicated_parse(expr, parent) { - self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) - .unwrap_or(0.into()) - } else { - 0.into() - } - } - } - } -} - -impl Analyzer { - pub fn complicated_parse( - &mut self, - expr: &Expression, - parent: Option, - ) -> Option { - tracing::trace!("Parsing required compile-time evaluation"); - - let ctx = if let Some(parent) = parent { - let pf = Function { - name: Some(Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".into(), - }), - ..Default::default() - }; - let parser_fn = FunctionNode::from(self.add_node(pf)); - self.add_edge(parser_fn, parent, Edge::Func); - - let dummy_ctx = Context::new(parser_fn, "".to_string(), expr.loc()); - let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); - self.add_edge(ctx, parser_fn, Edge::Context(ContextEdge::Context)); - ctx - } else { - let dummy_ctx = Context::new(self.parse_fn, "".to_string(), expr.loc()); - let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); - self.add_edge(ctx, self.entry(), Edge::Context(ContextEdge::Context)); - ctx - }; - - let full_stmt = solang_parser::pt::Statement::Return(expr.loc(), Some(expr.clone())); - self.parse_ctx_statement(&full_stmt, false, Some(ctx)); - let edges = self.add_if_err(ctx.all_edges(self).into_expr_err(expr.loc()))?; - if edges.len() == 1 { - let res = edges[0].return_nodes(self).into_expr_err(expr.loc()); - - let res = self.add_if_err(res); - - if let Some(res) = res { - res.last().map(|last| ExprRet::Single(last.1.into())) - } else { - None - } - } else if edges.is_empty() { - let res = ctx.return_nodes(self).into_expr_err(expr.loc()); - - let res = self.add_if_err(res); - - if let Some(res) = res { - res.last().map(|last| ExprRet::Single(last.1.into())) - } else { - None - } - } else { - self.add_expr_err(ExprErr::ParseError(expr.loc(), "Expected this to be compile-time evaluatable, but it was nondeterministic likely due to an external call via an interface".to_string())); - None - } - } - - pub fn set_remappings_and_root(&mut self, remappings_path: String) { - self.root = PathBuf::from(&remappings_path) - .parent() - .unwrap() - .to_path_buf(); - let remappings_file = fs::read_to_string(remappings_path) - .map_err(|err| err.to_string()) - .expect("Remappings file not found"); - - self.remappings = remappings_file - .lines() - .map(|x| x.trim()) - .filter(|x| !x.is_empty()) - .map(|x| x.split_once('=').expect("Invalid remapping")) - .map(|(name, path)| (name.to_owned(), path.to_owned())) - .collect(); - } - - pub fn print_errors( - &self, - file_mapping: &'_ BTreeMap, - mut src: &mut impl Cache, - ) { - if self.expr_errs.is_empty() { - } else { - self.expr_errs.iter().for_each(|error| { - let str_span = LocStrSpan::new(file_mapping, error.loc()); - let report = Report::build(ReportKind::Error, str_span.source(), str_span.start()) - .with_message(error.report_msg()) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ) - .with_label( - Label::new(str_span) - .with_color(Color::Red) - .with_message(format!("{}", error.msg().fg(Color::Red))), - ); - report.finish().print(&mut src).unwrap(); - }); - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse( - &mut self, - src: &str, - current_path: &Path, - entry: bool, - ) -> ( - Option, - Vec<(Option, String, String, usize)>, - ) { - // tracing::trace!("parsing: {:?}", current_path); - let file_no = self.file_no; - let mut imported = vec![]; - match solang_parser::parse(src, file_no) { - Ok((source_unit, _comments)) => { - let parent = self.add_node(Node::SourceUnit(file_no)); - self.add_edge(parent, self.entry, Edge::Source); - let final_pass_part = self.parse_source_unit( - source_unit, - file_no, - parent, - &mut imported, - current_path, - ); - self.final_pass_items.push(final_pass_part); - if entry { - self.final_pass(); - } - - (Some(parent), imported) - } - Err(diagnostics) => { - print_diagnostics_report(src, current_path, diagnostics).unwrap(); - panic!("Failed to parse Solidity code for {current_path:?}."); - } - } - } - - pub fn final_pass(&mut self) { - let elems = self.final_pass_items.clone(); - elems.iter().for_each(|final_pass_item| { - final_pass_item - .inherits - .iter() - .for_each(|(contract, inherits)| { - contract.inherit(inherits.to_vec(), self); - }); - final_pass_item.funcs.iter().for_each(|func| { - // add params now that parsing is done - func.set_params_and_ret(self).unwrap(); - }); - - final_pass_item - .usings - .iter() - .for_each(|(using, scope_node)| { - self.parse_using(using, *scope_node); - }); - final_pass_item.vars.iter().for_each(|(var, parent)| { - let loc = var.underlying(self).unwrap().loc; - let res = var.parse_initializer(self, *parent).into_expr_err(loc); - let _ = self.add_if_err(res); - }); - }); - - elems.into_iter().for_each(|final_pass_item| { - final_pass_item.funcs.into_iter().for_each(|func| { - if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(func)); - } - }); - }); - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_source_unit( - &mut self, - source_unit: SourceUnit, - file_no: usize, - parent: NodeIdx, - imported: &mut Vec<(Option, String, String, usize)>, - current_path: &Path, - ) -> FinalPassItem { - let mut all_funcs = vec![]; - let mut all_usings = vec![]; - let mut all_inherits = vec![]; - let mut all_vars = vec![]; - source_unit - .0 - .iter() - .enumerate() - .for_each(|(unit_part, source_unit_part)| { - let (_sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( - source_unit_part, - file_no, - unit_part, - parent, - imported, - current_path, - ); - all_funcs.extend(funcs); - all_usings.extend(usings); - all_inherits.extend(inherits); - all_vars.extend(vars); - }); - FinalPassItem::new(all_funcs, all_usings, all_inherits, all_vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_source_unit_part( - &mut self, - sup: &SourceUnitPart, - file_no: usize, - unit_part: usize, - parent: NodeIdx, - imported: &mut Vec<(Option, String, String, usize)>, - current_path: &Path, - ) -> ( - NodeIdx, - Vec, - Vec<(Using, NodeIdx)>, - Vec<(ContractNode, Vec)>, - Vec<(VarNode, NodeIdx)>, - ) { - use SourceUnitPart::*; - - let sup_node = self.add_node(Node::SourceUnitPart(file_no, unit_part)); - self.add_edge(sup_node, parent, Edge::Part); - - let mut func_nodes = vec![]; - let mut usings = vec![]; - let mut inherits = vec![]; - let mut vars = vec![]; - - match sup { - ContractDefinition(def) => { - let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = - self.parse_contract_def(def, parent, imported); - self.add_edge(node, sup_node, Edge::Contract); - func_nodes.extend(funcs); - usings.extend(con_usings); - inherits.push((node, unhandled_inherits)); - vars.extend(unhandled_vars); - } - StructDefinition(def) => { - let node = self.parse_struct_def(def); - self.add_edge(node, sup_node, Edge::Struct); - } - EnumDefinition(def) => { - let node = self.parse_enum_def(def); - self.add_edge(node, sup_node, Edge::Enum); - } - ErrorDefinition(def) => { - let node = self.parse_err_def(def); - self.add_edge(node, sup_node, Edge::Error); - } - VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); - if let Some(func) = maybe_func { - func_nodes.push(self.handle_func(func, None)); - } - - if needs_final_pass { - vars.push((node, parent)); - } - - self.add_edge(node, sup_node, Edge::Var); - } - FunctionDefinition(def) => { - let node = self.parse_func_def(def, None); - func_nodes.push(node); - self.add_edge(node, sup_node, Edge::Func); - } - TypeDefinition(def) => { - let node = self.parse_ty_def(def); - self.add_edge(node, sup_node, Edge::Ty); - } - EventDefinition(_def) => todo!(), - Annotation(_anno) => todo!(), - Using(using) => usings.push((*using.clone(), parent)), - StraySemicolon(_loc) => todo!(), - PragmaDirective(_, _, _) => {} - ImportDirective(import) => { - imported.extend(self.parse_import(import, current_path, parent)) - } - } - (sup_node, func_nodes, usings, inherits, vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_import( - &mut self, - import: &Import, - current_path: &Path, - parent: NodeIdx, - ) -> Vec<(Option, String, String, usize)> { - match import { - Import::Plain(import_path, _) => { - tracing::trace!("parse_import, path: {:?}", import_path); - let remapping = self - .remappings - .iter() - .find(|x| import_path.string.starts_with(&x.0)); - - let remapped = if let Some((name, path)) = remapping { - self.root.join(path).join( - import_path - .string - .replacen(name, "", 1) - .trim_start_matches('/'), - ) - } else { - current_path - .parent() - .unwrap() - .join(import_path.string.clone()) - }; - - let canonical = fs::canonicalize(&remapped) - .unwrap_or_else(|_| panic!( - "Could not find file: {remapped:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - ); - let canonical_str_path = canonical.as_os_str(); - if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { - if let Some(o_e) = other_entry { - self.add_edge(*o_e, parent, Edge::Import); - } - return vec![]; - } - - let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { - panic!( - "Could not find file for dependency: {canonical:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input (where `remappings.txt` is the output of `forge remappings > remappings.txt`)" - } else { "" } - ) - }); - self.file_no += 1; - let file_no = self.file_no; - // breaks recursion issues - self.imported_srcs.insert(canonical_str_path.into(), None); - let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); - self.imported_srcs - .insert(canonical_str_path.into(), maybe_entry); - if let Some(other_entry) = maybe_entry { - self.add_edge(other_entry, parent, Edge::Import); - } - - inner_sources.push(( - maybe_entry, - remapped.to_str().unwrap().to_owned(), - sol.to_string(), - file_no, - )); - inner_sources - } - Import::Rename(import_path, _elems, _) => { - tracing::trace!("parse_import, path: {:?}, Rename", import_path); - let remapping = self - .remappings - .iter() - .find(|x| import_path.string.starts_with(&x.0)); - - let remapped = if let Some((name, path)) = remapping { - self.root.join(path).join( - import_path - .string - .replacen(name, "", 1) - .trim_start_matches('/'), - ) - } else { - current_path - .parent() - .unwrap() - .join(import_path.string.clone()) - }; - - let canonical = fs::canonicalize(&remapped).unwrap_or_else(|_| panic!( - "Could not find file: {remapped:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - ); - let canonical_str_path = canonical.as_os_str(); - if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { - if let Some(o_e) = other_entry { - self.add_edge(*o_e, parent, Edge::Import); - } - return vec![]; - } - - let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { - panic!( - "Could not find file for dependency: {canonical:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - }); - self.file_no += 1; - let file_no = self.file_no; - - // breaks recursion issues - self.imported_srcs.insert(canonical_str_path.into(), None); - let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); - self.imported_srcs - .insert(canonical_str_path.into(), maybe_entry); - if let Some(other_entry) = maybe_entry { - self.add_edge(other_entry, parent, Edge::Import); - } - - inner_sources.push(( - maybe_entry, - remapped.to_str().unwrap().to_owned(), - sol.to_string(), - file_no, - )); - inner_sources - } - e => todo!("import {:?}", e), - } - } - - // #[tracing::instrument(name = "parse_contract_def", skip_all, fields(name = format!("{:?}", contract_def.name)))] - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_contract_def( - &mut self, - contract_def: &ContractDefinition, - source: NodeIdx, - imports: &[(Option, String, String, usize)], - ) -> ( - ContractNode, - Vec, - Vec<(Using, NodeIdx)>, - Vec, - Vec<(VarNode, NodeIdx)>, - ) { - tracing::trace!( - "Parsing contract {}", - if let Some(ident) = &contract_def.name { - ident.name.clone() - } else { - "interface".to_string() - } - ); - use ContractPart::*; - - let (contract, unhandled_inherits) = - Contract::from_w_imports(contract_def.clone(), source, imports, self); - - let inherits = contract.inherits.clone(); - let con_name = contract.name.clone().unwrap().name; - let con_node: ContractNode = - if let Some(user_ty_node) = self.user_types.get(&con_name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Contract(contract); - user_ty_node.into() - } else { - let node = self.add_node(Node::Contract(contract)); - self.user_types.insert(con_name, node); - node.into() - }; - - inherits.iter().for_each(|contract_node| { - self.add_edge(*contract_node, con_node, Edge::InheritedContract); - }); - let mut usings = vec![]; - let mut func_nodes = vec![]; - let mut vars = vec![]; - contract_def.parts.iter().for_each(|cpart| match cpart { - StructDefinition(def) => { - let node = self.parse_struct_def(def); - self.add_edge(node, con_node, Edge::Struct); - } - EnumDefinition(def) => { - let node = self.parse_enum_def(def); - self.add_edge(node, con_node, Edge::Enum); - } - ErrorDefinition(def) => { - let node = self.parse_err_def(def); - self.add_edge(node, con_node, Edge::Error); - } - VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, true); - if let Some(func) = maybe_func { - func_nodes.push(self.handle_func(func, Some(con_node))); - } - - if needs_final_pass { - vars.push((node, con_node.into())); - } - - self.add_edge(node, con_node, Edge::Var); - } - FunctionDefinition(def) => { - let node = self.parse_func_def(def, Some(con_node)); - func_nodes.push(node); - } - TypeDefinition(def) => { - let node = self.parse_ty_def(def); - self.add_edge(node, con_node, Edge::Ty); - } - EventDefinition(_def) => {} - Annotation(_anno) => todo!(), - Using(using) => usings.push((*using.clone(), con_node.0.into())), - StraySemicolon(_loc) => todo!(), - }); - (con_node, func_nodes, usings, unhandled_inherits, vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_using(&mut self, using_def: &Using, scope_node: NodeIdx) { - tracing::trace!("Parsing \"using\" {:?}", using_def); - let Some(ref using_def_ty) = using_def.ty else { - self.add_expr_err(ExprErr::Todo(using_def.loc(), "Using statements with wildcards currently unsupported".to_string())); - return; - }; - let maybe_cvar_idx = self.parse_expr(using_def_ty, None); - let ty_idx = match VarType::try_from_idx(self, maybe_cvar_idx) { - Some(v_ty) => v_ty.ty_idx(), - None => { - self.add_expr_err(ExprErr::Unresolved( - using_def.loc(), - "Unable to deduce the type for which to apply the `using` statement to" - .to_string(), - )); - return; - } - }; - - match &using_def.list { - UsingList::Library(ident_paths) => { - ident_paths.identifiers.iter().for_each(|ident| { - if let Some(hopefully_contract) = self.user_types.get(&ident.name) { - match self.node(*hopefully_contract) { - Node::Contract(_) => { - let funcs = ContractNode::from(*hopefully_contract).funcs(self); - let relevant_funcs: Vec<_> = funcs - .iter() - .filter_map(|func| { - let first_param: FunctionParamNode = - *func.params(self).iter().take(1).next()?; - let param_ty = first_param.ty(self).unwrap(); - if param_ty == ty_idx { - Some(func) - } else { - None - } - }) - .copied() - .collect(); - relevant_funcs.iter().for_each(|func| { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - }); - } - _ => self.add_expr_err(ExprErr::ParseError( - using_def.loc(), - "Tried to use a non-contract as a contract in a `using` statement" - .to_string(), - )), - } - } else { - panic!("Cannot find library contract {}", ident.name); - } - }); - } - UsingList::Functions(vec_ident_paths) => { - vec_ident_paths.iter().for_each(|ident_paths| { - if ident_paths.path.identifiers.len() == 2 { - if let Some(hopefully_contract) = - self.user_types.get(&ident_paths.path.identifiers[0].name) - { - if let Some(func) = ContractNode::from(*hopefully_contract) - .funcs(self) - .iter() - .find(|func| { - func.name(self) - .unwrap() - .starts_with(&ident_paths.path.identifiers[1].name) - }) - { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - } else { - panic!( - "Cannot find library function {}.{}", - ident_paths.path.identifiers[0].name, - ident_paths.path.identifiers[1].name - ); - } - } else { - panic!( - "Cannot find library contract {}", - ident_paths.path.identifiers[0].name - ); - } - } else { - // looking for free floating function - let funcs = match self.node(scope_node) { - Node::Contract(_) => self.search_children( - ContractNode::from(scope_node).associated_source(self), - &Edge::Func, - ), - Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), - _ => unreachable!(), - }; - if let Some(func) = funcs.iter().find(|func| { - FunctionNode::from(**func) - .name(self) - .unwrap() - .starts_with(&ident_paths.path.identifiers[0].name) - }) { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - } else { - panic!( - "Cannot find library function {}", - ident_paths.path.identifiers[0].name - ); - } - } - }); - } - UsingList::Error => todo!(), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_enum_def(&mut self, enum_def: &EnumDefinition) -> EnumNode { - tracing::trace!("Parsing enum {:?}", enum_def); - let enu = Enum::from(enum_def.clone()); - let name = enu.name.clone().expect("Enum was not named").name; - - // check if we have an unresolved type by the same name - let enu_node: EnumNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Enum(enu); - user_ty_node.into() - } else { - let node = self.add_node(enu); - self.user_types.insert(name, node); - node.into() - }; - - enu_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_struct_def(&mut self, struct_def: &StructDefinition) -> StructNode { - tracing::trace!("Parsing struct {:?}", struct_def.name); - let strukt = Struct::from(struct_def.clone()); - - let name = strukt.name.clone().expect("Struct was not named").name; - - // check if we have an unresolved type by the same name - let strukt_node: StructNode = - if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Struct(strukt); - user_ty_node.into() - } else { - let node = self.add_node(strukt); - self.user_types.insert(name, node); - node.into() - }; - - struct_def.fields.iter().for_each(|field| { - let f = Field::new(self, field.clone()); - let field_node = self.add_node(f); - self.add_edge(field_node, strukt_node, Edge::Field); - }); - strukt_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_err_def(&mut self, err_def: &ErrorDefinition) -> ErrorNode { - tracing::trace!("Parsing error {:?}", err_def); - let err_node = ErrorNode(self.add_node(Error::from(err_def.clone())).index()); - err_def.fields.iter().for_each(|field| { - let param = ErrorParam::new(self, field.clone()); - let field_node = self.add_node(param); - self.add_edge(field_node, err_node, Edge::ErrorParam); - }); - err_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_func_def( - &mut self, - func_def: &FunctionDefinition, - con_node: Option, - ) -> FunctionNode { - let func = Function::from(func_def.clone()); - tracing::trace!( - "Parsing function {:?}", - func.name - .clone() - .unwrap_or_else(|| solang_parser::pt::Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".to_string() - }) - .name - ); - self.handle_func(func, con_node) - } - - pub fn handle_func(&mut self, func: Function, con_node: Option) -> FunctionNode { - match func.ty { - FunctionTy::Constructor => { - let node = self.add_node(func); - let func_node = node.into(); - - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::Constructor); - } - func_node - } - FunctionTy::Fallback => { - let node = self.add_node(func); - let func_node = node.into(); - - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::FallbackFunc); - } - - func_node - } - FunctionTy::Receive => { - // receive function cannot have input/output - let node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::ReceiveFunc); - } - FunctionNode::from(node) - } - FunctionTy::Function => { - let fn_node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(fn_node, con_node, Edge::Func); - } - fn_node.into() - } - FunctionTy::Modifier => { - let fn_node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(fn_node, con_node, Edge::Modifier); - } - fn_node.into() - } - } - } - - pub fn parse_var_def( - &mut self, - var_def: &VariableDefinition, - in_contract: bool, - ) -> (VarNode, Option, bool) { - tracing::trace!("Parsing variable definition: {:?}", var_def.name); - let var = Var::new(self, var_def.clone(), in_contract); - let mut func = None; - if var.is_public() { - func = Some(Function::from(var_def.clone())); - } - let needs_final_pass = var.initializer_expr.is_some(); - let var_node = VarNode::from(self.add_node(var)); - self.user_types - .insert(var_node.name(self).unwrap(), var_node.into()); - (var_node, func, needs_final_pass) - } - - pub fn parse_ty_def(&mut self, ty_def: &TypeDefinition) -> TyNode { - tracing::trace!("Parsing type definition"); - let ty = Ty::new(self, ty_def.clone()); - let name = ty.name.name.clone(); - let ty_node: TyNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Ty(ty); - user_ty_node.into() - } else { - let node = self.add_node(Node::Ty(ty)); - self.user_types.insert(name, node); - node.into() - }; - ty_node - } -} - -/// Print the report of parser's diagnostics -pub fn print_diagnostics_report( - content: &str, - path: &Path, - diagnostics: Vec, -) -> std::io::Result<()> { - let filename = path.file_name().unwrap().to_string_lossy().to_string(); - for diag in diagnostics { - let (start, end) = (diag.loc.start(), diag.loc.end()); - let mut report = Report::build(ReportKind::Error, &filename, start) - .with_message(format!("{:?}", diag.ty)) - .with_label( - Label::new((&filename, start..end)) - .with_color(Color::Red) - .with_message(format!("{}", diag.message.fg(Color::Red))), - ); - - for note in diag.notes { - report = report.with_note(note.message); - } - - report.finish().print((&filename, Source::from(content)))?; - } - Ok(()) -} From 692ce4de752ca3688c33b7d89e7796efc5c173fb Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 15:26:51 -0800 Subject: [PATCH 07/71] graph improvements --- Cargo.lock | 2303 ----------------- Cargo.toml | 2 +- LICENSE | 674 ----- LICENSE-APACHE | 187 ++ LICENSE-MIT | 20 + cli/Cargo.lock | 1616 ------------ cli/Cargo.toml | 23 - cli/src/main.rs | 355 --- crates/cli/Cargo.lock | 1616 ------------ crates/graph/Cargo.toml | 1 + crates/graph/src/graph_elements.rs | 215 +- crates/graph/src/graph_like.rs | 12 +- crates/graph/src/nodes/builtin.rs | 34 +- crates/graph/src/nodes/concrete.rs | 35 +- crates/graph/src/nodes/context/context_tys.rs | 17 + crates/graph/src/nodes/context/expr_ret.rs | 28 +- crates/graph/src/nodes/context/mod.rs | 16 + crates/graph/src/nodes/context/node.rs | 1147 +------- crates/graph/src/nodes/context/querying.rs | 235 ++ crates/graph/src/nodes/context/solving.rs | 198 ++ crates/graph/src/nodes/context/typing.rs | 77 + crates/graph/src/nodes/context/underlying.rs | 14 +- crates/graph/src/nodes/context/var/mod.rs | 8 + crates/graph/src/nodes/context/var/node.rs | 290 +++ crates/graph/src/nodes/context/var/ranging.rs | 315 +++ crates/graph/src/nodes/context/var/typing.rs | 299 +++ .../graph/src/nodes/context/var/underlying.rs | 617 +++++ .../graph/src/nodes/context/var/versioning.rs | 189 ++ crates/graph/src/nodes/context/variables.rs | 258 ++ crates/graph/src/nodes/context/versioning.rs | 419 +++ crates/graph/src/nodes/contract_ty.rs | 25 +- crates/graph/src/nodes/var_ty.rs | 17 + crates/queries/Cargo.toml | 0 crates/queries/{mod.rs => lib.rs} | 0 crates/range/src/{mod.rs => lib.rs} | 0 crates/solvers/Cargo.toml | 21 + crates/solvers/src/dl.rs | 944 +++++++ crates/solvers/src/lib.rs | 341 +++ 38 files changed, 4848 insertions(+), 7720 deletions(-) delete mode 100644 Cargo.lock delete mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT delete mode 100644 cli/Cargo.lock delete mode 100644 cli/Cargo.toml delete mode 100644 cli/src/main.rs delete mode 100644 crates/cli/Cargo.lock create mode 100644 crates/graph/src/nodes/context/querying.rs create mode 100644 crates/graph/src/nodes/context/solving.rs create mode 100644 crates/graph/src/nodes/context/typing.rs create mode 100644 crates/graph/src/nodes/context/var/mod.rs create mode 100644 crates/graph/src/nodes/context/var/node.rs create mode 100644 crates/graph/src/nodes/context/var/ranging.rs create mode 100644 crates/graph/src/nodes/context/var/typing.rs create mode 100644 crates/graph/src/nodes/context/var/underlying.rs create mode 100644 crates/graph/src/nodes/context/var/versioning.rs create mode 100644 crates/graph/src/nodes/context/variables.rs create mode 100644 crates/graph/src/nodes/context/versioning.rs create mode 100644 crates/queries/Cargo.toml rename crates/queries/{mod.rs => lib.rs} (100%) rename crates/range/src/{mod.rs => lib.rs} (100%) create mode 100644 crates/solvers/Cargo.toml create mode 100644 crates/solvers/src/dl.rs create mode 100644 crates/solvers/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c89c6964..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,2303 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "anstream" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-wincon", - "concolor-override", - "concolor-query", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" - -[[package]] -name = "anstyle-parse" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-wincon" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" -dependencies = [ - "anstyle", - "windows-sys 0.45.0", -] - -[[package]] -name = "ariadne" -version = "0.2.0" -source = "git+https://github.com/brockelmore/ariadne#c2e3a8e79f369e8a785e1ca337e144ebc946f115" -dependencies = [ - "unicode-width", - "yansi", -] - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "ciborium" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" - -[[package]] -name = "ciborium-ll" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "bitflags", - "clap_lex 0.2.4", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" -dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", -] - -[[package]] -name = "clap_builder" -version = "4.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" -dependencies = [ - "anstream", - "anstyle", - "bitflags", - "clap_lex 0.4.1", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "clap_lex" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" - -[[package]] -name = "cli" -version = "0.1.0" -dependencies = [ - "ariadne", - "clap 4.2.1", - "petgraph", - "pyrometer", - "shared", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "concolor-override" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" - -[[package]] -name = "concolor-query" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" -dependencies = [ - "windows-sys 0.45.0", -] - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "cpufeatures" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap 3.2.25", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "ecdsa" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106401dadc137d05cb0d4ab4d42be089746aefdfe8992df4d0edcf351c16ddca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cdacd4d6ed3f9b98680b679c0e52a823b8a2c7a97358d508fe247f2180c282" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" -dependencies = [ - "log", -] - -[[package]] -name = "errno" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.45.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-core" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40bf114f1017ace0f622f1652f59c2c5e1abfe7d88891cca0c43da979b351de0" -dependencies = [ - "arrayvec", - "bytes", - "chrono", - "elliptic-curve", - "ethabi", - "generic-array", - "getrandom", - "hex", - "k256", - "num_enum", - "open-fastrlp", - "rand", - "rlp", - "serde", - "serde_json", - "strum", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955890845095ccf31ef83ad41a05aabb4d8cc23dc3cac5a9f5c89cf26dd0da75" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34313ec00c2eb5c3c87ca6732ea02dcf3af99c3ff7a8fb622ffb99c9d860a87" -dependencies = [ - "ascii-canvas", - "bit-set", - "diff", - "ena", - "is-terminal", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c1f7869c94d214466c5fd432dfed12c379fd87786768d36455892d46b18edd" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" - -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parity-scale-codec" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "windows-sys 0.45.0", -] - -[[package]] -name = "petgraph" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared 0.11.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared 0.11.1", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared 0.11.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "primitive-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pyrometer" -version = "0.1.0" -dependencies = [ - "ariadne", - "criterion", - "ethers-core", - "hex", - "petgraph", - "shared", - "solang-parser", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustix" -version = "0.37.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aef160324be24d31a62147fae491c14d2204a3865c7ca8c3b0d7f7bcb3ea635" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scale-info" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sec1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "serde_json" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared" -version = "0.1.0" -dependencies = [ - "ethers-core", - "hex", - "lazy_static", - "petgraph", - "solang-parser", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "signature" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "solang-parser" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c5ead679f39243782be98c2689e592fc0fc9489ca2e47c9e027bd30f948df31" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "serde", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "spki" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "toml_datetime" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" - -[[package]] -name = "toml_edit" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.13", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" - -[[package]] -name = "web-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winnow" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index 8e29e544..43ac5f81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ members = [ ] - [workspace.package] version = "0.2.0" edition = "2021" @@ -45,6 +44,7 @@ tracing-subscriber = "0.3" ethers-core = "*" hex = "0.4.3" ariadne = "0.2.0" +petgraph = "0.6.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f6f0bf49..00000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - Pyrometer - Copyright (C) 2023 Nascent - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Pyrometer Copyright (C) 2023 Nascent - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..a7b8b5e6 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,187 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. \ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..dc2b8972 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2022-2023 Nascent + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/cli/Cargo.lock b/cli/Cargo.lock deleted file mode 100644 index 16ae4bf4..00000000 --- a/cli/Cargo.lock +++ /dev/null @@ -1,1616 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "ariadne" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702" -dependencies = [ - "unicode-width", - "yansi", -] - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "clap" -version = "4.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" -dependencies = [ - "bitflags", - "clap_derive", - "clap_lex", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "cli" -version = "0.1.0" -dependencies = [ - "ariadne", - "clap", - "pyrometer", - "shared", -] - -[[package]] -name = "const-oid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest", - "ff", - "generic-array", - "group", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" -dependencies = [ - "arrayvec", - "bytes", - "chrono", - "elliptic-curve", - "ethabi", - "generic-array", - "hex", - "k256", - "open-fastrlp", - "rand", - "rlp", - "rlp-derive", - "serde", - "serde_json", - "strum", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes", - "rustix", - "windows-sys", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", - "sha3", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "parity-scale-codec" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared 0.11.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared 0.11.1", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared 0.11.1", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "primitive-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pyrometer" -version = "0.1.0" -dependencies = [ - "ariadne", - "ethers-core", - "hex", - "petgraph", - "shared", - "solang-parser", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustix" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "scale-info" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "shared" -version = "0.1.0" -dependencies = [ - "ethers-core", - "hex", - "lazy_static", - "petgraph", - "solang-parser", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "solang-parser" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87dae6cdccacdbf3b19e99b271083556e808de0f59c74a01482f64fdbc61fc" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "serde", - "unicode-xid", -] - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/cli/Cargo.toml b/cli/Cargo.toml deleted file mode 100644 index 9ac847ea..00000000 --- a/cli/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "cli" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap = { version = "4.1.4", features = ["derive"] } -pyrometer = { path = "../" } -shared = { path = "../shared" } -ariadne = "0.2.0" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } -petgraph = "0.6.2" - -[[bin]] -name = "pyrometer" -path = "src/main.rs" - - -[profile.release] -debug = true \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs deleted file mode 100644 index 5449ab71..00000000 --- a/cli/src/main.rs +++ /dev/null @@ -1,355 +0,0 @@ -use crate::analyzers::ReportConfig; -use ariadne::sources; -use clap::{ArgAction, Parser, ValueHint}; -use pyrometer::context::analyzers::FunctionVarsBoundAnalyzer; -use pyrometer::{ - context::{analyzers::ReportDisplay, *}, - Analyzer, -}; - -use shared::nodes::FunctionNode; - -use shared::Edge; -use shared::{ - analyzer::{GraphLike, Search}, - nodes::ContractNode, -}; -use tracing_subscriber::prelude::*; - -use std::collections::{BTreeMap, HashMap}; -use std::path::PathBuf; - -use std::env::{self}; -use std::fs; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - /// The path to the solidity file to process - #[clap(value_hint = ValueHint::FilePath, value_name = "PATH")] - pub path: String, - /// The path to the `remappings.txt` as per the output of `forge remappings` - #[clap(long, short)] - pub remappings: Option, - /// Limit the output to just contracts that start with the name passed. i.e. `--contracts "MyCon"` woudl match "MyContract", "MyCon2", .. etc. - /// - /// Can be passed multiple times, i.e. `--contract "MyCon" --contract "MyOtherContract"` - #[clap(long, short)] - pub contracts: Vec, - /// Limit the output to just functions that start with the name passed. i.e. `--funcs "myFunc"` would match "myFunction", "myFunc2", .. etc. - /// - /// Can be passed multiple times, i.e. `--funcs "myFunc" --funcs "myOtherFunc"` - #[clap(long, short)] - pub funcs: Vec, - /// Verbosity of the bounds analysis - /// - /// Pass multiple times to increase the verbosity (e.g. -v, -vv, -vvv). - /// - /// Verbosity levels: - /// - /// 0: Print return value changes - /// 1: Print storage variable changes, input variable changes, and return value changes - /// 2: Print all previous values as well as temporary values - /// 3: Print all previous values as well as initial values - /// 4: Print all previous values as well as constants - /// 5: Print all previous values for all successful branches and reverting branches - /// 6: Print all previous values for all successful branches, reverting branches, and unreachable branches - #[clap(long, short, verbatim_doc_comment, action = ArgAction::Count)] - pub verbosity: u8, - /// Whether to print out a dot string of the analyzed contracts - #[clap(long, short, default_value = "false")] - pub dot: bool, - /// Whether to generate and open a dot visualization of the analyzed contracts - #[clap(long, short, default_value = "false")] - pub open_dot: bool, - /// Whether to evaluate variables down to their intervals or to keep them symbolic/relational to other variables - #[clap(long, short)] - pub eval: Option, - /// Whether to simplify expressions down to variables down to their intervals or to keep them symbolic/relational to other variables - #[clap(long, short)] - pub simplify: Option, - /// Whether to show initial values in the bounds analysis output - #[clap(long)] - pub show_inits: Option, - /// Show reverting paths - #[clap(long)] - pub show_reverts: Option, - /// Show unreachable paths - #[clap(long)] - pub show_unreachables: Option, - /// Show non-revert paths - #[clap(long)] - pub show_nonreverts: Option, - // #[clap(long, short)] - // pub access_query: Vec, - // #[clap(long, short)] - // pub query: Vec, - // #[clap(long, short)] - // pub write_query: Vec, - /// A debugging command to prevent bound analysis printing. Useful for debugging parse errors during development. Only prints out parse errors - /// then ends the program - #[clap(long)] - pub debug: bool, -} - -pub fn subscriber() { - tracing_subscriber::Registry::default() - .with(tracing_subscriber::filter::EnvFilter::from_default_env()) - .with(tracing_subscriber::fmt::layer()) - .init() -} - -fn main() { - subscriber(); - let args = Args::parse(); - let path_str = args.path.to_string(); - let verbosity = args.verbosity; - let config = match verbosity { - 0 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: false, - show_consts: false, - show_symbolics: false, - show_initial_bounds: args.show_inits.unwrap_or(false), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(false), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 1 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: false, - show_consts: false, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(false), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(false), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 2 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: false, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(false), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(false), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 3 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: false, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(true), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(false), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 4 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: true, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(true), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(false), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 5 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: true, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(true), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(true), - show_unreachables: args.show_unreachables.unwrap_or(false), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - 6 => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: true, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(true), - show_all_lines: false, - show_reverts: args.show_reverts.unwrap_or(true), - show_unreachables: args.show_unreachables.unwrap_or(true), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - _ => ReportConfig { - eval_bounds: args.eval.unwrap_or(true), - simplify_bounds: args.simplify.unwrap_or(false), - show_tmps: true, - show_consts: true, - show_symbolics: true, - show_initial_bounds: args.show_inits.unwrap_or(true), - show_all_lines: true, - show_reverts: args.show_reverts.unwrap_or(true), - show_unreachables: args.show_unreachables.unwrap_or(true), - show_nonreverts: args.show_nonreverts.unwrap_or(true), - }, - }; - - let sol = fs::read_to_string(args.path.clone()).expect("Could not find file"); - - let mut analyzer = Analyzer { - root: env::current_dir().unwrap(), - ..Default::default() - }; - if args.remappings.is_some() { - let remappings = args.remappings.unwrap(); - analyzer.set_remappings_and_root(remappings); - } - let t0 = std::time::Instant::now(); - let (maybe_entry, mut all_sources) = - analyzer.parse(&sol, &PathBuf::from(args.path.clone()), true); - let parse_time = t0.elapsed().as_millis(); - - println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); - - all_sources.push((maybe_entry, args.path, sol, 0)); - let entry = maybe_entry.unwrap(); - - let mut file_mapping: BTreeMap<_, _> = vec![(0usize, path_str)].into_iter().collect(); - file_mapping.extend( - all_sources - .iter() - .map(|(_entry, name, _src, num)| (*num, name.clone())) - .collect::>(), - ); - - let mut source_map = sources( - all_sources - .iter() - .map(|(_entry, name, src, _num)| (name.clone(), src)) - .collect::>(), - ); - - // let t = petgraph::algo::toposort(&analyzer.graph, None); - analyzer.print_errors(&file_mapping, &mut source_map); - - if args.open_dot { - analyzer.open_dot() - } - - if args.dot { - println!("{}", analyzer.dot_str_no_tmps()); - } - - if args.debug { - return; - } - - let all_contracts = analyzer - .search_children(entry, &Edge::Contract) - .into_iter() - .map(ContractNode::from) - .collect::>(); - let _t1 = std::time::Instant::now(); - if args.contracts.is_empty() { - let funcs = analyzer.search_children(entry, &Edge::Func); - for func in funcs.into_iter() { - if !args.funcs.is_empty() { - if args.funcs.iter().any(|analyze_for| { - FunctionNode::from(func) - .name(&analyzer) - .unwrap() - .starts_with(analyze_for) - }) { - if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { - let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) - .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); - } - } - } else if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { - let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) - .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); - } - } - } else { - all_contracts - .iter() - .filter(|contract| { - let name: String = contract.name(&analyzer).unwrap(); - args.contracts.contains(&name) - }) - .collect::>() - .iter() - .for_each(|contract| { - let funcs = contract.funcs(&analyzer); - for func in funcs.into_iter() { - if !args.funcs.is_empty() { - if args.funcs.contains(&func.name(&analyzer).unwrap()) { - let ctx = func.body_ctx(&mut analyzer); - let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) - .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); - } - } else { - let ctx = func.body_ctx(&mut analyzer); - let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) - .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); - } - } - }); - } - - // args.query.iter().for_each(|query| { - // analyzer.taint_query(entry, query.to_string()); - // println!(); - // }); - - // args.access_query.iter().for_each(|query| { - // let split: Vec<&str> = query.split('.').collect(); - // analyzer - // .access_query( - // entry, - // &file_mapping, - // config, - // split[0].to_string(), - // split[1].to_string(), - // ) - // .print_reports(&mut source_map, &analyzer); - // println!(); - // }); - - // args.write_query.iter().for_each(|query| { - // let split: Vec<&str> = query.split('.').collect(); - // if let Some(report) = analyzer.func_query( - // entry, - // &file_mapping, - // config, - // split[0].to_string(), - // split[1].to_string(), - // split[2].to_string(), - // SolcRange::new( - // Concrete::Bool(true).into(), - // Concrete::Bool(true).into(), - // vec![], - // ), - // ) { - // report.print_reports(&mut source_map, &analyzer); - // } - // println!(); - // }); -} diff --git a/crates/cli/Cargo.lock b/crates/cli/Cargo.lock deleted file mode 100644 index 16ae4bf4..00000000 --- a/crates/cli/Cargo.lock +++ /dev/null @@ -1,1616 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "ariadne" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702" -dependencies = [ - "unicode-width", - "yansi", -] - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "clap" -version = "4.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" -dependencies = [ - "bitflags", - "clap_derive", - "clap_lex", - "is-terminal", - "once_cell", - "strsim", - "termcolor", -] - -[[package]] -name = "clap_derive" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "cli" -version = "0.1.0" -dependencies = [ - "ariadne", - "clap", - "pyrometer", - "shared", -] - -[[package]] -name = "const-oid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest", - "ff", - "generic-array", - "group", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-core" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" -dependencies = [ - "arrayvec", - "bytes", - "chrono", - "elliptic-curve", - "ethabi", - "generic-array", - "hex", - "k256", - "open-fastrlp", - "rand", - "rlp", - "rlp-derive", - "serde", - "serde_json", - "strum", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes", - "rustix", - "windows-sys", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", - "sha3", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lalrpop" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30455341b0e18f276fa64540aff54deafb54c589de6aca68659c63dd2d5d823" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "lalrpop-util" -version = "0.19.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf796c978e9b4d983414f4caedc9273aa33ee214c5b887bd55fde84c85d2dc4" -dependencies = [ - "regex", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "parity-scale-codec" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3840933452adf7b3b9145e27086a5a3376c619dca1a21b1e5a5af0d54979bed" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared 0.11.1", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared 0.11.1", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared 0.11.1", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pico-args" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "primitive-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pyrometer" -version = "0.1.0" -dependencies = [ - "ariadne", - "ethers-core", - "hex", - "petgraph", - "shared", - "solang-parser", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustix" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustversion" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "scale-info" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" -dependencies = [ - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", -] - -[[package]] -name = "scale-info-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha3" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "shared" -version = "0.1.0" -dependencies = [ - "ethers-core", - "hex", - "lazy_static", - "petgraph", - "solang-parser", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "solang-parser" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff87dae6cdccacdbf3b19e99b271083556e808de0f59c74a01482f64fdbc61fc" -dependencies = [ - "itertools", - "lalrpop", - "lalrpop-util", - "phf", - "serde", - "unicode-xid", -] - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml index 1c26fe07..033f4f8b 100644 --- a/crates/graph/Cargo.toml +++ b/crates/graph/Cargo.toml @@ -11,6 +11,7 @@ homepage.workspace = true repository.workspace = true [dependencies] +petgraph.workspace = true range.workspace = true solang-parser.workspace = true ethers-core.workspace = true diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 4f5439fd..c45e00d9 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -15,31 +15,77 @@ use solang_parser::pt::Identifier; pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; +#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] +pub enum GraphError { + /// The analyzer thought the node was suppose to be one type, but it was a different one + NodeConfusion(String), + /// Call depth limit reached + MaxStackDepthReached(String), + /// Fork width limit reached + MaxStackWidthReached(String), + /// Tried to set the subcontext of a context that already had a subcontext + ChildRedefinition(String), + /// Tried to update a variable that is in an old context + VariableUpdateInOldContext(String), + /// Variable is detached from all contexts + DetachedVariable(String), + /// Expected a single element, found multiple + ExpectedSingle(String), + /// Expected a vector with a certain number of elements, but it was a different number of elements + StackLengthMismatch(String), + /// A variable had a cyclic reference to another variable and we were unable to break the cycle + UnbreakableRecursion(String), +} + #[derive(Debug, Clone, Eq, PartialEq)] pub enum Node { + /// An analyzed function body/context Context(Context), + /// A variable attached to a context or the previous version of this variable (akin to SSA form) ContextVar(ContextVar), + /// A fork in execution caused by an if-like statement ContextFork, + /// A call to another function, either public or internal FunctionCall, + /// A builtin solidity type (i.e. Address, Uint, Bytes, etc) Builtin(Builtin), + /// A node that represents whether a variable's type is a User-defined type, builtin type or a concrete VarType(VarType), + /// The entry node in the graph Entry, + /// A source unit (i.e. a source file) SourceUnit(usize), + /// A subcomponent of the source unit SourceUnitPart(usize, usize), + /// A contract Contract(Contract), + /// A solidity-based function Function(Function), + /// A solidity-based function parameter FunctionParam(FunctionParam), + /// A solidity-based function return parameter FunctionReturn(FunctionReturn), + /// A solidity-based struct Struct(Struct), + /// A solidity-based enum Enum(Enum), + /// A solidity-based error Error(Error), + /// A solidity-based error parameter ErrorParam(ErrorParam), + /// A solidity-based struct or contract field Field(Field), + /// A storage or constant variable on a contract Var(Var), + /// A solidity-based type alias Ty(Ty), + /// An unresolved type Unresolved(Identifier), + /// A concrete value (i.e. '1' or '0x111') Concrete(Concrete), + /// The `msg` global in solidity Msg(Msg), + /// The `block` global in solidity Block(Block), } @@ -83,13 +129,68 @@ impl Node { } } +pub fn num_to_color(x: usize) -> String { + let c = match x % 29 { + 0 => TOKYO_NIGHT_COLORS.get("default").unwrap(), + 1 => TOKYO_NIGHT_COLORS.get("font").unwrap(), + 2 => TOKYO_NIGHT_COLORS.get("bg_highlight").unwrap(), + 3 => TOKYO_NIGHT_COLORS.get("terminal_black").unwrap(), + 4 => TOKYO_NIGHT_COLORS.get("fg_dark").unwrap(), + 5 => TOKYO_NIGHT_COLORS.get("fg_gutter").unwrap(), + 6 => TOKYO_NIGHT_COLORS.get("dark3").unwrap(), + 7 => TOKYO_NIGHT_COLORS.get("dark5").unwrap(), + 8 => TOKYO_NIGHT_COLORS.get("blue0").unwrap(), + 9 => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), + 10 => TOKYO_NIGHT_COLORS.get("blue2").unwrap(), + 11 => TOKYO_NIGHT_COLORS.get("blue5").unwrap(), + 12 => TOKYO_NIGHT_COLORS.get("blue6").unwrap(), + 13 => TOKYO_NIGHT_COLORS.get("blue7").unwrap(), + 14 => TOKYO_NIGHT_COLORS.get("magenta2").unwrap(), + 15 => TOKYO_NIGHT_COLORS.get("purple").unwrap(), + 16 => TOKYO_NIGHT_COLORS.get("orange").unwrap(), + 17 => TOKYO_NIGHT_COLORS.get("yellow").unwrap(), + 18 => TOKYO_NIGHT_COLORS.get("green").unwrap(), + 19 => TOKYO_NIGHT_COLORS.get("green1").unwrap(), + 20 => TOKYO_NIGHT_COLORS.get("teal").unwrap(), + 21 => TOKYO_NIGHT_COLORS.get("red").unwrap(), + 22 => TOKYO_NIGHT_COLORS.get("red1").unwrap(), + 23 => TOKYO_NIGHT_COLORS.get("cyan").unwrap(), + 24 => TOKYO_NIGHT_COLORS.get("teal").unwrap(), + 25 => TOKYO_NIGHT_COLORS.get("darkblue").unwrap(), + 26 => TOKYO_NIGHT_COLORS.get("purple").unwrap(), + 27 => TOKYO_NIGHT_COLORS.get("bg1").unwrap(), + 28 => TOKYO_NIGHT_COLORS.get("deepred").unwrap(), + _ => unreachable!(), + }; + c.to_string() +} + lazy_static! { pub static ref TOKYO_NIGHT_COLORS: HashMap<&'static str, &'static str> = { let mut m = HashMap::new(); - m.insert("red", "#f7768e"); + m.insert("bg_dark", "#1f2335"); + m.insert("bg1", "#24283b"); + m.insert("bg_highlight", "#292e42"); + m.insert("terminal_black", "#414868"); + m.insert("fg_dark", "#a9b1d6"); + m.insert("fg_gutter", "#3b4261"); + m.insert("dark3", "#545c7e"); + m.insert("dark5", "#737aa2"); + m.insert("blue0", "#3d59a1"); + m.insert("cyan", "#7dcfff"); + m.insert("blue2", "#0db9d7"); + m.insert("blue5", "#89ddff"); + m.insert("blue6", "#b4f9f8"); + m.insert("blue7", "#394b70"); + m.insert("magenta2", "#ff007c"); + m.insert("purple", "#9d7cd8"); m.insert("orange", "#ff9e64"); m.insert("yellow", "#e0af68"); m.insert("green", "#9ece6a"); + m.insert("green1", "#41a6b5"); + m.insert("teal", "#1abc9c"); + m.insert("red", "#f7768e"); + m.insert("red1", "#db4b4b"); m.insert("cyan", "#73daca"); m.insert("teal", "#2ac3de"); m.insert("darkblue", "#7aa2f7"); @@ -104,78 +205,162 @@ lazy_static! { #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Edge { + /// A connection between a Source and the Entry Source, + /// A connection between a SourceUnitPart and a Source Part, + /// An edge indicating that a source or contract was imported Import, + /// An edge that contains a subtype of edge corresponding to some + /// kind of context-based relationship Context(ContextEdge), + /// A connection for a contract to it's parent Contract, + /// A connection for a contract to it's parent contract InheritedContract, + /// A connection for a field to it's parent Field, + /// A connection for an enum to it's parent Enum, + /// A connection for a struct to it's parent Struct, + /// A connection for an error to it's parent Error, + /// A connection for an error parameter to it's parent error ErrorParam, + /// A connection for an event to it's parent Event, + /// A connection for a storage/constant variable to it's parent Var, Ty, + /// A connection for a function to it's parent Func, + /// A connection for a function parameter to it's parent function FunctionParam, + /// A connection for a function return to it's parent function FunctionReturn, + /// A connection for a function modifier to it's parent function, with its order FuncModifier(usize), + /// A connection for a modifier to it's parent Modifier, + /// A connection for a fallback function to it's parent contract FallbackFunc, + /// A connection for a contract constructor function to it's parent contract Constructor, + /// A connection for a receive function to it's parent contract ReceiveFunc, + /// A connection for a library-based function to a contract LibraryFunction(NodeIdx), + /// A connection for a builtin function BuiltinFunction, } +impl Edge { + pub fn heirarchical_num(&self) -> usize { + use crate::Edge::*; + match self { + Source => 0, + Part | Import => 1, + + Contract | Ty | Field | Enum | Struct | Error | Event | Var | InheritedContract + | Modifier | FallbackFunc | Constructor | ReceiveFunc | LibraryFunction(_) + | BuiltinFunction | Func => 2, + + Context(_) | ErrorParam | FunctionParam | FunctionReturn | FuncModifier(_) => 3, + } + } +} + +/// An enum denoting either a call or a fork +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] +pub enum CallFork { + Call(ContextNode), + Fork(ContextNode, ContextNode), +} + +impl CallFork { + pub fn maybe_call(&self) -> Option { + match self { + CallFork::Call(c) => Some(*c), + _ => None, + } + } + + pub fn maybe_fork(&self) -> Option<(ContextNode, ContextNode)> { + match self { + CallFork::Fork(w1, w2) => Some((*w1, *w2)), + _ => None, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum ContextEdge { // Control flow + /// A connection for a context to a function Context, + /// A connection for a subcontext to it's parent context Subcontext, + /// A connection for a context to another context in which the source is the new + /// context and the target is the original context. That is: + /// ContextA -subcontext-> ContextB -subcontext> ContextAPrime + /// ^-----------------------ReturningContext--------| + ReturningContext, + /// A connection to a ContextFork to denote a fork in execution ContextFork, + /// Currently unused ContextMerge, + /// A call to a function, a connection from a context to a `FuncCall` node Call, // Context Variables + /// A new variable in cotext Variable, + /// A connection between a variable in a new context and that variable in a parent context denoting + /// that it is inherited from a parent scope InheritedVariable, + /// A connection between a `Var` and a context variable denoting that the variable reads from storage + InheritedStorageVariable, + /// A connection to the calldata variable + CalldataVariable, + /// A connection between a variable and a parent variable where the child is some attribute on the parent + /// (i.e. `.length`) AttrAccess, + /// A connection between a variable and the index that was used to create the variable from an IndexAccess Index, + /// A connection between a variable and a parent variable where the child is some index into the parent + /// (i.e. `x[1]`) IndexAccess, + /// A connection between a variable and a parent variable where the child is some field of the parent StructAccess, + /// A connection between a function-as-a-variable and the contract that holds that function FuncAccess, + /// A write to a storage variable, connecting the variable that is written to the variable and the storage variable itself + StorageWrite, // Variable incoming edges + /// Unused Assign, + /// Unused StorageAssign, + /// Unused MemoryAssign, + /// A connection of a variable to the previous version of that variable Prev, // Control flow + /// A connection between a variable and the context denoting that the variable is returned Return, + /// A continuation of a context Continue, + /// A connection between a brand new created variable for a function's context and the variable InputVariable, + /// A connection to a return variable that should be assigned ReturnAssign(bool), // Range analysis + /// Unused Range, } - -#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] -pub enum GraphError { - NodeConfusion(String), - MaxStackDepthReached(String), - MaxStackWidthReached(String), - ChildRedefinition(String), - VariableUpdateInOldContext(String), - DetachedVariable(String), - ExpectedSingle(String), - StackLengthMismatch(String), - UnbreakableRecursion(String), -} - diff --git a/crates/graph/src/graph_like.rs b/crates/graph/src/graph_like.rs index 2edec838..a4c710db 100644 --- a/crates/graph/src/graph_like.rs +++ b/crates/graph/src/graph_like.rs @@ -6,25 +6,27 @@ pub trait AsDotStr { /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphLike { + /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; + /// Get a reference to the graph fn graph(&self) -> &Graph; - + /// Add a node to the graph fn add_node(&mut self, node: impl Into) -> NodeIdx { self.graph_mut().add_node(node.into()) } - + /// Get a reference to a node in the graph fn node(&self, node: impl Into) -> &Node { self.graph() .node_weight(node.into()) .expect("Index not in graph") } - + /// Get a mutable reference to a node in the graph fn node_mut(&mut self, node: impl Into) -> &mut Node { self.graph_mut() .node_weight_mut(node.into()) .expect("Index not in graph") } - + /// Add an edge to the graph fn add_edge( &mut self, from_node: impl Into, @@ -40,6 +42,7 @@ impl GraphDot for T {} /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphDot: GraphLike { + /// Open a dot using graphviz fn open_dot(&self) where Self: std::marker::Sized, @@ -264,6 +267,7 @@ pub trait GraphDot: GraphLike { dot_str.join("\n") } + /// Construct a dot string while filtering temporary variables fn dot_str_no_tmps(&self) -> String where Self: std::marker::Sized, diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 865bbcf8..78d24d1d 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -376,4 +376,36 @@ impl Builtin { )), } } -} + + pub fn basic_as_string(&self) -> String { + use Builtin::*; + match self { + Address => "address".to_string(), + AddressPayable => "address".to_string(), + Payable => "address".to_string(), + Bool => "bool".to_string(), + String => "string".to_string(), + Int(size) => format!("int{size}"), + Uint(size) => format!("uint{size}"), + Bytes(size) => format!("bytes{size}"), + Rational => "rational".to_string(), + DynamicBytes => "bytes".to_string(), + Array(_v_ty) => "[]".to_string(), + SizedArray(s, _v_ty) => format!("[{}]", s), + Mapping(_key_ty, _v_ty) => "mapping ( => )".to_string(), + Func(inputs, outputs) => format!( + "function({}) returns ({})", + inputs + .iter() + .map(|_input| "") + .collect::>() + .join(", "), + outputs + .iter() + .map(|_output| "") + .collect::>() + .join(", ") + ), + } + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 542c83f6..65004c19 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -194,12 +194,16 @@ impl Concrete { /// be fine. pub fn u256_as_original(&self, uint: U256) -> Self { match self { - Concrete::Uint(size, _) => Concrete::Uint(*size, uint), - Concrete::Int(size, _) => Concrete::Int(*size, I256::from_raw(uint)), + Concrete::Uint(size, _) => Concrete::Uint(256, uint) + .cast(Builtin::Uint(*size)) + .unwrap(), + Concrete::Int(size, _) => Concrete::Int(256, I256::from_raw(uint)) + .cast(Builtin::Int(*size)) + .unwrap(), Concrete::Bytes(size, _) => { let mut h = H256::default(); uint.to_big_endian(h.as_mut()); - Concrete::Bytes(*size, h) + Concrete::Bytes(32, h).cast(Builtin::Bytes(*size)).unwrap() } Concrete::Address(_) => { let mut bytes = [0u8; 32]; @@ -313,11 +317,13 @@ impl Concrete { if val < mask { Some(Concrete::Uint(size, val)) } else { - Some(Concrete::Uint(size, mask)) + Some(Concrete::Uint(size, val & mask)) } } } - Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), + Builtin::Int(size) => { + Some(Concrete::Int(size, I256::from_raw(val))) + } Builtin::Bytes(size) => { let mask = if size == 32 { U256::MAX @@ -366,14 +372,23 @@ impl Concrete { U256::from(2).pow((size - 1).into()) - 1 }; - let (sign, abs) = val.into_sign_and_abs(); + let (_sign, abs) = val.into_sign_and_abs(); + if abs < mask { Some(Concrete::Int(size, val)) } else { - Some(Concrete::Int( - size, - I256::checked_from_sign_and_abs(sign, mask).unwrap(), - )) + // check if the top bit for the new value is set on the existing value + // if it is, then the cast will result in a negative number + let top_mask = + if abs & (U256::from(1) << U256::from(size)) != U256::zero() { + // sign extension + ((U256::from(1) << U256::from(257 - size)) - U256::from(1)) + << U256::from(size - 1) + } else { + U256::from(0) + }; + + Some(Concrete::Int(size, I256::from_raw((abs & mask) | top_mask))) } } } diff --git a/crates/graph/src/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs index d61b06cc..c8bc81a0 100644 --- a/crates/graph/src/nodes/context/context_tys.rs +++ b/crates/graph/src/nodes/context/context_tys.rs @@ -1,4 +1,5 @@ +/// An enum that denotes either a call or a fork of a context #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub enum CallFork { Call(ContextNode), @@ -6,6 +7,7 @@ pub enum CallFork { } impl CallFork { + /// Returns an option of the call context pub fn maybe_call(&self) -> Option { match self { CallFork::Call(c) => Some(*c), @@ -13,6 +15,7 @@ impl CallFork { } } + /// Returns an option of the two fork contexts pub fn maybe_fork(&self) -> Option<(ContextNode, ContextNode)> { match self { CallFork::Fork(w1, w2) => Some((*w1, *w2)), @@ -21,17 +24,25 @@ impl CallFork { } } +/// Holds the current modifier state #[derive(Debug, Clone, Eq, PartialEq)] pub struct ModifierState { + /// The number of the current modifier being evaluated pub num: usize, + /// The location in source pub loc: Loc, + /// The calling function pub parent_fn: FunctionNode, + /// The context of the caller to the function that had this modifier pub parent_caller_ctx: ContextNode, + /// The parent context pub parent_ctx: ContextNode, + /// Renamed inputs based on the modifier pub renamed_inputs: BTreeMap, } impl ModifierState { + /// Constructs a modifier state pub fn new( num: usize, loc: Loc, @@ -51,11 +62,17 @@ impl ModifierState { } } +/// Holds cached information about the context to speed up lookups #[derive(Default, Debug, Clone, Eq, PartialEq)] pub struct ContextCache { + /// Variables in this context pub vars: BTreeMap, + /// Visible functions from this context pub visible_funcs: Option>, + /// First ancestor of this context pub first_ancestor: Option, + /// Associated source of this context pub associated_source: Option, + /// Associated contract of this context pub associated_contract: Option, } \ No newline at end of file diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index 00640a60..ef29d3e8 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -2,6 +2,7 @@ use crate::analyzer::AsDotStr; use crate::context::GraphError; use crate::{ContextVarNode, GraphLike, Node, NodeIdx, VarType}; +/// The reason a context was killed #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum KilledKind { Ended, @@ -11,6 +12,7 @@ pub enum KilledKind { } impl KilledKind { + /// Returns a string explanation of the KilledKind pub fn analysis_str(&self) -> &str { use KilledKind::*; match self { @@ -22,16 +24,23 @@ impl KilledKind { } } +/// A representation of the evaluation of an expression #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum ExprRet { + /// The expression resulted in a killing of the context CtxKilled(KilledKind), + /// The expression resulted in nothing Null, + /// The expression resulted in a single element Single(NodeIdx), + /// The expression resulted in a single element that was a literal SingleLiteral(NodeIdx), + /// The expression resulted in multiple elements Multi(Vec), } impl ExprRet { + /// Converts the expression return into a debug string pub fn debug_str(&self, analyzer: &impl GraphLike) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => match analyzer.node(*inner) { @@ -53,6 +62,7 @@ impl ExprRet { } } + /// Take one element from the expression return. pub fn take_one(&mut self) -> Result, GraphError> { match self { ExprRet::Single(..) | ExprRet::SingleLiteral(..) => { @@ -70,6 +80,8 @@ impl ExprRet { } } + /// Checks if the expression return is a `SingleLiteral`. It returns + /// a list of bools that match if each is a literal pub fn literals_list(&self) -> Result, GraphError> { match self { ExprRet::SingleLiteral(..) => Ok(vec![true]), @@ -88,6 +100,7 @@ impl ExprRet { } } + /// Expect the expression result to be the Single variant pub fn expect_single(&self) -> Result { match self { ExprRet::Single(inner) => Ok(*inner), @@ -99,6 +112,7 @@ impl ExprRet { } } + /// Expect the expression result to be some length pub fn expect_length(&self, len: usize) -> Result<(), GraphError> { match self { ExprRet::Single(_) | ExprRet::SingleLiteral(_) => { @@ -130,6 +144,7 @@ impl ExprRet { } } + /// Return whether the expression return is a Single or SingleLiteral pub fn is_single(&self) -> bool { match self { ExprRet::Single(_inner) => true, @@ -139,10 +154,12 @@ impl ExprRet { } } + /// Return whether the expression return resulted in the Context being killed pub fn is_killed(&self) -> bool { matches!(self, ExprRet::CtxKilled(_)) } + /// Return the kind of the killed context if it was killed pub fn killed_kind(&self) -> Option { match self { ExprRet::CtxKilled(k) => Some(*k), @@ -151,10 +168,7 @@ impl ExprRet { } } - pub fn has_fork(&self) -> bool { - false - } - + /// Check if any of the expression returns are killed pub fn has_killed(&self) -> bool { match self { ExprRet::CtxKilled(_) => true, @@ -163,6 +177,7 @@ impl ExprRet { } } + /// Check if any of the expression returns are literals pub fn has_literal(&self) -> bool { match self { ExprRet::SingleLiteral(..) => true, @@ -171,6 +186,7 @@ impl ExprRet { } } + /// Expect the return to be a multi, and return the inner list. Panics if not mulit pub fn expect_multi(self) -> Vec { match self { ExprRet::Multi(inner) => inner, @@ -178,6 +194,7 @@ impl ExprRet { } } + /// Try to convert to a solidity-like function input string, i.e. `(uint256, uint256, bytes32)` pub fn try_as_func_input_str(&self, analyzer: &impl GraphLike) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { @@ -204,6 +221,7 @@ impl ExprRet { } } + /// Flatten the expression returns recursively into a single list of node indices pub fn as_flat_vec(&self) -> Vec { let mut idxs = vec![]; match self { @@ -221,6 +239,7 @@ impl ExprRet { idxs } + /// Convert to a normal vector, does not recurse pub fn as_vec(&self) -> Vec { match self { s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => vec![s.clone()], @@ -231,6 +250,7 @@ impl ExprRet { } } + /// Flatten into a single ExprRet pub fn flatten(self) -> Self { match self { ExprRet::Single(_) | ExprRet::SingleLiteral(_) => self, diff --git a/crates/graph/src/nodes/context/mod.rs b/crates/graph/src/nodes/context/mod.rs index e69de29b..8f239016 100644 --- a/crates/graph/src/nodes/context/mod.rs +++ b/crates/graph/src/nodes/context/mod.rs @@ -0,0 +1,16 @@ +mod context_tys; +mod expr_ret; +mod node; +mod underlying; + +pub use node::ContextNode; +pub use underlying::Context; +pub mod var; + + +// ContextNode implementations are split to ease in maintainability +mod querying; +mod solving; +mod typing; +mod variables; +mod versioning; \ No newline at end of file diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index f49764ce..cc41f802 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,6 +1,3 @@ - - - #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] /// A wrapper of a node index that corresponds to a [`Context`] pub struct ContextNode(pub usize); @@ -12,21 +9,6 @@ impl AsDotStr for ContextNode { } impl ContextNode { - // pub fn called_functions(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // self.underlying(analyzer)?.children.iter().filter_map(|child| { - // match child.maybe_call()?.underlying(analyzer) { - // Ok(underlying) => { - // match (underlying.fn_call, underlying.ext_fn_call) { - // (Some(fn_call), _) => Some(Ok(fn_call)), - // (_, Some(ext_fn_call)) => Some(Ok(ext_fn_call)), - // (None, None) => None - // } - // } - // Err(_) => None - // } - // }).collect() - // } - pub fn join( &self, _func: FunctionNode, @@ -34,85 +16,6 @@ impl ContextNode { _analyzer: &mut (impl GraphLike + AnalyzerLike), ) { todo!("Joining not supported yet"); - // println!("joining"); - // if let Some(body_ctx) = func.maybe_body_ctx(analyzer) { - // let vars: Vec<_> = body_ctx.vars(analyzer).values().map(|var| var.latest_version(analyzer)).collect(); - // println!("vars: {vars:#?}"); - // let replacements: Vec<(ContextVarNode, ContextVarNode)> = mapping.iter().filter_map(|(input_var, param)| { - // vars.iter().find(|var| var.name(analyzer).unwrap() == param.name(analyzer).unwrap()).map(|var| { - // (*var, *input_var) - // }) - // }).collect(); - - // let mut mapping = BTreeMap::default(); - // replacements.into_iter().for_each(|(var, replacement)| { - // mapping.insert(var, replacement); - // let mut latest = var; - // while let Some(next) = latest.next_version(analyzer) { - // latest = next; - // mapping.insert(latest, replacement); - // } - // }); - - // println!("mapping: {mapping:#?}"); - - // vars.iter().for_each(|var| { - // let mut latest = *var; - // let mut range = latest.range(analyzer).unwrap().unwrap(); - // println!("var: {var:?}, depends on: {:#?}, {range:#?}", var.range_deps(analyzer)); - // range.uncache_range_min(); - // range.uncache_range_max(); - // mapping.iter().for_each(|(to_replace, replacement)| { - // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); - // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); - // }); - // latest.set_range(analyzer, range).unwrap(); - // while let Some(next) = latest.next_version(analyzer) { - // latest = next; - // let mut range = latest.range(analyzer).unwrap().unwrap(); - // range.uncache_range_min(); - // range.uncache_range_max(); - // mapping.iter().for_each(|(to_replace, replacement)| { - // // range.filter_min_recursion((*to_replace).into(), (*replacement).into()); - // // range.filter_max_recursion((*to_replace).into(), (*replacement).into()); - // }); - // latest.set_range(analyzer, range).unwrap(); - // } - // }); - - // } else { - // // need to process the function - // } - } - - pub fn is_ext_fn(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) - } - - pub fn add_var( - &self, - var: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let name = var.name(analyzer)?; - let vars = &mut self.underlying_mut(analyzer)?.cache.vars; - vars.insert(name, var); - Ok(()) - } - - pub fn first_ancestor( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { - Ok(first_ancestor) - } else if let Some(parent) = self.underlying(analyzer)?.parent_ctx { - let first = parent.first_ancestor(analyzer)?; - self.underlying_mut(analyzer)?.cache.first_ancestor = Some(first); - Ok(first) - } else { - Ok(*self) - } } pub fn total_width( @@ -123,211 +26,6 @@ impl ContextNode { .number_of_live_edges(analyzer) } - pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.unchecked) - } - - pub fn set_unchecked( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.unchecked = true; - Ok(()) - } - - pub fn unset_unchecked( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.unchecked = false; - Ok(()) - } - - pub fn push_tmp_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - underlying_mut.tmp_expr.push(Some(expr_ret)); - Ok(()) - } - - pub fn append_tmp_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - match underlying_mut.tmp_expr.pop() { - Some(Some(s @ ExprRet::Single(_))) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(s @ ExprRet::SingleLiteral(_))) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(ExprRet::Multi(ref mut inner))) => { - inner.push(expr_ret); - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(inner.to_vec()))); - } - Some(Some(s @ ExprRet::Null)) => { - underlying_mut - .tmp_expr - .push(Some(ExprRet::Multi(vec![s, expr_ret]))); - } - Some(Some(ExprRet::CtxKilled(kind))) => { - underlying_mut.tmp_expr = vec![Some(ExprRet::CtxKilled(kind))]; - underlying_mut.expr_ret_stack = vec![ExprRet::CtxKilled(kind)]; - } - _ => { - underlying_mut.tmp_expr.push(Some(expr_ret)); - } - } - Ok(()) - } - - pub fn pop_tmp_expr( - &self, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { - Ok(Some(self.maybe_move_expr(expr, loc, analyzer)?)) - } else { - Ok(None) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn push_expr( - &self, - expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - tracing::trace!( - "pushing: {}, existing: {:?}, path: {}", - expr_ret.debug_str(analyzer), - self.underlying(analyzer)? - .expr_ret_stack - .iter() - .map(|i| i.debug_str(analyzer)) - .collect::>(), - self.path(analyzer) - ); - let underlying_mut = self.underlying_mut(analyzer)?; - underlying_mut.expr_ret_stack.push(expr_ret); - Ok(()) - } - - pub fn maybe_move_expr( - &self, - expr: ExprRet, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match expr { - ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( - self.maybe_move_var(var.into(), loc, analyzer)?.into(), - )), - ExprRet::Single(var) => Ok(ExprRet::Single( - self.maybe_move_var(var.into(), loc, analyzer)?.into(), - )), - ExprRet::Multi(inner) => Ok(ExprRet::Multi( - inner - .iter() - .map(|i| self.maybe_move_expr(i.clone(), loc, analyzer)) - .collect::>()?, - )), - e => Ok(e), - } - } - - pub fn maybe_move_var( - &self, - var: ContextVarNode, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(ctx) = var.maybe_ctx(analyzer) { - if ctx != *self { - let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); - new_cvar.loc = Some(loc); - - let new_cvarnode = analyzer.add_node(Node::ContextVar(new_cvar)); - analyzer.add_edge(new_cvarnode, *self, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge( - new_cvarnode, - var.0, - Edge::Context(ContextEdge::InheritedVariable), - ); - Ok(new_cvarnode.into()) - } else { - Ok(var) - } - } else { - Ok(var) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn pop_expr( - &self, - _loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - tracing::trace!("popping var from: {}", self.path(analyzer)); - let underlying_mut = self.underlying_mut(analyzer)?; - - let new: Vec = Vec::with_capacity(5); - - let old = std::mem::replace(&mut underlying_mut.expr_ret_stack, new); - if old.is_empty() { - Ok(None) - } else { - Ok(Some(ExprRet::Multi(old))) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn pop_expr_latest( - &self, - loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - let underlying_mut = self.underlying_mut(analyzer)?; - if let Some(elem) = underlying_mut.expr_ret_stack.pop() { - tracing::trace!( - "popping var {} from: {}", - elem.debug_str(analyzer), - self.path(analyzer) - ); - Ok(Some(self.maybe_move_expr(elem, loc, analyzer)?)) - } else { - Ok(None) - } - } - - pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { - self.local_vars(analyzer) - .iter() - .flat_map(|(_name, var)| var.return_assignments(analyzer)) - .collect() - } - - pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { - self.local_vars(analyzer) - .iter() - .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) - .collect() - } - pub fn depth(&self, analyzer: &impl GraphLike) -> usize { self.underlying(analyzer).unwrap().depth } @@ -337,270 +35,6 @@ impl ContextNode { self.underlying(analyzer).unwrap().path.clone() } - /// *All* subcontexts (including subcontexts of subcontexts, recursively) - pub fn subcontexts(&self, analyzer: &impl GraphLike) -> Vec { - let underlying = self.underlying(analyzer).unwrap(); - match underlying.child { - Some(CallFork::Call(c)) => vec![c], - Some(CallFork::Fork(w1, w2)) => vec![w1, w2], - None => vec![], - } - } - - /// Gets the associated contract for the function for the context - pub fn associated_contract( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - Ok(self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer) - .expect("No associated contract for context")) - } - - /// Tries to get the associated function for the context - pub fn maybe_associated_contract( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - Ok(self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer)) - } - - pub fn maybe_associated_source( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Option { - let context = self.underlying(analyzer).unwrap(); - if let Some(src) = context.cache.associated_source { - Some(src) - } else if let Some(parent_ctx) = context.parent_ctx { - let src = parent_ctx.maybe_associated_source(analyzer)?; - self.underlying_mut(analyzer) - .unwrap() - .cache - .associated_source = Some(src); - Some(src) - } else { - let func = self.associated_fn(analyzer).unwrap(); - func.maybe_associated_source(analyzer) - } - } - - pub fn associated_source_unit_part( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - if let Some(sup) = self - .associated_fn(analyzer)? - .maybe_associated_source_unit_part(analyzer) - { - Ok(sup) - } else { - Err(GraphError::NodeConfusion( - "Expected context to have an associated source but didnt".to_string(), - )) - } - } - - /// Gets visible functions - pub fn visible_modifiers( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())) - }; - if let Some(contract) = self.maybe_associated_contract(analyzer)? { - let mut modifiers = contract.modifiers(analyzer); - // extend with free floating functions - modifiers.extend( - analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>(), - ); - - // extend with inherited functions - let inherited_contracts = analyzer.search_children_exclude_via( - contract.0.into(), - &Edge::InheritedContract, - &[Edge::Func], - ); - modifiers.extend( - inherited_contracts - .into_iter() - .flat_map(|inherited_contract| { - ContractNode::from(inherited_contract).modifiers(analyzer) - }) - .collect::>(), - ); - - let mut mapping: BTreeMap> = BTreeMap::new(); - for modifier in modifiers.iter() { - let entry = mapping.entry(modifier.name(analyzer)?).or_default(); - entry.insert(*modifier); - } - mapping - .into_values() - .map(|modifier_set| { - let as_vec = modifier_set.iter().collect::>(); - - if as_vec.len() > 2 { - println!("{}", as_vec.iter().map(|i| i.name(analyzer).unwrap()).collect::>().join(", ")); - panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") - } else if as_vec.len() == 2 { - as_vec[0].get_overriding(as_vec[1], analyzer) - } else { - Ok(*as_vec[0]) - } - }) - .collect() - } else { - // we are in a free floating function, only look at free floating functions - let Some(source) = self.maybe_associated_source(analyzer) else { - return Err(GraphError::NodeConfusion("Expected context to have an associated source but didnt".to_string())); - }; - Ok(analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>()) - } - } - - /// Gets visible functions - pub fn visible_funcs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - // TODO: filter privates - if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { - return Ok(vis.clone()); - } - if let Some(contract) = self.maybe_associated_contract(analyzer)? { - let mut mapping = contract.linearized_functions(analyzer); - // extend with free floating functions - mapping.extend( - analyzer - .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) - .into_iter() - .filter_map(|i| { - let fn_node = FunctionNode::from(i); - if let Ok(name) = fn_node.name(analyzer) { - if !mapping.contains_key(&name) { - Some((name, fn_node)) - } else { - None - } - } else { - None - } - }) - .collect::>(), - ); - let funcs: Vec<_> = mapping.values().copied().collect(); - self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); - Ok(funcs) - } else { - // we are in a free floating function, only look at free floating functions - let funcs = analyzer - .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) - .into_iter() - .map(FunctionNode::from) - .collect::>(); - - self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); - Ok(funcs) - } - } - - /// Gets all visible functions - pub fn source_funcs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Vec { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return vec![] - }; - analyzer - .search_children_exclude_via( - source, - &Edge::Func, - &[ - Edge::Context(ContextEdge::Context), - Edge::Context(ContextEdge::Variable), - ], - ) - .into_iter() - .map(FunctionNode::from) - .collect::>() - } - - /// Gets all visible structs - pub fn visible_structs( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Vec { - // TODO: filter privates - let Some(source) = self.maybe_associated_source(analyzer) else { - return vec![] - }; - - analyzer - .search_children_exclude_via(source, &Edge::Struct, &[Edge::Func]) - .into_iter() - .map(StructNode::from) - .collect::>() - } - - /// Gets the associated function for the context - pub fn associated_fn(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - if let Some(fn_call) = underlying.fn_call { - Ok(fn_call) - } else if let Some(ext_fn_call) = underlying.ext_fn_call { - Ok(ext_fn_call) - } else { - Ok(underlying.parent_fn) - } - } - - /// Checks whether a function is external to the current context - pub fn is_fn_ext( - &self, - fn_node: FunctionNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - match fn_node.maybe_associated_contract(analyzer) { - None => Ok(false), - Some(fn_ctrt) => { - if let Some(self_ctrt) = self - .associated_fn(analyzer)? - .maybe_associated_contract(analyzer) - { - Ok(Some(self_ctrt) != Some(fn_ctrt) - && !self_ctrt - .underlying(analyzer)? - .inherits - .iter() - .any(|inherited| *inherited == fn_ctrt)) - } else { - Ok(false) - } - } - } - } - - /// Gets the associated function name for the context - pub fn associated_fn_name(&self, analyzer: &impl GraphLike) -> Result { - self.associated_fn(analyzer)?.name(analyzer) - } - /// Gets a mutable reference to the underlying context in the graph pub fn underlying_mut<'a>( &self, @@ -624,499 +58,6 @@ impl ContextNode { } } - /// Gets a variable by name in the context - pub fn var_by_name(&self, analyzer: &impl GraphLike, name: &str) -> Option { - self.underlying(analyzer) - .unwrap() - .cache - .vars - .get(name) - .copied() - } - - pub fn var_by_name_or_recurse( - &self, - analyzer: &impl GraphLike, - name: &str, - ) -> Result, GraphError> { - if let Some(var) = self.var_by_name(analyzer, name) { - Ok(Some(var)) - } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { - parent.var_by_name_or_recurse(analyzer, name) - } else { - Ok(None) - } - } - - pub fn ancestor_in_fn( - &self, - analyzer: &impl GraphLike, - associated_fn: FunctionNode, - ) -> Result, GraphError> { - if let Some(ret) = self.underlying(analyzer)?.returning_ctx { - if ret.associated_fn(analyzer)? == associated_fn { - return Ok(Some(ret)); - } - } - - if let Some(parent) = self.underlying(analyzer)?.parent_ctx { - if parent.associated_fn(analyzer)? == associated_fn { - Ok(Some(parent)) - } else if let Some(mod_state) = &parent.underlying(analyzer)?.modifier_state { - if mod_state.parent_fn == associated_fn { - Ok(Some(parent)) - } else { - parent.ancestor_in_fn(analyzer, associated_fn) - } - } else { - parent.ancestor_in_fn(analyzer, associated_fn) - } - } else { - Ok(None) - } - } - - /// Gets all variables associated with a context - pub fn vars<'a>(&self, analyzer: &'a impl GraphLike) -> &'a BTreeMap { - &self.underlying(analyzer).unwrap().cache.vars - } - - /// Gets all variables associated with a context - pub fn local_vars<'a>( - &self, - analyzer: &'a impl GraphLike, - ) -> &'a BTreeMap { - self.vars(analyzer) - } - - /// Gets the latest version of a variable associated with a context - pub fn latest_var_by_name( - &self, - analyzer: &impl GraphLike, - name: &str, - ) -> Option { - self.var_by_name(analyzer, name) - .map(|var| var.latest_version(analyzer)) - } - - /// Reads the current temporary counter and increments the counter - pub fn new_tmp( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result { - let context = self.underlying_mut(analyzer)?; - let ret = context.tmp_var_ctr; - context.tmp_var_ctr += 1; - Ok(ret) - } - - /// Returns all forks associated with the context - pub fn calls(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let descendents = self.descendents(analyzer)?; - Ok(descendents - .into_iter() - .filter_map(|c| c.maybe_call()) - .collect()) - } - - /// Returns all forks associated with the context - // pub fn forks(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // todo!() - // let descendents = self.descendents(analyzer)?; - // Ok(descendents.into_iter().filter_map(|c| c.maybe_fork()).collect()) - // } - - // /// Returns all *live* forks associated with the context - // pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - // let forks = self.forks(analyzer)?; - // let mut live = vec![]; - // for fork in forks { - // if !fork.is_ended(analyzer)? { - // live.push(fork); - // } - // } - // Ok(live) - // } - - /// Returns tail contexts associated with the context - pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.live_edges(analyzer)?; - if call_edges.is_empty() && !call.is_ended(analyzer)? { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.live_edges(analyzer)?; - if fork_edges.is_empty() && !w1.is_ended(analyzer)? { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.live_edges(analyzer)?; - if fork_edges.is_empty() && !w2.is_ended(analyzer)? { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.reverted_edges(analyzer)?; - if call_edges.is_empty() && call.is_killed(analyzer)? { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.reverted_edges(analyzer)?; - if fork_edges.is_empty() && w1.is_killed(analyzer)? { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.reverted_edges(analyzer)?; - if fork_edges.is_empty() && w2.is_killed(analyzer)? { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.number_of_live_edges) - // if let Some(child) = self.underlying(analyzer)?.child { - // let mut edges = 0; - // match child { - // CallFork::Call(call) => { - // let call_edges = call.number_of_live_edges(analyzer)?; - // if call_edges == 0 && !call.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += call_edges; - // } - // } - // CallFork::Fork(w1, w2) => { - // let fork_edges = w1.number_of_live_edges(analyzer)?; - // if fork_edges == 0 && !w1.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += fork_edges; - // } - - // let fork_edges = w2.number_of_live_edges(analyzer)?; - // if fork_edges == 0 && !w2.is_ended(analyzer)? { - // edges += 1; - // } else { - // edges += fork_edges; - // } - // } - // } - // Ok(edges) - // } else { - // Ok(0) - // } - } - - /// Returns tail contexts associated with the context - pub fn all_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut lineage = vec![]; - match child { - CallFork::Call(call) => { - let call_edges = call.all_edges(analyzer)?; - if call_edges.is_empty() { - lineage.push(call) - } else { - lineage.extend(call_edges); - } - } - CallFork::Fork(w1, w2) => { - let fork_edges = w1.all_edges(analyzer)?; - if fork_edges.is_empty() { - lineage.push(w1) - } else { - lineage.extend(fork_edges); - } - - let fork_edges = w2.all_edges(analyzer)?; - if fork_edges.is_empty() { - lineage.push(w2) - } else { - lineage.extend(fork_edges); - } - } - } - Ok(lineage) - } else { - Ok(vec![]) - } - } - - pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - let mut descendents = vec![child]; - match child { - CallFork::Call(c) => descendents.extend(c.descendents(analyzer)?), - CallFork::Fork(w1, w2) => { - descendents.extend(w1.descendents(analyzer)?); - descendents.extend(w2.descendents(analyzer)?); - } - } - Ok(descendents) - } else { - Ok(vec![]) - } - } - - /// Adds a fork to the context - pub fn set_child_fork( - &self, - w1: ContextNode, - w2: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - assert!(matches!(analyzer.node(w1), Node::Context(_))); - assert!(matches!(analyzer.node(w2), Node::Context(_))); - assert!(*self != w1 && *self != w2, "Tried to set child to self"); - let context = self.underlying_mut(analyzer)?; - if !context.set_child_fork(w1, w2) { - let child_str = match context.child { - Some(CallFork::Fork(w1, w2)) => { - format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) - } - Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), - None => unreachable!(), - }; - Err(GraphError::ChildRedefinition(format!( - "This is a bug. Tried to redefine a child context, parent:\n{}, current child:\n{},\nnew child: Fork({}, {})", - self.path(analyzer), - child_str, - w1.path(analyzer), - w2.path(analyzer), - ))) - } else { - Ok(()) - } - } - - /// Adds a child to the context - pub fn set_child_call( - &self, - call: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - assert!(matches!(analyzer.node(call), Node::Context(_))); - assert!(*self != call, "Tried to set child to self"); - let context = self.underlying_mut(analyzer)?; - if !context.set_child_call(call) { - let child_str = match context.child { - Some(CallFork::Fork(w1, w2)) => { - format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) - } - Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), - None => unreachable!(), - }; - tracing::trace!("Error setting child as a call"); - Err(GraphError::ChildRedefinition(format!( - "This is a bug. Tried to redefine a child context, parent: {}, current child: {}, new child: {}", - self.path(analyzer), - child_str, - call.path(analyzer) - ) - )) - } else { - Ok(()) - } - } - - pub fn delete_child( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result<(), GraphError> { - if let Some(child) = self.underlying(analyzer)?.child { - match child { - CallFork::Fork(w1, w2) => { - w1.propogate_end(analyzer)?; - w2.propogate_end(analyzer)?; - } - CallFork::Call(c) => { - c.propogate_end(analyzer)?; - } - } - } - let context = self.underlying_mut(analyzer)?; - context.delete_child(); - Ok(()) - } - - /// Kills the context by denoting it as killed. Recurses up the contexts and kills - /// parent contexts if all subcontexts of that context are killed - pub fn kill( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - kill_loc: Loc, - kill_kind: KilledKind, - ) -> Result<(), GraphError> { - tracing::trace!("killing: {}", self.path(analyzer)); - if let Some(child) = self.underlying(analyzer)?.child { - match child { - CallFork::Call(call) => { - if !call.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - call.kill(analyzer, kill_loc, kill_kind)?; - } - CallFork::Fork(w1, w2) => { - if !w1.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - - if !w2.underlying(analyzer)?.ret.is_empty() { - return Ok(()); - } - - w1.kill(analyzer, kill_loc, kill_kind)?; - w2.kill(analyzer, kill_loc, kill_kind)?; - } - } - } - - let context = self.underlying_mut(analyzer)?; - let parent = context.parent_ctx; - if context.killed.is_none() { - context.killed = Some((kill_loc, kill_kind)); - } - - if let Some(parent_ctx) = parent { - parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; - } - - self.propogate_end(analyzer)?; - - Ok(()) - } - - /// Kills if and only if all subcontexts are killed - pub fn end_if_all_forks_ended( - &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), - kill_loc: Loc, - kill_kind: KilledKind, - ) -> Result<(), GraphError> { - let all_edges = self.all_edges(analyzer)?; - let reverted_edges = self.reverted_edges(analyzer)?; - if reverted_edges.len() == all_edges.len() { - tracing::trace!("killing recursively: {}", self.path(analyzer)); - let context = self.underlying_mut(analyzer)?; - if context.ret.is_empty() { - if context.killed.is_none() { - context.killed = Some((kill_loc, kill_kind)); - } - if let Some(parent_ctx) = context.parent_ctx { - parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; - } - } - } - Ok(()) - } - - /// Gets parent list - pub fn parent_list(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - let context = self.underlying(analyzer)?; - let mut parents = vec![]; - if let Some(parent_ctx) = context.parent_ctx { - parents.push(parent_ctx); - parents.extend(parent_ctx.parent_list(analyzer)?); - } - Ok(parents) - } - - pub fn recursive_calls( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - // Ok( - let calls = self.calls(analyzer)?; - Ok(calls - .iter() - .flat_map(|call| { - let mut inner_calls = call.recursive_calls(analyzer).unwrap(); - inner_calls.insert(0, *call); - inner_calls - }) - .collect::>()) - } - - /// Gets the lineage for a context - /// A lineage is of the form `[ancestor N, .. , ancestor0, SELF, call0, .., call N]`. It - /// gives the user a full picture of control flow - pub fn lineage( - &self, - _analyzer: &impl GraphLike, - _entry: bool, - ) -> Result, GraphError> { - todo!() - } - - pub fn terminal_child_list( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let calls = self.calls(analyzer)?; - if calls.is_empty() { - Ok(vec![*self]) - } else { - let mut children = vec![]; - - for child in calls.into_iter() { - children.extend(child.terminal_child_list(analyzer)?) - } - Ok(children) - } - } - - /// Returns whether the context is killed - pub fn is_killed(&self, analyzer: &impl GraphLike) -> Result { - Ok(self.underlying(analyzer)?.killed.is_some()) - } - - /// Returns whether the context is killed - pub fn is_ended(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) - } - - pub fn killed_or_ret(&self, analyzer: &impl GraphLike) -> Result { - let underlying = self.underlying(analyzer)?; - Ok(underlying.killed.is_some() - || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) - } - /// Returns an option to where the context was killed pub fn killed_loc( &self, @@ -1125,36 +66,27 @@ impl ContextNode { Ok(self.underlying(analyzer)?.killed) } - /// Returns a map of variable dependencies for this context - pub fn ctx_deps( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.ctx_deps.clone()) - } - - /// Returns a vector of variable dependencies for this context - pub fn add_ctx_dep( + pub fn add_return_node( &self, - dep: ContextVarNode, + ret_stmt_loc: Loc, + ret: ContextVarNode, analyzer: &mut (impl GraphLike + AnalyzerLike), ) -> Result<(), GraphError> { - tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); - if dep.is_symbolic(analyzer)? { - let dep_name = dep.name(analyzer)?; - let underlying = self.underlying_mut(analyzer)?; - underlying.ctx_deps.insert(dep_name, dep); - } + self.underlying_mut(analyzer)? + .ret + .push((ret_stmt_loc, Some(ret))); + self.propogate_end(analyzer)?; Ok(()) } - pub fn add_return_node( + pub fn add_empty_return( &self, ret_stmt_loc: Loc, - ret: ContextVarNode, analyzer: &mut (impl GraphLike + AnalyzerLike), ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.ret.push((ret_stmt_loc, ret)); + self.underlying_mut(analyzer)? + .ret + .push((ret_stmt_loc, None)); self.propogate_end(analyzer)?; Ok(()) } @@ -1178,7 +110,16 @@ impl ContextNode { &self, analyzer: &impl GraphLike, ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.ret.clone()) + let rets = &self.underlying(analyzer)?.ret.clone(); + let all_good = rets.iter().all(|(_, node)| node.is_some()); + if all_good { + Ok(rets + .iter() + .map(|(loc, node)| (*loc, node.unwrap())) + .collect()) + } else { + Ok(vec![]) + } } pub fn as_string(&mut self) -> String { @@ -1187,23 +128,43 @@ impl ContextNode { pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { let deps = self.ctx_deps(g)?; - #[derive(Debug, Copy, Clone)] - pub enum DepEdge { - Lhs, - Rhs, - } + // #[derive(Debug, Copy, Clone)] + // pub enum DepEdge { + // Lhs, + // Rhs, + // } - let mut gr: petgraph::Graph = + let mut gr: petgraph::Graph = petgraph::Graph::default(); - deps.iter().try_for_each(|(_, dep)| { + + let mut contains: BTreeMap> = + BTreeMap::default(); + deps.iter().try_for_each(|dep| { let mapping = dep.graph_dependent_on(g)?; - mapping.into_iter().for_each(|(k, tmp)| { - let top = gr.add_node(k.into()); - let lhs = gr.add_node(tmp.lhs.into()); - gr.add_edge(top, lhs, DepEdge::Lhs); + mapping.into_iter().for_each(|(_k, tmp)| { if let Some(rhs) = tmp.rhs { - let rhs = gr.add_node(rhs.into()); - gr.add_edge(top, rhs, DepEdge::Rhs); + let lhs = if let Some(ver) = contains.keys().find(|other| { + other.range(g).unwrap() == tmp.lhs.range(g).unwrap() + && tmp.lhs.display_name(g).unwrap() == other.display_name(g).unwrap() + }) { + *contains.get(ver).unwrap() + } else { + let lhs = gr.add_node(tmp.lhs.into()); + contains.insert(tmp.lhs, lhs); + lhs + }; + + let new_rhs = if let Some(ver) = contains.keys().find(|other| { + other.range(g).unwrap() == rhs.range(g).unwrap() + && rhs.display_name(g).unwrap() == other.display_name(g).unwrap() + }) { + *contains.get(ver).unwrap() + } else { + let new_rhs = gr.add_node(rhs.into()); + contains.insert(rhs, new_rhs); + new_rhs + }; + gr.add_edge(lhs, new_rhs, tmp.op); } }); Ok(()) diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs new file mode 100644 index 00000000..dfb3f59a --- /dev/null +++ b/crates/graph/src/nodes/context/querying.rs @@ -0,0 +1,235 @@ + + +impl ContextNode { + /// Gets the associated contract for the function for the context + pub fn associated_contract( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + Ok(self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer) + .expect("No associated contract for context")) + } + + /// Tries to get the associated function for the context + pub fn maybe_associated_contract( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + Ok(self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer)) + } + + pub fn maybe_associated_source( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Option { + let context = self.underlying(analyzer).unwrap(); + if let Some(src) = context.cache.associated_source { + Some(src) + } else if let Some(parent_ctx) = context.parent_ctx { + let src = parent_ctx.maybe_associated_source(analyzer)?; + self.underlying_mut(analyzer) + .unwrap() + .cache + .associated_source = Some(src); + Some(src) + } else { + let func = self.associated_fn(analyzer).unwrap(); + func.maybe_associated_source(analyzer) + } + } + + pub fn associated_source_unit_part( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(sup) = self + .associated_fn(analyzer)? + .maybe_associated_source_unit_part(analyzer) + { + Ok(sup) + } else { + Err(GraphError::NodeConfusion( + "Expected context to have an associated source but didnt".to_string(), + )) + } + } + + /// Gets visible functions + pub fn visible_modifiers( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return Err(GraphError::NodeConfusion( + "Expected context to have an associated source but didnt".to_string(), + )); + }; + if let Some(contract) = self.maybe_associated_contract(analyzer)? { + let mut modifiers = contract.modifiers(analyzer); + // extend with free floating functions + modifiers.extend( + analyzer + .search_children_depth(source, &Edge::Modifier, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>(), + ); + + // extend with inherited functions + let inherited_contracts = analyzer.search_children_exclude_via( + contract.0.into(), + &Edge::InheritedContract, + &[Edge::Func], + ); + modifiers.extend( + inherited_contracts + .into_iter() + .flat_map(|inherited_contract| { + ContractNode::from(inherited_contract).modifiers(analyzer) + }) + .collect::>(), + ); + + let mut mapping: BTreeMap> = BTreeMap::new(); + for modifier in modifiers.iter() { + let entry = mapping.entry(modifier.name(analyzer)?).or_default(); + entry.insert(*modifier); + } + mapping + .into_values() + .map(|modifier_set| { + let as_vec = modifier_set.iter().collect::>(); + + if as_vec.len() > 2 { + println!("{}", as_vec.iter().map(|i| i.name(analyzer).unwrap()).collect::>().join(", ")); + panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") + } else if as_vec.len() == 2 { + as_vec[0].get_overriding(as_vec[1], analyzer) + } else { + Ok(*as_vec[0]) + } + }) + .collect() + } else { + // we are in a free floating function, only look at free floating functions + let Some(source) = self.maybe_associated_source(analyzer) else { + return Err(GraphError::NodeConfusion( + "Expected context to have an associated source but didnt".to_string(), + )); + }; + Ok(analyzer + .search_children_depth(source, &Edge::Modifier, 1, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>()) + } + } + + /// Gets visible functions + pub fn visible_funcs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + // TODO: filter privates + if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { + return Ok(vis.clone()); + } + if let Some(contract) = self.maybe_associated_contract(analyzer)? { + let mut mapping = contract.linearized_functions(analyzer); + // extend with free floating functions + mapping.extend( + analyzer + .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) + .into_iter() + .filter_map(|i| { + let fn_node = FunctionNode::from(i); + if let Ok(name) = fn_node.name(analyzer) { + if !mapping.contains_key(&name) { + Some((name, fn_node)) + } else { + None + } + } else { + None + } + }) + .collect::>(), + ); + let funcs: Vec<_> = mapping.values().copied().collect(); + self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); + Ok(funcs) + } else { + // we are in a free floating function, only look at free floating functions + let funcs = analyzer + .search_children_depth(analyzer.entry(), &Edge::Func, 2, 0) + .into_iter() + .map(FunctionNode::from) + .collect::>(); + + self.underlying_mut(analyzer)?.cache.visible_funcs = Some(funcs.clone()); + Ok(funcs) + } + } + + /// Gets all visible functions + pub fn source_funcs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Vec { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return vec![]; + }; + analyzer + .search_children_exclude_via( + source, + &Edge::Func, + &[ + Edge::Context(ContextEdge::Context), + Edge::Context(ContextEdge::Variable), + ], + ) + .into_iter() + .map(FunctionNode::from) + .collect::>() + } + + /// Gets all visible structs + pub fn visible_structs( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Vec { + // TODO: filter privates + let Some(source) = self.maybe_associated_source(analyzer) else { + return vec![]; + }; + + analyzer + .search_children_exclude_via(source, &Edge::Struct, &[Edge::Func]) + .into_iter() + .map(StructNode::from) + .collect::>() + } + + /// Gets the associated function for the context + pub fn associated_fn(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + if let Some(fn_call) = underlying.fn_call { + Ok(fn_call) + } else if let Some(ext_fn_call) = underlying.ext_fn_call { + Ok(ext_fn_call) + } else { + Ok(underlying.parent_fn) + } + } + + /// Gets the associated function name for the context + pub fn associated_fn_name(&self, analyzer: &impl GraphLike) -> Result { + self.associated_fn(analyzer)?.name(analyzer) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs new file mode 100644 index 00000000..0b76d07d --- /dev/null +++ b/crates/graph/src/nodes/context/solving.rs @@ -0,0 +1,198 @@ + + +impl ContextNode { + pub fn unreachable(&self, analyzer: &impl GraphLike) -> Result { + let mut solver = self.dl_solver(analyzer)?.clone(); + match solver.solve_partial(analyzer)? { + SolveStatus::Unsat => Ok(true), + _ => Ok(false), + } + } + + pub fn dep_atoms(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let deps: Vec<_> = self.ctx_deps(analyzer)?; + let mut ranges = BTreeMap::default(); + deps.iter().try_for_each(|dep| { + let range = dep.ref_range(analyzer)?.unwrap(); + if range.unsat(analyzer) { + panic!( + "initial range for {} not sat", + dep.display_name(analyzer).unwrap() + ); + } + let r = range.into_flattened_range(analyzer)?; + // println!("dep {} range: [{}, {}]", dep.display_name(analyzer).unwrap(), r.min, r.max); + ranges.insert(*dep, r); + Ok(()) + })?; + + Ok(ranges + .iter() + .filter_map(|(_dep, range)| { + if let Some(atom) = range.min.atomize() { + // println!("dep {} atomized min: {:?}", dep.display_name(analyzer).unwrap(), atom); + Some(atom) + } else { + // println!("dep {} atomized max: {:?}", dep.display_name(analyzer).unwrap(), atom); + range.max.atomize() + } + }) + .collect::>()) + } + + pub fn dl_solver<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a DLSolver, GraphError> { + Ok(&self.underlying(analyzer)?.dl_solver) + } + + pub fn dep_graph(&self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + let deps = self.ctx_deps(analyzer)?; + println!("{}:\n", self.path(analyzer)); + deps.iter().try_for_each(|dep| { + let t = dep.graph_dependent_on(analyzer)?; + println!("{:#?}", t); + Ok::<(), GraphError>(()) + })?; + Ok(()) + } + + /// Returns a map of variable dependencies for this context + pub fn ctx_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.ctx_deps.clone()) + } + + pub fn ctx_deps_as_controllables_str( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let deps: Vec<_> = self.ctx_deps(analyzer)?.into_iter().collect(); + println!("here: {}, {}", deps.len(), self.ctx_deps(analyzer)?.len()); + fn decompose( + dep: ContextVarNode, + acc: &mut String, + analyzer: &impl GraphLike, + ) -> Result<(), GraphError> { + println!("acc: {acc}"); + if let Ok(Some(tmp)) = dep.tmp_of(analyzer) { + decompose(tmp.lhs, acc, analyzer)?; + *acc = acc.to_owned() + &tmp.op.to_string(); + if let Some(rhs) = tmp.rhs { + decompose(rhs, acc, analyzer)?; + } + } else { + *acc = acc.to_owned() + &dep.display_name(analyzer)?; + } + Ok(()) + } + + deps.iter() + .map(|dep| { + let mut t = "".to_string(); + decompose(*dep, &mut t, analyzer)?; + Ok(t) + }) + .collect::, _>>() + } + + pub fn flat_ctx_deps( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + fn decompose( + dep: ContextVarNode, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + println!("decomposing: {}", dep.display_name(analyzer).unwrap()); + let mut top_level_deps = vec![]; + if let Ok(Some(tmp)) = dep.tmp_of(analyzer) { + if dep.is_controllable(analyzer)? { + if let Some(rhs) = tmp.rhs { + top_level_deps.extend(decompose(rhs, analyzer)?); + } + top_level_deps.extend(decompose(tmp.lhs, analyzer)?); + println!("{} is controllable", dep.display_name(analyzer).unwrap()); + top_level_deps.push(dep); + } + } else if dep.is_controllable(analyzer)? { + println!( + "atomic {} is controllable", + dep.display_name(analyzer).unwrap() + ); + top_level_deps.push(dep); + } + + Ok(top_level_deps) + } + + Ok(self + .ctx_deps(analyzer)? + .into_iter() + .map(|dep| decompose(dep, analyzer)) + .collect::, _>>()? + .into_iter() + .flatten() + .collect()) + } + + pub fn ctx_dep_ranges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self + .underlying(analyzer)? + .ctx_deps + .clone() + .into_iter() + .flat_map(|dep| { + let tmp = dep.tmp_of(analyzer).unwrap().unwrap(); + if let Some(rhs) = tmp.rhs { + println!("dep lhs: {}", tmp.lhs.display_name(analyzer).unwrap()); + println!("dep rhs: {}", rhs.display_name(analyzer).unwrap()); + vec![ + tmp.lhs + .ref_range(analyzer) + .unwrap() + .unwrap() + .into_flattened_range(analyzer) + .unwrap(), + rhs.ref_range(analyzer) + .unwrap() + .unwrap() + .into_flattened_range(analyzer) + .unwrap(), + ] + } else { + println!("dep lhs: {}", tmp.lhs.display_name(analyzer).unwrap()); + vec![tmp + .lhs + .ref_range(analyzer) + .unwrap() + .unwrap() + .into_flattened_range(analyzer) + .unwrap()] + } + }) + .collect()) + } + + /// Adds a dependency for this context to exit successfully + pub fn add_ctx_dep( + &self, + dep: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); + if dep.is_controllable(analyzer)? { + let range = dep.ref_range(analyzer)?.unwrap(); + let r = range.into_flattened_range(analyzer)?; + let underlying = self.underlying_mut(analyzer)?; + if !underlying.ctx_deps.contains(&dep) { + // add the atomic constraint + if let Some(atom) = r.min.atomize() { + underlying.dl_solver.add_constraints(vec![atom]); + } else if let Some(atom) = r.max.atomize() { + underlying.dl_solver.add_constraints(vec![atom]); + } + + underlying.ctx_deps.push(dep); + } + } + Ok(()) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs new file mode 100644 index 00000000..a31f2f0d --- /dev/null +++ b/crates/graph/src/nodes/context/typing.rs @@ -0,0 +1,77 @@ + + +impl ContextNode { + /// Returns whether this context is killed or returned + pub fn killed_or_ret(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + Ok(underlying.killed.is_some() + || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) + } + + /// Returns whether the context is killed + pub fn is_returned(&self, analyzer: &impl GraphLike) -> Result { + Ok(!self.underlying(analyzer)?.ret.is_empty()) + } + + /// Returns whether the context is killed + pub fn is_killed(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.killed.is_some()) + } + + /// Returns whether the context is killed + pub fn is_ended(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) + } + + /// Check if this context is in an external function call + pub fn is_ext_fn(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) + } + + /// Checks whether a function is external to the current context + pub fn is_fn_ext( + &self, + fn_node: FunctionNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match fn_node.maybe_associated_contract(analyzer) { + None => Ok(false), + Some(fn_ctrt) => { + if let Some(self_ctrt) = self + .associated_fn(analyzer)? + .maybe_associated_contract(analyzer) + { + Ok(Some(self_ctrt) != Some(fn_ctrt) + && !self_ctrt + .underlying(analyzer)? + .inherits + .iter() + .any(|inherited| *inherited == fn_ctrt)) + } else { + Ok(false) + } + } + } + } + + pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.unchecked) + } + + pub fn set_unchecked( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.unchecked = true; + Ok(()) + } + + pub fn unset_unchecked( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.unchecked = false; + Ok(()) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 37df88d9..75c80256 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -1,4 +1,3 @@ - #[derive(Debug, Clone, Eq, PartialEq)] pub struct Context { /// The function associated with this context @@ -10,7 +9,7 @@ pub struct Context { pub returning_ctx: Option, /// Variables whose bounds are required to be met for this context fork to exist. i.e. a conditional operator /// like an if statement - pub ctx_deps: BTreeMap, + pub ctx_deps: Vec, /// A string that represents the path taken from the root context (i.e. `fn_entry.fork.1`) pub path: String, /// Denotes whether this context was killed by an unsatisfiable require, assert, etc. statement @@ -29,7 +28,7 @@ pub struct Context { /// The location in source of the context pub loc: Loc, /// The return node and the return location - pub ret: Vec<(Loc, ContextVarNode)>, + pub ret: Vec<(Loc, Option)>, /// Depth tracker pub depth: usize, /// Width tracker @@ -41,6 +40,7 @@ pub struct Context { // caching related things pub cache: ContextCache, + pub dl_solver: DLSolver, } impl Context { @@ -68,6 +68,7 @@ impl Context { unchecked: false, number_of_live_edges: 0, cache: Default::default(), + dl_solver: Default::default(), } } @@ -88,6 +89,12 @@ impl Context { let width = parent_ctx.underlying(analyzer)?.width + if fork_expr.is_some() { 1 } else { 0 }; + let modifier_state = if let Some(mstate) = modifier_state { + Some(mstate) + } else { + parent_ctx.underlying(analyzer)?.modifier_state.clone() + }; + if analyzer.max_depth() < depth { return Err(GraphError::MaxStackDepthReached(format!( "Stack depth limit reached: {}", @@ -195,6 +202,7 @@ impl Context { associated_source: None, associated_contract: None, }, + dl_solver: parent_ctx.underlying(analyzer)?.dl_solver.clone(), }) } diff --git a/crates/graph/src/nodes/context/var/mod.rs b/crates/graph/src/nodes/context/var/mod.rs new file mode 100644 index 00000000..d4909ebe --- /dev/null +++ b/crates/graph/src/nodes/context/var/mod.rs @@ -0,0 +1,8 @@ +mod node; +mod ranging; +mod underlying; +mod typing; +mod versioning; + +pub use node::*; +pub use underlying::*; \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs new file mode 100644 index 00000000..8ce0b48a --- /dev/null +++ b/crates/graph/src/nodes/context/var/node.rs @@ -0,0 +1,290 @@ +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct ContextVarNode(pub usize); + +impl AsDotStr for ContextVarNode { + fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + let underlying = self.underlying(analyzer).unwrap(); + + let range_str = if let Some(r) = underlying.ty.ref_range(analyzer).unwrap() { + format!( + "[{}, {}]", + r.evaled_range_min(analyzer) + .unwrap() + .to_range_string(false, analyzer) + .s, + r.evaled_range_max(analyzer) + .unwrap() + .to_range_string(true, analyzer) + .s + ) + } else { + "".to_string() + }; + + format!( + "{} - {} -- {} -- range: {}", + underlying.display_name, + self.0, + underlying.ty.as_string(analyzer).unwrap(), + range_str + ) + } +} + +impl From for NodeIdx { + fn from(val: ContextVarNode) -> Self { + val.0.into() + } +} + +impl From for ContextVarNode { + fn from(idx: NodeIdx) -> Self { + ContextVarNode(idx.index()) + } +} + +impl ContextVarNode { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> Result<&'a ContextVar, GraphError> { + match analyzer.node(*self) { + Node::ContextVar(c) => Ok(c), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be ContextVar but it was: {e:?}" + ))), + } + } + + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut impl GraphLike, + ) -> Result<&'a mut ContextVar, GraphError> { + match analyzer.node_mut(*self) { + Node::ContextVar(c) => Ok(c), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be ContextVar but it was: {e:?}" + ))), + } + } + + pub fn storage<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> Result<&'a Option, GraphError> { + Ok(&self.underlying(analyzer)?.storage) + } + + + pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + Ok(self + .underlying(analyzer)? + .loc + .expect("No loc for ContextVar")) + } + + pub fn ctx(&self, analyzer: &impl GraphLike) -> ContextNode { + ContextNode::from( + analyzer + .search_for_ancestor(self.0.into(), &Edge::Context(ContextEdge::Variable)) + .into_iter() + .take(1) + .next() + .expect("No associated ctx"), + ) + } + + pub fn maybe_ctx(&self, analyzer: &impl GraphLike) -> Option { + let first = self.first_version(analyzer); + analyzer + .graph() + .edges_directed(first.0.into(), Direction::Outgoing) + .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::Variable)) + .map(|edge| ContextNode::from(edge.target())) + .take(1) + .next() + } + + pub fn maybe_storage_var(&self, analyzer: &impl GraphLike) -> Option { + Some( + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .find(|edge| { + *edge.weight() == Edge::Context(ContextEdge::InheritedStorageVariable) + })? + .target() + .into(), + ) + } + + pub fn name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.name.clone()) + } + + pub fn as_controllable_name(&self, analyzer: &impl GraphLike) -> Result { + if let Some(ref_range) = self.ref_range(analyzer)? { + let mut exclude = vec![]; + let min_name = ref_range + .range_min() + .simplify_minimize(&mut exclude, analyzer)? + .to_range_string(false, analyzer) + .s; + exclude = vec![]; + let max_name = ref_range + .range_max() + .simplify_maximize(&mut exclude, analyzer)? + .to_range_string(true, analyzer) + .s; + if max_name == min_name { + Ok(max_name) + } else { + self.display_name(analyzer) + } + } else { + self.display_name(analyzer) + } + } + + pub fn display_name(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.display_name.clone()) + } + + pub fn return_assignments(&self, analyzer: &impl GraphLike) -> Vec { + let latest = self.latest_version(analyzer); + let mut earlier = latest; + let mut return_assignments = vec![]; + while let Some(prev) = earlier.previous_version(analyzer) { + if earlier.is_return_assignment(analyzer) { + return_assignments.push(earlier) + } + earlier = prev; + } + return_assignments + } + + pub fn ext_return_assignments(&self, analyzer: &impl GraphLike) -> Vec { + let latest = self.latest_version(analyzer); + let mut earlier = latest; + let mut return_assignments = vec![]; + if earlier.is_ext_return_assignment(analyzer) { + return_assignments.push(earlier) + } + while let Some(prev) = earlier.previous_version(analyzer) { + earlier = prev; + if earlier.is_ext_return_assignment(analyzer) { + return_assignments.push(earlier) + } + } + return_assignments + } + + pub fn tmp_of(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(self.underlying(analyzer)?.tmp_of()) + } + + pub fn len_var_to_array( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + if self.name(analyzer)?.ends_with(".length") { + if let Some(arr) = analyzer.search_for_ancestor( + self.first_version(analyzer).into(), + &Edge::Context(ContextEdge::AttrAccess), + ) { + Ok(Some(ContextVarNode::from(arr).latest_version(analyzer))) + } else { + Ok(None) + } + } else { + Ok(None) + } + } + + pub fn index_to_array(&self, analyzer: &impl GraphLike) -> Option { + let arr = analyzer + .graph() + .edges_directed(self.first_version(analyzer).into(), Direction::Outgoing) + .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) + .map(|edge| edge.target()) + .take(1) + .next()?; + Some(ContextVarNode::from(arr).latest_version(analyzer)) + } + + pub fn index_access_to_index(&self, analyzer: &impl GraphLike) -> Option { + let index = analyzer.find_child_exclude_via( + self.first_version(analyzer).into(), + &Edge::Context(ContextEdge::Index), + &[], + &|idx, _| Some(idx), + )?; + Some(ContextVarNode::from(index)) + } + + pub fn index_or_attr_access(&self, analyzer: &impl GraphLike) -> Vec { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| { + Edge::Context(ContextEdge::IndexAccess) == *edge.weight() + || Edge::Context(ContextEdge::AttrAccess) == *edge.weight() + }) + .map(|edge| ContextVarNode::from(edge.source())) + .collect() + } + + + pub fn dependent_on( + &self, + analyzer: &impl GraphLike, + return_self: bool, + ) -> Result, GraphError> { + let underlying = self.underlying(analyzer)?; + if let Some(tmp) = underlying.tmp_of() { + let mut nodes = tmp.lhs.dependent_on(analyzer, true)?; + if let Some(rhs) = tmp.rhs { + nodes.extend(rhs.dependent_on(analyzer, true)?); + } + Ok(nodes) + } else if return_self { + Ok(vec![*self]) + } else { + Ok(vec![]) + } + } + + pub fn graph_dependent_on( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let underlying = self.underlying(analyzer)?; + let mut tree = BTreeMap::default(); + if let Some(tmp) = underlying.tmp_of() { + tree.insert(*self, tmp); + tmp.lhs + .graph_dependent_on(analyzer)? + .into_iter() + .for_each(|(key, v)| { + if let Some(_v) = tree.get_mut(&key) { + panic!("here") + } else { + tree.insert(key, v); + } + }); + if let Some(rhs) = tmp.rhs { + rhs.graph_dependent_on(analyzer)? + .into_iter() + .for_each(|(key, v)| { + if let Some(_v) = tree.get_mut(&key) { + panic!("here") + } else { + tree.insert(key, v); + } + }); + } + } + + Ok(tree) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs new file mode 100644 index 00000000..93ccc3ff --- /dev/null +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -0,0 +1,315 @@ + + +impl ContextVarNode { + #[tracing::instrument(level = "trace", skip_all)] + pub fn update_deps( + &mut self, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + if let Some(mut range) = self.range(analyzer)? { + range.update_deps(*self, ctx, analyzer); + self.set_range_min(analyzer, range.min)?; + self.set_range_max(analyzer, range.max)?; + } + Ok(()) + } + + pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + self.underlying(analyzer)?.ty.range(analyzer) + } + + pub fn range_string(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(range) = self.ref_range(analyzer)? { + Ok(Some(format!( + "[ {}, {} ]", + range + .evaled_range_min(analyzer)? + .to_range_string(false, analyzer) + .s, + range + .evaled_range_max(analyzer)? + .to_range_string(true, analyzer) + .s + ))) + } else { + Ok(None) + } + } + + pub fn ref_range<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> Result>, GraphError> { + self.underlying(analyzer)?.ty.ref_range(analyzer) + } + + pub fn range_min( + &self, + analyzer: &impl GraphLike, + ) -> Result>, GraphError> { + if let Some(r) = self.ref_range(analyzer)? { + Ok(Some(r.range_min().into_owned())) + } else { + Ok(None) + } + } + + pub fn range_max( + &self, + analyzer: &impl GraphLike, + ) -> Result>, GraphError> { + if let Some(r) = self.ref_range(analyzer)? { + Ok(Some(r.range_max().into_owned())) + } else { + Ok(None) + } + } + + pub fn evaled_range_min( + &self, + analyzer: &impl GraphLike, + ) -> Result>, GraphError> { + if let Some(r) = self.ref_range(analyzer)? { + Ok(Some(r.evaled_range_min(analyzer)?)) + } else { + Ok(None) + } + } + + pub fn evaled_range_max( + &self, + analyzer: &impl GraphLike, + ) -> Result>, GraphError> { + if let Some(r) = self.ref_range(analyzer)? { + Ok(Some(r.evaled_range_max(analyzer)?)) + } else { + Ok(None) + } + } + + pub fn as_range_elem( + &self, + analyzer: &impl GraphLike, + loc: Loc, + ) -> Result, GraphError> { + match self.underlying(analyzer)?.ty { + VarType::Concrete(c) => Ok(Elem::Concrete(RangeConcrete { + val: c.underlying(analyzer)?.clone(), + loc, + })), + _ => Ok(Elem::from(*self)), + } + } + + pub fn cache_range(&self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { + if let Some(mut range) = self.range(analyzer)? { + range.cache_eval(analyzer)?; + self.set_range(analyzer, range)?; + } + Ok(()) + } + + pub fn set_range( + &self, + analyzer: &mut impl GraphLike, + new_range: SolcRange, + ) -> Result<(), GraphError> { + let underlying = self.underlying_mut(analyzer)?; + underlying.set_range(new_range); + Ok(()) + } + + pub fn fallback_range( + &self, + analyzer: &mut impl GraphLike, + ) -> Result, GraphError> { + let underlying = self.underlying(analyzer)?; + underlying.fallback_range(analyzer) + } + + pub fn needs_fallback(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.needs_fallback()) + } + // #[tracing::instrument(level = "trace", skip_all)] + pub fn set_range_min( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + mut new_min: Elem, + ) -> Result<(), GraphError> { + if new_min.contains_node((*self).into()) { + if let Some(prev) = self.previous_or_inherited_version(analyzer) { + new_min.filter_recursion((*self).into(), prev.into()); + } else { + return Err(GraphError::UnbreakableRecursion(format!("The variable {}'s range is self-referential and we cannot break the recursion.", self.display_name(analyzer)?))); + } + } + + tracing::trace!( + "setting range minimum: {} (node idx: {}), current:\n{:#?}, new_min:\n{:#?}", + self.display_name(analyzer)?, + self.0, + self.range_min(analyzer)?, + new_min + ); + + if self.is_concrete(analyzer)? { + let mut new_ty = self.ty(analyzer)?.clone(); + new_ty.concrete_to_builtin(analyzer)?; + self.underlying_mut(analyzer)?.ty = new_ty; + self.set_range_min(analyzer, new_min)?; + } else { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + self.underlying_mut(analyzer)? + .set_range_min(new_min, fallback); + } + self.cache_range(analyzer)?; + Ok(()) + } + + // #[tracing::instrument(level = "trace", skip_all)] + pub fn set_range_max( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + mut new_max: Elem, + ) -> Result<(), GraphError> { + if new_max.contains_node((*self).into()) { + if let Some(prev) = self.previous_or_inherited_version(analyzer) { + new_max.filter_recursion((*self).into(), prev.into()); + } + } + + tracing::trace!( + "setting range maximum: {:?}, {}, current:\n{:#?}, new:\n{:#?}", + self, + self.display_name(analyzer)?, + self.ref_range(analyzer)?.unwrap().range_max(), // .unwrap() + new_max + ); + + if self.is_concrete(analyzer)? { + let mut new_ty = self.ty(analyzer)?.clone(); + new_ty.concrete_to_builtin(analyzer)?; + self.underlying_mut(analyzer)?.ty = new_ty; + self.set_range_max(analyzer, new_max)?; + } else { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + + self.underlying_mut(analyzer)? + .set_range_max(new_max, fallback) + } + + self.cache_range(analyzer)?; + Ok(()) + } + + pub fn set_range_exclusions( + &self, + analyzer: &mut impl GraphLike, + new_exclusions: Vec>, + ) -> Result<(), GraphError> { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + self.underlying_mut(analyzer)? + .set_range_exclusions(new_exclusions, fallback); + Ok(()) + } + + pub fn try_set_range_min( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + mut new_min: Elem, + ) -> Result { + if new_min.contains_node((*self).into()) { + if let Some(prev) = self.previous_version(analyzer) { + new_min.filter_recursion((*self).into(), prev.into()); + } + } + + if self.is_concrete(analyzer)? { + let mut new_ty = self.ty(analyzer)?.clone(); + new_ty.concrete_to_builtin(analyzer)?; + self.underlying_mut(analyzer)?.ty = new_ty; + self.try_set_range_min(analyzer, new_min) + } else { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + Ok(self + .underlying_mut(analyzer)? + .try_set_range_min(new_min, fallback)) + } + } + + pub fn try_set_range_max( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + mut new_max: Elem, + ) -> Result { + if new_max.contains_node((*self).into()) { + if let Some(prev) = self.previous_version(analyzer) { + new_max.filter_recursion((*self).into(), prev.into()); + } + } + + if self.is_concrete(analyzer)? { + let mut new_ty = self.ty(analyzer)?.clone(); + new_ty.concrete_to_builtin(analyzer)?; + self.underlying_mut(analyzer)?.ty = new_ty; + self.try_set_range_max(analyzer, new_max) + } else { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + Ok(self + .underlying_mut(analyzer)? + .try_set_range_max(new_max, fallback)) + } + } + + pub fn try_set_range_exclusions( + &self, + analyzer: &mut impl GraphLike, + new_exclusions: Vec>, + ) -> Result { + let fallback = if self.needs_fallback(analyzer)? { + self.fallback_range(analyzer)? + } else { + None + }; + Ok(self + .underlying_mut(analyzer)? + .try_set_range_exclusions(new_exclusions, fallback)) + } + + pub fn range_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(range) = self.ref_range(analyzer)? { + Ok(range.dependent_on()) + } else { + Ok(vec![]) + } + } + + pub fn sol_delete_range(&mut self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { + let ty = self.ty(analyzer)?; + if let Some(delete_range) = ty.delete_range_result(analyzer)? { + self.set_range(analyzer, delete_range)?; + } + Ok(()) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs new file mode 100644 index 00000000..0db11a1b --- /dev/null +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -0,0 +1,299 @@ +impl ContextVarNode { + pub fn ty<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a VarType, GraphError> { + Ok(&self.underlying(analyzer)?.ty) + } + + pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + self.ty(analyzer)?.is_mapping(analyzer) + } + + pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + self.ty(analyzer)?.is_dyn(analyzer) + } + + pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + self.ty(analyzer)?.is_indexable(analyzer) + } + + pub fn is_storage(&self, analyzer: &impl GraphLike) -> Result { + Ok(matches!( + self.underlying(analyzer)?.storage, + Some(StorageLocation::Storage(..)) + )) + } + + pub fn is_return_assignment(&self, analyzer: &impl GraphLike) -> bool { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .any(|edge| { + Edge::Context(ContextEdge::ReturnAssign(true)) == *edge.weight() + || Edge::Context(ContextEdge::ReturnAssign(false)) == *edge.weight() + }) + } + + pub fn is_ext_return_assignment(&self, analyzer: &impl GraphLike) -> bool { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .any(|edge| Edge::Context(ContextEdge::ReturnAssign(true)) == *edge.weight()) + } + + pub fn is_storage_or_calldata_input( + &self, + analyzer: &impl GraphLike, + ) -> Result { + let global_first = self.global_first_version(analyzer); + Ok(global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer)) + } + + pub fn is_independent_and_storage_or_calldata( + &self, + analyzer: &impl GraphLike, + ) -> Result { + let global_first = self.global_first_version(analyzer); + let is_independent = self.is_independent(analyzer)?; + + Ok((global_first.is_storage(analyzer)? + || global_first.is_calldata_input(analyzer) + || ( + // if its a function input, and we are evaluating the function + // as a standalone (i.e. its internal, but we are treating it like its external) + // it wont be marked as calldata, but for the purposes + // of determining controllability it is to better to assume there is some path that lets us + // control it + global_first.is_func_input(analyzer) + && global_first.maybe_ctx(analyzer).is_some() + && !global_first.ctx(analyzer).has_parent(analyzer)? + )) + && is_independent) + } + + pub fn is_independent(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.dependent_on(analyzer, false)?.is_empty() && self.tmp_of(analyzer)?.is_none()) + } + + pub fn is_controllable(&self, analyzer: &impl GraphLike) -> Result { + if self.is_storage_or_calldata_input(analyzer)? { + Ok(true) + } else if let Some(tmp) = self.tmp_of(analyzer)? { + let rhs_controllable = if let Some(rhs) = tmp.rhs { + rhs.is_controllable(analyzer)? + } else { + false + }; + let lhs_controllable = tmp.lhs.is_controllable(analyzer)?; + Ok(lhs_controllable || rhs_controllable) + } else { + Ok(false) + } + } + + pub fn is_calldata_input(&self, analyzer: &impl GraphLike) -> bool { + let global_first = self.global_first_version(analyzer); + analyzer + .graph() + .edges_directed(global_first.0.into(), Direction::Outgoing) + .any(|edge| Edge::Context(ContextEdge::CalldataVariable) == *edge.weight()) + } + + pub fn is_func_input(&self, analyzer: &impl GraphLike) -> bool { + let first = self.first_version(analyzer); + analyzer + .graph() + .edges_directed(first.0.into(), Direction::Outgoing) + .any(|edge| { + Edge::Context(ContextEdge::InputVariable) == *edge.weight() + || Edge::Context(ContextEdge::CalldataVariable) == *edge.weight() + }) + } + + pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + underlying.ty.is_const(analyzer) + } + + pub fn is_symbolic(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.is_symbolic) + } + + pub fn is_tmp(&self, analyzer: &impl GraphLike) -> Result { + let underlying = self.underlying(analyzer)?; + Ok(underlying.is_tmp()) + } + + pub fn is_return_node(&self, analyzer: &impl GraphLike) -> Result { + if let Some(ctx) = self.maybe_ctx(analyzer) { + return Ok(ctx.underlying(analyzer)?.ret.iter().any(|(_, node)| { + if let Some(node) = node { + node.name(analyzer).unwrap() == self.name(analyzer).unwrap() + } else { + false + } + })); + } + Ok(false) + } + + pub fn is_return_node_in_any(&self, ctxs: &[ContextNode], analyzer: &impl GraphLike) -> bool { + ctxs.iter().any(|ctx| { + ctx.underlying(analyzer) + .unwrap() + .ret + .iter() + .any(|(_, node)| { + if let Some(node) = node { + node.name(analyzer).unwrap() == self.name(analyzer).unwrap() + } else { + false + } + }) + }) + } + + pub fn is_len_var(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.name(analyzer)?.ends_with(".length") + && analyzer + .search_for_ancestor( + self.first_version(analyzer).into(), + &Edge::Context(ContextEdge::AttrAccess), + ) + .is_some()) + } + + pub fn is_array_index_access(&self, analyzer: &impl GraphLike) -> bool { + analyzer + .search_for_ancestor( + self.first_version(analyzer).into(), + &Edge::Context(ContextEdge::IndexAccess), + ) + .is_some() + } + + pub fn is_concrete(&self, analyzer: &impl GraphLike) -> Result { + Ok(matches!(self.ty(analyzer)?, VarType::Concrete(_))) + } + + pub fn as_concrete(&self, analyzer: &impl GraphLike) -> Result { + match &self.ty(analyzer)? { + VarType::Concrete(c) => Ok(c.underlying(analyzer)?.clone()), + e => Err(GraphError::NodeConfusion(format!( + "Expected variable type to be concrete but was: {e:?}" + ))), + } + } + + pub fn as_cast_tmp( + &self, + loc: Loc, + ctx: ContextNode, + cast_ty: Builtin, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let new_underlying = self + .underlying(analyzer)? + .clone() + .as_cast_tmp(loc, ctx, cast_ty, analyzer)?; + let node = analyzer.add_node(Node::ContextVar(new_underlying)); + ctx.add_var(node.into(), analyzer)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(node.into()) + } + + pub fn as_tmp( + &self, + loc: Loc, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let new_underlying = self + .underlying(analyzer)? + .clone() + .as_tmp(loc, ctx, analyzer)?; + Ok(analyzer.add_node(Node::ContextVar(new_underlying)).into()) + } + + pub fn ty_eq(&self, other: &Self, analyzer: &mut impl GraphLike) -> Result { + self.ty(analyzer)?.ty_eq(other.ty(analyzer)?, analyzer) + } + + pub fn cast_from( + &self, + other: &Self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let to_ty = other.ty(analyzer)?.clone(); + self.cast_from_ty(to_ty, analyzer)?; + Ok(()) + } + + pub fn literal_cast_from( + &self, + other: &Self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let to_ty = other.ty(analyzer)?.clone(); + self.literal_cast_from_ty(to_ty, analyzer)?; + Ok(()) + } + + pub fn cast_from_ty( + &self, + to_ty: VarType, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let from_ty = self.ty(analyzer)?.clone(); + if !from_ty.ty_eq(&to_ty, analyzer)? { + if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { + self.underlying_mut(analyzer)?.ty = new_ty; + } + if let (Some(r), Some(r2)) = (self.range(analyzer)?, to_ty.range(analyzer)?) { + let min = r.min.cast(r2.min); + let max = r.max.cast(r2.max); + self.set_range_min(analyzer, min)?; + self.set_range_max(analyzer, max)?; + } + } + + if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { + // update name + let display_name = cnode.underlying(analyzer)?.as_human_string(); + self.underlying_mut(analyzer)?.display_name = display_name; + } + Ok(()) + } + + pub fn literal_cast_from_ty( + &self, + to_ty: VarType, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let from_ty = self.ty(analyzer)?.clone(); + if !from_ty.ty_eq(&to_ty, analyzer)? { + if let Some(new_ty) = from_ty.try_literal_cast(&to_ty, analyzer)? { + self.underlying_mut(analyzer)?.ty = new_ty; + } + // we dont need to update the ranges because a literal by definition is concrete + } + + if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { + // update name + let display_name = cnode.underlying(analyzer)?.as_human_string(); + self.underlying_mut(analyzer)?.display_name = display_name; + } + Ok(()) + } + + pub fn try_increase_size( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let from_ty = self.ty(analyzer)?.clone(); + self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer)?; + Ok(()) + } + + pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { + self.ty(analyzer)?.is_int(analyzer) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs new file mode 100644 index 00000000..532ead5a --- /dev/null +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -0,0 +1,617 @@ +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ContextVar { + pub loc: Option, + pub name: String, + pub display_name: String, + pub storage: Option, + pub is_tmp: bool, + pub tmp_of: Option, + pub is_symbolic: bool, + pub is_return: bool, + pub ty: VarType, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TmpConstruction { + pub lhs: ContextVarNode, + pub op: RangeOp, + pub rhs: Option, +} + +impl TmpConstruction { + pub fn new(lhs: ContextVarNode, op: RangeOp, rhs: Option) -> Self { + Self { lhs, op, rhs } + } +} + +impl ContextVar { + pub fn eq_ignore_loc(&self, other: &Self) -> bool { + self.name == other.name + && self.display_name == other.display_name + && self.storage == other.storage + && self.is_tmp == other.is_tmp + && self.tmp_of == other.tmp_of + && self.is_symbolic == other.is_symbolic + && self.is_return == other.is_return + && self.ty == other.ty + } + + pub fn is_tmp(&self) -> bool { + self.is_tmp || self.tmp_of.is_some() + } + + pub fn tmp_of(&self) -> Option { + self.tmp_of + } + + pub fn new_from_concrete( + loc: Loc, + ctx: ContextNode, + concrete_node: ConcreteNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let name = format!( + "tmp_{}({})", + ctx.new_tmp(analyzer)?, + concrete_node.underlying(analyzer)?.as_string() + ); + Ok(ContextVar { + loc: Some(loc), + name, + display_name: concrete_node.underlying(analyzer)?.as_human_string(), + storage: None, + is_tmp: true, + tmp_of: None, + is_symbolic: false, + is_return: false, + ty: VarType::Concrete(concrete_node), + }) + } + + pub fn as_cast_tmp( + &self, + loc: Loc, + ctx: ContextNode, + cast_ty: Builtin, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let mut new_tmp = self.clone(); + new_tmp.loc = Some(loc); + new_tmp.is_tmp = true; + new_tmp.name = format!( + "tmp_{}({}({}))", + ctx.new_tmp(analyzer)?, + cast_ty.as_string(analyzer)?, + self.name + ); + new_tmp.display_name = format!("{}({})", cast_ty.as_string(analyzer)?, self.display_name); + Ok(new_tmp) + } + + pub fn as_tmp( + &self, + loc: Loc, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let mut new_tmp = self.clone(); + new_tmp.loc = Some(loc); + new_tmp.is_tmp = true; + new_tmp.name = format!("tmp{}({})", ctx.new_tmp(analyzer)?, self.name); + new_tmp.display_name = format!("tmp_{}", self.display_name); + Ok(new_tmp) + } + + pub fn new_from_contract( + loc: Loc, + contract_node: ContractNode, + analyzer: &impl GraphLike, + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: contract_node.name(analyzer)?, + display_name: contract_node.name(analyzer)?, + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::User( + TypeNode::Contract(contract_node), + SolcRange::try_from_builtin(&Builtin::Address), + ), + }) + } + + pub fn new_from_struct( + loc: Loc, + struct_node: StructNode, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: format!( + "tmp_struct_{}_{}", + ctx.new_tmp(analyzer)?, + struct_node.name(analyzer)? + ), + display_name: struct_node.name(analyzer)?, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::User(TypeNode::Struct(struct_node), None), + }) + } + + pub fn new_from_ty( + loc: Loc, + ty_node: TyNode, + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: format!( + "tmp_ty_{}_{}", + ctx.new_tmp(analyzer)?, + ty_node.name(analyzer)? + ), + display_name: ty_node.name(analyzer)?, + storage: Some(StorageLocation::Memory(Loc::Implicit)), + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::try_from_idx(analyzer, ty_node.0.into()).unwrap(), + }) + } + + pub fn new_from_builtin( + loc: Loc, + bn_node: BuiltInNode, + analyzer: &impl GraphLike, + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: format!("tmp_{}", bn_node.underlying(analyzer)?.as_string(analyzer)?), + display_name: format!("tmp_{}", bn_node.underlying(analyzer)?.as_string(analyzer)?), + storage: None, + is_tmp: true, + tmp_of: None, + is_symbolic: false, + is_return: false, + ty: VarType::try_from_idx(analyzer, bn_node.into()).unwrap(), + }) + } + + pub fn fallback_range( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + match &self.ty { + VarType::User(TypeNode::Contract(_), ref maybe_range) => { + if let Some(range) = maybe_range { + Ok(Some(range.clone())) + } else { + Ok(SolcRange::try_from_builtin(&Builtin::Address)) + } + } + VarType::User(TypeNode::Enum(enum_node), ref maybe_range) => { + if let Some(range) = maybe_range { + Ok(Some(range.clone())) + } else { + Ok(enum_node.maybe_default_range(analyzer)?) + } + } + VarType::User(TypeNode::Ty(ty_node), ref maybe_range) => { + if let Some(range) = maybe_range { + Ok(Some(range.clone())) + } else { + let underlying = + BuiltInNode::from(ty_node.underlying(analyzer)?.ty).underlying(analyzer)?; + Ok(SolcRange::try_from_builtin(underlying)) + } + } + VarType::BuiltIn(bn, ref maybe_range) => { + if let Some(range) = maybe_range { + Ok(Some(range.clone())) + } else { + let underlying = bn.underlying(analyzer)?; + Ok(SolcRange::try_from_builtin(underlying)) + } + } + VarType::Concrete(cn) => Ok(SolcRange::from(cn.underlying(analyzer)?.clone())), + _ => Ok(None), + } + } + + pub fn set_range(&mut self, new_range: SolcRange) { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + *maybe_range = Some(new_range); + } + VarType::Concrete(_) => {} + e => panic!("wasnt builtin: {e:?}"), + } + } + + pub fn needs_fallback(&self) -> bool { + match &self.ty { + VarType::User(TypeNode::Contract(_), ref maybe_range) + | VarType::User(TypeNode::Enum(_), ref maybe_range) + | VarType::User(TypeNode::Ty(_), ref maybe_range) + | VarType::BuiltIn(_, ref maybe_range) => maybe_range.is_some(), + _ => false, + } + } + + // #[tracing::instrument(level = "trace", skip_all)] + pub fn set_range_min(&mut self, new_min: Elem, fallback_range: Option) { + // tracing::trace!("Setting range min in underlying: {:?}", self.ty); + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_min(new_min); + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_min(new_min); + *maybe_range = Some(fr); + } + } + VarType::Concrete(_) => {} + e => panic!("wasnt builtin: {e:?}"), + } + } + + pub fn try_set_range_min( + &mut self, + new_min: Elem, + fallback_range: Option, + ) -> bool { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_min(new_min); + true + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_min(new_min); + *maybe_range = Some(fr); + true + } + } + VarType::Concrete(_) => true, + _ => false, + } + } + + pub fn set_range_max(&mut self, new_max: Elem, fallback_range: Option) { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_max(new_max); + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_max(new_max); + *maybe_range = Some(fr); + } + } + VarType::Concrete(_) => {} + e => panic!("wasnt builtin or concrete: {e:?}"), + } + } + + pub fn set_range_exclusions( + &mut self, + new_exclusions: Vec>, + fallback_range: Option, + ) { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_exclusions(new_exclusions); + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_exclusions(new_exclusions); + *maybe_range = Some(fr); + } + } + VarType::Concrete(_) => {} + e => panic!("wasnt builtin or concrete: {e:?}"), + } + } + + pub fn try_set_range_max( + &mut self, + new_max: Elem, + fallback_range: Option, + ) -> bool { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_max(new_max); + true + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_max(new_max); + *maybe_range = Some(fr); + true + } + } + VarType::Concrete(_) => true, + _ => false, + } + } + + pub fn try_set_range_exclusions( + &mut self, + new_exclusions: Vec>, + fallback_range: Option, + ) -> bool { + match &mut self.ty { + VarType::User(TypeNode::Contract(_), ref mut maybe_range) + | VarType::User(TypeNode::Enum(_), ref mut maybe_range) + | VarType::User(TypeNode::Ty(_), ref mut maybe_range) + | VarType::BuiltIn(_, ref mut maybe_range) => { + if let Some(range) = maybe_range { + range.set_range_exclusions(new_exclusions); + true + } else { + let mut fr = fallback_range.expect("No range and no fallback_range"); + fr.set_range_exclusions(new_exclusions); + *maybe_range = Some(fr); + true + } + } + VarType::Concrete(_) => true, + _ => false, + } + } + + pub fn maybe_from_user_ty( + analyzer: &impl GraphLike, + loc: Loc, + node_idx: NodeIdx, + ) -> Option { + if let Some(ty) = VarType::try_from_idx(analyzer, node_idx) { + let (name, storage) = match analyzer.node(node_idx) { + Node::Contract(c) => { + let name = c.name.clone().expect("Contract had no name").name; + (name, None) + } + Node::Function(f) => { + let name = f.name.clone().expect("Function had no name").name; + (name, None) + } + Node::Struct(s) => { + let name = s.name.clone().expect("Struct had no name").name; + (name, None) + } + Node::Enum(e) => { + let name = e.name.clone().expect("Enum had no name").name; + (name, None) + } + Node::Var(var) => { + let name = var.name.clone().expect("Variable had no name").name; + let storage = if var.in_contract { + if !var.attrs.iter().any(|attr| { + matches!(attr, solang_parser::pt::VariableAttribute::Constant(_)) + }) { + Some(StorageLocation::Storage(var.loc)) + } else { + None + } + } else { + None + }; + (name, storage) + } + Node::Ty(ty) => { + let name = &ty.name.name; + (name.clone(), None) + } + _ => return None, + }; + + Some(ContextVar { + loc: Some(loc), + name: name.clone(), + display_name: name, + storage, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty, + }) + } else { + None + } + } + + pub fn maybe_new_from_field( + analyzer: &impl GraphLike, + loc: Loc, + parent_var: &ContextVar, + field: Field, + ) -> Option { + if let Some(ty) = VarType::try_from_idx(analyzer, field.ty) { + Some(ContextVar { + loc: Some(loc), + name: parent_var.name.clone() + + "." + + &field.name.clone().expect("Field had no name").name, + display_name: parent_var.name.clone() + + "." + + &field.name.expect("Field had no name").name, + storage: parent_var.storage.clone(), + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty, + }) + } else { + None + } + } + + pub fn new_from_enum_variant( + analyzer: &mut (impl GraphLike + AnalyzerLike), + ctx: ContextNode, + loc: Loc, + enum_node: EnumNode, + variant: String, + ) -> Result { + let enum_name = enum_node.name(analyzer)?; + Ok(ContextVar { + loc: Some(loc), + name: format!("{}.{}_{}", enum_name, variant, ctx.new_tmp(analyzer)?), + display_name: format!("{}.{}", enum_name, variant), + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::User( + TypeNode::Enum(enum_node), + Some(enum_node.range_from_variant(variant, analyzer)?), + ), + }) + } + + pub fn new_from_index( + analyzer: &mut (impl GraphLike + AnalyzerLike), + loc: Loc, + parent_name: String, + parent_display_name: String, + parent_storage: StorageLocation, + parent_var: &BuiltInNode, + index: ContextVarNode, + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: parent_name + "[" + &index.name(analyzer)? + "]", + display_name: parent_display_name + "[" + &index.display_name(analyzer)? + "]", + storage: Some(parent_storage), + is_tmp: false, + tmp_of: None, + is_symbolic: index.underlying(analyzer)?.is_symbolic, + is_return: false, + ty: parent_var.dynamic_underlying_ty(analyzer)?, + }) + } + + pub fn new_from_func( + analyzer: &mut (impl GraphLike + AnalyzerLike), + func: FunctionNode, + ) -> Result { + Ok(ContextVar { + loc: Some(func.underlying(analyzer)?.loc), + name: func.name(analyzer)?, + display_name: func.name(analyzer)?, + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: false, + is_return: false, + ty: VarType::User(TypeNode::Func(func), None), + }) + } + + pub fn maybe_new_from_func_param( + analyzer: &impl GraphLike, + param: FunctionParam, + ) -> Option { + if let Some(name) = param.name { + if let Some(ty) = VarType::try_from_idx(analyzer, param.ty) { + Some(ContextVar { + loc: Some(param.loc), + name: name.name.clone(), + display_name: name.name, + storage: param.storage, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty, + }) + } else { + None + } + } else { + None + } + } + + pub fn maybe_new_from_func_ret(analyzer: &impl GraphLike, ret: FunctionReturn) -> Option { + if let Some(name) = ret.name { + if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { + Some(ContextVar { + loc: Some(ret.loc), + name: name.name.clone(), + display_name: name.name, + storage: ret.storage, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: true, + ty, + }) + } else { + None + } + } else { + None + } + } + + pub fn new_from_func_ret( + ctx: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ret: FunctionReturn, + ) -> Result, GraphError> { + let (is_tmp, name) = if let Some(name) = ret.name { + (false, name.name) + } else { + (true, format!("tmp_func_ret_{}", ctx.new_tmp(analyzer)?)) + }; + + if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { + Ok(Some(ContextVar { + loc: Some(ret.loc), + name: name.clone(), + display_name: name, + storage: ret.storage, + is_tmp, + tmp_of: None, + is_symbolic: true, + is_return: true, + ty, + })) + } else { + Ok(None) + } + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs new file mode 100644 index 00000000..4867bc5c --- /dev/null +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -0,0 +1,189 @@ + + +impl ContextVarNode { + pub fn latest_version(&self, analyzer: &impl GraphLike) -> Self { + let mut latest = *self; + while let Some(next) = latest.next_version(analyzer) { + latest = next; + } + latest + } + + pub fn latest_version_less_than(&self, idx: NodeIdx, analyzer: &impl GraphLike) -> Self { + let mut latest = *self; + while let Some(next) = latest.next_version(analyzer) { + if next.0 <= idx.index() { + latest = next; + } else { + break; + } + } + latest + } + + pub fn latest_version_in_ctx( + &self, + ctx: ContextNode, + analyzer: &impl GraphLike, + ) -> Result { + if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { + Ok(cvar.latest_version(analyzer)) + } else { + Ok(*self) + } + } + + pub fn latest_version_in_ctx_less_than( + &self, + idx: NodeIdx, + ctx: ContextNode, + analyzer: &impl GraphLike, + ) -> Result { + if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { + Ok(cvar.latest_version_less_than(idx, analyzer)) + } else { + Ok(*self) + } + } + + pub fn global_first_version(&self, analyzer: &impl GraphLike) -> Self { + let first = self.first_version(analyzer); + if let Some(inherited_from) = analyzer + .graph() + .edges_directed(first.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + { + inherited_from.global_first_version(analyzer) + } else if let Some(input_from) = analyzer + .graph() + .edges_directed(first.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + { + input_from.global_first_version(analyzer) + } else { + first + } + } + + pub fn first_version(&self, analyzer: &impl GraphLike) -> Self { + let mut earlier = *self; + while let Some(prev) = earlier.previous_version(analyzer) { + earlier = prev; + } + earlier + } + + pub fn num_versions(&self, analyzer: &impl GraphLike) -> usize { + let mut count = 1; + let mut earlier = self.latest_version(analyzer); + while let Some(prev) = earlier.previous_version(analyzer) { + earlier = prev; + count += 1; + } + count + } + + pub fn curr_version_num(&self, analyzer: &impl GraphLike) -> usize { + let mut count = 0; + let mut earlier = self.first_version(analyzer); + while let Some(next) = earlier.next_version(analyzer) { + if next == *self { + break; + } + earlier = next; + count += 1; + } + count + } + + pub fn global_curr_version_num(&self, analyzer: &impl GraphLike) -> usize { + let mut curr_num = self.curr_version_num(analyzer); + if let Some(inherited_from) = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + { + curr_num += inherited_from.global_curr_version_num(analyzer); + } else if let Some(input_from) = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + { + curr_num += input_from.global_curr_version_num(analyzer); + } + curr_num + } + + pub fn all_versions(&self, analyzer: &impl GraphLike) -> Vec { + let mut versions = vec![]; + let mut earlier = self.latest_version(analyzer); + while let Some(prev) = earlier.previous_version(analyzer) { + versions.push(prev); + earlier = prev; + } + versions + } + + pub fn next_version(&self, analyzer: &impl GraphLike) -> Option { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| Edge::Context(ContextEdge::Prev) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.source())) + .take(1) + .next() + } + + pub fn next_version_or_inheriteds(&self, analyzer: &impl GraphLike) -> Vec { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| { + Edge::Context(ContextEdge::Prev) == *edge.weight() + || Edge::Context(ContextEdge::InheritedVariable) == *edge.weight() + }) + .map(|edge| ContextVarNode::from(edge.source())) + .collect() + } + + pub fn other_is_version(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + self.all_versions(analyzer).contains(other) + } + + pub fn previous_version(&self, analyzer: &impl GraphLike) -> Option { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::Prev) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + } + + pub fn previous_or_inherited_version(&self, analyzer: &impl GraphLike) -> Option { + if let Some(prev) = self.previous_version(analyzer) { + Some(prev) + } else { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + } + } +} + diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs new file mode 100644 index 00000000..6a0f951f --- /dev/null +++ b/crates/graph/src/nodes/context/variables.rs @@ -0,0 +1,258 @@ + + +impl ContextNode { + /// Add a variable to this context + pub fn add_var( + &self, + var: ContextVarNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let name = var.name(analyzer)?; + let vars = &mut self.underlying_mut(analyzer)?.cache.vars; + vars.insert(name, var); + Ok(()) + } + + /// Gets a variable by name in the context + pub fn var_by_name(&self, analyzer: &impl GraphLike, name: &str) -> Option { + self.underlying(analyzer) + .unwrap() + .cache + .vars + .get(name) + .copied() + } + + pub fn var_by_name_or_recurse( + &self, + analyzer: &impl GraphLike, + name: &str, + ) -> Result, GraphError> { + if let Some(var) = self.var_by_name(analyzer, name) { + Ok(Some(var)) + } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { + parent.var_by_name_or_recurse(analyzer, name) + } else { + Ok(None) + } + } + + /// Gets all variables associated with a context + pub fn vars<'a>(&self, analyzer: &'a impl GraphLike) -> &'a BTreeMap { + &self.underlying(analyzer).unwrap().cache.vars + } + + /// Gets all variables associated with a context + pub fn local_vars<'a>( + &self, + analyzer: &'a impl GraphLike, + ) -> &'a BTreeMap { + self.vars(analyzer) + } + + /// Gets the latest version of a variable associated with a context + pub fn latest_var_by_name( + &self, + analyzer: &impl GraphLike, + name: &str, + ) -> Option { + self.var_by_name(analyzer, name) + .map(|var| var.latest_version(analyzer)) + } + + /// Reads the current temporary counter and increments the counter + pub fn new_tmp( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + let context = self.underlying_mut(analyzer)?; + let ret = context.tmp_var_ctr; + context.tmp_var_ctr += 1; + Ok(ret) + } + + pub fn push_tmp_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + underlying_mut.tmp_expr.push(Some(expr_ret)); + Ok(()) + } + + pub fn append_tmp_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + match underlying_mut.tmp_expr.pop() { + Some(Some(s @ ExprRet::Single(_))) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(s @ ExprRet::SingleLiteral(_))) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(ExprRet::Multi(ref mut inner))) => { + inner.push(expr_ret); + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(inner.to_vec()))); + } + Some(Some(s @ ExprRet::Null)) => { + underlying_mut + .tmp_expr + .push(Some(ExprRet::Multi(vec![s, expr_ret]))); + } + Some(Some(ExprRet::CtxKilled(kind))) => { + underlying_mut.tmp_expr = vec![Some(ExprRet::CtxKilled(kind))]; + underlying_mut.expr_ret_stack = vec![ExprRet::CtxKilled(kind)]; + } + _ => { + underlying_mut.tmp_expr.push(Some(expr_ret)); + } + } + Ok(()) + } + + pub fn pop_tmp_expr( + &self, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { + Ok(Some(self.maybe_move_expr(expr, loc, analyzer)?)) + } else { + Ok(None) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn push_expr( + &self, + expr_ret: ExprRet, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + tracing::trace!( + "pushing: {}, existing: {:?}, path: {}", + expr_ret.debug_str(analyzer), + self.underlying(analyzer)? + .expr_ret_stack + .iter() + .map(|i| i.debug_str(analyzer)) + .collect::>(), + self.path(analyzer) + ); + let underlying_mut = self.underlying_mut(analyzer)?; + underlying_mut.expr_ret_stack.push(expr_ret); + Ok(()) + } + + pub fn maybe_move_expr( + &self, + expr: ExprRet, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + match expr { + ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( + self.maybe_move_var(var.into(), loc, analyzer)?.into(), + )), + ExprRet::Single(var) => Ok(ExprRet::Single( + self.maybe_move_var(var.into(), loc, analyzer)?.into(), + )), + ExprRet::Multi(inner) => Ok(ExprRet::Multi( + inner + .iter() + .map(|i| self.maybe_move_expr(i.clone(), loc, analyzer)) + .collect::>()?, + )), + e => Ok(e), + } + } + + pub fn maybe_move_var( + &self, + var: ContextVarNode, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(ctx) = var.maybe_ctx(analyzer) { + if ctx != *self { + let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); + new_cvar.loc = Some(loc); + + let new_cvarnode = analyzer.add_node(Node::ContextVar(new_cvar)); + analyzer.add_edge(new_cvarnode, *self, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge( + new_cvarnode, + var.0, + Edge::Context(ContextEdge::InheritedVariable), + ); + Ok(new_cvarnode.into()) + } else { + Ok(var) + } + } else { + Ok(var) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn pop_expr( + &self, + _loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + tracing::trace!("popping var from: {}", self.path(analyzer)); + let underlying_mut = self.underlying_mut(analyzer)?; + + let new: Vec = Vec::with_capacity(5); + + let old = std::mem::replace(&mut underlying_mut.expr_ret_stack, new); + if old.is_empty() { + Ok(None) + } else { + Ok(Some(ExprRet::Multi(old))) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn pop_expr_latest( + &self, + loc: Loc, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result, GraphError> { + let underlying_mut = self.underlying_mut(analyzer)?; + if let Some(elem) = underlying_mut.expr_ret_stack.pop() { + tracing::trace!( + "popping var {} from: {}", + elem.debug_str(analyzer), + self.path(analyzer) + ); + Ok(Some(self.maybe_move_expr(elem, loc, analyzer)?)) + } else { + Ok(None) + } + } + + pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + self.local_vars(analyzer) + .iter() + .flat_map(|(_name, var)| var.return_assignments(analyzer)) + .collect() + } + + pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + self.local_vars(analyzer) + .iter() + .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) + .collect() + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs new file mode 100644 index 00000000..9fcbedec --- /dev/null +++ b/crates/graph/src/nodes/context/versioning.rs @@ -0,0 +1,419 @@ + + +impl ContextNode { + /// Query whether this context has a parent + pub fn has_parent(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.parent_ctx.is_some()) + } + + pub fn first_ancestor( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result { + if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { + Ok(first_ancestor) + } else if let Some(parent) = self.underlying(analyzer)?.parent_ctx { + let first = parent.first_ancestor(analyzer)?; + self.underlying_mut(analyzer)?.cache.first_ancestor = Some(first); + Ok(first) + } else { + Ok(*self) + } + } + + /// Gets the subcontexts of this context + pub fn subcontexts(&self, analyzer: &impl GraphLike) -> Vec { + let underlying = self.underlying(analyzer).unwrap(); + match underlying.child { + Some(CallFork::Call(c)) => vec![c], + Some(CallFork::Fork(w1, w2)) => vec![w1, w2], + None => vec![], + } + } + + /// Get the first ancestor context that is in the same function + pub fn ancestor_in_fn( + &self, + analyzer: &impl GraphLike, + associated_fn: FunctionNode, + ) -> Result, GraphError> { + if let Some(ret) = self.underlying(analyzer)?.returning_ctx { + if ret.associated_fn(analyzer)? == associated_fn { + return Ok(Some(ret)); + } + } + + if let Some(parent) = self.underlying(analyzer)?.parent_ctx { + if parent.associated_fn(analyzer)? == associated_fn { + Ok(Some(parent)) + } else if let Some(mod_state) = &parent.underlying(analyzer)?.modifier_state { + if mod_state.parent_fn == associated_fn { + Ok(Some(parent)) + } else { + parent.ancestor_in_fn(analyzer, associated_fn) + } + } else { + parent.ancestor_in_fn(analyzer, associated_fn) + } + } else { + Ok(None) + } + } + + /// Returns all forks associated with the context + pub fn calls(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let descendents = self.descendents(analyzer)?; + Ok(descendents + .into_iter() + .filter_map(|c| c.maybe_call()) + .collect()) + } + + /// Returns tail contexts associated with the context + pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.live_edges(analyzer)?; + if call_edges.is_empty() && !call.is_ended(analyzer)? { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.live_edges(analyzer)?; + if fork_edges.is_empty() && !w1.is_ended(analyzer)? { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.live_edges(analyzer)?; + if fork_edges.is_empty() && !w2.is_ended(analyzer)? { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.reverted_edges(analyzer)?; + if call_edges.is_empty() && call.is_killed(analyzer)? { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.reverted_edges(analyzer)?; + if fork_edges.is_empty() && w1.is_killed(analyzer)? { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.reverted_edges(analyzer)?; + if fork_edges.is_empty() && w2.is_killed(analyzer)? { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn successful_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.successful_edges(analyzer)?; + if call_edges.is_empty() && !call.is_killed(analyzer)? { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.successful_edges(analyzer)?; + if fork_edges.is_empty() && !w1.is_killed(analyzer)? { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.successful_edges(analyzer)?; + if fork_edges.is_empty() && !w2.is_killed(analyzer)? { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { + Ok(self.underlying(analyzer)?.number_of_live_edges) + } + + /// Returns tail contexts associated with the context + pub fn all_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut lineage = vec![]; + match child { + CallFork::Call(call) => { + let call_edges = call.all_edges(analyzer)?; + if call_edges.is_empty() { + lineage.push(call) + } else { + lineage.extend(call_edges); + } + } + CallFork::Fork(w1, w2) => { + let fork_edges = w1.all_edges(analyzer)?; + if fork_edges.is_empty() { + lineage.push(w1) + } else { + lineage.extend(fork_edges); + } + + let fork_edges = w2.all_edges(analyzer)?; + if fork_edges.is_empty() { + lineage.push(w2) + } else { + lineage.extend(fork_edges); + } + } + } + Ok(lineage) + } else { + Ok(vec![]) + } + } + + pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + let mut descendents = vec![child]; + match child { + CallFork::Call(c) => descendents.extend(c.descendents(analyzer)?), + CallFork::Fork(w1, w2) => { + descendents.extend(w1.descendents(analyzer)?); + descendents.extend(w2.descendents(analyzer)?); + } + } + Ok(descendents) + } else { + Ok(vec![]) + } + } + + /// Adds a fork to the context + pub fn set_child_fork( + &self, + w1: ContextNode, + w2: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + assert!(matches!(analyzer.node(w1), Node::Context(_))); + assert!(matches!(analyzer.node(w2), Node::Context(_))); + assert!(*self != w1 && *self != w2, "Tried to set child to self"); + let context = self.underlying_mut(analyzer)?; + if !context.set_child_fork(w1, w2) { + let child_str = match context.child { + Some(CallFork::Fork(w1, w2)) => { + format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) + } + Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), + None => unreachable!(), + }; + Err(GraphError::ChildRedefinition(format!( + "This is a bug. Tried to redefine a child context, parent:\n{}, current child:\n{},\nnew child: Fork({}, {})", + self.path(analyzer), + child_str, + w1.path(analyzer), + w2.path(analyzer), + ))) + } else { + Ok(()) + } + } + + /// Adds a child to the context + pub fn set_child_call( + &self, + call: ContextNode, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + assert!(matches!(analyzer.node(call), Node::Context(_))); + assert!(*self != call, "Tried to set child to self"); + let context = self.underlying_mut(analyzer)?; + if !context.set_child_call(call) { + let child_str = match context.child { + Some(CallFork::Fork(w1, w2)) => { + format!("fork {{ {}, {} }}", w1.path(analyzer), w2.path(analyzer)) + } + Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), + None => unreachable!(), + }; + tracing::trace!("Error setting child as a call"); + Err(GraphError::ChildRedefinition(format!( + "This is a bug. Tried to redefine a child context, parent: {}, current child: {}, new child: {}", + self.path(analyzer), + child_str, + call.path(analyzer) + ) + )) + } else { + Ok(()) + } + } + + pub fn delete_child( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + ) -> Result<(), GraphError> { + if let Some(child) = self.underlying(analyzer)?.child { + match child { + CallFork::Fork(w1, w2) => { + w1.propogate_end(analyzer)?; + w2.propogate_end(analyzer)?; + } + CallFork::Call(c) => { + c.propogate_end(analyzer)?; + } + } + } + let context = self.underlying_mut(analyzer)?; + context.delete_child(); + Ok(()) + } + + /// Kills the context by denoting it as killed. Recurses up the contexts and kills + /// parent contexts if all subcontexts of that context are killed + pub fn kill( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + kill_loc: Loc, + kill_kind: KilledKind, + ) -> Result<(), GraphError> { + tracing::trace!("killing: {}", self.path(analyzer)); + if let Some(child) = self.underlying(analyzer)?.child { + match child { + CallFork::Call(call) => { + if !call.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + call.kill(analyzer, kill_loc, kill_kind)?; + } + CallFork::Fork(w1, w2) => { + if !w1.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + + if !w2.underlying(analyzer)?.ret.is_empty() { + return Ok(()); + } + + w1.kill(analyzer, kill_loc, kill_kind)?; + w2.kill(analyzer, kill_loc, kill_kind)?; + } + } + } + + let context = self.underlying_mut(analyzer)?; + let parent = context.parent_ctx; + if context.killed.is_none() { + context.killed = Some((kill_loc, kill_kind)); + } + + if let Some(parent_ctx) = parent { + parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; + } + + self.propogate_end(analyzer)?; + + Ok(()) + } + + /// Kills if and only if all subcontexts are killed + pub fn end_if_all_forks_ended( + &self, + analyzer: &mut (impl GraphLike + AnalyzerLike), + kill_loc: Loc, + kill_kind: KilledKind, + ) -> Result<(), GraphError> { + let all_edges = self.all_edges(analyzer)?; + let reverted_edges = self.reverted_edges(analyzer)?; + if reverted_edges.len() == all_edges.len() { + tracing::trace!("killing recursively: {}", self.path(analyzer)); + let context = self.underlying_mut(analyzer)?; + if context.ret.is_empty() { + if context.killed.is_none() { + context.killed = Some((kill_loc, kill_kind)); + } + if let Some(parent_ctx) = context.parent_ctx { + parent_ctx.end_if_all_forks_ended(analyzer, kill_loc, kill_kind)?; + } + } + } + Ok(()) + } + + /// Gets parent list + pub fn parent_list(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + let context = self.underlying(analyzer)?; + let mut parents = vec![]; + if let Some(parent_ctx) = context.parent_ctx { + parents.push(parent_ctx); + parents.extend(parent_ctx.parent_list(analyzer)?); + } + Ok(parents) + } + + pub fn recursive_calls( + &self, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + // Ok( + let calls = self.calls(analyzer)?; + Ok(calls + .iter() + .flat_map(|call| { + let mut inner_calls = call.recursive_calls(analyzer).unwrap(); + inner_calls.insert(0, *call); + inner_calls + }) + .collect::>()) + } + + /// Gets the lineage for a context + /// A lineage is of the form `[ancestor N, .. , ancestor0, SELF, call0, .., call N]`. It + /// gives the user a full picture of control flow + pub fn lineage( + &self, + _analyzer: &impl GraphLike, + _entry: bool, + ) -> Result, GraphError> { + todo!() + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index e9654238..6fdd4ebb 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -7,6 +7,7 @@ use crate::FunctionNode; use crate::Node; use crate::NodeIdx; use crate::StructNode; +use crate::VarNode; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{ContractDefinition, ContractTy, Identifier, Loc}; use std::collections::BTreeMap; @@ -127,6 +128,26 @@ impl ContractNode { .collect() } + /// Gets all associated storage vars from the underlying node data for the [`Contract`] + pub fn direct_storage_vars(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + analyzer + .search_children_depth(self.0.into(), &Edge::Var, 1, 0) + .into_iter() + .map(VarNode::from) + .collect() + } + + /// Gets all associated storage vars from the underlying node data for the [`Contract`] + pub fn all_storage_vars(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + let mut ret = self + .all_inherited_contracts(analyzer) + .iter() + .flat_map(|contract| contract.direct_storage_vars(analyzer)) + .collect::>(); + ret.extend(self.direct_storage_vars(analyzer)); + ret + } + pub fn funcs_mapping( &self, analyzer: &(impl GraphLike + Search + AnalyzerLike), @@ -228,7 +249,7 @@ impl Contract { pub fn from_w_imports( con: ContractDefinition, source: NodeIdx, - imports: &[(Option, String, String, usize)], + imports: &[Option], analyzer: &impl GraphLike, ) -> (Contract, Vec) { let mut inherits = vec![]; @@ -249,7 +270,7 @@ impl Contract { } if !found { - for entry in imports.iter().filter_map(|import| import.0) { + for entry in imports.iter().filter_map(|&import| import) { for contract in analyzer .search_children_exclude_via(entry, &Edge::Contract, &[Edge::Func]) .into_iter() diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index c15d1285..704d1212 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,5 +1,8 @@ use crate::analyzer::Search; use crate::nodes::GraphError; +use crate::ContextEdge; + +use crate::ContextVarNode; use crate::ContractNode; use crate::VarType; @@ -143,6 +146,20 @@ impl VarNode { } Ok(None) } + + pub fn inherited_into(&self, analyzer: &impl GraphLike) -> Vec { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .filter(|edge| { + matches!( + *edge.weight(), + Edge::Context(ContextEdge::InheritedStorageVariable) + ) + }) + .map(|edge| ContextVarNode::from(edge.source())) + .collect() + } } impl AsDotStr for VarNode { diff --git a/crates/queries/Cargo.toml b/crates/queries/Cargo.toml new file mode 100644 index 00000000..e69de29b diff --git a/crates/queries/mod.rs b/crates/queries/lib.rs similarity index 100% rename from crates/queries/mod.rs rename to crates/queries/lib.rs diff --git a/crates/range/src/mod.rs b/crates/range/src/lib.rs similarity index 100% rename from crates/range/src/mod.rs rename to crates/range/src/lib.rs diff --git a/crates/solvers/Cargo.toml b/crates/solvers/Cargo.toml new file mode 100644 index 00000000..7b409227 --- /dev/null +++ b/crates/solvers/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "solvers" +description = "SMT solvers" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +petgraph.workspace = true +graph.workspace = true +range.workspace = true +ethers-core.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true + +itertools = "0.12.0" diff --git a/crates/solvers/src/dl.rs b/crates/solvers/src/dl.rs new file mode 100644 index 00000000..428a99b8 --- /dev/null +++ b/crates/solvers/src/dl.rs @@ -0,0 +1,944 @@ +use petgraph::stable_graph::StableGraph; + +use crate::analyzer::GraphError; +use crate::range::elem::RangeElem; +use crate::range::elem::RangeOp; +use crate::range::elem_ty::Elem; +use crate::solvers::AtomOrPart; +use crate::solvers::Atomize; +use crate::solvers::OpType; +use crate::solvers::SolverAtom; +use crate::Concrete; +use crate::ContextVarNode; +use crate::GraphLike; +use ethers_core::types::I256; +use ethers_core::types::U256; +use itertools::Itertools; +use petgraph::graph::NodeIndex; +use petgraph::visit::EdgeRef; +use petgraph::visit::IntoNodeIdentifiers; +use petgraph::visit::NodeIndexable; +use petgraph::visit::VisitMap; +use petgraph::visit::Visitable; +use petgraph::Directed; +use std::collections::BTreeMap; + +pub type DLGraph = StableGraph; + +#[derive(Debug, Clone, Default)] +pub struct DLSolver { + constraints: Vec, + normalized_constraints: BTreeMap>>, + root_node: NodeIndex, + pub const_solves: SolveMap, + pub cached_dl_solves: Option, + pub graph: DLGraph, + pub graph_map: BTreeMap>, + pub var_to_atom_idx: BTreeMap>, +} + +impl PartialEq for DLSolver { + fn eq(&self, other: &Self) -> bool { + self.constraints() == other.constraints() + && self.graph_map == other.graph_map + && self.var_to_atom_idx == other.var_to_atom_idx + } +} + +impl Eq for DLSolver {} + +pub enum SolveStatus { + Unsat, + Sat { + const_solves: SolveMap, + dl_solves: SolveMap, + }, + Indeterminate { + const_solves: SolveMap, + }, +} + +pub type SolveMap = BTreeMap>; + +pub struct DLSolveResult { + pub status: SolveStatus, + pub added_atoms: Vec, + pub added_deps: Vec, +} + +impl DLSolver { + pub fn new(mut constraints: Vec) -> Self { + constraints.iter_mut().for_each(|c| { + c.update_max_ty(); + }); + let mut graph: DLGraph = Default::default(); + let root_node = graph.add_node(AtomOrPart::Part(Elem::Null)); + let mut s = Self { + constraints, + graph, + root_node, + ..Default::default() + }; + s.add_constraints(vec![]); + s + } + + pub fn constraints(&self) -> &[SolverAtom] { + &self.constraints + } + + pub fn add_constraint( + &mut self, + mut constraint: SolverAtom, + normalized_forms: Vec>, + ) { + if !self.constraints.contains(&constraint) { + constraint.update_max_ty(); + self.constraints.push(constraint.clone()); + self.normalized_constraints + .insert(constraint.clone(), normalized_forms); + self.cached_dl_solves = None; + } + } + + pub fn add_constraints( + &mut self, + constraints: Vec, + ) -> BTreeMap>> { + let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); + self.constraints.iter().for_each(|constraint| { + let deps = constraint.dependent_on(); + deps.into_iter().for_each(|dep| { + if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { + if constraint.ty == OpType::Const { + *entry = vec![constraint.clone()]; + } else if entry[0].ty != OpType::Const { + // Constant requirements always take precedent + entry.push(constraint.clone()); + } + } else { + dep_to_solve_ty.insert(dep, vec![constraint.clone()]); + } + }); + }); + + let constraints: Vec<_> = constraints + .iter() + .filter(|c| !self.constraints.contains(c)) + .collect(); + + constraints.iter().for_each(|constraint| { + let deps = constraint.dependent_on(); + deps.into_iter().for_each(|dep| { + if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { + if constraint.ty == OpType::Const { + *entry = vec![(*constraint).clone()]; + } else if entry[0].ty != OpType::Const { + // Constant requirements always take precedent + entry.push((*constraint).clone()); + } + } else { + dep_to_solve_ty.insert(dep, vec![(*constraint).clone()]); + } + }); + }); + + // filter out self equality + let non_self_equality: Vec<_> = dep_to_solve_ty + .iter() + .filter_map(|(dep, atoms)| { + if atoms.len() == 1 && atoms[0].op == RangeOp::Eq && atoms[0].lhs == atoms[0].rhs { + return None; + } + Some((*dep, atoms)) + }) + .collect(); + // solve constant deps + let const_solves = non_self_equality + .iter() + .filter_map(|(dep, atoms)| { + if atoms.len() == 1 && atoms[0].ty == OpType::Const { + if atoms[0].rhs.is_part() { + return Some((*dep, atoms[0].rhs.into_elem())); + } else { + return Some((*dep, atoms[0].lhs.into_elem())); + } + } + None + }) + .collect::>(); + self.const_solves = const_solves.clone(); + + // widdle down constraints based on if we constant solved them + let still_unknown_constraints: Vec<_> = self + .constraints + .clone() + .into_iter() + .filter(|constraint| { + let deps = constraint.dependent_on(); + !deps.iter().all(|dep| const_solves.contains_key(dep)) + }) + .collect(); + + if still_unknown_constraints.is_empty() { + return Default::default(); + } + + still_unknown_constraints + .into_iter() + .filter(|constraint| { + let deps = constraint.dependent_on(); + deps.iter().all(|dep| { + dep_to_solve_ty + .get(dep) + .unwrap() + .iter() + .all(|constraint| constraint.ty == OpType::DL) + }) + }) + .map(|constraint| (constraint.clone(), Self::dl_atom_normalize(constraint))) + .collect::>>>() + } + + pub fn dl_solvable_constraints(&self) -> Vec>> { + self.normalized_constraints.values().cloned().collect() + } + + pub fn solve_partial(&mut self, analyzer: &impl GraphLike) -> Result { + let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); + self.constraints.iter().for_each(|constraint| { + let deps = constraint.dependent_on(); + deps.into_iter().for_each(|dep| { + if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { + if constraint.ty == OpType::Const { + *entry = vec![constraint.clone()]; + } else if entry[0].ty != OpType::Const { + // Constant requirements always take precedent + entry.push(constraint.clone()); + } + } else { + dep_to_solve_ty.insert(dep, vec![constraint.clone()]); + } + }); + }); + + if let Some(_self_inequality) = dep_to_solve_ty.iter().find(|(_dep, atoms)| { + atoms.iter().any(|atom| { + atom.op == RangeOp::Neq + && atom.lhs == atom.rhs + && !atom.lhs.dependent_on().is_empty() + }) + }) { + return Ok(SolveStatus::Unsat); + } + + // filter out self equality + let non_self_equality: Vec<_> = dep_to_solve_ty + .iter() + .filter_map(|(dep, atoms)| { + if atoms.len() == 1 && atoms[0].op == RangeOp::Eq && atoms[0].lhs == atoms[0].rhs { + return None; + } + Some((*dep, atoms)) + }) + .collect(); + // solve constant deps + let const_solves = non_self_equality + .iter() + .filter_map(|(dep, atoms)| { + if atoms.len() == 1 && atoms[0].ty == OpType::Const { + if atoms[0].rhs.is_part() { + return Some((*dep, atoms[0].rhs.into_elem())); + } else { + return Some((*dep, atoms[0].lhs.into_elem())); + } + } + None + }) + .collect::>(); + + // println!("const solves: {const_solves:#?}"); + + // widdle down constraints based on if we constant solved them + let still_unknown_constraints: Vec<_> = self + .constraints + .clone() + .into_iter() + .filter(|constraint| { + let deps = constraint.dependent_on(); + !deps.iter().all(|dep| const_solves.contains_key(dep)) + }) + .collect(); + + if still_unknown_constraints.is_empty() { + // TODO: Check that the constraints still hold + return Ok(SolveStatus::Sat { + const_solves, + dl_solves: Default::default(), + }); + } + + let dl_solvable = self.dl_solvable_constraints(); + // constraints -> paths -> constraint + + let basic: Vec = dl_solvable + .iter() + .filter_map(|c| if c.len() == 1 { Some(c.clone()) } else { None }) + .flatten() + .flatten() + .collect(); + + // check if basics are unsat, if so the extra constraints wont help that + // so its truly unsat + let basic_solve = self.dl_solve(basic.clone(), analyzer)?; + if matches!(basic_solve.status, SolveStatus::Unsat) { + return Ok(SolveStatus::Unsat); + } + + let multi: Vec<_> = dl_solvable + .iter() + .filter_map(|c| if c.len() > 1 { Some(c.clone()) } else { None }) + .collect(); + + if multi.is_empty() { + // we had no branches, just use the basic solve + return match basic_solve.status { + SolveStatus::Unsat => Ok(SolveStatus::Unsat), + SolveStatus::Sat { dl_solves, .. } => Ok(SolveStatus::Sat { + const_solves, + dl_solves, + }), + SolveStatus::Indeterminate { .. } => { + Ok(SolveStatus::Indeterminate { const_solves }) + } + }; + } else if !basic.is_empty() { + let mut cnt = 0; + let mut unsat = 0; + for permutation in multi.iter().multi_cartesian_product() { + cnt += 1; + // flatten out the permutation + let mut flattened: Vec = permutation + .into_iter() + .flat_map(|constraint| constraint.clone()) + .collect(); + // add the constant paths + flattened.extend(basic.clone()); + let solve = self.dl_solve(flattened, analyzer)?; + // remove the added constraints, keeping the basic graph in tact + self.remove_added(&solve); + // now that we checked that + match solve.status { + SolveStatus::Sat { dl_solves, .. } => { + return Ok(SolveStatus::Sat { + const_solves, + dl_solves, + }); + } + SolveStatus::Unsat => { + unsat += 1; + continue; + } + SolveStatus::Indeterminate { .. } => continue, + } + } + + if cnt == unsat { + return Ok(SolveStatus::Unsat); + } + } + + Ok(SolveStatus::Indeterminate { const_solves }) + } + + pub fn remove_added(&mut self, result: &DLSolveResult) { + result.added_atoms.iter().for_each(|c| { + let idx = self.graph_map.remove(c).unwrap(); + self.graph.remove_node(idx); + }); + result.added_deps.iter().for_each(|dep| { + self.var_to_atom_idx.remove(dep); + }); + } + + pub fn dl_solve( + &mut self, + normalized_constraints: Vec, + analyzer: &impl GraphLike, + ) -> Result { + let mut added_atoms = vec![]; + let mut added_deps = vec![]; + if normalized_constraints.is_empty() { + return Ok(DLSolveResult { + status: SolveStatus::Indeterminate { + const_solves: Default::default(), + }, + added_atoms, + added_deps, + }); + } + let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); + let mut indeterminate = false; + normalized_constraints.iter().for_each(|constraint| { + let a = if let Some(idx) = self.graph_map.get(&constraint.lhs.clone()) { + *idx + } else { + let idx = self.graph.add_node(*constraint.lhs.clone()); + self.graph_map.insert(*constraint.lhs.clone(), idx); + added_atoms.push(*constraint.lhs.clone()); + idx + }; + + let rhs_atom = constraint.rhs.expect_atom(); + let rhs_lhs_deps = rhs_atom.lhs.dependent_on(); + let rhs_rhs_deps = rhs_atom.rhs.dependent_on(); + let ((dyn_elem, dep), const_elem) = + match (!rhs_lhs_deps.is_empty(), !rhs_rhs_deps.is_empty()) { + (true, true) => { + // panic!("here: {} {} {}", constraint.lhs.into_elem(), constraint.op.to_string(), rhs_atom.into_expr_elem()); + indeterminate = true; + return; + } + (true, false) => { + if matches!(rhs_atom.op, RangeOp::Sub(_)) { + let const_elem = (rhs_atom.rhs.into_elem() + * Elem::from(Concrete::from(I256::from(-1)))) + .maximize(analyzer) + .unwrap(); + ( + (rhs_atom.lhs, Some(rhs_lhs_deps[0])), + Box::new(AtomOrPart::Part(const_elem)), + ) + } else { + ((rhs_atom.lhs, Some(rhs_lhs_deps[0])), rhs_atom.rhs) + } + } + (false, true) => { + if matches!(rhs_atom.op, RangeOp::Sub(_)) { + let const_elem = (rhs_atom.lhs.into_elem() + * Elem::from(Concrete::from(I256::from(-1)))) + .maximize(analyzer) + .unwrap(); + ( + (rhs_atom.rhs, Some(rhs_rhs_deps[0])), + Box::new(AtomOrPart::Part(const_elem)), + ) + } else { + ((rhs_atom.rhs, Some(rhs_rhs_deps[0])), rhs_atom.lhs) + } + } + (false, false) => { + if *rhs_atom.rhs == zero_part { + ((rhs_atom.rhs, None), rhs_atom.lhs) + } else { + ((rhs_atom.lhs, None), rhs_atom.rhs) + } + } + }; + + let b = if let Some(idx) = self.graph_map.get(&dyn_elem) { + *idx + } else { + let idx = self.graph.add_node(*dyn_elem.clone()); + added_atoms.push(*dyn_elem.clone()); + self.graph_map.insert(*dyn_elem, idx); + if let Some(dep) = dep { + if self.var_to_atom_idx.get(&dep).is_none() { + added_deps.push(dep); + self.var_to_atom_idx.insert(dep, idx); + } + } + idx + }; + + self.graph.add_edge(a, b, *const_elem); + }); + + let root_node = self.root_node; + added_atoms.iter().for_each(|c| { + let idx = self.graph_map.get(c).unwrap(); + self.graph.add_edge( + root_node, + *idx, + AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))), + ); + }); + + if find_negative_cycle(&self.graph, root_node, analyzer).is_some() { + return Ok(DLSolveResult { + status: SolveStatus::Unsat, + added_atoms, + added_deps, + }); + } + + let (mut dists, _) = bellman_ford_initialize_relax(&self.graph, root_node, analyzer); + + dists = dists + .into_iter() + .map(|dist| { + (dist * Elem::from(Concrete::from(I256::from(-1)))) + .maximize(analyzer) + .unwrap() + }) + .collect(); + + let res = self + .var_to_atom_idx + .iter() + .map(|(dep, idx)| (*dep, dists[idx.index()].clone())) + .collect(); + + if indeterminate { + return Ok(DLSolveResult { + status: SolveStatus::Indeterminate { + const_solves: Default::default(), + }, + added_atoms, + added_deps, + }); + } + + Ok(DLSolveResult { + status: SolveStatus::Sat { + const_solves: Default::default(), + dl_solves: res, + }, + added_atoms, + added_deps, + }) + } + + /// Normalizes a DL atom into x <= y - k, where x and y are variables and k is a constant. + /// Needed for running negative cycle check. Additionally, if we have an `OR`, we + pub fn dl_atom_normalize(constraint: SolverAtom) -> Vec> { + // println!("normalizing: {}", constraint.into_expr_elem()); + let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); + let false_part = AtomOrPart::Part(Elem::from(Concrete::from(false))); + let true_part = AtomOrPart::Part(Elem::from(Concrete::from(true))); + + match ( + *constraint.lhs == true_part || *constraint.lhs == false_part, + *constraint.rhs == true_part || *constraint.rhs == false_part, + ) { + (true, true) => { + if constraint.lhs == constraint.rhs { + // true == true || false == false, just disregard this atom + return vec![vec![]]; + } else { + panic!("During normalization of a DL atom, got true == false"); + } + } + (true, false) => { + // lhs is just a boolean, drop it + return Self::dl_atom_normalize(constraint.rhs.as_solver_atom()); + } + (false, true) => { + // rhs is just a boolean, drop it + return Self::dl_atom_normalize(constraint.lhs.as_solver_atom()); + } + _ => {} + } + match constraint.op { + RangeOp::Eq => { + // convert `x == y` into `x <= y - 0 || y <= x - 0` + let mut res = Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs.clone(), + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs.clone(), + op: RangeOp::Sub(true), + rhs: Box::new(zero_part.clone()), + })), + }); + + assert!(res.len() == 1); + res[0].extend( + Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Sub(true), + rhs: Box::new(zero_part.clone()), + })), + }) + .remove(0), + ); + res + } + RangeOp::Neq => { + // convert `x != y` into `x <= y - 1 || y <= x - 1` + let mut res = Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs.clone(), + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs.clone(), + op: RangeOp::Sub(true), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::from(1))))), + })), + }); + + assert!(res.len() == 1); + + res[0].extend( + Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Sub(true), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + U256::from(1), + )))), + })), + }) + .remove(0), + ); + res + } + RangeOp::Lt => { + let lhs_symb = !constraint.lhs.dependent_on().is_empty(); + let rhs_symb = !constraint.rhs.dependent_on().is_empty(); + match (lhs_symb, rhs_symb) { + (true, true) => { + let new_lhs = AtomOrPart::Atom( + constraint + .lhs + .into_elem() + .wrapping_sub(constraint.rhs.into_elem()) + .atomize() + .expect("unable to atomize?"), + ); + Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + I256::from(-1), + )))), + }) + } + (true, false) => { + let new_lhs = AtomOrPart::Atom( + constraint + .lhs + .into_elem() + .wrapping_sub(Elem::from(Concrete::from(U256::zero()))) + .atomize() + .expect("unable to atomize?"), + ); + + Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: constraint.rhs, + }) + } + (false, true) => { + let new_lhs = AtomOrPart::Atom( + Elem::from(Concrete::from(U256::zero())) + .wrapping_sub(constraint.rhs.into_elem()) + .atomize() + .expect("unable to atomize?"), + ); + Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: constraint.lhs, + }) + } + _ => panic!("here"), + } + } + RangeOp::Lte => { + if constraint.lhs.is_atom() { + // some form of (x + k <= y) + let lhs_atom = constraint.lhs.expect_atom(); + let atom_lhs_is_symb = !lhs_atom.lhs.dependent_on().is_empty(); + let atom_rhs_is_symb = !lhs_atom.rhs.dependent_on().is_empty(); + + match lhs_atom.op { + RangeOp::Sub(_) => { + match (atom_lhs_is_symb, atom_rhs_is_symb) { + (false, _) => { + // (k - x <= y) + // ==> (-k + x >= y) + // ==> (y <= x - k) + Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: lhs_atom.rhs, + op: RangeOp::Sub(true), + rhs: Box::new(*lhs_atom.lhs), + })), + }) + } + _ => { + // (x - k <= y) + // ==> (x <= y + k) + Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Add(true), + rhs: Box::new(*lhs_atom.rhs), + })), + }) + } + } + } + RangeOp::Add(_) => { + // (k + x <= y) || (x + k <= y) + // ==> (x <= y - k) + Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: Box::new(*lhs_atom.rhs), + })), + }) + } + RangeOp::And => { + let mut res = Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: constraint.rhs.clone(), + }); + + let mut rhs = Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.rhs), + op: constraint.op, + rhs: constraint.rhs.clone(), + }); + match (res.len() > 1, rhs.len() > 1) { + (true, true) => { + res.extend(rhs); + res + } + (true, false) => { + res.iter_mut().for_each(|path| path.extend(rhs[0].clone())); + res + } + (false, true) => { + rhs.iter_mut().for_each(|path| path.extend(res[0].clone())); + rhs + } + (false, false) => { + res[0].extend(rhs.remove(0)); + res + } + } + } + // RangeOp::Eq => { + // // (atom.lhs == atom.rhs) <= rhs + // // try just swapping + // // rhs >= + // let new_lhs_atom = SolverAtom { + // ty: constraint.ty, + // lhs: lhs_atom.lhs, + // op: RangeOp::Sub(true), + // rhs: lhs_atom.rhs + // }; + // Self::dl_atom_normalize(SolverAtom { + // ty: constraint.ty, + // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), + // op: constraint.op, + // rhs: constraint.rhs.clone(), + // }) + // } + // RangeOp::Neq => { + // // (atom.lhs != atom.rhs) <= rhs + // // (atom.lhs - atom.rhs) <= rhs + // let new_lhs_atom = SolverAtom { + // ty: constraint.ty, + // lhs: lhs_atom.lhs, + // op: RangeOp::Sub(true), + // rhs: lhs_atom.rhs + // }; + // Self::dl_atom_normalize(SolverAtom { + // ty: constraint.ty, + // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), + // op: constraint.op, + // rhs: constraint.rhs.clone(), + // }) + // } + other => panic!("other op: {}, {constraint:#?}", other.to_string()), + } + } else if constraint.rhs.is_part() { + let new_rhs = AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), + }); + + Self::dl_atom_normalize(SolverAtom { + ty: constraint.ty, + lhs: constraint.lhs, + op: constraint.op, + rhs: Box::new(new_rhs), + }) + } else { + vec![vec![constraint]] + } + } + RangeOp::Gte => Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: constraint.lhs, + }), + RangeOp::Gt => Self::dl_atom_normalize(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lt, + rhs: constraint.lhs, + }), + RangeOp::Or => { + let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom()); + res.extend(Self::dl_atom_normalize(constraint.rhs.as_solver_atom())); + res + } + _other => { + // println!("other: {}, {}", other.to_string(), constraint.into_expr_elem()); + Self::dl_atom_normalize(constraint) + } + } + } +} + +pub fn find_negative_cycle( + g: &DLGraph, + source: NodeIndex, + analyzer: &impl GraphLike, +) -> Option>> { + let ix = |i| g.to_index(i); + let mut path = Vec::>::new(); + + // Step 1: initialize and relax + let (distance, predecessor) = bellman_ford_initialize_relax(g, source, analyzer); + + // Step 2: Check for negative weight cycle + 'outer: for i in g.node_identifiers() { + for edge in g.edges(i) { + let j = edge.target(); + let w = edge.weight(); + let dist = (distance[ix(i)].clone() + w.into_elem()) + .maximize(analyzer) + .unwrap(); + let lt = matches!( + dist.range_ord(&distance[ix(j)]), + Some(std::cmp::Ordering::Less) + ); + if lt { + // Step 3: negative cycle found + let start = j; + let mut node = start; + let mut visited = g.visit_map(); + // Go backward in the predecessor chain + loop { + let ancestor = match predecessor[ix(node)] { + Some(predecessor_node) => predecessor_node, + None => node, // no predecessor, self cycle + }; + // We have only 2 ways to find the cycle and break the loop: + // 1. start is reached + if ancestor == start { + path.push(ancestor); + break; + } + // 2. some node was reached twice + else if visited.is_visited(&ancestor) { + // Drop any node in path that is before the first ancestor + let pos = path + .iter() + .position(|&p| p == ancestor) + .expect("we should always have a position"); + path = path[pos..path.len()].to_vec(); + + break; + } + + // None of the above, some middle path node + path.push(ancestor); + visited.visit(ancestor); + node = ancestor; + } + // We are done here + break 'outer; + } + } + } + if !path.is_empty() { + // Users will probably need to follow the path of the negative cycle + // so it should be in the reverse order than it was found by the algorithm. + path.reverse(); + Some(path) + } else { + None + } +} + +// Perform Step 1 and Step 2 of the Bellman-Ford algorithm. +#[inline(always)] +fn bellman_ford_initialize_relax( + g: &DLGraph, + source: NodeIndex, + analyzer: &impl GraphLike, +) -> (Vec>, Vec>>) { + // Step 1: initialize graph + let mut predecessor = vec![None; g.node_bound()]; + let mut distance = vec![Elem::from(Concrete::from(U256::MAX)); g.node_bound()]; + let ix = |i| g.to_index(i); + distance[ix(source)] = Elem::from(Concrete::from(U256::zero())); + + // Step 2: relax edges repeatedly + for _ in 1..g.node_count() { + let mut did_update = false; + for i in g.node_identifiers() { + for edge in g.edges(i) { + let j = edge.target(); + let w = edge.weight(); + let dist = (distance[ix(i)].clone() + w.into_elem()) + .maximize(analyzer) + .unwrap(); + let lt = matches!( + dist.range_ord(&distance[ix(j)]), + Some(std::cmp::Ordering::Less) + ); + if lt { + distance[ix(j)] = dist; + predecessor[ix(j)] = Some(i); + did_update = true; + } + } + } + if !did_update { + break; + } + } + (distance, predecessor) +} \ No newline at end of file diff --git a/crates/solvers/src/lib.rs b/crates/solvers/src/lib.rs new file mode 100644 index 00000000..0f82879d --- /dev/null +++ b/crates/solvers/src/lib.rs @@ -0,0 +1,341 @@ +use crate::range::elem::RangeElem; +use crate::range::elem::RangeOp; +use crate::range::elem_ty::Dynamic; +use crate::range::elem_ty::Elem; +use crate::range::elem_ty::RangeExpr; +use crate::range::range_string::RangeElemString; +use crate::range::range_string::ToRangeString; +use crate::Concrete; +use crate::ContextVarNode; +use crate::GraphLike; +use ethers_core::types::U256; +use std::collections::BTreeMap; + +pub mod dl; + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum AtomOrPart { + Part(Elem), + Atom(SolverAtom), +} + +impl AtomOrPart { + pub fn into_elem(&self) -> Elem { + match self { + AtomOrPart::Part(part) => part.clone(), + AtomOrPart::Atom(atom) => atom.into_expr_elem(), + } + } + + pub fn as_solver_atom(&self) -> SolverAtom { + match self { + AtomOrPart::Part(_) => SolverAtom { + ty: OpType::DL, + lhs: Box::new(self.clone()), + op: RangeOp::Sub(false), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), + }, + AtomOrPart::Atom(atom) => atom.clone(), + } + } + + pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + match self { + AtomOrPart::Part(part) => { + let mut new_part = part.clone(); + solves.iter().for_each(|(dep, replacement)| { + new_part.replace_dep(dep.0.into(), replacement.clone()) + }); + AtomOrPart::Part(new_part) + } + AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves)), + } + } + + pub fn maybe_max_ty(&self) -> Option { + match self { + AtomOrPart::Part(_part) => None, + AtomOrPart::Atom(atom) => Some(atom.max_ty()), + } + } + + pub fn is_part(&self) -> bool { + if let AtomOrPart::Part(_) = self { + true + } else { + false + } + } + + pub fn is_atom(&self) -> bool { + if let AtomOrPart::Atom(_) = self { + true + } else { + false + } + } + + pub fn expect_atom(&self) -> SolverAtom { + if let AtomOrPart::Atom(atom) = self { + atom.clone() + } else { + panic!("Expected atom, was part: {self:?}") + } + } + + pub fn dependent_on(&self) -> Vec { + match self { + AtomOrPart::Part(e) => e.dependent_on(), + AtomOrPart::Atom(a) => a.dependent_on(), + } + } +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum OpType { + Const, + DL, + Linear, + Other, +} + +impl OpType { + pub fn new(op: RangeOp) -> Self { + if LIA_OPS.contains(&op) { + OpType::Linear + } else if DL_OPS.contains(&op) { + OpType::DL + } else if CONST_OPS.contains(&op) { + OpType::Const + } else { + OpType::Other + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct SolverAtom { + pub ty: OpType, + pub lhs: Box, + pub op: RangeOp, + pub rhs: Box, +} + +impl ToRangeString for SolverAtom { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + self.into_expr_elem().def_string(analyzer) + } + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + self.into_expr_elem().to_range_string(maximize, analyzer) + } +} + +impl SolverAtom { + pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + SolverAtom { + ty: self.ty, + lhs: Box::new(self.lhs.clone().replace_deps(solves)), + op: self.op, + rhs: Box::new(self.rhs.clone().replace_deps(solves)), + } + } + + pub fn max_ty(&self) -> OpType { + let mut max = OpType::new(self.op); + if let Some(lhs_max_ty) = self.lhs.maybe_max_ty() { + if lhs_max_ty > max { + max = lhs_max_ty; + } + } + if let Some(rhs_max_ty) = self.rhs.maybe_max_ty() { + if rhs_max_ty > max { + max = rhs_max_ty; + } + } + max + } + + pub fn update_max_ty(&mut self) { + self.ty = self.max_ty(); + } + + pub fn dependent_on(&self) -> Vec { + let mut deps = self.lhs.dependent_on(); + deps.extend(self.rhs.dependent_on()); + deps + } + + pub fn into_expr_elem(&self) -> Elem { + Elem::Expr(RangeExpr::new( + self.lhs.into_elem(), + self.op, + self.rhs.into_elem(), + )) + } + + pub fn add_rhs(&self, op: RangeOp, rhs: AtomOrPart) -> Self { + let new_ty = OpType::new(op); + if self.ty >= new_ty { + // keep ty + Self { + ty: self.ty, + lhs: Box::new(AtomOrPart::Atom(self.clone())), + op, + rhs: Box::new(rhs), + } + } else { + Self { + ty: new_ty, + lhs: Box::new(AtomOrPart::Atom(self.clone())), + op, + rhs: Box::new(rhs), + } + } + } + + pub fn add_lhs(&self, op: RangeOp, lhs: AtomOrPart) -> Self { + let new_ty = OpType::new(op); + + if self.ty >= new_ty { + // keep ty + Self { + ty: self.ty, + lhs: Box::new(lhs), + op, + rhs: Box::new(AtomOrPart::Atom(self.clone())), + } + } else { + Self { + ty: new_ty, + lhs: Box::new(lhs), + op, + rhs: Box::new(AtomOrPart::Atom(self.clone())), + } + } + } +} + +pub static CONST_OPS: &[RangeOp] = &[RangeOp::Eq]; +pub static DL_OPS: &[RangeOp] = &[ + RangeOp::Neq, + RangeOp::Add(true), + RangeOp::Add(false), + RangeOp::Sub(true), + RangeOp::Sub(false), + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::And, + RangeOp::Or, +]; +pub static LIA_OPS: &[RangeOp] = &[ + RangeOp::Mul(true), + RangeOp::Mul(false), + RangeOp::Div(true), + RangeOp::Div(false), + RangeOp::Mod, + RangeOp::Exp, +]; + +pub trait Atomize { + fn atoms_or_part(&self) -> AtomOrPart; + fn atomize(&self) -> Option; +} + +impl Atomize for Elem { + fn atoms_or_part(&self) -> AtomOrPart { + match self { + Elem::Concrete(_) | Elem::Dynamic(_) => AtomOrPart::Part(self.clone()), + Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), + Elem::Expr(expr) => { + // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); + match (expr.lhs.atoms_or_part(), expr.rhs.atoms_or_part()) { + (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { + match (l, r) { + (Elem::Dynamic(Dynamic { .. }), Elem::Concrete(_)) + | (Elem::Concrete(_), Elem::Dynamic(Dynamic { .. })) => { + let ty = OpType::new(expr.op); + let atom = SolverAtom { + ty, + lhs: Box::new(lp.clone()), + op: expr.op, + rhs: Box::new(rp.clone()), + }; + AtomOrPart::Atom(atom) + } + (Elem::Dynamic(Dynamic { .. }), Elem::Dynamic(Dynamic { .. })) => { + let ty = if DL_OPS.contains(&expr.op) { + OpType::DL + } else if CONST_OPS.contains(&expr.op) { + OpType::Const + } else { + OpType::Other + }; + let atom = SolverAtom { + ty, + lhs: Box::new(lp.clone()), + op: expr.op, + rhs: Box::new(rp.clone()), + }; + AtomOrPart::Atom(atom) + } + (Elem::Expr(_), Elem::Expr(_)) => { + todo!("here"); + } + (Elem::Expr(_), Elem::Dynamic(Dynamic { .. })) => { + todo!("here1"); + } + (Elem::Dynamic(Dynamic { .. }), Elem::Expr(_)) => { + todo!("here2"); + } + (Elem::Expr(_), Elem::Concrete(_)) => { + todo!("here3"); + } + (Elem::Concrete(_), Elem::Expr(_)) => { + todo!("here4"); + } + (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => { + todo!("Should have simplified? {l} {r}") + } + (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), + (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), + (Elem::Null, _) => AtomOrPart::Part(Elem::Null), + (_, Elem::Null) => AtomOrPart::Part(Elem::Null), + } + } + (AtomOrPart::Atom(l_atom), r @ AtomOrPart::Part(_)) => { + AtomOrPart::Atom(l_atom.add_rhs(expr.op, r)) + } + (l @ AtomOrPart::Part(_), AtomOrPart::Atom(r_atom)) => { + AtomOrPart::Atom(r_atom.add_lhs(expr.op, l)) + } + (AtomOrPart::Atom(l_atoms), AtomOrPart::Atom(r_atoms)) => { + AtomOrPart::Atom(r_atoms.add_lhs(expr.op, AtomOrPart::Atom(l_atoms))) + } + } + } + Elem::Null => AtomOrPart::Part(self.clone()), + } + } + + fn atomize(&self) -> Option { + use Elem::*; + + match self { + Dynamic(_) => None, //{ println!("was dyn"); None}, + Null => None, //{ println!("was null"); None}, + Concrete(_c) => None, //{ println!("was conc: {}", c.val.as_human_string()); None }, + ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, + Expr(_) => { + // println!("atomized: was expr"); + let AtomOrPart::Atom(mut a) = self.atoms_or_part() else { + return None; + }; + a.update_max_ty(); + Some(a) + } + } + } +} From 4c4392e734a67bb7ddaa5312d2d9a96e8e2378cd Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 16:03:36 -0800 Subject: [PATCH 08/71] docs --- crates/graph/src/nodes/builtin.rs | 43 ++++ crates/graph/src/nodes/concrete.rs | 21 +- crates/graph/src/nodes/context/expr_ret.rs | 4 + crates/graph/src/nodes/context/node.rs | 127 +--------- crates/graph/src/nodes/context/querying.rs | 2 + crates/graph/src/nodes/context/solving.rs | 246 ++++++++++--------- crates/graph/src/nodes/context/typing.rs | 3 + crates/graph/src/nodes/context/underlying.rs | 8 +- crates/graph/src/nodes/context/variables.rs | 30 +-- crates/graph/src/nodes/context/versioning.rs | 7 + 10 files changed, 222 insertions(+), 269 deletions(-) diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 78d24d1d..722d5e61 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -1,7 +1,9 @@ +/// A builtin node #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct BuiltInNode(pub usize); impl BuiltInNode { + /// Gets the underlying builtin from the graph pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Builtin, GraphError> { match analyzer.node(*self) { Node::Builtin(b) => Ok(b), @@ -11,11 +13,13 @@ impl BuiltInNode { } } + /// Gets the size of the builtin pub fn num_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; Ok(underlying.num_size()) } + /// Checks if this builtin is implicitly castable to another builtin pub fn implicitly_castable_to( &self, other: &Self, @@ -26,6 +30,7 @@ impl BuiltInNode { .implicitly_castable_to(other.underlying(analyzer)?)) } + /// Gets the maximum size version of this builtin, i.e. uint16 -> uint256 pub fn max_size( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -34,6 +39,7 @@ impl BuiltInNode { Ok(analyzer.builtin_or_add(m).into()) } + /// Gets the underlying type of the dynamic builtin backing it. i.e. uint256[] -> uint256 pub fn dynamic_underlying_ty( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -57,10 +63,12 @@ impl BuiltInNode { } } + /// Returns whether the builtin is a mapping pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { Ok(matches!(self.underlying(analyzer)?, Builtin::Mapping(_, _))) } + /// Returns whether the builtin is a sized array pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { Ok(matches!( self.underlying(analyzer)?, @@ -68,6 +76,7 @@ impl BuiltInNode { )) } + /// Returns whether the builtin is a sized array or bytes pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { match self.underlying(analyzer)? { Builtin::SizedArray(s, _) => Ok(Some(*s)), @@ -76,14 +85,17 @@ impl BuiltInNode { } } + /// Returns whether the builtin is a dynamic type pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.is_dyn()) } + /// Returns whether the builtin is indexable pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.is_indexable()) } + /// Returns the zero range for this builtin type, i.e. uint256 -> [0, 0] pub fn zero_range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { Ok(self.underlying(analyzer)?.zero_range()) } @@ -101,25 +113,42 @@ impl From for NodeIdx { } } +/// A fundamental builtin type #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum Builtin { + /// An address Address, + /// A payable address AddressPayable, + /// A payable address, differentiated in Solang so we differentiate Payable, + /// A boolean Bool, + /// A string - TODO: we should represent this as bytes internally String, + /// A signed integer that has a size Int(u16), + /// An unsigned integer that has a size Uint(u16), + /// A bytes that has a size, i.e. bytes8 Bytes(u8), + /// A rational. Rarely used in practice Rational, + /// A byte array, i.e. bytes DynamicBytes, + /// An array that has an internal type, i.e. uint256[] Array(VarType), + /// An array that has an internal type and is sized, i.e. uint256[5] SizedArray(U256, VarType), + /// A mapping, i.e. `mapping (address => uint)` Mapping(VarType, VarType), + /// A function pointer that takes a vector of types and returns a vector of types Func(Vec, Vec), } impl Builtin { + /// Resolves the `VarType` in dynamic builtins due to parse order - i.e. we could + /// `mapping (uint => MyType)`, we may not have parsed `MyType`, so we now try to resolve it pub fn unresolved_as_resolved( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -137,6 +166,8 @@ impl Builtin { } } + /// Possible types that this type could have been had a literal been parsed differently - i.e. a `1` + /// could be uint8 to uint256. pub fn possible_builtins_from_ty_inf(&self) -> Vec { let mut builtins = vec![]; match self { @@ -166,6 +197,7 @@ impl Builtin { builtins } + /// Construct a [`SolcRange`] that is zero pub fn zero_range(&self) -> Option { match self { Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { @@ -200,6 +232,8 @@ impl Builtin { Builtin::Rational | Builtin::Func(_, _) => None, } } + + /// Try to convert from a [`Type`] to a Builtin pub fn try_from_ty( ty: Type, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -257,6 +291,7 @@ impl Builtin { } } + /// Returns whether the builtin is dynamic pub fn is_dyn(&self) -> bool { matches!( self, @@ -268,6 +303,7 @@ impl Builtin { ) } + /// Returns whether the builtin requires input to perform an operation on (like addition) pub fn requires_input(&self) -> bool { matches!( self, @@ -275,6 +311,7 @@ impl Builtin { ) } + /// Returns the size of the integer if it is an integer (signed or unsigned) pub fn num_size(&self) -> Option { match self { Builtin::Uint(size) => Some(*size), @@ -283,10 +320,12 @@ impl Builtin { } } + /// Returns whether the builtin is a signed integer pub fn is_int(&self) -> bool { matches!(self, Builtin::Int(_)) } + /// Returns whether the builtin is indexable (bytes, array[], array[5], mapping(..), bytes32, string) pub fn is_indexable(&self) -> bool { matches!( self, @@ -299,6 +338,7 @@ impl Builtin { ) } + /// Checks if self is implicitly castable to another builtin pub fn implicitly_castable_to(&self, other: &Self) -> bool { use Builtin::*; match (self, other) { @@ -322,6 +362,7 @@ impl Builtin { } } + /// Returns the max size version of this builtin pub fn max_size(&self) -> Self { use Builtin::*; match self { @@ -332,6 +373,7 @@ impl Builtin { } } + /// Converts the builtin to a string pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { use Builtin::*; match self { @@ -377,6 +419,7 @@ impl Builtin { } } + /// Converts the builtin to a string if it is not dynamic pub fn basic_as_string(&self) -> String { use Builtin::*; match self { diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 65004c19..2c55c41b 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -20,6 +20,7 @@ impl ConcreteNode { } } + /// Creates a version of this concrete that is max size pub fn max_size( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -28,6 +29,7 @@ impl ConcreteNode { Ok(analyzer.add_node(Node::Concrete(c)).into()) } + /// Gets the internal type of the dynamic that backs this. Panics if this is not a dynamic concrete pub fn dynamic_underlying_ty( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -38,18 +40,22 @@ impl ConcreteNode { Ok(v_ty) } + /// Returns whether this is a dynamic concrete pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.is_dyn()) } + /// Returns whether this is a concrete sized array pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.is_sized_array()) } + /// Returns the size of the array size if it is an array-like concrete pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { Ok(self.underlying(analyzer)?.maybe_array_size()) } + /// Returns whether this concrete is indexable pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.is_indexable()) } @@ -67,12 +73,6 @@ impl From for NodeIdx { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub enum DynCapacity { - Cap(U256), - Unlimited, -} - /// EVM/Solidity basic concrete types #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Concrete { @@ -153,6 +153,7 @@ impl> From> for Concrete { } impl Concrete { + /// Returns whether this concrete is a dynamic type pub fn is_dyn(&self) -> bool { matches!( self, @@ -160,10 +161,12 @@ impl Concrete { ) } + /// Returns whether this concrete is a sized array pub fn is_sized_array(&self) -> bool { matches!(self, Concrete::DynBytes(..) | Concrete::Array(..)) } + /// Returns the internal type of this dynamic concrete pub fn dynamic_underlying_ty(&self) -> Option { match self { Concrete::DynBytes(_v) => Some(Builtin::Bytes(1)), @@ -174,6 +177,7 @@ impl Concrete { } } + /// Returns the length of the array if it is an array pub fn maybe_array_size(&self) -> Option { match self { Concrete::DynBytes(v) => Some(U256::from(v.len())), @@ -184,6 +188,7 @@ impl Concrete { } } + /// Returns whether this concrete is indexable pub fn is_indexable(&self) -> bool { self.is_dyn() || matches!(self, Concrete::Bytes(..)) } @@ -254,10 +259,12 @@ impl Concrete { } } + /// Returns whether this concrete is an unsigned integer pub fn is_int(&self) -> bool { matches!(self, Concrete::Int(_, _)) } + /// Performs a literal cast to another type pub fn literal_cast(self, builtin: Builtin) -> Option { match self { Concrete::Uint(_, val) => match builtin { @@ -283,6 +290,7 @@ impl Concrete { } } + /// Concatenate two concretes together pub fn concat(self, other: &Self) -> Option { match (self, other) { (Concrete::String(a), Concrete::String(b)) => Some(Concrete::from(format!("{a}{b}"))), @@ -572,6 +580,7 @@ impl Concrete { } } + /// Returns this concrete as a max-sized version pub fn max_size(&self) -> Self { match self { Concrete::Uint(_, val) => Concrete::Uint(256, *val), diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index ef29d3e8..61e33362 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -5,9 +5,13 @@ use crate::{ContextVarNode, GraphLike, Node, NodeIdx, VarType}; /// The reason a context was killed #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum KilledKind { + /// Execution ended here successfully Ended, + /// Unsatisifiable bounds, therefore dead code Unreachable, + /// Execution guaranteed to revert here! Revert, + /// Unexpected parse error. This is likely a bug or invalid solidity. See the `errors` section of the CLI output or rerun with `--debug` for more information ParseError, } diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index cc41f802..5f7662fa 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -18,6 +18,7 @@ impl ContextNode { todo!("Joining not supported yet"); } + /// Gets the total context width pub fn total_width( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -26,6 +27,7 @@ impl ContextNode { .number_of_live_edges(analyzer) } + /// Gets the total context depth pub fn depth(&self, analyzer: &impl GraphLike) -> usize { self.underlying(analyzer).unwrap().depth } @@ -66,6 +68,7 @@ impl ContextNode { Ok(self.underlying(analyzer)?.killed) } + /// Add a return node to the context pub fn add_return_node( &self, ret_stmt_loc: Loc, @@ -79,6 +82,7 @@ impl ContextNode { Ok(()) } + /// Add an empty/placeholder return to the context pub fn add_empty_return( &self, ret_stmt_loc: Loc, @@ -91,6 +95,7 @@ impl ContextNode { Ok(()) } + /// Propogate that this context has ended up the context graph pub fn propogate_end( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -106,6 +111,7 @@ impl ContextNode { Ok(()) } + /// Gets the return nodes for this context pub fn return_nodes( &self, analyzer: &impl GraphLike, @@ -122,129 +128,10 @@ impl ContextNode { } } + /// Returns a string for dot-string things pub fn as_string(&mut self) -> String { "Context".to_string() } - - pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { - let deps = self.ctx_deps(g)?; - // #[derive(Debug, Copy, Clone)] - // pub enum DepEdge { - // Lhs, - // Rhs, - // } - - let mut gr: petgraph::Graph = - petgraph::Graph::default(); - - let mut contains: BTreeMap> = - BTreeMap::default(); - deps.iter().try_for_each(|dep| { - let mapping = dep.graph_dependent_on(g)?; - mapping.into_iter().for_each(|(_k, tmp)| { - if let Some(rhs) = tmp.rhs { - let lhs = if let Some(ver) = contains.keys().find(|other| { - other.range(g).unwrap() == tmp.lhs.range(g).unwrap() - && tmp.lhs.display_name(g).unwrap() == other.display_name(g).unwrap() - }) { - *contains.get(ver).unwrap() - } else { - let lhs = gr.add_node(tmp.lhs.into()); - contains.insert(tmp.lhs, lhs); - lhs - }; - - let new_rhs = if let Some(ver) = contains.keys().find(|other| { - other.range(g).unwrap() == rhs.range(g).unwrap() - && rhs.display_name(g).unwrap() == other.display_name(g).unwrap() - }) { - *contains.get(ver).unwrap() - } else { - let new_rhs = gr.add_node(rhs.into()); - contains.insert(rhs, new_rhs); - new_rhs - }; - gr.add_edge(lhs, new_rhs, tmp.op); - } - }); - Ok(()) - })?; - - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &gr, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - let e = edge_ref.weight(); - format!("label = \"{e:?}\"") - }, - &|_graph, (idx, node_ref)| { - let inner = match g.node(*node_ref) { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(g).unwrap() { - r.as_dot_str(g) - // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - } else { - "".to_string() - }; - - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(g).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, g), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - g.node(*node_ref).dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - let dot_str = dot_str.join("\n"); - - println!("{dot_str}"); - use std::env::temp_dir; - use std::fs; - use std::io::Write; - use std::process::Command; - let mut dir = temp_dir(); - let file_name = "dot.dot"; - dir.push(file_name); - - let mut file = fs::File::create(dir.clone()).unwrap(); - file.write_all(dot_str.as_bytes()).unwrap(); - Command::new("dot") - .arg("-Tsvg") - .arg(dir) - .arg("-o") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Command::new("open") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Ok(()) - } } impl From for NodeIdx { diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index dfb3f59a..852da7db 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -22,6 +22,7 @@ impl ContextNode { .maybe_associated_contract(analyzer)) } + /// Tries to get the associated source for the context pub fn maybe_associated_source( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -42,6 +43,7 @@ impl ContextNode { } } + /// Tries to get the associated source unit part for the context pub fn associated_source_unit_part( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 0b76d07d..f25e93a3 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,6 +1,7 @@ impl ContextNode { + /// Use a Difference Logic solver to see if it is unreachable pub fn unreachable(&self, analyzer: &impl GraphLike) -> Result { let mut solver = self.dl_solver(analyzer)?.clone(); match solver.solve_partial(analyzer)? { @@ -9,6 +10,7 @@ impl ContextNode { } } + /// Get the dependencies as normalized solver atoms pub fn dep_atoms(&self, analyzer: &impl GraphLike) -> Result, GraphError> { let deps: Vec<_> = self.ctx_deps(analyzer)?; let mut ranges = BTreeMap::default(); @@ -40,137 +42,16 @@ impl ContextNode { .collect::>()) } + /// Get the difference logic solver associated with this context pub fn dl_solver<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a DLSolver, GraphError> { Ok(&self.underlying(analyzer)?.dl_solver) } - pub fn dep_graph(&self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - let deps = self.ctx_deps(analyzer)?; - println!("{}:\n", self.path(analyzer)); - deps.iter().try_for_each(|dep| { - let t = dep.graph_dependent_on(analyzer)?; - println!("{:#?}", t); - Ok::<(), GraphError>(()) - })?; - Ok(()) - } - /// Returns a map of variable dependencies for this context pub fn ctx_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { Ok(self.underlying(analyzer)?.ctx_deps.clone()) } - pub fn ctx_deps_as_controllables_str( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let deps: Vec<_> = self.ctx_deps(analyzer)?.into_iter().collect(); - println!("here: {}, {}", deps.len(), self.ctx_deps(analyzer)?.len()); - fn decompose( - dep: ContextVarNode, - acc: &mut String, - analyzer: &impl GraphLike, - ) -> Result<(), GraphError> { - println!("acc: {acc}"); - if let Ok(Some(tmp)) = dep.tmp_of(analyzer) { - decompose(tmp.lhs, acc, analyzer)?; - *acc = acc.to_owned() + &tmp.op.to_string(); - if let Some(rhs) = tmp.rhs { - decompose(rhs, acc, analyzer)?; - } - } else { - *acc = acc.to_owned() + &dep.display_name(analyzer)?; - } - Ok(()) - } - - deps.iter() - .map(|dep| { - let mut t = "".to_string(); - decompose(*dep, &mut t, analyzer)?; - Ok(t) - }) - .collect::, _>>() - } - - pub fn flat_ctx_deps( - &self, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - fn decompose( - dep: ContextVarNode, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - println!("decomposing: {}", dep.display_name(analyzer).unwrap()); - let mut top_level_deps = vec![]; - if let Ok(Some(tmp)) = dep.tmp_of(analyzer) { - if dep.is_controllable(analyzer)? { - if let Some(rhs) = tmp.rhs { - top_level_deps.extend(decompose(rhs, analyzer)?); - } - top_level_deps.extend(decompose(tmp.lhs, analyzer)?); - println!("{} is controllable", dep.display_name(analyzer).unwrap()); - top_level_deps.push(dep); - } - } else if dep.is_controllable(analyzer)? { - println!( - "atomic {} is controllable", - dep.display_name(analyzer).unwrap() - ); - top_level_deps.push(dep); - } - - Ok(top_level_deps) - } - - Ok(self - .ctx_deps(analyzer)? - .into_iter() - .map(|dep| decompose(dep, analyzer)) - .collect::, _>>()? - .into_iter() - .flatten() - .collect()) - } - - pub fn ctx_dep_ranges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(self - .underlying(analyzer)? - .ctx_deps - .clone() - .into_iter() - .flat_map(|dep| { - let tmp = dep.tmp_of(analyzer).unwrap().unwrap(); - if let Some(rhs) = tmp.rhs { - println!("dep lhs: {}", tmp.lhs.display_name(analyzer).unwrap()); - println!("dep rhs: {}", rhs.display_name(analyzer).unwrap()); - vec![ - tmp.lhs - .ref_range(analyzer) - .unwrap() - .unwrap() - .into_flattened_range(analyzer) - .unwrap(), - rhs.ref_range(analyzer) - .unwrap() - .unwrap() - .into_flattened_range(analyzer) - .unwrap(), - ] - } else { - println!("dep lhs: {}", tmp.lhs.display_name(analyzer).unwrap()); - vec![tmp - .lhs - .ref_range(analyzer) - .unwrap() - .unwrap() - .into_flattened_range(analyzer) - .unwrap()] - } - }) - .collect()) - } - /// Adds a dependency for this context to exit successfully pub fn add_ctx_dep( &self, @@ -195,4 +76,125 @@ impl ContextNode { } Ok(()) } + + /// Creates a DAG of the context dependencies and opens it with graphviz + pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { + let deps = self.ctx_deps(g)?; + // #[derive(Debug, Copy, Clone)] + // pub enum DepEdge { + // Lhs, + // Rhs, + // } + + let mut gr: petgraph::Graph = + petgraph::Graph::default(); + + let mut contains: BTreeMap> = + BTreeMap::default(); + deps.iter().try_for_each(|dep| { + let mapping = dep.graph_dependent_on(g)?; + mapping.into_iter().for_each(|(_k, tmp)| { + if let Some(rhs) = tmp.rhs { + let lhs = if let Some(ver) = contains.keys().find(|other| { + other.range(g).unwrap() == tmp.lhs.range(g).unwrap() + && tmp.lhs.display_name(g).unwrap() == other.display_name(g).unwrap() + }) { + *contains.get(ver).unwrap() + } else { + let lhs = gr.add_node(tmp.lhs.into()); + contains.insert(tmp.lhs, lhs); + lhs + }; + + let new_rhs = if let Some(ver) = contains.keys().find(|other| { + other.range(g).unwrap() == rhs.range(g).unwrap() + && rhs.display_name(g).unwrap() == other.display_name(g).unwrap() + }) { + *contains.get(ver).unwrap() + } else { + let new_rhs = gr.add_node(rhs.into()); + contains.insert(rhs, new_rhs); + new_rhs + }; + gr.add_edge(lhs, new_rhs, tmp.op); + } + }); + Ok(()) + })?; + + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26";"##; + dot_str.push(raw_start_str.to_string()); + let nodes_and_edges_str = format!( + "{:?}", + Dot::with_attr_getters( + &gr, + &[ + petgraph::dot::Config::GraphContentOnly, + petgraph::dot::Config::NodeNoLabel, + petgraph::dot::Config::EdgeNoLabel + ], + &|_graph, edge_ref| { + let e = edge_ref.weight(); + format!("label = \"{e:?}\"") + }, + &|_graph, (idx, node_ref)| { + let inner = match g.node(*node_ref) { + Node::ContextVar(cvar) => { + let range_str = if let Some(r) = cvar.ty.ref_range(g).unwrap() { + r.as_dot_str(g) + // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) + } else { + "".to_string() + }; + + format!( + "{} -- {} -- range: {}", + cvar.display_name, + cvar.ty.as_string(g).unwrap(), + range_str + ) + } + _ => as_dot_str(idx, g), + }; + format!( + "label = \"{}\", color = \"{}\"", + inner.replace('\"', "\'"), + g.node(*node_ref).dot_str_color() + ) + } + ) + ); + dot_str.push(nodes_and_edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + let dot_str = dot_str.join("\n"); + + println!("{dot_str}"); + use std::env::temp_dir; + use std::fs; + use std::io::Write; + use std::process::Command; + let mut dir = temp_dir(); + let file_name = "dot.dot"; + dir.push(file_name); + + let mut file = fs::File::create(dir.clone()).unwrap(); + file.write_all(dot_str.as_bytes()).unwrap(); + Command::new("dot") + .arg("-Tsvg") + .arg(dir) + .arg("-o") + .arg("dot.svg") + .output() + .expect("failed to execute process"); + Command::new("open") + .arg("dot.svg") + .output() + .expect("failed to execute process"); + Ok(()) + } } \ No newline at end of file diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index a31f2f0d..c0d997f7 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -55,10 +55,12 @@ impl ContextNode { } } + /// Returns whether this context *currently* uses unchecked math pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.unchecked) } + /// Sets the context to use unchecked math pub fn set_unchecked( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -67,6 +69,7 @@ impl ContextNode { Ok(()) } + /// Sets the context to use checked math pub fn unset_unchecked( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 75c80256..37c84a35 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -33,13 +33,17 @@ pub struct Context { pub depth: usize, /// Width tracker pub width: usize, + /// A temporary stack of ExprRets for this context pub tmp_expr: Vec>, + /// The stack of ExprRets for this context pub expr_ret_stack: Vec, + /// Whether the context currently uses unchecked math pub unchecked: bool, + /// The number of live edges pub number_of_live_edges: usize, - - // caching related things + /// Caching related things pub cache: ContextCache, + /// A difference logic solver used for determining reachability pub dl_solver: DLSolver, } diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 6a0f951f..0a1ecb28 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -23,6 +23,7 @@ impl ContextNode { .copied() } + /// Gets a variable by name or recurses up the relevant scopes/contexts until it is found pub fn var_by_name_or_recurse( &self, analyzer: &impl GraphLike, @@ -71,6 +72,7 @@ impl ContextNode { Ok(ret) } + /// Push an expression return into the temporary stack pub fn push_tmp_expr( &self, expr_ret: ExprRet, @@ -81,6 +83,8 @@ impl ContextNode { Ok(()) } + /// Append a new expression return to an expression return + /// currently in the temporary stack pub fn append_tmp_expr( &self, expr_ret: ExprRet, @@ -120,6 +124,7 @@ impl ContextNode { Ok(()) } + /// Pops a from the temporary ExprRet stack pub fn pop_tmp_expr( &self, loc: Loc, @@ -133,6 +138,7 @@ impl ContextNode { } } + /// Pushes an ExprRet to the stack #[tracing::instrument(level = "trace", skip_all)] pub fn push_expr( &self, @@ -154,6 +160,7 @@ impl ContextNode { Ok(()) } + /// May move the inner variables of an ExprRet from an old context to this context pub fn maybe_move_expr( &self, expr: ExprRet, @@ -177,6 +184,7 @@ impl ContextNode { } } + /// May move the variable from an old context to this context pub fn maybe_move_var( &self, var: ContextVarNode, @@ -204,25 +212,7 @@ impl ContextNode { } } - #[tracing::instrument(level = "trace", skip_all)] - pub fn pop_expr( - &self, - _loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), - ) -> Result, GraphError> { - tracing::trace!("popping var from: {}", self.path(analyzer)); - let underlying_mut = self.underlying_mut(analyzer)?; - - let new: Vec = Vec::with_capacity(5); - - let old = std::mem::replace(&mut underlying_mut.expr_ret_stack, new); - if old.is_empty() { - Ok(None) - } else { - Ok(Some(ExprRet::Multi(old))) - } - } - + /// Pop the latest expression return off the stack #[tracing::instrument(level = "trace", skip_all)] pub fn pop_expr_latest( &self, @@ -242,6 +232,7 @@ impl ContextNode { } } + /// Gets local vars that were assigned from a function return pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { self.local_vars(analyzer) .iter() @@ -249,6 +240,7 @@ impl ContextNode { .collect() } + /// Gets local vars that were assigned from an external function return pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { self.local_vars(analyzer) .iter() diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 9fcbedec..f073ef2e 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -6,6 +6,7 @@ impl ContextNode { Ok(self.underlying(analyzer)?.parent_ctx.is_some()) } + /// Gets the first ancestor of this context pub fn first_ancestor( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -104,6 +105,7 @@ impl ContextNode { } } + /// Gets all reverted descendents pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; @@ -138,6 +140,7 @@ impl ContextNode { } } + /// Gets all successful descendents pub fn successful_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; @@ -172,6 +175,7 @@ impl ContextNode { } } + /// Returns the current number of live edges pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { Ok(self.underlying(analyzer)?.number_of_live_edges) } @@ -211,6 +215,7 @@ impl ContextNode { } } + /// Gets all descendents recursively pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut descendents = vec![child]; @@ -288,6 +293,7 @@ impl ContextNode { } } + /// Removes the child of this context pub fn delete_child( &self, analyzer: &mut (impl GraphLike + AnalyzerLike), @@ -390,6 +396,7 @@ impl ContextNode { Ok(parents) } + /// Gets all calls recursively pub fn recursive_calls( &self, analyzer: &impl GraphLike, From d40f023ae9a01f846e189096f049fab332089493 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 17:26:28 -0800 Subject: [PATCH 09/71] resolve cyclic package deps --- Cargo.lock | 2001 +++++++++++++++++ Cargo.toml | 29 +- crates/analyzer/src/lib.rs | 1 - crates/{analyzer => analyzers}/Cargo.toml | 5 +- .../src/analyzers => analyzers/src}/bounds.rs | 0 .../src}/func_analyzer/mod.rs | 0 .../src}/func_analyzer/report_display.rs | 0 .../analyzers/mod.rs => analyzers/src/lib.rs} | 0 .../src}/var_analyzer/mod.rs | 0 .../src}/var_analyzer/report_display.rs | 0 crates/cli/Cargo.toml | 26 +- crates/graph/Cargo.toml | 8 +- crates/graph/src/graph_elements.rs | 3 - crates/graph/src/lib.rs | 5 + crates/graph/src/range_impl/elem/concrete.rs | 136 ++ crates/graph/src/range_impl/elem/elem_enum.rs | 376 ++++ crates/graph/src/range_impl/elem/expr.rs | 539 +++++ .../graph/src/range_impl/elem/map_or_array.rs | 169 ++ crates/graph/src/range_impl/elem/reference.rs | 179 ++ .../src => graph/src/range_impl}/exec/add.rs | 6 - .../src/range_impl}/exec/bitwise.rs | 11 - .../src => graph/src/range_impl}/exec/cast.rs | 5 - .../src/range_impl}/exec/concat.rs | 5 - .../src => graph/src/range_impl}/exec/div.rs | 7 - .../src => graph/src/range_impl}/exec/exp.rs | 5 - .../src/range_impl}/exec/logical.rs | 9 - .../src => graph/src/range_impl}/exec/max.rs | 5 - .../src => graph/src/range_impl}/exec/min.rs | 5 - .../src => graph/src/range_impl}/exec/mod.rs | 50 - .../src/range_impl}/exec/modulo.rs | 5 - .../src => graph/src/range_impl}/exec/mul.rs | 6 - .../src => graph/src/range_impl}/exec/ord.rs | 15 - .../src/range_impl}/exec/shift.rs | 7 - .../src => graph/src/range_impl}/exec/sub.rs | 6 - crates/graph/src/range_impl/mod.rs | 6 + crates/graph/src/range_impl/range_string.rs | 227 ++ .../src/range_impl}/solc_range.rs | 122 +- .../{solvers/src => graph/src/solvers}/dl.rs | 0 .../src/lib.rs => graph/src/solvers/mod.rs} | 0 crates/pyrometer/Cargo.toml | 5 +- crates/queries/Cargo.toml | 23 + crates/queries/{ => src}/lib.rs | 0 .../queries/{ => src}/storage_write/access.rs | 0 crates/queries/{ => src}/storage_write/mod.rs | 0 .../queries/{ => src}/storage_write/target.rs | 0 crates/queries/{ => src}/taint.rs | 0 crates/range/Cargo.toml | 4 +- crates/range/src/elem/elem_enum.rs | 409 +--- crates/range/src/elem/expr.rs | 538 +---- crates/range/src/elem/map_or_array.rs | 176 +- crates/range/src/elem/mod.rs | 14 +- crates/range/src/elem/reference.rs | 190 +- crates/range/src/exec.rs | 146 ++ crates/range/src/lib.rs | 69 +- crates/range/src/range_string.rs | 225 -- crates/{solvers => shared}/Cargo.toml | 13 +- .../{analyzer => shared}/src/analyzer_like.rs | 0 crates/{graph => shared}/src/graph_like.rs | 2 + crates/shared/src/lib.rs | 0 .../Cargo.toml | 4 +- .../src/array.rs | 7 +- .../src/bin_op.rs | 5 +- .../src/cmp.rs | 18 +- .../src/cond_op.rs | 8 +- .../src/env.rs | 0 .../src/func_call/internal_call.rs | 0 .../src/func_call/intrinsic_call.rs | 0 .../src/func_call/mod.rs | 0 .../src/func_call/modifier.rs | 0 .../src/func_call/namespaced_call.rs | 0 .../src/lib.rs | 0 .../src/list.rs | 52 +- .../src/literal.rs | 0 .../src/loops.rs | 0 .../src/member_access.rs | 12 +- .../src/require.rs | 342 ++- .../src/variable.rs | 24 +- .../src/yul/mod.rs | 0 .../src/yul/yul_cond_op.rs | 0 .../src/yul/yul_funcs.rs | 0 80 files changed, 4352 insertions(+), 1913 deletions(-) create mode 100644 Cargo.lock delete mode 100644 crates/analyzer/src/lib.rs rename crates/{analyzer => analyzers}/Cargo.toml (82%) rename crates/{analyzer/src/analyzers => analyzers/src}/bounds.rs (100%) rename crates/{analyzer/src/analyzers => analyzers/src}/func_analyzer/mod.rs (100%) rename crates/{analyzer/src/analyzers => analyzers/src}/func_analyzer/report_display.rs (100%) rename crates/{analyzer/src/analyzers/mod.rs => analyzers/src/lib.rs} (100%) rename crates/{analyzer/src/analyzers => analyzers/src}/var_analyzer/mod.rs (100%) rename crates/{analyzer/src/analyzers => analyzers/src}/var_analyzer/report_display.rs (100%) create mode 100644 crates/graph/src/range_impl/elem/concrete.rs create mode 100644 crates/graph/src/range_impl/elem/elem_enum.rs create mode 100644 crates/graph/src/range_impl/elem/expr.rs create mode 100644 crates/graph/src/range_impl/elem/map_or_array.rs create mode 100644 crates/graph/src/range_impl/elem/reference.rs rename crates/{range/src => graph/src/range_impl}/exec/add.rs (95%) rename crates/{range/src => graph/src/range_impl}/exec/bitwise.rs (93%) rename crates/{range/src => graph/src/range_impl}/exec/cast.rs (98%) rename crates/{range/src => graph/src/range_impl}/exec/concat.rs (96%) rename crates/{range/src => graph/src/range_impl}/exec/div.rs (96%) rename crates/{range/src => graph/src/range_impl}/exec/exp.rs (95%) rename crates/{range/src => graph/src/range_impl}/exec/logical.rs (84%) rename crates/{range/src => graph/src/range_impl}/exec/max.rs (91%) rename crates/{range/src => graph/src/range_impl}/exec/min.rs (91%) rename crates/{range/src => graph/src/range_impl}/exec/mod.rs (97%) rename crates/{range/src => graph/src/range_impl}/exec/modulo.rs (91%) rename crates/{range/src => graph/src/range_impl}/exec/mul.rs (95%) rename crates/{range/src => graph/src/range_impl}/exec/ord.rs (92%) rename crates/{range/src => graph/src/range_impl}/exec/shift.rs (96%) rename crates/{range/src => graph/src/range_impl}/exec/sub.rs (96%) create mode 100644 crates/graph/src/range_impl/mod.rs create mode 100644 crates/graph/src/range_impl/range_string.rs rename crates/{range/src => graph/src/range_impl}/solc_range.rs (91%) rename crates/{solvers/src => graph/src/solvers}/dl.rs (100%) rename crates/{solvers/src/lib.rs => graph/src/solvers/mod.rs} (100%) rename crates/queries/{ => src}/lib.rs (100%) rename crates/queries/{ => src}/storage_write/access.rs (100%) rename crates/queries/{ => src}/storage_write/mod.rs (100%) rename crates/queries/{ => src}/storage_write/target.rs (100%) rename crates/queries/{ => src}/taint.rs (100%) create mode 100644 crates/range/src/exec.rs rename crates/{solvers => shared}/Cargo.toml (60%) rename crates/{analyzer => shared}/src/analyzer_like.rs (100%) rename crates/{graph => shared}/src/graph_like.rs (99%) create mode 100644 crates/shared/src/lib.rs rename crates/{solc_expressions => solc-expressions}/Cargo.toml (81%) rename crates/{solc_expressions => solc-expressions}/src/array.rs (97%) rename crates/{solc_expressions => solc-expressions}/src/bin_op.rs (99%) rename crates/{solc_expressions => solc-expressions}/src/cmp.rs (97%) rename crates/{solc_expressions => solc-expressions}/src/cond_op.rs (97%) rename crates/{solc_expressions => solc-expressions}/src/env.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/func_call/internal_call.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/func_call/intrinsic_call.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/func_call/mod.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/func_call/modifier.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/func_call/namespaced_call.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/lib.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/list.rs (74%) rename crates/{solc_expressions => solc-expressions}/src/literal.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/loops.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/member_access.rs (99%) rename crates/{solc_expressions => solc-expressions}/src/require.rs (84%) rename crates/{solc_expressions => solc-expressions}/src/variable.rs (84%) rename crates/{solc_expressions => solc-expressions}/src/yul/mod.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/yul/yul_cond_op.rs (100%) rename crates/{solc_expressions => solc-expressions}/src/yul/yul_funcs.rs (100%) diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..bb486a2a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2001 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "analyzers" +version = "0.2.0" +dependencies = [ + "ariadne", + "graph", + "range", + "solang-parser", +] + +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a318f1f38d2418400f8209655bfd825785afd25aa30bb7ba6cc792e4596748" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "ariadne" +version = "0.2.0" +source = "git+https://github.com/brockelmore/ariadne#c2e3a8e79f369e8a785e1ca337e144ebc946f115" +dependencies = [ + "unicode-width", + "yansi", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +dependencies = [ + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "num-traits", +] + +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "cli" +version = "0.1.0" +dependencies = [ + "ariadne", + "clap", + "graph", + "petgraph", + "pyrometer", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-core" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f03e0bdc216eeb9e355b90cf610ef6c5bb8aca631f97b5ae9980ce34ea7878d" +dependencies = [ + "arrayvec", + "bytes", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array", + "k256", + "num_enum", + "open-fastrlp", + "rand", + "rlp", + "serde", + "serde_json", + "strum", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "graph" +version = "0.2.0" +dependencies = [ + "ethers-core", + "hex", + "lazy_static", + "petgraph", + "range", + "shared", + "solang-parser", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "k256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +dependencies = [ + "proc-macro-crate 2.0.1", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.2", + "unarray", +] + +[[package]] +name = "pyrometer" +version = "0.2.0" +dependencies = [ + "analyzers", + "ariadne", + "ethers-core", + "graph", + "range", + "solang-parser", + "solc-expressions", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "queries" +version = "0.2.0" +dependencies = [ + "analyzers", + "ariadne", + "ethers-core", + "graph", + "range", + "solang-parser", + "solc-expressions", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "range" +version = "0.2.0" +dependencies = [ + "ethers-core", + "hex", + "shared", + "solang-parser", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.38.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scale-info" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" +dependencies = [ + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shared" +version = "0.2.0" +dependencies = [ + "ethers-core", + "hex", + "solang-parser", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "solang-parser" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5ead679f39243782be98c2689e592fc0fc9489ca2e47c9e027bd30f948df31" +dependencies = [ + "itertools", + "lalrpop", + "lalrpop-util", + "phf", + "serde", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "solc-expressions" +version = "0.2.0" +dependencies = [ + "analyzers", + "ethers-core", + "graph", + "hex", + "solang-parser", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.39", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 43ac5f81..32b1b778 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [workspace] members = [ - "crates/analyzer", + "crates/analyzers", "crates/cli", "crates/graph", "crates/pyrometer", "crates/queries", "crates/range", - "crates/solc_expressions", + "crates/shared", + "crates/solc-expressions", ] @@ -17,8 +18,8 @@ authors = ["Brock Elmore"] license = "MIT OR Apache-2.0" homepage = "https://github.com/nascentxyz/pyrometer" repository = "https://github.com/nascentxyz/pyrometer" -exclude = ["benches/", "tests/"] # exclude the benches directory from the build - +exclude = ["benches/", "tests/", "examples/"] # exclude the benches directory from the build +rust-version = "1.74" [profile.release] debug = true @@ -31,12 +32,13 @@ inline = true debug = true [workspace.dependencies] -analyzer = { path = "crates/analyzer" } +analyzers = { path = "crates/analyzers" } graph = { path = "crates/graph" } pyrometer = { path = "crates/pyrometer" } queries = { path = "crates/queries" } range = { path = "crates/range" } -solc_expressions = { path = "crates/solc_expressions" } +shared = { path = "crates/shared" } +solc-expressions = { path = "crates/solc-expressions" } solang-parser = { version = "0.2.4", features = ["pt-serde"] } tracing = { version = "0.1", features = ["attributes"] } @@ -58,13 +60,10 @@ petgraph = "0.6.2" [patch.crates-io] ariadne = {git = "https://github.com/brockelmore/ariadne"} -###################################### -# Benchmarks -###################################### -[[example]] -name = "parse" -path = "examples/parse.rs" +# ###################################### +# # Benchmarks +# ###################################### -[[bench]] -name = "parse" -harness = false \ No newline at end of file +# [[bench]] +# name = "parse" +# harness = false \ No newline at end of file diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs deleted file mode 100644 index 24835819..00000000 --- a/crates/analyzer/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod analyzer_like; \ No newline at end of file diff --git a/crates/analyzer/Cargo.toml b/crates/analyzers/Cargo.toml similarity index 82% rename from crates/analyzer/Cargo.toml rename to crates/analyzers/Cargo.toml index b89e4fec..18eacaf6 100644 --- a/crates/analyzer/Cargo.toml +++ b/crates/analyzers/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "range" -description = "Pyrometer's analyzer traits" +name = "analyzers" +description = "Pyrometer's builtin analyzers" version.workspace = true edition.workspace = true @@ -13,5 +13,6 @@ repository.workspace = true [dependencies] graph.workspace = true range.workspace = true + solang-parser.workspace = true ariadne.workspace = true \ No newline at end of file diff --git a/crates/analyzer/src/analyzers/bounds.rs b/crates/analyzers/src/bounds.rs similarity index 100% rename from crates/analyzer/src/analyzers/bounds.rs rename to crates/analyzers/src/bounds.rs diff --git a/crates/analyzer/src/analyzers/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs similarity index 100% rename from crates/analyzer/src/analyzers/func_analyzer/mod.rs rename to crates/analyzers/src/func_analyzer/mod.rs diff --git a/crates/analyzer/src/analyzers/func_analyzer/report_display.rs b/crates/analyzers/src/func_analyzer/report_display.rs similarity index 100% rename from crates/analyzer/src/analyzers/func_analyzer/report_display.rs rename to crates/analyzers/src/func_analyzer/report_display.rs diff --git a/crates/analyzer/src/analyzers/mod.rs b/crates/analyzers/src/lib.rs similarity index 100% rename from crates/analyzer/src/analyzers/mod.rs rename to crates/analyzers/src/lib.rs diff --git a/crates/analyzer/src/analyzers/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs similarity index 100% rename from crates/analyzer/src/analyzers/var_analyzer/mod.rs rename to crates/analyzers/src/var_analyzer/mod.rs diff --git a/crates/analyzer/src/analyzers/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs similarity index 100% rename from crates/analyzer/src/analyzers/var_analyzer/report_display.rs rename to crates/analyzers/src/var_analyzer/report_display.rs diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 9ac847ea..e3671939 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -6,18 +6,22 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pyrometer.workspace = true +graph.workspace = true +# queries.workspace = true + +ariadne.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +petgraph.workspace = true + + clap = { version = "4.1.4", features = ["derive"] } -pyrometer = { path = "../" } -shared = { path = "../shared" } -ariadne = "0.2.0" -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } -petgraph = "0.6.2" -[[bin]] -name = "pyrometer" -path = "src/main.rs" +# [[bin]] +# name = "pyrometer" +# path = "src/main.rs" -[profile.release] -debug = true \ No newline at end of file +# [profile.release] +# debug = true \ No newline at end of file diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml index 033f4f8b..57913b6d 100644 --- a/crates/graph/Cargo.toml +++ b/crates/graph/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "range" -description = "Pyrometer's representation of a range" +name = "graph" +description = "Pyrometer's internal graph" version.workspace = true edition.workspace = true @@ -11,9 +11,11 @@ homepage.workspace = true repository.workspace = true [dependencies] -petgraph.workspace = true +shared.workspace = true range.workspace = true solang-parser.workspace = true + +petgraph.workspace = true ethers-core.workspace = true hex.workspace = true tracing.workspace = true diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index c45e00d9..46a3d4cd 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -12,9 +12,6 @@ use lazy_static::lazy_static; use petgraph::graph::*; use solang_parser::pt::Identifier; -pub type NodeIdx = NodeIndex; -pub type EdgeIdx = EdgeIndex; - #[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] pub enum GraphError { /// The analyzer thought the node was suppose to be one type, but it was a different one diff --git a/crates/graph/src/lib.rs b/crates/graph/src/lib.rs index 4f37b450..596e7a43 100644 --- a/crates/graph/src/lib.rs +++ b/crates/graph/src/lib.rs @@ -1,11 +1,16 @@ mod graph_elements; mod graph_like; mod search; +mod range_impl; mod var_type; +mod solvers; pub mod nodes; +pub mod solvers; + pub use var_type::*; pub use graph_elements::*; pub use graph_like::*; +pub use range_impl::*; pub use search::*; diff --git a/crates/graph/src/range_impl/elem/concrete.rs b/crates/graph/src/range_impl/elem/concrete.rs new file mode 100644 index 00000000..45439072 --- /dev/null +++ b/crates/graph/src/range_impl/elem/concrete.rs @@ -0,0 +1,136 @@ +impl From for RangeConcrete { + fn from(c: Concrete) -> Self { + Self { + val: c, + loc: Loc::Implicit, + } + } +} + +impl RangeElem for RangeConcrete { + // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { + // Elem::Concrete(self.clone()) + // } + + fn flatten( + &self, + _maximize: bool, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + + fn range_eq(&self, other: &Self) -> bool { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(self_val), Some(other_val)) => self_val == other_val, + _ => match (&self.val, &other.val) { + (Concrete::Int(_, s), Concrete::Int(_, o)) => s == o, + (Concrete::DynBytes(s), Concrete::DynBytes(o)) => s == o, + (Concrete::String(s), Concrete::String(o)) => s == o, + (Concrete::DynBytes(s), Concrete::String(o)) => s == o.as_bytes(), + (Concrete::String(s), Concrete::DynBytes(o)) => s.as_bytes() == o, + (Concrete::Array(a), Concrete::Array(b)) => { + if a.len() == b.len() { + a.iter().zip(b.iter()).all(|(a, b)| { + let a = RangeConcrete { + val: a.clone(), + loc: self.loc, + }; + + let b = RangeConcrete { + val: b.clone(), + loc: other.loc, + }; + + a.range_eq(&b) + }) + } else { + false + } + } + _ => false, + }, + } + } + + fn range_ord(&self, other: &Self) -> Option { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), + (Some(_), _) => { + match other.val { + Concrete::Int(_, _) => { + // if we couldnt convert an int to uint, its negative + // so self must be > other + Some(std::cmp::Ordering::Greater) + } + _ => None, + } + } + (_, Some(_)) => { + match self.val { + Concrete::Int(_, _) => { + // if we couldnt convert an int to uint, its negative + // so self must be < other + Some(std::cmp::Ordering::Less) + } + _ => None, + } + } + _ => { + match (&self.val, &other.val) { + // two negatives + (Concrete::Int(_, s), Concrete::Int(_, o)) => Some(s.cmp(o)), + (Concrete::DynBytes(b0), Concrete::DynBytes(b1)) => Some(b0.cmp(b1)), + _ => None, + } + } + } + } + + fn dependent_on(&self) -> Vec { + vec![] + } + fn update_deps(&mut self, _mapping: &BTreeMap) {} + + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + + fn maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + fn minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + + fn simplify_maximize( + &self, + _exclude: &mut Vec, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + fn simplify_minimize( + &self, + _exclude: &mut Vec, + _analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Concrete(self.clone())) + } + + fn cache_maximize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + Ok(()) + } + + fn cache_minimize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + Ok(()) + } + fn uncache(&mut self) {} + + fn contains_op_set( + &self, + _: bool, + _op_set: &[RangeOp], + _analyzer: &impl GraphLike, + ) -> Result { + Ok(false) + } +} \ No newline at end of file diff --git a/crates/graph/src/range_impl/elem/elem_enum.rs b/crates/graph/src/range_impl/elem/elem_enum.rs new file mode 100644 index 00000000..bb8ed9e8 --- /dev/null +++ b/crates/graph/src/range_impl/elem/elem_enum.rs @@ -0,0 +1,376 @@ + + +impl std::fmt::Display for Elem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::ConcreteDyn(..) => write!(f, "range_elem"), + Elem::Concrete(RangeConcrete { val, .. }) => { + write!(f, "{}", val.as_string()) + } + Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { + RangeOp::Min | RangeOp::Max => { + write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) + } + RangeOp::Cast => match &**rhs { + Elem::Concrete(RangeConcrete { val, .. }) => { + write!( + f, + "{}({}, {})", + op.to_string(), + lhs, + val.as_builtin().basic_as_string() + ) + } + _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), + }, + RangeOp::BitNot => { + write!(f, "~{}", lhs) + } + _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), + }, + _ => write!(f, ""), + } + } +} + +impl From for Elem { + fn from(c: Concrete) -> Self { + Elem::Concrete(RangeConcrete { + val: c, + loc: Loc::Implicit, + }) + } +} + +impl From for Elem { + fn from(c: ContextVarNode) -> Self { + Elem::Reference(Reference::new(c.into())) + } +} + +impl From for Elem { + fn from(idx: NodeIdx) -> Self { + Elem::Reference(Reference::new(idx)) + } +} + + +impl Elem { + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { + match self { + Self::Reference(Reference { idx, .. }) => { + if *idx == to_replace { + *self = replacement; + } + } + Self::Concrete(_) => {} + Self::Expr(expr) => { + expr.lhs.replace_dep(to_replace, replacement.clone()); + expr.rhs.replace_dep(to_replace, replacement); + expr.maximized = None; + expr.minimized = None; + } + Self::ConcreteDyn(_d) => todo!(), + Self::Null => {} + } + } + + pub fn inverse_if_boolean(&self) -> Option { + match self { + Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), + Self::ConcreteDyn(_d) => None, + Self::Null => None, + } + } + + pub fn node_idx(&self) -> Option { + match self { + Self::Reference(Reference { idx, .. }) => Some(*idx), + _ => None, + } + } + + pub fn concrete(&self) -> Option { + match self { + Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), + _ => None, + } + } + + pub fn is_negative( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result { + let res = match self { + Elem::Concrete(RangeConcrete { + val: Concrete::Int(_, val), + .. + }) if val < &I256::zero() => true, + Elem::Reference(dy) => { + if maximize { + dy.maximize(analyzer)?.is_negative(maximize, analyzer)? + } else { + dy.minimize(analyzer)?.is_negative(maximize, analyzer)? + } + } + Elem::Expr(expr) => { + if maximize { + expr.maximize(analyzer)?.is_negative(maximize, analyzer)? + } else { + expr.minimize(analyzer)?.is_negative(maximize, analyzer)? + } + } + _ => false, + }; + Ok(res) + } + + pub fn pre_evaled_is_negative(&self) -> bool { + matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) + } + + pub fn maybe_concrete(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + + pub fn maybe_concrete_value(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + + pub fn maybe_range_dyn(&self) -> Option> { + match self { + Elem::ConcreteDyn(a) => Some(*a.clone()), + _ => None, + } + } +} + +impl RangeElem for Elem { + fn range_eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), + _ => false, + } + } + + fn range_ord(&self, other: &Self) -> Option { + match (self, other) { + (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), + (Self::Reference(a), Self::Reference(b)) => a.range_ord(b), + _ => None, + } + } + + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + match self { + Self::Reference(d) => d.flatten(maximize, analyzer), + Self::Concrete(c) => c.flatten(maximize, analyzer), + Self::Expr(expr) => expr.flatten(maximize, analyzer), + Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), + Self::Null => Ok(Elem::Null), + } + } + + fn dependent_on(&self) -> Vec { + match self { + Self::Reference(d) => d.dependent_on(), + Self::Concrete(_) => vec![], + Self::Expr(expr) => expr.dependent_on(), + Self::ConcreteDyn(d) => d.dependent_on(), + Self::Null => vec![], + } + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + match self { + Self::Reference(d) => d.update_deps(mapping), + Self::Concrete(_) => {} + Self::Expr(expr) => expr.update_deps(mapping), + Self::ConcreteDyn(d) => d.update_deps(mapping), + Self::Null => {} + } + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + match self { + Self::Reference(ref mut d) => { + if d.idx == node_idx { + d.idx = new_idx + } + } + Self::Concrete(_) => {} + Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx), + Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx), + Self::Null => {} + } + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.maximize(analyzer)?, + Concrete(inner) => inner.maximize(analyzer)?, + ConcreteDyn(inner) => inner.maximize(analyzer)?, + Expr(expr) => expr.maximize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.minimize(analyzer)?, + Concrete(inner) => inner.minimize(analyzer)?, + ConcreteDyn(inner) => inner.minimize(analyzer)?, + Expr(expr) => expr.minimize(analyzer)?, + Null => Elem::Null, + }; + Ok(res) + } + + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.simplify_maximize(exclude, analyzer), + Concrete(inner) => inner.simplify_maximize(exclude, analyzer), + ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), + Expr(expr) => expr.simplify_maximize(exclude, analyzer), + Null => Ok(Elem::Null), + } + } + + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.simplify_minimize(exclude, analyzer), + Concrete(inner) => inner.simplify_minimize(exclude, analyzer), + ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), + Expr(expr) => expr.simplify_minimize(exclude, analyzer), + Null => Ok(Elem::Null), + } + } + + fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_maximize(analyzer), + Concrete(inner) => inner.cache_maximize(analyzer), + ConcreteDyn(inner) => inner.cache_maximize(analyzer), + Expr(expr) => expr.cache_maximize(analyzer), + Null => Ok(()), + } + } + + fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_minimize(analyzer), + Concrete(inner) => inner.cache_minimize(analyzer), + ConcreteDyn(inner) => inner.cache_minimize(analyzer), + Expr(expr) => expr.cache_minimize(analyzer), + Null => Ok(()), + } + } + fn uncache(&mut self) { + use Elem::*; + match self { + Reference(dy) => dy.uncache(), + Concrete(inner) => inner.uncache(), + ConcreteDyn(inner) => inner.uncache(), + Expr(expr) => expr.uncache(), + Null => {} + } + } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + use Elem::*; + match self { + Reference(dy) => dy.contains_op_set(max, op_set, analyzer), + Concrete(inner) => inner.contains_op_set(max, op_set, analyzer), + ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), + Expr(expr) => expr.contains_op_set(max, op_set, analyzer), + Null => Ok(false), + } + } +} + +impl Elem { + pub fn wrapping_add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(true), other); + Self::Expr(expr) + } + pub fn wrapping_sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(true), other); + Self::Expr(expr) + } + pub fn wrapping_mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(true), other); + Self::Expr(expr) + } + pub fn wrapping_div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(true), other); + Self::Expr(expr) + } + + /// Creates a logical AND of two range elements + pub fn and(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::And, other); + Self::Expr(expr) + } + + /// Creates a logical OR of two range elements + pub fn or(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Or, other); + Self::Expr(expr) + } + + pub fn maybe_elem_min(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::min(val)?)), + _ => None, + } + } + + pub fn maybe_elem_max(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::max(val)?)), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/graph/src/range_impl/elem/expr.rs b/crates/graph/src/range_impl/elem/expr.rs new file mode 100644 index 00000000..bc535473 --- /dev/null +++ b/crates/graph/src/range_impl/elem/expr.rs @@ -0,0 +1,539 @@ + + +static SINGLETON_EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, +]; + +static EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::And, + RangeOp::Or, +]; + +static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; + +impl RangeExpr { + pub fn inverse_if_boolean(&self) -> Option { + if EQ_OPS.contains(&self.op) { + if SINGLETON_EQ_OPS.contains(&self.op) { + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.logical_inverse().unwrap(); + Some(new_self) + } else { + // non-singleton, i.e. AND or OR + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.inverse().unwrap(); + if let Some(new_lhs) = new_self.inverse_if_boolean() { + *new_self.lhs = Elem::Expr(new_lhs); + } + if let Some(new_rhs) = new_self.inverse_if_boolean() { + *new_self.rhs = Elem::Expr(new_rhs); + } + Some(new_self) + } + } else { + None + } + } +} + + +impl RangeElem for RangeExpr { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::Expr(RangeExpr::new( + self.lhs.flatten(maximize, analyzer)?, + self.op, + self.rhs.flatten(maximize, analyzer)?, + ))) + } + + fn range_ord(&self, _other: &Self) -> Option { + todo!() + } + + fn dependent_on(&self) -> Vec { + let mut deps = self.lhs.dependent_on(); + deps.extend(self.rhs.dependent_on()); + deps + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + self.lhs.update_deps(mapping); + self.rhs.update_deps(mapping); + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + self.lhs.filter_recursion(node_idx, new_idx); + self.rhs.filter_recursion(node_idx, new_idx); + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + Ok(*cached) + } else { + self.exec_op(true, analyzer) + } + } + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + Ok(*cached) + } else { + self.exec_op(false, analyzer) + } + } + + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let l = self.lhs.simplify_maximize(exclude, analyzer)?; + let r = self.rhs.simplify_maximize(exclude, analyzer)?; + match collapse(l, self.op, r) { + MaybeCollapsed::Collapsed(collapsed) => collapsed + .expect_into_expr() + .simplify_exec_op(true, exclude, analyzer), + MaybeCollapsed::Not(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(true, exclude, analyzer) + } + } + } + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let l = self.lhs.simplify_minimize(exclude, analyzer)?; + let r = self.rhs.simplify_minimize(exclude, analyzer)?; + match collapse(l, self.op, r) { + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) + } + } + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.cache_exec_op(true, g)?; + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.cache_exec_op(false, g)?; + } + Ok(()) + } + + fn uncache(&mut self) { + self.uncache_exec(); + } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + if op_set.contains(&self.op) { + Ok(true) + } else { + self.lhs.contains_op_set(max, op_set, analyzer)?; + self.rhs.contains_op_set(max, op_set, analyzer) + } + } +} + +enum MaybeCollapsed { + Collapsed(Elem), + Not(Elem, Elem), +} + +fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { + let zero = Elem::from(Concrete::from(U256::zero())); + match (l.clone(), r.clone()) { + // if we have an expression, it fundamentally must have a dynamic in it + (Elem::Expr(expr), c @ Elem::Concrete(_)) => { + // potentially collapsible + let x = expr.lhs; + let y = expr.rhs; + let z = c; + match (expr.op, op) { + (RangeOp::Eq, RangeOp::Eq) => { + // ((x == y) == z) + // can skip if x and z eq + if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z) { + MaybeCollapsed::Collapsed(l) + } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z) { + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(true))) { + MaybeCollapsed::Collapsed(l) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(l_op), RangeOp::Add(r_op)) => { + // ((x + y) + z) + let op_fn = if l_op && r_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { + // ((x + y) - z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && y >= z ==> x + (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + let new_expr = Elem::Expr(RangeExpr::new(*x, expr.op, new)); + MaybeCollapsed::Collapsed(new_expr) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x - (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => { + // x and z are concrete, if x >= z, just do (x - z) + y + // else do (y - (z - x)) + match x.range_ord(&z) { + Some(std::cmp::Ordering::Equal) + | Some(std::cmp::Ordering::Greater) => { + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, expr.op, new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // (y - (z - x)) because z > x, therefore its (-k + y) ==> (y - k) where k = (x - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *y, + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => MaybeCollapsed::Not(l, r), + } + } + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { + // ((x - y) + z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && z <= y ==> x - (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, expr.op, new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x + (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + *x, + RangeOp::Add(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + None => { + // x and z are concrete, just add them ==> (x + z) - y + let op_fn = if l_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + new, expr.op, *y, + ))) + } else { + MaybeCollapsed::Not(l, r) + } + } + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Mul(l_op), RangeOp::Mul(r_op)) => { + // ((x * y) * z) + if l_op == r_op { + let op_fn = if l_op { + // unchecked + RangeMul::range_wrapping_mul + } else { + // checked + as RangeMul>::range_mul + }; + if let Some(new) = op_fn(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_fn(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(wrapping), op) if EQ_OPS.contains(&op) => { + let const_op = if wrapping { + RangeSub::range_wrapping_sub + } else { + RangeSub::range_sub + }; + // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) + // .. + // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) + if let Some(new) = const_op(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = const_op(&z, &x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Sub(wrapping), op) if EQ_OPS.contains(&op) => { + let op_y = if wrapping { + as RangeAdd>::range_wrapping_add + } else { + as RangeAdd>::range_add + }; + let op_x = if wrapping { + as RangeSub>::range_wrapping_sub + } else { + as RangeSub>::range_sub + }; + // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) + // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) + if let Some(new) = op_x(&x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else if let Some(new) = op_y(&y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Mul(wrapping), op) if EQ_OPS.contains(&op) => { + let div_op = if wrapping { + RangeDiv::range_wrapping_div + } else { + RangeDiv::range_div + }; + // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) + // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) + if let Some(new) = div_op(&z, &x) { + let new_op = if matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, new_op, new))) + } else if let Some(new) = div_op(&z, &y) { + let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Div(wrapping), op) if EQ_OPS.contains(&op) => { + let mul_op = if wrapping { + as RangeMul>::range_wrapping_mul + } else { + as RangeMul>::range_mul + }; + let div_op = if wrapping { + as RangeDiv>::range_wrapping_div + } else { + as RangeDiv>::range_div + }; + + // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) + // .. + // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) + if let Some(new) = mul_op(&z, &y) { + let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + && FLIP_INEQ_OPS.contains(&op) + { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + } else if !FLIP_INEQ_OPS.contains(&op) { + if let Some(new) = div_op(&x, &z) { + // y is the dynamic element + // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially + // but we dont know if y was negative. so we limit to just eq & neq + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + } else { + MaybeCollapsed::Not(l, r) + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (_, RangeOp::Eq) => { + // (x _ y) == z ==> (x _ y if z == true) + if z.range_eq(&Elem::from(Concrete::from(true))) { + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(false))) { + // (!x && !y) + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(l, r), + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (_, RangeOp::Neq) => { + // (x _ y) != z ==> (x _ y if z != false) + if z.range_eq(&Elem::from(Concrete::from(false))) { + // != false is == true + MaybeCollapsed::Collapsed(l) + } else if z.range_eq(&Elem::from(Concrete::from(true))) { + // != true is == false, to make it == true, inverse everything + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(l, r), + } + } else { + MaybeCollapsed::Not(l, r) + } + } + _ => MaybeCollapsed::Not(l, r), + } + } + (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone()) { + collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, + MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), + }, + _ => MaybeCollapsed::Not(l, r), + } +} \ No newline at end of file diff --git a/crates/graph/src/range_impl/elem/map_or_array.rs b/crates/graph/src/range_impl/elem/map_or_array.rs new file mode 100644 index 00000000..129f4af9 --- /dev/null +++ b/crates/graph/src/range_impl/elem/map_or_array.rs @@ -0,0 +1,169 @@ +impl RangeElem for RangeDyn { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn range_ord(&self, _other: &Self) -> Option { + None + } + + fn dependent_on(&self) -> Vec { + let mut deps: Vec = self.len.dependent_on(); + deps.extend( + self.val + .iter() + .flat_map(|(_, val)| val.dependent_on()) + .collect::>(), + ); + deps + } + + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.flatten(maximize, analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.flatten(maximize, analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + self.len.update_deps(mapping); + self.val + .iter_mut() + .for_each(|(_, val)| val.update_deps(mapping)); + } + + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + self.len.filter_recursion(node_idx, new_idx); + self.val = self + .val + .clone() + .into_iter() + .map(|(mut k, mut v)| { + k.filter_recursion(node_idx, new_idx); + v.filter_recursion(node_idx, new_idx); + (k, v) + }) + .collect(); + } + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + return Ok(*cached); + } + + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.maximize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.maximize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + return Ok(*cached); + } + + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.minimize(analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.minimize(analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.simplify_maximize(exclude, analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.simplify_maximize(exclude, analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + Ok(Elem::ConcreteDyn(Box::new(Self { + minimized: None, + maximized: None, + len: self.len.simplify_minimize(exclude, analyzer)?, + val: { + let mut map = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + map.insert(idx, val.simplify_minimize(exclude, analyzer)?); + } + map + }, + loc: self.loc, + }))) + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + } + Ok(()) + } + + fn uncache(&mut self) { + self.minimized = None; + self.maximized = None; + } + + fn contains_op_set( + &self, + _max: bool, + _op_set: &[RangeOp], + _: &impl GraphLike, + ) -> Result { + // TODO: reevaluate this + Ok(false) + } +} \ No newline at end of file diff --git a/crates/graph/src/range_impl/elem/reference.rs b/crates/graph/src/range_impl/elem/reference.rs new file mode 100644 index 00000000..287297ad --- /dev/null +++ b/crates/graph/src/range_impl/elem/reference.rs @@ -0,0 +1,179 @@ +impl RangeElem for Reference { + fn range_eq(&self, _other: &Self) -> bool { + false + } + + fn range_ord(&self, other: &Self) -> Option { + if self.idx == other.idx { + Some(std::cmp::Ordering::Equal) + } else { + None + } + } + + fn dependent_on(&self) -> Vec { + vec![self.idx] + } + + fn update_deps(&mut self, mapping: &BTreeMap) { + if let Some(new) = mapping.get(self.idx) { + self.idx = new; + } + } + + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + if cvar.is_independent_and_storage_or_calldata(analyzer)? { + return Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))); + } + if maximize { + cvar.range_max(analyzer)? + .unwrap() + .flatten(maximize, analyzer) + } else { + let flattened = cvar + .range_min(analyzer)? + .unwrap() + .flatten(maximize, analyzer)?; + Ok(flattened) + } + } + + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + + fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + return Ok(*cached); + } + + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + range.evaled_range_max(analyzer) + } else { + Ok(Elem::Reference(self.clone())) + } + } + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + val: concrete_node.underlying(analyzer)?.clone(), + loc: cvar.loc.unwrap_or(Loc::Implicit), + })), + _e => Ok(Elem::Reference(self.clone())), + } + } + + fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + return Ok(*cached); + } + + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + range.evaled_range_min(analyzer) + } else { + Ok(Elem::Reference(self.clone())) + } + } + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { + val: concrete_node.underlying(analyzer)?.clone(), + loc: cvar.loc.unwrap_or(Loc::Implicit), + })), + _e => Ok(Elem::Reference(self.clone())), + } + } + + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + + let independent = cvar.is_independent_and_storage_or_calldata(analyzer)?; + if independent { + Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))) + } else { + self.flatten(true, analyzer)? + .simplify_maximize(exclude, analyzer) + } + } + + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); + if cvar.is_independent_and_storage_or_calldata(analyzer)? { + Ok(Elem::Reference(Reference::new( + cvar.global_first_version(analyzer).into(), + ))) + } else { + self.flatten(false, analyzer)? + .simplify_minimize(exclude, analyzer) + } + } + + fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.maximized.is_none() { + self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + } + Ok(()) + } + + fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + if self.minimized.is_none() { + self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + } + Ok(()) + } + + fn uncache(&mut self) { + self.minimized = None; + self.maximized = None; + } + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphLike, + ) -> Result { + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; + match &cvar.ty { + VarType::User(TypeNode::Contract(_), maybe_range) + | VarType::User(TypeNode::Enum(_), maybe_range) + | VarType::User(TypeNode::Ty(_), maybe_range) + | VarType::BuiltIn(_, maybe_range) => { + if let Some(range) = maybe_range { + if max { + range.max.contains_op_set(max, op_set, analyzer) + } else { + range.min.contains_op_set(max, op_set, analyzer) + } + } else { + Ok(false) + } + } + VarType::Concrete(_concrete_node) => Ok(false), + _e => Ok(false), + } + } +} \ No newline at end of file diff --git a/crates/range/src/exec/add.rs b/crates/graph/src/range_impl/exec/add.rs similarity index 95% rename from crates/range/src/exec/add.rs rename to crates/graph/src/range_impl/exec/add.rs index a9bf7a18..bcb4c717 100644 --- a/crates/range/src/exec/add.rs +++ b/crates/graph/src/range_impl/exec/add.rs @@ -1,9 +1,3 @@ -pub trait RangeAdd { - /// Perform addition between two range elements - fn range_add(&self, other: &Rhs) -> Option>; - fn range_wrapping_add(&self, other: &Rhs) -> Option>; -} - impl RangeAdd for RangeConcrete { fn range_add(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/bitwise.rs b/crates/graph/src/range_impl/exec/bitwise.rs similarity index 93% rename from crates/range/src/exec/bitwise.rs rename to crates/graph/src/range_impl/exec/bitwise.rs index d8984ae9..33d2e7aa 100644 --- a/crates/range/src/exec/bitwise.rs +++ b/crates/graph/src/range_impl/exec/bitwise.rs @@ -1,14 +1,3 @@ -pub trait RangeBitwise { - /// Perform a bitwise AND - fn range_bit_and(&self, other: &Rhs) -> Option>; - /// Perform a bitwise OR - fn range_bit_or(&self, other: &Rhs) -> Option>; - /// Perform a bitwise XOR - fn range_bit_xor(&self, other: &Rhs) -> Option>; - /// Perform a bitwise NOT - fn range_bit_not(&self) -> Option>; -} - impl RangeBitwise for RangeConcrete { fn range_bit_and(&self, other: &Self) -> Option> { match (&self.val, &other.val) { diff --git a/crates/range/src/exec/cast.rs b/crates/graph/src/range_impl/exec/cast.rs similarity index 98% rename from crates/range/src/exec/cast.rs rename to crates/graph/src/range_impl/exec/cast.rs index ec122be9..2c0f7803 100644 --- a/crates/range/src/exec/cast.rs +++ b/crates/graph/src/range_impl/exec/cast.rs @@ -1,8 +1,3 @@ -pub trait RangeCast { - /// Perform a cast on an element to the type of the right hand side - fn range_cast(&self, other: &Rhs) -> Option>; -} - impl RangeCast for RangeConcrete { fn range_cast(&self, other: &Self) -> Option> { Some(Elem::Concrete(RangeConcrete { diff --git a/crates/range/src/exec/concat.rs b/crates/graph/src/range_impl/exec/concat.rs similarity index 96% rename from crates/range/src/exec/concat.rs rename to crates/graph/src/range_impl/exec/concat.rs index 194506e2..96c5e759 100644 --- a/crates/range/src/exec/concat.rs +++ b/crates/graph/src/range_impl/exec/concat.rs @@ -1,8 +1,3 @@ -pub trait RangeConcat { - /// Perform a cast on an element to the type of the right hand side - fn range_concat(&self, other: &Rhs) -> Option>; -} - impl RangeConcat for RangeConcrete { fn range_concat(&self, other: &Self) -> Option> { Some(Elem::Concrete(RangeConcrete { diff --git a/crates/range/src/exec/div.rs b/crates/graph/src/range_impl/exec/div.rs similarity index 96% rename from crates/range/src/exec/div.rs rename to crates/graph/src/range_impl/exec/div.rs index f64a4205..c3f0e91b 100644 --- a/crates/range/src/exec/div.rs +++ b/crates/graph/src/range_impl/exec/div.rs @@ -1,10 +1,3 @@ -pub trait RangeDiv { - /// Perform division between two range elements - fn range_div(&self, other: &Rhs) -> Option>; - - fn range_wrapping_div(&self, other: &Rhs) -> Option>; -} - impl RangeDiv for RangeConcrete { fn range_div(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/exp.rs b/crates/graph/src/range_impl/exec/exp.rs similarity index 95% rename from crates/range/src/exec/exp.rs rename to crates/graph/src/range_impl/exec/exp.rs index 6ef682cf..0ecc95a0 100644 --- a/crates/range/src/exec/exp.rs +++ b/crates/graph/src/range_impl/exec/exp.rs @@ -1,8 +1,3 @@ -pub trait RangeExp { - /// Perform exponentiation between two range elements - fn range_exp(&self, other: &Rhs) -> Option>; -} - impl RangeExp for RangeConcrete { fn range_exp(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/logical.rs b/crates/graph/src/range_impl/exec/logical.rs similarity index 84% rename from crates/range/src/exec/logical.rs rename to crates/graph/src/range_impl/exec/logical.rs index 0f26c602..40b0035f 100644 --- a/crates/range/src/exec/logical.rs +++ b/crates/graph/src/range_impl/exec/logical.rs @@ -1,12 +1,3 @@ -pub trait RangeUnary { - /// Perform a logical NOT - fn range_not(&self) -> Option>; - /// Perform a logical AND - fn range_and(&self, other: &Rhs) -> Option>; - /// Perform a logical OR - fn range_or(&self, other: &Rhs) -> Option>; -} - impl RangeUnary for RangeConcrete { fn range_not(&self) -> Option> { match self.val { diff --git a/crates/range/src/exec/max.rs b/crates/graph/src/range_impl/exec/max.rs similarity index 91% rename from crates/range/src/exec/max.rs rename to crates/graph/src/range_impl/exec/max.rs index 0a5da292..079a96f3 100644 --- a/crates/range/src/exec/max.rs +++ b/crates/graph/src/range_impl/exec/max.rs @@ -1,8 +1,3 @@ -pub trait RangeMax { - /// Take the maximum of two range elements - fn range_max(&self, other: &Rhs) -> Option>; -} - impl RangeMax for RangeConcrete { fn range_max(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/min.rs b/crates/graph/src/range_impl/exec/min.rs similarity index 91% rename from crates/range/src/exec/min.rs rename to crates/graph/src/range_impl/exec/min.rs index faafb73c..87a857c3 100644 --- a/crates/range/src/exec/min.rs +++ b/crates/graph/src/range_impl/exec/min.rs @@ -1,8 +1,3 @@ -pub trait RangeMin { - /// Take the minimum of two range elements - fn range_min(&self, other: &Rhs) -> Option>; -} - impl RangeMin for RangeConcrete { fn range_min(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/mod.rs b/crates/graph/src/range_impl/exec/mod.rs similarity index 97% rename from crates/range/src/exec/mod.rs rename to crates/graph/src/range_impl/exec/mod.rs index 71a14f4d..f329167c 100644 --- a/crates/range/src/exec/mod.rs +++ b/crates/graph/src/range_impl/exec/mod.rs @@ -1,53 +1,3 @@ -/// For execution of operations to be performed on range expressions -pub trait ExecOp { - /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side - /// and right-hand-side - fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError> { - self.exec(self.spread(analyzer)?, maximize) - } - - fn exec( - &self, - parts: (Elem, Elem, Elem, Elem), - maximize: bool, - ) -> Result, GraphError>; - /// Cache execution - fn cache_exec_op( - &mut self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result<(), GraphError>; - - fn spread( - &self, - analyzer: &impl GraphLike, - ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; - - fn simplify_spread( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result<((Elem, Elem, Elem, Elem), bool), GraphError>; - - fn uncache_exec(&mut self); - - fn simplify_exec_op( - &self, - maximize: bool, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError>; - - /// Attempts to simplify an expression (i.e. just apply constant folding) - fn simplify_exec( - &self, - parts: (Elem, Elem, Elem, Elem), - maximize: bool, - ) -> Result, GraphError> { - self.exec(parts, maximize) - } -} - impl ExecOp for RangeExpr { fn cache_exec_op( &mut self, diff --git a/crates/range/src/exec/modulo.rs b/crates/graph/src/range_impl/exec/modulo.rs similarity index 91% rename from crates/range/src/exec/modulo.rs rename to crates/graph/src/range_impl/exec/modulo.rs index fa643b8e..5fb6fa0c 100644 --- a/crates/range/src/exec/modulo.rs +++ b/crates/graph/src/range_impl/exec/modulo.rs @@ -1,8 +1,3 @@ -pub trait RangeMod { - /// Perform modulo between two range elements - fn range_mod(&self, other: &Rhs) -> Option>; -} - impl RangeMod for RangeConcrete { fn range_mod(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/mul.rs b/crates/graph/src/range_impl/exec/mul.rs similarity index 95% rename from crates/range/src/exec/mul.rs rename to crates/graph/src/range_impl/exec/mul.rs index 409af3cc..91a6a6c2 100644 --- a/crates/range/src/exec/mul.rs +++ b/crates/graph/src/range_impl/exec/mul.rs @@ -1,9 +1,3 @@ -pub trait RangeMul { - /// Perform multiplication between two range elements - fn range_mul(&self, other: &Rhs) -> Option>; - fn range_wrapping_mul(&self, other: &Rhs) -> Option>; -} - impl RangeMul for RangeConcrete { fn range_mul(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/ord.rs b/crates/graph/src/range_impl/exec/ord.rs similarity index 92% rename from crates/range/src/exec/ord.rs rename to crates/graph/src/range_impl/exec/ord.rs index cd9b9431..8feb9795 100644 --- a/crates/range/src/exec/ord.rs +++ b/crates/graph/src/range_impl/exec/ord.rs @@ -1,18 +1,3 @@ -pub trait RangeOrd { - /// Perform a logical equality test - fn range_ord_eq(&self, other: &Rhs) -> Option>; - /// Perform a logical inequality test - fn range_neq(&self, other: &Rhs) -> Option>; - /// Perform a logical greater than test - fn range_gt(&self, other: &Rhs) -> Option>; - /// Perform a logical less than test - fn range_lt(&self, other: &Rhs) -> Option>; - /// Perform a logical greater than or equal test - fn range_gte(&self, other: &Rhs) -> Option>; - /// Perform a logical less than or equal test - fn range_lte(&self, other: &Rhs) -> Option>; -} - impl RangeOrd for RangeConcrete { fn range_ord_eq(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/shift.rs b/crates/graph/src/range_impl/exec/shift.rs similarity index 96% rename from crates/range/src/exec/shift.rs rename to crates/graph/src/range_impl/exec/shift.rs index 2af111a7..92636dc6 100644 --- a/crates/range/src/exec/shift.rs +++ b/crates/graph/src/range_impl/exec/shift.rs @@ -1,10 +1,3 @@ -pub trait RangeShift { - /// Perform a bitwise shift left - fn range_shl(&self, other: &Rhs) -> Option>; - /// Perform a bitwise shift right - fn range_shr(&self, other: &Rhs) -> Option>; -} - impl RangeShift for RangeConcrete { fn range_shl(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/range/src/exec/sub.rs b/crates/graph/src/range_impl/exec/sub.rs similarity index 96% rename from crates/range/src/exec/sub.rs rename to crates/graph/src/range_impl/exec/sub.rs index 5673d3be..6a6f8293 100644 --- a/crates/range/src/exec/sub.rs +++ b/crates/graph/src/range_impl/exec/sub.rs @@ -1,9 +1,3 @@ -pub trait RangeSub { - /// Perform subtraction between two range elements - fn range_sub(&self, other: &Rhs) -> Option>; - fn range_wrapping_sub(&self, other: &Rhs) -> Option>; -} - impl RangeSub for RangeConcrete { fn range_sub(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/mod.rs b/crates/graph/src/range_impl/mod.rs new file mode 100644 index 00000000..89b8850e --- /dev/null +++ b/crates/graph/src/range_impl/mod.rs @@ -0,0 +1,6 @@ +mod elem; +mod exec; +mod range_string; +mod solc_range; + +pub use solc_range::SolcRange; \ No newline at end of file diff --git a/crates/graph/src/range_impl/range_string.rs b/crates/graph/src/range_impl/range_string.rs new file mode 100644 index 00000000..f89c4f1c --- /dev/null +++ b/crates/graph/src/range_impl/range_string.rs @@ -0,0 +1,227 @@ + + + +impl ToRangeString for Elem { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + match self { + Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), + Elem::Reference(Reference { idx, .. }) => { + let cvar = ContextVarNode::from(*idx) + .first_version(analyzer) + .underlying(analyzer) + .unwrap(); + RangeElemString::new(cvar.display_name.clone(), cvar.loc.unwrap_or(Loc::Implicit)) + } + Elem::ConcreteDyn(rd) => rd.def_string(analyzer), + Elem::Expr(expr) => expr.def_string(analyzer), + Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + } + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + match self { + Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), + Elem::Reference(Reference { idx, .. }) => { + let as_var = ContextVarNode::from(*idx); + let name = as_var.display_name(analyzer).unwrap(); + RangeElemString::new(name, as_var.loc(analyzer).unwrap()) + } + Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), + Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), + Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + } + } +} + +impl ToRangeString for RangeDyn { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + let displayed_vals = self + .val + .iter() + .take(20) + .map(|(key, val)| (key.minimize(analyzer).unwrap(), val)) + .collect::>(); + + let val_str = displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + + RangeElemString::new( + format!( + "{{len: {}, indices: [{}]}}", + self.len.to_range_string(false, analyzer).s, + val_str + ), + self.loc, + ) + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + let val_str = if self.val.len() > 10 { + let displayed_vals = self + .val + .iter() + .take(5) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + let val_str_head = displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + + let displayed_vals_tail = self + .val + .iter() + .rev() + .take(5) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + let val_str_tail = displayed_vals_tail + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", "); + format!("{val_str_head} ... {val_str_tail}") + } else { + let displayed_vals = self + .val + .iter() + .take(10) + .map(|(key, val)| { + if maximize { + (key.maximize(analyzer).unwrap(), val) + } else { + (key.minimize(analyzer).unwrap(), val) + } + }) + .collect::>(); + + displayed_vals + .iter() + .map(|(key, val)| { + format!( + "{}: {}", + key.def_string(analyzer).s, + val.def_string(analyzer).s + ) + }) + .collect::>() + .join(", ") + }; + + RangeElemString::new( + format!( + "{{len: {}, indices: {{{}}}}}", + self.len.to_range_string(maximize, analyzer).s, + val_str + ), + self.loc, + ) + } +} + +impl ToRangeString for RangeExpr { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + self.lhs.def_string(analyzer) + } + + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); + let lhs_str = match *self.lhs { + Elem::Expr(_) => { + let new_str = format!("({})", lhs_r_str.s); + RangeElemString::new(new_str, lhs_r_str.loc) + } + _ => lhs_r_str, + }; + + let rhs_r_str = self.rhs.to_range_string(maximize, analyzer); + + let rhs_str = match *self.rhs { + Elem::Expr(_) => { + let new_str = format!("({})", rhs_r_str.s); + RangeElemString::new(new_str, rhs_r_str.loc) + } + _ => rhs_r_str, + }; + + if matches!(self.op, RangeOp::Min | RangeOp::Max) { + RangeElemString::new( + format!("{}{{{}, {}}}", self.op.to_string(), lhs_str.s, rhs_str.s), + lhs_str.loc, + ) + } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { + let rhs = if maximize { + self.rhs.maximize(analyzer).unwrap() + } else { + self.rhs.minimize(analyzer).unwrap() + }; + + match rhs { + Elem::Concrete(c) => RangeElemString::new( + format!( + "{}({})", + c.val.as_builtin().as_string(analyzer).unwrap(), + lhs_str.s + ), + lhs_str.loc, + ), + _ => RangeElemString::new( + format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), + lhs_str.loc, + ), + } + } else if matches!(self.op, RangeOp::BitNot) { + let lhs = if maximize { + self.lhs.maximize(analyzer).unwrap() + } else { + self.lhs.minimize(analyzer).unwrap() + }; + + match lhs { + Elem::Concrete(_c) => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), + _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), + } + } else { + RangeElemString::new( + format!("{} {} {}", lhs_str.s, self.op.to_string(), rhs_str.s), + lhs_str.loc, + ) + } + } +} diff --git a/crates/range/src/solc_range.rs b/crates/graph/src/range_impl/solc_range.rs similarity index 91% rename from crates/range/src/solc_range.rs rename to crates/graph/src/range_impl/solc_range.rs index 86b629ed..ce5e0f12 100644 --- a/crates/range/src/solc_range.rs +++ b/crates/graph/src/range_impl/solc_range.rs @@ -1,5 +1,3 @@ - - use ethers_core::types::Address; use ethers_core::types::H256; use ethers_core::types::I256; @@ -55,6 +53,43 @@ impl From> for SolcRange { } impl SolcRange { + /// Get all ContextVarNodes that this range references + pub fn dependent_on(&self) -> Vec { + let mut deps = self.range_min().dependent_on(); + deps.extend(self.range_max().dependent_on()); + deps.dedup(); + + deps.into_iter().map(ContextVarNode::from).collect() + } + + /// Update a particular context variable with the latest version + pub fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphLike) { + let deps = self.dependent_on(); + let mapping: BTreeMap = deps + .into_iter() + .filter(|dep| !dep.is_const(analyzer).unwrap()) + .map(|dep| { + let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); + if latest == node { + if let Some(prev) = latest.previous_version(analyzer) { + (dep.0.into(), prev.0.into()) + } else { + (dep.0.into(), dep.0.into()) + } + } else { + (dep.0.into(), latest.0.into()) + } + }) + .collect(); + + let mut min = self.range_min().into_owned(); + let mut max = self.range_max().into_owned(); + min.update_deps(&mapping); + max.update_deps(&mapping); + self.set_range_min(min); + self.set_range_max(max); + } + pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { Self { min, @@ -622,89 +657,6 @@ impl Range for SolcRange { } } -pub trait Range { - type ElemTy: RangeElem + Clone; - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; - fn simplified_range_min( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result; - fn simplified_range_max( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result; - fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; - fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy>; - fn uncache_range_min(&mut self) { - self.range_min_mut().uncache(); - } - fn uncache_range_max(&mut self) { - self.range_max_mut().uncache(); - } - fn range_min_mut(&mut self) -> &mut Self::ElemTy; - fn range_max_mut(&mut self) -> &mut Self::ElemTy; - fn range_exclusions(&self) -> Vec - where - Self: std::marker::Sized; - fn set_range_min(&mut self, new: Self::ElemTy); - fn set_range_max(&mut self, new: Self::ElemTy); - fn set_range_exclusions(&mut self, new: Vec) - where - Self: std::marker::Sized; - fn add_range_exclusion(&mut self, new: Self::ElemTy) - where - Self: std::marker::Sized; - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); - fn dependent_on(&self) -> Vec { - let mut deps = self.range_min().dependent_on(); - deps.extend(self.range_max().dependent_on()); - deps.dedup(); - deps - } - - fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphLike) { - let deps = self.dependent_on(); - let mapping: BTreeMap = deps - .into_iter() - .filter(|dep| !dep.is_const(analyzer).unwrap()) - .map(|dep| { - let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); - if latest == node { - if let Some(prev) = latest.previous_version(analyzer) { - (dep, prev) - } else { - (dep, dep) - } - } else { - (dep, latest) - } - }) - .collect(); - - let mut min = self.range_min().into_owned(); - let mut max = self.range_max().into_owned(); - min.update_deps(&mapping); - max.update_deps(&mapping); - self.set_range_min(min); - self.set_range_max(max); - } -} - -pub trait RangeEval>: Range { - fn sat(&self, analyzer: &impl GraphLike) -> bool; - fn unsat(&self, analyzer: &impl GraphLike) -> bool { - !self.sat(analyzer) - } - fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool; - fn contains_elem(&self, other: &T, analyzer: &impl GraphLike) -> bool; - fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool; -} - impl RangeEval> for SolcRange { fn sat(&self, analyzer: &impl GraphLike) -> bool { matches!( diff --git a/crates/solvers/src/dl.rs b/crates/graph/src/solvers/dl.rs similarity index 100% rename from crates/solvers/src/dl.rs rename to crates/graph/src/solvers/dl.rs diff --git a/crates/solvers/src/lib.rs b/crates/graph/src/solvers/mod.rs similarity index 100% rename from crates/solvers/src/lib.rs rename to crates/graph/src/solvers/mod.rs diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml index 46c81db9..bdf54361 100644 --- a/crates/pyrometer/Cargo.toml +++ b/crates/pyrometer/Cargo.toml @@ -11,10 +11,11 @@ homepage.workspace = true repository.workspace = true [dependencies] -analyzer.workspace = true +analyzers.workspace = true graph.workspace = true range.workspace = true -solc_expressions.workspace = true +solc-expressions.workspace = true + solang-parser.workspace = true ethers-core.workspace = true ariadne.workspace = true diff --git a/crates/queries/Cargo.toml b/crates/queries/Cargo.toml index e69de29b..746fcc9a 100644 --- a/crates/queries/Cargo.toml +++ b/crates/queries/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "queries" +description = "Core Pyrometer library and analyzer implementation" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[dependencies] +analyzers.workspace = true +graph.workspace = true +range.workspace = true +solc-expressions.workspace = true + +solang-parser.workspace = true +ethers-core.workspace = true +ariadne.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true \ No newline at end of file diff --git a/crates/queries/lib.rs b/crates/queries/src/lib.rs similarity index 100% rename from crates/queries/lib.rs rename to crates/queries/src/lib.rs diff --git a/crates/queries/storage_write/access.rs b/crates/queries/src/storage_write/access.rs similarity index 100% rename from crates/queries/storage_write/access.rs rename to crates/queries/src/storage_write/access.rs diff --git a/crates/queries/storage_write/mod.rs b/crates/queries/src/storage_write/mod.rs similarity index 100% rename from crates/queries/storage_write/mod.rs rename to crates/queries/src/storage_write/mod.rs diff --git a/crates/queries/storage_write/target.rs b/crates/queries/src/storage_write/target.rs similarity index 100% rename from crates/queries/storage_write/target.rs rename to crates/queries/src/storage_write/target.rs diff --git a/crates/queries/taint.rs b/crates/queries/src/taint.rs similarity index 100% rename from crates/queries/taint.rs rename to crates/queries/src/taint.rs diff --git a/crates/range/Cargo.toml b/crates/range/Cargo.toml index 0e16aa5d..36bf9983 100644 --- a/crates/range/Cargo.toml +++ b/crates/range/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "range" -description = "Pyrometer's representation of a range" +description = "Pyrometer's trait and generics based representation of a range" version.workspace = true edition.workspace = true @@ -11,7 +11,7 @@ homepage.workspace = true repository.workspace = true [dependencies] -graph.workspace = true +shared.workspace = true solang-parser.workspace = true ethers-core.workspace = true hex.workspace = true diff --git a/crates/range/src/elem/elem_enum.rs b/crates/range/src/elem/elem_enum.rs index b8cb6287..5f774e31 100644 --- a/crates/range/src/elem/elem_enum.rs +++ b/crates/range/src/elem/elem_enum.rs @@ -2,7 +2,7 @@ #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Elem { /// A range element that is a reference to another node - Reference(Reference), + Reference(Reference), /// A concrete range element of type `T`. e.g.: some number like `10` ConcreteDyn(Box>), /// A concrete range element of type `T`. e.g.: some number like `10` @@ -13,60 +13,6 @@ pub enum Elem { Null, } -impl std::fmt::Display for Elem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), - Elem::ConcreteDyn(..) => write!(f, "range_elem"), - Elem::Concrete(RangeConcrete { val, .. }) => { - write!(f, "{}", val.as_string()) - } - Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { - RangeOp::Min | RangeOp::Max => { - write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) - } - RangeOp::Cast => match &**rhs { - Elem::Concrete(RangeConcrete { val, .. }) => { - write!( - f, - "{}({}, {})", - op.to_string(), - lhs, - val.as_builtin().basic_as_string() - ) - } - _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), - }, - RangeOp::BitNot => { - write!(f, "~{}", lhs) - } - _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), - }, - _ => write!(f, ""), - } - } -} - -impl From for Elem { - fn from(c: Concrete) -> Self { - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }) - } -} - -impl From for Elem { - fn from(c: ContextVarNode) -> Self { - Elem::Reference(Reference::new(c.into())) - } -} - -impl From for Elem { - fn from(idx: NodeIdx) -> Self { - Elem::Reference(Reference::new(idx)) - } -} impl Elem { pub fn contains_node(&self, node_idx: NodeIdx) -> bool { @@ -154,344 +100,70 @@ impl From> for Elem { } } -impl Elem { - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { - match self { - Self::Reference(Reference { idx, .. }) => { - if *idx == to_replace { - *self = replacement; - } - } - Self::Concrete(_) => {} - Self::Expr(expr) => { - expr.lhs.replace_dep(to_replace, replacement.clone()); - expr.rhs.replace_dep(to_replace, replacement); - expr.maximized = None; - expr.minimized = None; - } - Self::ConcreteDyn(_d) => todo!(), - Self::Null => {} - } - } - - pub fn inverse_if_boolean(&self) -> Option { - match self { - Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), - Self::ConcreteDyn(_d) => None, - Self::Null => None, - } - } - - pub fn node_idx(&self) -> Option { - match self { - Self::Reference(Reference { idx, .. }) => Some(*idx), - _ => None, - } - } - - pub fn concrete(&self) -> Option { - match self { - Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), - _ => None, - } - } - - pub fn is_negative( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result { - let res = match self { - Elem::Concrete(RangeConcrete { - val: Concrete::Int(_, val), - .. - }) if val < &I256::zero() => true, - Elem::Reference(dy) => { - if maximize { - dy.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - dy.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - Elem::Expr(expr) => { - if maximize { - expr.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - expr.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - _ => false, - }; - Ok(res) - } - - pub fn pre_evaled_is_negative(&self) -> bool { - matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) - } - - pub fn maybe_concrete(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } - } - - pub fn maybe_concrete_value(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } - } - - pub fn maybe_range_dyn(&self) -> Option> { - match self { - Elem::ConcreteDyn(a) => Some(*a.clone()), - _ => None, - } - } -} - -impl RangeElem for Elem { - fn range_eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), - _ => false, - } - } - - fn range_ord(&self, other: &Self) -> Option { - match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), - (Self::Reference(a), Self::Reference(b)) => a.range_ord(b), - _ => None, - } - } - - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - match self { - Self::Reference(d) => d.flatten(maximize, analyzer), - Self::Concrete(c) => c.flatten(maximize, analyzer), - Self::Expr(expr) => expr.flatten(maximize, analyzer), - Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), - Self::Null => Ok(Elem::Null), - } - } - - fn dependent_on(&self) -> Vec { - match self { - Self::Reference(d) => d.dependent_on(), - Self::Concrete(_) => vec![], - Self::Expr(expr) => expr.dependent_on(), - Self::ConcreteDyn(d) => d.dependent_on(), - Self::Null => vec![], - } - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - match self { - Self::Reference(d) => d.update_deps(mapping), - Self::Concrete(_) => {} - Self::Expr(expr) => expr.update_deps(mapping), - Self::ConcreteDyn(d) => d.update_deps(mapping), - Self::Null => {} - } - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - match self { - Self::Reference(ref mut d) => { - if d.idx == node_idx { - d.idx = new_idx - } - } - Self::Concrete(_) => {} - Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx), - Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx), - Self::Null => {} - } - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Reference(dy) => dy.maximize(analyzer)?, - Concrete(inner) => inner.maximize(analyzer)?, - ConcreteDyn(inner) => inner.maximize(analyzer)?, - Expr(expr) => expr.maximize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - use Elem::*; - let res = match self { - Reference(dy) => dy.minimize(analyzer)?, - Concrete(inner) => inner.minimize(analyzer)?, - ConcreteDyn(inner) => inner.minimize(analyzer)?, - Expr(expr) => expr.minimize(analyzer)?, - Null => Elem::Null, - }; - Ok(res) - } - - fn simplify_maximize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.simplify_maximize(exclude, analyzer), - Concrete(inner) => inner.simplify_maximize(exclude, analyzer), - ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), - Expr(expr) => expr.simplify_maximize(exclude, analyzer), - Null => Ok(Elem::Null), - } - } - - fn simplify_minimize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.simplify_minimize(exclude, analyzer), - Concrete(inner) => inner.simplify_minimize(exclude, analyzer), - ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), - Expr(expr) => expr.simplify_minimize(exclude, analyzer), - Null => Ok(Elem::Null), - } - } - - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.cache_maximize(analyzer), - Concrete(inner) => inner.cache_maximize(analyzer), - ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => expr.cache_maximize(analyzer), - Null => Ok(()), - } - } - - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.cache_minimize(analyzer), - Concrete(inner) => inner.cache_minimize(analyzer), - ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => expr.cache_minimize(analyzer), - Null => Ok(()), - } - } - fn uncache(&mut self) { - use Elem::*; - match self { - Reference(dy) => dy.uncache(), - Concrete(inner) => inner.uncache(), - ConcreteDyn(inner) => inner.uncache(), - Expr(expr) => expr.uncache(), - Null => {} - } - } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphLike, - ) -> Result { - use Elem::*; - match self { - Reference(dy) => dy.contains_op_set(max, op_set, analyzer), - Concrete(inner) => inner.contains_op_set(max, op_set, analyzer), - ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), - Expr(expr) => expr.contains_op_set(max, op_set, analyzer), - Null => Ok(false), - } - } -} - -impl Add for Elem { +impl Add for Elem { type Output = Self; - fn add(self, other: Elem) -> Self { + fn add(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Add(false), other); Self::Expr(expr) } } -impl Sub for Elem { +impl Sub for Elem { type Output = Self; - fn sub(self, other: Elem) -> Self { + fn sub(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Sub(false), other); Self::Expr(expr) } } -impl Mul for Elem { +impl Mul for Elem { type Output = Self; - fn mul(self, other: Elem) -> Self { + fn mul(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Mul(false), other); Self::Expr(expr) } } -impl Div for Elem { +impl Div for Elem { type Output = Self; - fn div(self, other: Elem) -> Self { + fn div(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Div(false), other); Self::Expr(expr) } } -impl Shl for Elem { +impl Shl for Elem { type Output = Self; - fn shl(self, other: Elem) -> Self { + fn shl(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Shl, other); Self::Expr(expr) } } -impl Shr for Elem { +impl Shr for Elem { type Output = Self; - fn shr(self, other: Elem) -> Self { + fn shr(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Shr, other); Self::Expr(expr) } } -impl Rem for Elem { +impl Rem for Elem { type Output = Self; - fn rem(self, other: Elem) -> Self { + fn rem(self, other: Elem) -> Self { let expr = RangeExpr::new(self, RangeOp::Mod, other); Self::Expr(expr) } } -impl BitAnd for Elem { +impl BitAnd for Elem { type Output = Self; fn bitand(self, other: Self) -> Self::Output { @@ -500,7 +172,7 @@ impl BitAnd for Elem { } } -impl BitOr for Elem { +impl BitOr for Elem { type Output = Self; fn bitor(self, other: Self) -> Self::Output { @@ -509,56 +181,11 @@ impl BitOr for Elem { } } -impl BitXor for Elem { +impl BitXor for Elem { type Output = Self; fn bitxor(self, other: Self) -> Self::Output { let expr = RangeExpr::new(self, RangeOp::BitXor, other); Self::Expr(expr) } -} - -impl Elem { - pub fn wrapping_add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(true), other); - Self::Expr(expr) - } - pub fn wrapping_sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(true), other); - Self::Expr(expr) - } - pub fn wrapping_mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(true), other); - Self::Expr(expr) - } - pub fn wrapping_div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(true), other); - Self::Expr(expr) - } - - /// Creates a logical AND of two range elements - pub fn and(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::And, other); - Self::Expr(expr) - } - - /// Creates a logical OR of two range elements - pub fn or(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Or, other); - Self::Expr(expr) - } - - pub fn maybe_elem_min(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::min(val)?)), - _ => None, - } - } - - pub fn maybe_elem_max(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::max(val)?)), - _ => None, - } - } } \ No newline at end of file diff --git a/crates/range/src/elem/expr.rs b/crates/range/src/elem/expr.rs index e0870e86..37d38801 100644 --- a/crates/range/src/elem/expr.rs +++ b/crates/range/src/elem/expr.rs @@ -1,28 +1,5 @@ -static SINGLETON_EQ_OPS: &[RangeOp] = &[ - RangeOp::Eq, - RangeOp::Neq, - RangeOp::Lt, - RangeOp::Lte, - RangeOp::Gt, - RangeOp::Gte, -]; - -static EQ_OPS: &[RangeOp] = &[ - RangeOp::Eq, - RangeOp::Neq, - RangeOp::Lt, - RangeOp::Lte, - RangeOp::Gt, - RangeOp::Gte, - RangeOp::And, - RangeOp::Or, -]; - -static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; - - /// A range expression composed of other range [`Elem`] #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeExpr { @@ -33,32 +10,7 @@ pub struct RangeExpr { pub rhs: Box>, } -impl RangeExpr { - pub fn inverse_if_boolean(&self) -> Option { - if EQ_OPS.contains(&self.op) { - if SINGLETON_EQ_OPS.contains(&self.op) { - let mut new_self = self.clone(); - new_self.uncache(); - new_self.op = new_self.op.logical_inverse().unwrap(); - Some(new_self) - } else { - // non-singleton, i.e. AND or OR - let mut new_self = self.clone(); - new_self.uncache(); - new_self.op = new_self.op.inverse().unwrap(); - if let Some(new_lhs) = new_self.inverse_if_boolean() { - *new_self.lhs = Elem::Expr(new_lhs); - } - if let Some(new_rhs) = new_self.inverse_if_boolean() { - *new_self.rhs = Elem::Expr(new_rhs); - } - Some(new_self) - } - } else { - None - } - } -} + impl RangeExpr { /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. @@ -76,491 +28,3 @@ impl RangeExpr { self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) } } - -impl RangeElem for RangeExpr { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::Expr(RangeExpr::new( - self.lhs.flatten(maximize, analyzer)?, - self.op, - self.rhs.flatten(maximize, analyzer)?, - ))) - } - - fn range_ord(&self, _other: &Self) -> Option { - todo!() - } - - fn dependent_on(&self) -> Vec { - let mut deps = self.lhs.dependent_on(); - deps.extend(self.rhs.dependent_on()); - deps - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - self.lhs.update_deps(mapping); - self.rhs.update_deps(mapping); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.lhs.filter_recursion(node_idx, new_idx); - self.rhs.filter_recursion(node_idx, new_idx); - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - Ok(*cached) - } else { - self.exec_op(true, analyzer) - } - } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - Ok(*cached) - } else { - self.exec_op(false, analyzer) - } - } - - fn simplify_maximize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let l = self.lhs.simplify_maximize(exclude, analyzer)?; - let r = self.rhs.simplify_maximize(exclude, analyzer)?; - match collapse(l, self.op, r) { - MaybeCollapsed::Collapsed(collapsed) => collapsed - .expect_into_expr() - .simplify_exec_op(true, exclude, analyzer), - MaybeCollapsed::Not(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(true, exclude, analyzer) - } - } - } - fn simplify_minimize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let l = self.lhs.simplify_minimize(exclude, analyzer)?; - let r = self.rhs.simplify_minimize(exclude, analyzer)?; - match collapse(l, self.op, r) { - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) - } - } - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.cache_exec_op(true, g)?; - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.cache_exec_op(false, g)?; - } - Ok(()) - } - - fn uncache(&mut self) { - self.uncache_exec(); - } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphLike, - ) -> Result { - if op_set.contains(&self.op) { - Ok(true) - } else { - self.lhs.contains_op_set(max, op_set, analyzer)?; - self.rhs.contains_op_set(max, op_set, analyzer) - } - } -} - -enum MaybeCollapsed { - Collapsed(Elem), - Not(Elem, Elem), -} - -fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { - let zero = Elem::from(Concrete::from(U256::zero())); - match (l.clone(), r.clone()) { - // if we have an expression, it fundamentally must have a dynamic in it - (Elem::Expr(expr), c @ Elem::Concrete(_)) => { - // potentially collapsible - let x = expr.lhs; - let y = expr.rhs; - let z = c; - match (expr.op, op) { - (RangeOp::Eq, RangeOp::Eq) => { - // ((x == y) == z) - // can skip if x and z eq - if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z) { - MaybeCollapsed::Collapsed(l) - } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z) { - MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(true))) { - MaybeCollapsed::Collapsed(l) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(l_op), RangeOp::Add(r_op)) => { - // ((x + y) + z) - let op_fn = if l_op && r_op { - // unchecked - RangeAdd::range_wrapping_add - } else { - // checked - as RangeAdd>::range_add - }; - if let Some(new) = op_fn(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { - // ((x + y) - z) => k - y || x + k - if l_op == r_op { - match y.range_ord(&z) { - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { - // y and z are concrete && y >= z ==> x + (y - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&y, &z) { - let new_expr = Elem::Expr(RangeExpr::new(*x, expr.op, new)); - MaybeCollapsed::Collapsed(new_expr) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // y and z are concrete && y < z ==> x - (z - y) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&z, &y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, - RangeOp::Sub(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => { - // x and z are concrete, if x >= z, just do (x - z) + y - // else do (y - (z - x)) - match x.range_ord(&z) { - Some(std::cmp::Ordering::Equal) - | Some(std::cmp::Ordering::Greater) => { - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, expr.op, new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // (y - (z - x)) because z > x, therefore its (-k + y) ==> (y - k) where k = (x - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&z, &x) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *y, - RangeOp::Sub(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => MaybeCollapsed::Not(l, r), - } - } - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { - // ((x - y) + z) => k - y || x + k - if l_op == r_op { - match y.range_ord(&z) { - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { - // y and z are concrete && z <= y ==> x - (y - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, expr.op, new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // y and z are concrete && y < z ==> x + (z - y) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(&z, &y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, - RangeOp::Add(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => { - // x and z are concrete, just add them ==> (x + z) - y - let op_fn = if l_op { - // unchecked - RangeAdd::range_wrapping_add - } else { - // checked - as RangeAdd>::range_add - }; - if let Some(new) = op_fn(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - new, expr.op, *y, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Mul(l_op), RangeOp::Mul(r_op)) => { - // ((x * y) * z) - if l_op == r_op { - let op_fn = if l_op { - // unchecked - RangeMul::range_wrapping_mul - } else { - // checked - as RangeMul>::range_mul - }; - if let Some(new) = op_fn(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(wrapping), op) if EQ_OPS.contains(&op) => { - let const_op = if wrapping { - RangeSub::range_wrapping_sub - } else { - RangeSub::range_sub - }; - // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) - // .. - // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) - if let Some(new) = const_op(&z, &y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = const_op(&z, &x) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Sub(wrapping), op) if EQ_OPS.contains(&op) => { - let op_y = if wrapping { - as RangeAdd>::range_wrapping_add - } else { - as RangeAdd>::range_add - }; - let op_x = if wrapping { - as RangeSub>::range_wrapping_sub - } else { - as RangeSub>::range_sub - }; - // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) - // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) - if let Some(new) = op_x(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_y(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Mul(wrapping), op) if EQ_OPS.contains(&op) => { - let div_op = if wrapping { - RangeDiv::range_wrapping_div - } else { - RangeDiv::range_div - }; - // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) - // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) - if let Some(new) = div_op(&z, &x) { - let new_op = if matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, new_op, new))) - } else if let Some(new) = div_op(&z, &y) { - let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Div(wrapping), op) if EQ_OPS.contains(&op) => { - let mul_op = if wrapping { - as RangeMul>::range_wrapping_mul - } else { - as RangeMul>::range_mul - }; - let div_op = if wrapping { - as RangeDiv>::range_wrapping_div - } else { - as RangeDiv>::range_div - }; - - // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) - // .. - // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) - if let Some(new) = mul_op(&z, &y) { - let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) - } else if !FLIP_INEQ_OPS.contains(&op) { - if let Some(new) = div_op(&x, &z) { - // y is the dynamic element - // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially - // but we dont know if y was negative. so we limit to just eq & neq - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (_, RangeOp::Eq) => { - // (x _ y) == z ==> (x _ y if z == true) - if z.range_eq(&Elem::from(Concrete::from(true))) { - MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(false))) { - // (!x && !y) - match ( - x.inverse_if_boolean(), - y.inverse_if_boolean(), - expr.op.logical_inverse(), - ) { - (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( - Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), - ), - _ => MaybeCollapsed::Not(l, r), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (_, RangeOp::Neq) => { - // (x _ y) != z ==> (x _ y if z != false) - if z.range_eq(&Elem::from(Concrete::from(false))) { - // != false is == true - MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(true))) { - // != true is == false, to make it == true, inverse everything - match ( - x.inverse_if_boolean(), - y.inverse_if_boolean(), - expr.op.logical_inverse(), - ) { - (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( - Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), - ), - _ => MaybeCollapsed::Not(l, r), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - _ => MaybeCollapsed::Not(l, r), - } - } - (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone()) { - collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, - MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), - }, - _ => MaybeCollapsed::Not(l, r), - } -} \ No newline at end of file diff --git a/crates/range/src/elem/map_or_array.rs b/crates/range/src/elem/map_or_array.rs index 57814a3a..54c094c0 100644 --- a/crates/range/src/elem/map_or_array.rs +++ b/crates/range/src/elem/map_or_array.rs @@ -1,189 +1,27 @@ /// A concrete value for a range element #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeDyn { + /// Cached minimized value pub minimized: Option>, + /// Cached maximized value pub maximized: Option>, + /// Length of the dynamic variable pub len: Elem, + /// Values of the dynamic variable pub val: BTreeMap, Elem>, + /// Sourcecode location pub loc: Loc, } impl RangeDyn { + /// Set the length pub fn set_len(&mut self, new_len: Elem) { self.len = new_len; } + /// Check if the node contains a reference to a node index pub fn contains_node(&self, node_idx: NodeIdx) -> bool { self.len.contains_node(node_idx) // || self.val.iter().any(|(k, v)| k.contains_node(node_idx) || v.contains_node(node_idx)) } } -impl RangeElem for RangeDyn { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn range_ord(&self, _other: &Self) -> Option { - None - } - - fn dependent_on(&self) -> Vec { - let mut deps: Vec = self.len.dependent_on(); - deps.extend( - self.val - .iter() - .flat_map(|(_, val)| val.dependent_on()) - .collect::>(), - ); - deps - } - - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.flatten(maximize, analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.flatten(maximize, analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - self.len.update_deps(mapping); - self.val - .iter_mut() - .for_each(|(_, val)| val.update_deps(mapping)); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.len.filter_recursion(node_idx, new_idx); - self.val = self - .val - .clone() - .into_iter() - .map(|(mut k, mut v)| { - k.filter_recursion(node_idx, new_idx); - v.filter_recursion(node_idx, new_idx); - (k, v) - }) - .collect(); - } - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - return Ok(*cached); - } - - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.maximize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.maximize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - return Ok(*cached); - } - - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.minimize(analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.minimize(analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn simplify_maximize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_maximize(exclude, analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_maximize(exclude, analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - fn simplify_minimize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_minimize(exclude, analyzer)?, - val: { - let mut map = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_minimize(exclude, analyzer)?); - } - map - }, - loc: self.loc, - }))) - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); - } - Ok(()) - } - - fn uncache(&mut self) { - self.minimized = None; - self.maximized = None; - } - - fn contains_op_set( - &self, - _max: bool, - _op_set: &[RangeOp], - _: &impl GraphLike, - ) -> Result { - // TODO: reevaluate this - Ok(false) - } -} \ No newline at end of file diff --git a/crates/range/src/elem/mod.rs b/crates/range/src/elem/mod.rs index 9eb8b0b9..d376f30b 100644 --- a/crates/range/src/elem/mod.rs +++ b/crates/range/src/elem/mod.rs @@ -1,6 +1,3 @@ - - - use std::collections::BTreeMap; mod concrete; @@ -9,6 +6,12 @@ mod expr; mod map_or_array; mod reference; +pub use concrete::*; +pub use elem_enum::*; +pub use expr::*; +pub use map_or_array::*; +pub use reference::*; + #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum MinMaxed { @@ -94,6 +97,7 @@ impl RangeOp { } } + /// Gets the logical inverse of a boolean operation pub fn logical_inverse(self) -> Option { use RangeOp::*; match self { @@ -196,7 +200,7 @@ pub trait RangeElem { } /// Traverses the range expression and finds all nodes that are dynamically pointed to /// and returns it in a vector. - fn dependent_on(&self) -> Vec; + fn dependent_on(&self) -> Vec; /// Traverses the range expression and updates stale pointers from older versions /// of a variable to a newer version. /// @@ -204,7 +208,7 @@ pub trait RangeElem { /// without the `require` statement, `z`'s max is `2**256 - 1`, but with /// the introduction of the `require` statement, we do a little backtracking /// and can update `z`'s max to be `200`. - fn update_deps(&mut self, mapping: &BTreeMap); + fn update_deps(&mut self, mapping: &BTreeMap); /// Attempts to replace range elements that form a cyclic dependency by replacing /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now /// but in theory it can make sense. diff --git a/crates/range/src/elem/reference.rs b/crates/range/src/elem/reference.rs index 7269770a..6ff39b21 100644 --- a/crates/range/src/elem/reference.rs +++ b/crates/range/src/elem/reference.rs @@ -1,13 +1,15 @@ /// A dynamic range element value #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct Reference { +pub struct Reference { /// Index of the node that is referenced pub idx: NodeIdx, - pub minimized: Option>, - pub maximized: Option>, + /// Cached minimized value + pub minimized: Option>, + /// Cached maximized value + pub maximized: Option>, } -impl Reference { +impl Reference { pub fn new(idx: NodeIdx) -> Self { Self { idx, @@ -15,184 +17,4 @@ impl Reference { maximized: None, } } -} - -impl RangeElem for Reference { - fn range_eq(&self, _other: &Self) -> bool { - false - } - - fn range_ord(&self, other: &Self) -> Option { - if self.idx == other.idx { - Some(std::cmp::Ordering::Equal) - } else { - None - } - } - - fn dependent_on(&self) -> Vec { - vec![ContextVarNode::from(self.idx)] - } - - fn update_deps(&mut self, mapping: &BTreeMap) { - if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { - self.idx = NodeIdx::from(new.0); - } - } - - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let cvar = ContextVarNode::from(self.idx); - if cvar.is_independent_and_storage_or_calldata(analyzer)? { - return Ok(Elem::Reference(Reference::new( - cvar.global_first_version(analyzer).into(), - ))); - } - if maximize { - cvar.range_max(analyzer)? - .unwrap() - .flatten(maximize, analyzer) - } else { - let flattened = cvar - .range_min(analyzer)? - .unwrap() - .flatten(maximize, analyzer)?; - Ok(flattened) - } - } - - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - return Ok(*cached); - } - - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - range.evaled_range_max(analyzer) - } else { - Ok(Elem::Reference(self.clone())) - } - } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), - _e => Ok(Elem::Reference(self.clone())), - } - } - - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - return Ok(*cached); - } - - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - range.evaled_range_min(analyzer) - } else { - Ok(Elem::Reference(self.clone())) - } - } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), - _e => Ok(Elem::Reference(self.clone())), - } - } - - fn simplify_maximize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let cvar = ContextVarNode::from(self.idx); - - let independent = cvar.is_independent_and_storage_or_calldata(analyzer)?; - if independent { - Ok(Elem::Reference(Reference::new( - cvar.global_first_version(analyzer).into(), - ))) - } else { - self.flatten(true, analyzer)? - .simplify_maximize(exclude, analyzer) - } - } - - fn simplify_minimize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let cvar = ContextVarNode::from(self.idx); - if cvar.is_independent_and_storage_or_calldata(analyzer)? { - Ok(Elem::Reference(Reference::new( - cvar.global_first_version(analyzer).into(), - ))) - } else { - self.flatten(false, analyzer)? - .simplify_minimize(exclude, analyzer) - } - } - - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.maximized.is_none() { - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); - } - Ok(()) - } - - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { - if self.minimized.is_none() { - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); - } - Ok(()) - } - - fn uncache(&mut self) { - self.minimized = None; - self.maximized = None; - } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphLike, - ) -> Result { - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - if max { - range.max.contains_op_set(max, op_set, analyzer) - } else { - range.min.contains_op_set(max, op_set, analyzer) - } - } else { - Ok(false) - } - } - VarType::Concrete(_concrete_node) => Ok(false), - _e => Ok(false), - } - } } \ No newline at end of file diff --git a/crates/range/src/exec.rs b/crates/range/src/exec.rs new file mode 100644 index 00000000..2c3bd3ac --- /dev/null +++ b/crates/range/src/exec.rs @@ -0,0 +1,146 @@ +/// For execution of operations to be performed on range expressions +pub trait ExecOp { + /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side + /// and right-hand-side + fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError> { + self.exec(self.spread(analyzer)?, maximize) + } + + fn exec( + &self, + parts: (Elem, Elem, Elem, Elem), + maximize: bool, + ) -> Result, GraphError>; + /// Cache execution + fn cache_exec_op( + &mut self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result<(), GraphError>; + + fn spread( + &self, + analyzer: &impl GraphLike, + ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; + + fn simplify_spread( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result<((Elem, Elem, Elem, Elem), bool), GraphError>; + + fn uncache_exec(&mut self); + + fn simplify_exec_op( + &self, + maximize: bool, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError>; + + /// Attempts to simplify an expression (i.e. just apply constant folding) + fn simplify_exec( + &self, + parts: (Elem, Elem, Elem, Elem), + maximize: bool, + ) -> Result, GraphError> { + self.exec(parts, maximize) + } +} + +pub trait RangeAdd { + /// Perform addition between two range elements + fn range_add(&self, other: &Rhs) -> Option>; + fn range_wrapping_add(&self, other: &Rhs) -> Option>; +} + +pub trait RangeSub { + /// Perform subtraction between two range elements + fn range_sub(&self, other: &Rhs) -> Option>; + fn range_wrapping_sub(&self, other: &Rhs) -> Option>; +} + +pub trait RangeDiv { + /// Perform division between two range elements + fn range_div(&self, other: &Rhs) -> Option>; + + fn range_wrapping_div(&self, other: &Rhs) -> Option>; +} + +pub trait RangeExp { + /// Perform exponentiation between two range elements + fn range_exp(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMul { + /// Perform multiplication between two range elements + fn range_mul(&self, other: &Rhs) -> Option>; + fn range_wrapping_mul(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMod { + /// Perform modulo between two range elements + fn range_mod(&self, other: &Rhs) -> Option>; +} + +pub trait RangeBitwise { + /// Perform a bitwise AND + fn range_bit_and(&self, other: &Rhs) -> Option>; + /// Perform a bitwise OR + fn range_bit_or(&self, other: &Rhs) -> Option>; + /// Perform a bitwise XOR + fn range_bit_xor(&self, other: &Rhs) -> Option>; + /// Perform a bitwise NOT + fn range_bit_not(&self) -> Option>; +} + +pub trait RangeShift { + /// Perform a bitwise shift left + fn range_shl(&self, other: &Rhs) -> Option>; + /// Perform a bitwise shift right + fn range_shr(&self, other: &Rhs) -> Option>; +} + +pub trait RangeCast { + /// Perform a cast on an element to the type of the right hand side + fn range_cast(&self, other: &Rhs) -> Option>; +} + +pub trait RangeConcat { + /// Perform a cast on an element to the type of the right hand side + fn range_concat(&self, other: &Rhs) -> Option>; +} + +pub trait RangeUnary { + /// Perform a logical NOT + fn range_not(&self) -> Option>; + /// Perform a logical AND + fn range_and(&self, other: &Rhs) -> Option>; + /// Perform a logical OR + fn range_or(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMax { + /// Take the maximum of two range elements + fn range_max(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMin { + /// Take the minimum of two range elements + fn range_min(&self, other: &Rhs) -> Option>; +} + +pub trait RangeOrd { + /// Perform a logical equality test + fn range_ord_eq(&self, other: &Rhs) -> Option>; + /// Perform a logical inequality test + fn range_neq(&self, other: &Rhs) -> Option>; + /// Perform a logical greater than test + fn range_gt(&self, other: &Rhs) -> Option>; + /// Perform a logical less than test + fn range_lt(&self, other: &Rhs) -> Option>; + /// Perform a logical greater than or equal test + fn range_gte(&self, other: &Rhs) -> Option>; + /// Perform a logical less than or equal test + fn range_lte(&self, other: &Rhs) -> Option>; +} diff --git a/crates/range/src/lib.rs b/crates/range/src/lib.rs index 2cfa78e4..da36dd38 100644 --- a/crates/range/src/lib.rs +++ b/crates/range/src/lib.rs @@ -5,5 +5,72 @@ mod range_string; pub use elem::*; pub use exec::*; -pub use solc_range::*; pub use range_string::*; + +pub trait Range { + type ElemTy: RangeElem + Clone; + /// Evaluate both the minimum and the maximum - cache along the way + fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + /// Evaluate the range minimum + fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; + /// Evaluate the range maximum + fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; + /// Simplify the minimum, leaving references in place + fn simplified_range_min( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result; + /// Simplify the maximum, leaving references in place + fn simplified_range_max( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result; + /// Return the range minimum + fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; + /// Return the range maximum + fn range_max(&self) -> std::borrow::Cow<'_, Self::ElemTy>; + /// Uncache the range minimum + fn uncache_range_min(&mut self) { + self.range_min_mut().uncache(); + } + /// Uncache the range maximum + fn uncache_range_max(&mut self) { + self.range_max_mut().uncache(); + } + /// Get a mutable reference to the minimum + fn range_min_mut(&mut self) -> &mut Self::ElemTy; + /// Get a mutable reference to the maximum + fn range_max_mut(&mut self) -> &mut Self::ElemTy; + /// Get the range exclusions + fn range_exclusions(&self) -> Vec + where + Self: std::marker::Sized; + /// Set the range minimum + fn set_range_min(&mut self, new: Self::ElemTy); + /// Set the range maximum + fn set_range_max(&mut self, new: Self::ElemTy); + /// Set the range exclusions + fn set_range_exclusions(&mut self, new: Vec) + where + Self: std::marker::Sized; + /// Add an exclusion value to the range + fn add_range_exclusion(&mut self, new: Self::ElemTy) + where + Self: std::marker::Sized; + /// Replace a potential recursion causing node index with a new index + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + /// Replace a potential recursion causing node index with a new index + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); +} + +pub trait RangeEval>: Range { + fn sat(&self, analyzer: &impl GraphLike) -> bool; + fn unsat(&self, analyzer: &impl GraphLike) -> bool { + !self.sat(analyzer) + } + fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool; + fn contains_elem(&self, other: &T, analyzer: &impl GraphLike) -> bool; + fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool; +} \ No newline at end of file diff --git a/crates/range/src/range_string.rs b/crates/range/src/range_string.rs index 05d10914..49004f0b 100644 --- a/crates/range/src/range_string.rs +++ b/crates/range/src/range_string.rs @@ -38,228 +38,3 @@ pub trait ToRangeString { /// Converts a range to a human string fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString; } - -impl ToRangeString for Elem { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - match self { - Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { - let cvar = ContextVarNode::from(*idx) - .first_version(analyzer) - .underlying(analyzer) - .unwrap(); - RangeElemString::new(cvar.display_name.clone(), cvar.loc.unwrap_or(Loc::Implicit)) - } - Elem::ConcreteDyn(rd) => rd.def_string(analyzer), - Elem::Expr(expr) => expr.def_string(analyzer), - Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - } - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - match self { - Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), - Elem::Reference(Reference { idx, .. }) => { - let as_var = ContextVarNode::from(*idx); - let name = as_var.display_name(analyzer).unwrap(); - RangeElemString::new(name, as_var.loc(analyzer).unwrap()) - } - Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), - Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), - Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - } - } -} - -impl ToRangeString for RangeDyn { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - let displayed_vals = self - .val - .iter() - .take(20) - .map(|(key, val)| (key.minimize(analyzer).unwrap(), val)) - .collect::>(); - - let val_str = displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - - RangeElemString::new( - format!( - "{{len: {}, indices: [{}]}}", - self.len.to_range_string(false, analyzer).s, - val_str - ), - self.loc, - ) - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - let val_str = if self.val.len() > 10 { - let displayed_vals = self - .val - .iter() - .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - let val_str_head = displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - - let displayed_vals_tail = self - .val - .iter() - .rev() - .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - let val_str_tail = displayed_vals_tail - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", "); - format!("{val_str_head} ... {val_str_tail}") - } else { - let displayed_vals = self - .val - .iter() - .take(10) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } - }) - .collect::>(); - - displayed_vals - .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s - ) - }) - .collect::>() - .join(", ") - }; - - RangeElemString::new( - format!( - "{{len: {}, indices: {{{}}}}}", - self.len.to_range_string(maximize, analyzer).s, - val_str - ), - self.loc, - ) - } -} - -impl ToRangeString for RangeExpr { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - self.lhs.def_string(analyzer) - } - - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); - let lhs_str = match *self.lhs { - Elem::Expr(_) => { - let new_str = format!("({})", lhs_r_str.s); - RangeElemString::new(new_str, lhs_r_str.loc) - } - _ => lhs_r_str, - }; - - let rhs_r_str = self.rhs.to_range_string(maximize, analyzer); - - let rhs_str = match *self.rhs { - Elem::Expr(_) => { - let new_str = format!("({})", rhs_r_str.s); - RangeElemString::new(new_str, rhs_r_str.loc) - } - _ => rhs_r_str, - }; - - if matches!(self.op, RangeOp::Min | RangeOp::Max) { - RangeElemString::new( - format!("{}{{{}, {}}}", self.op.to_string(), lhs_str.s, rhs_str.s), - lhs_str.loc, - ) - } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { - let rhs = if maximize { - self.rhs.maximize(analyzer).unwrap() - } else { - self.rhs.minimize(analyzer).unwrap() - }; - - match rhs { - Elem::Concrete(c) => RangeElemString::new( - format!( - "{}({})", - c.val.as_builtin().as_string(analyzer).unwrap(), - lhs_str.s - ), - lhs_str.loc, - ), - _ => RangeElemString::new( - format!("{}({}, {})", self.op.to_string(), lhs_str.s, rhs_str.s), - lhs_str.loc, - ), - } - } else if matches!(self.op, RangeOp::BitNot) { - let lhs = if maximize { - self.lhs.maximize(analyzer).unwrap() - } else { - self.lhs.minimize(analyzer).unwrap() - }; - - match lhs { - Elem::Concrete(_c) => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), - _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), - } - } else { - RangeElemString::new( - format!("{} {} {}", lhs_str.s, self.op.to_string(), rhs_str.s), - lhs_str.loc, - ) - } - } -} diff --git a/crates/solvers/Cargo.toml b/crates/shared/Cargo.toml similarity index 60% rename from crates/solvers/Cargo.toml rename to crates/shared/Cargo.toml index 7b409227..aa1e2a3c 100644 --- a/crates/solvers/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "solvers" -description = "SMT solvers" +name = "shared" +description = "Shared utilities and structures" version.workspace = true edition.workspace = true @@ -11,11 +11,8 @@ homepage.workspace = true repository.workspace = true [dependencies] -petgraph.workspace = true -graph.workspace = true -range.workspace = true +solang-parser.workspace = true ethers-core.workspace = true +hex.workspace = true tracing.workspace = true -tracing-subscriber.workspace = true - -itertools = "0.12.0" +tracing-subscriber.workspace = true \ No newline at end of file diff --git a/crates/analyzer/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs similarity index 100% rename from crates/analyzer/src/analyzer_like.rs rename to crates/shared/src/analyzer_like.rs diff --git a/crates/graph/src/graph_like.rs b/crates/shared/src/graph_like.rs similarity index 99% rename from crates/graph/src/graph_like.rs rename to crates/shared/src/graph_like.rs index a4c710db..3303bf0c 100644 --- a/crates/graph/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,4 +1,6 @@ +pub type NodeIdx = NodeIndex; +pub type EdgeIdx = EdgeIndex; pub trait AsDotStr { fn as_dot_str(&self, analyzer: &impl GraphLike) -> String; diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/solc_expressions/Cargo.toml b/crates/solc-expressions/Cargo.toml similarity index 81% rename from crates/solc_expressions/Cargo.toml rename to crates/solc-expressions/Cargo.toml index 3f244fc1..a8cb83f2 100644 --- a/crates/solc_expressions/Cargo.toml +++ b/crates/solc-expressions/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "solc-expressions" -description = "Pyrometer's parsing of solidity based expressions" +description = "Pyrometer's parsing of solidity-based expressions" version.workspace = true edition.workspace = true @@ -11,7 +11,7 @@ homepage.workspace = true repository.workspace = true [dependencies] -analyzer.workspace = true +analyzers.workspace = true graph.workspace = true solang-parser.workspace = true ethers-core.workspace = true diff --git a/crates/solc_expressions/src/array.rs b/crates/solc-expressions/src/array.rs similarity index 97% rename from crates/solc_expressions/src/array.rs rename to crates/solc-expressions/src/array.rs index 2acc730b..7507af3b 100644 --- a/crates/solc_expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -83,7 +83,10 @@ pub trait Array: AnalyzerLike + Sized { self.parse_ctx_expr(index_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(index_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Could not find the index variable".to_string())) + return Err(ExprErr::NoRhs( + loc, + "Could not find the index variable".to_string(), + )); }; if matches!(index_tys, ExprRet::CtxKilled(_)) { ctx.push_expr(index_tys, analyzer).into_expr_err(loc)?; @@ -92,7 +95,7 @@ pub trait Array: AnalyzerLike + Sized { analyzer.parse_ctx_expr(ty_expr, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(inner_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Could not find the array".to_string())) + return Err(ExprErr::NoLhs(loc, "Could not find the array".to_string())); }; if matches!(inner_tys, ExprRet::CtxKilled(_)) { ctx.push_expr(inner_tys, analyzer).into_expr_err(loc)?; diff --git a/crates/solc_expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs similarity index 99% rename from crates/solc_expressions/src/bin_op.rs rename to crates/solc-expressions/src/bin_op.rs index 22804398..7c0140e2 100644 --- a/crates/solc_expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -713,7 +713,10 @@ pub trait BinOp: AnalyzerLike + Sized { self.parse_ctx_expr(lhs_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + return Err(ExprErr::NoRhs( + loc, + "Not operation had no element".to_string(), + )); }; if matches!(lhs, ExprRet::CtxKilled(_)) { diff --git a/crates/solc_expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs similarity index 97% rename from crates/solc_expressions/src/cmp.rs rename to crates/solc-expressions/src/cmp.rs index f7fe03a1..a538a9f0 100644 --- a/crates/solc_expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -25,7 +25,10 @@ pub trait Cmp: AnalyzerLike + Sized { self.parse_ctx_expr(lhs_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + return Err(ExprErr::NoRhs( + loc, + "Not operation had no element".to_string(), + )); }; if matches!(lhs, ExprRet::CtxKilled(_)) { @@ -98,7 +101,10 @@ pub trait Cmp: AnalyzerLike + Sized { analyzer.parse_ctx_expr(rhs_expr, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Cmp operation had no right hand side".to_string())) + return Err(ExprErr::NoRhs( + loc, + "Cmp operation had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -109,8 +115,12 @@ pub trait Cmp: AnalyzerLike + Sized { analyzer.parse_ctx_expr(lhs_expr, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Cmp operation had no left hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Cmp operation had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { diff --git a/crates/solc_expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs similarity index 97% rename from crates/solc_expressions/src/cond_op.rs rename to crates/solc-expressions/src/cond_op.rs index 3938a0d3..e0bc9d4a 100644 --- a/crates/solc_expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -44,7 +44,9 @@ pub trait CondOp: AnalyzerLike + Require + // we want to check if the true branch is possible to take analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; let mut true_killed = false; - if true_subctx.is_killed(analyzer).into_expr_err(loc)? { + if true_subctx.is_killed(analyzer).into_expr_err(loc)? + || true_subctx.unreachable(analyzer).into_expr_err(loc)? + { // it was killed, therefore true branch is unreachable. // since it is unreachable, we want to not create // unnecessary subcontexts @@ -54,7 +56,9 @@ pub trait CondOp: AnalyzerLike + Require + // we want to check if the false branch is possible to take analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; let mut false_killed = false; - if false_subctx.is_killed(analyzer).into_expr_err(loc)? { + if false_subctx.is_killed(analyzer).into_expr_err(loc)? + || false_subctx.unreachable(analyzer).into_expr_err(loc)? + { // it was killed, therefore true branch is unreachable. // since it is unreachable, we want to not create // unnecessary subcontexts diff --git a/crates/solc_expressions/src/env.rs b/crates/solc-expressions/src/env.rs similarity index 100% rename from crates/solc_expressions/src/env.rs rename to crates/solc-expressions/src/env.rs diff --git a/crates/solc_expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs similarity index 100% rename from crates/solc_expressions/src/func_call/internal_call.rs rename to crates/solc-expressions/src/func_call/internal_call.rs diff --git a/crates/solc_expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs similarity index 100% rename from crates/solc_expressions/src/func_call/intrinsic_call.rs rename to crates/solc-expressions/src/func_call/intrinsic_call.rs diff --git a/crates/solc_expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs similarity index 100% rename from crates/solc_expressions/src/func_call/mod.rs rename to crates/solc-expressions/src/func_call/mod.rs diff --git a/crates/solc_expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs similarity index 100% rename from crates/solc_expressions/src/func_call/modifier.rs rename to crates/solc-expressions/src/func_call/modifier.rs diff --git a/crates/solc_expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs similarity index 100% rename from crates/solc_expressions/src/func_call/namespaced_call.rs rename to crates/solc-expressions/src/func_call/namespaced_call.rs diff --git a/crates/solc_expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs similarity index 100% rename from crates/solc_expressions/src/lib.rs rename to crates/solc-expressions/src/lib.rs diff --git a/crates/solc_expressions/src/list.rs b/crates/solc-expressions/src/list.rs similarity index 74% rename from crates/solc_expressions/src/list.rs rename to crates/solc-expressions/src/list.rs index a5fae6e1..66ffa16f 100644 --- a/crates/solc_expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -13,31 +13,37 @@ impl List for T where T: AnalyzerLike + pub trait List: AnalyzerLike + Sized { #[tracing::instrument(level = "trace", skip_all)] fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { - params - .iter() - .try_for_each(|(loc, input)| { - if let Some(input) = input { - self.parse_ctx_expr(&input.ty, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - ctx.append_tmp_expr(analyzer.match_ty(ctx, &loc, &ret, input)?, analyzer).into_expr_err(loc) - }) - } else { - // create a dummy var - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.append_tmp_expr(ExprRet::Null, analyzer).into_expr_err(loc) - }) - } - })?; + params.iter().try_for_each(|(loc, input)| { + if let Some(input) = input { + self.parse_ctx_expr(&input.ty, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "List did not have left hand sides".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + ctx.append_tmp_expr(analyzer.match_ty(ctx, &loc, &ret, input)?, analyzer) + .into_expr_err(loc) + }) + } else { + // create a dummy var + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + ctx.append_tmp_expr(ExprRet::Null, analyzer) + .into_expr_err(loc) + }) + } + })?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "List did not have left hand sides".to_string())); + return Err(ExprErr::NoLhs( + loc, + "List did not have left hand sides".to_string(), + )); }; ctx.push_expr(ret, analyzer).into_expr_err(loc) }) diff --git a/crates/solc_expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs similarity index 100% rename from crates/solc_expressions/src/literal.rs rename to crates/solc-expressions/src/literal.rs diff --git a/crates/solc_expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs similarity index 100% rename from crates/solc_expressions/src/loops.rs rename to crates/solc-expressions/src/loops.rs diff --git a/crates/solc_expressions/src/member_access.rs b/crates/solc-expressions/src/member_access.rs similarity index 99% rename from crates/solc_expressions/src/member_access.rs rename to crates/solc-expressions/src/member_access.rs index b3b68111..9bab2c39 100644 --- a/crates/solc_expressions/src/member_access.rs +++ b/crates/solc-expressions/src/member_access.rs @@ -112,7 +112,10 @@ pub trait MemberAccess: AnalyzerLike + Siz self.parse_ctx_expr(member_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); + return Err(ExprErr::NoLhs( + loc, + "Attempted to perform member access without a left-hand side".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -805,7 +808,7 @@ pub trait MemberAccess: AnalyzerLike + Siz self.variable(ident, ctx, None)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())) + return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())); }; if matches!(index_paths, ExprRet::CtxKilled(_)) { @@ -882,7 +885,10 @@ pub trait MemberAccess: AnalyzerLike + Siz self.parse_ctx_expr(input_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Attempted to perform member access without a left-hand side".to_string())); + return Err(ExprErr::NoLhs( + loc, + "Attempted to perform member access without a left-hand side".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; diff --git a/crates/solc_expressions/src/require.rs b/crates/solc-expressions/src/require.rs similarity index 84% rename from crates/solc_expressions/src/require.rs rename to crates/solc-expressions/src/require.rs index 0852ad30..1faefab8 100644 --- a/crates/solc_expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -37,6 +37,9 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { // Expression::And(loc, lhs, rhs) => { // Expression::Or(loc, Box::new(self.inverse_expr(*lhs)), Box::new(self.inverse_expr(*rhs))) // } + // Expression::Or(loc, lhs, rhs) => { + // Expression::And(loc, Box::new(self.inverse_expr(*lhs)), Box::new(self.inverse_expr(*rhs))) + // } // Expression::Not(loc, lhs) => { // Expression::Equal(loc, lhs, Box::new(Expression::BoolLiteral(loc, true))) // } @@ -47,12 +50,16 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { /// Handles a require expression #[tracing::instrument(level = "trace", skip_all)] fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { - match inputs.get(0).expect("No lhs input for require statement") { + match inputs.first().expect("No lhs input for require statement") { Expression::Equal(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `==` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `==` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -64,8 +71,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `==` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `==` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { @@ -87,8 +99,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::NotEqual(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `!=` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `!=` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -98,8 +114,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { } analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `!=` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `!=` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -120,8 +141,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::Less(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `<` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `<` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -132,8 +157,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `<` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `<` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -154,8 +184,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::More(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `>` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `>` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -166,8 +200,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `>` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `>` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -188,8 +227,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::MoreEqual(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `>=` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `>=` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -200,8 +243,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `>=` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `>=` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -222,8 +270,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::LessEqual(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Require operation `<=` had no right hand side".to_string())) + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Require operation `<=` had no right hand side".to_string(), + )); }; let rhs_paths = rhs_paths.flatten(); @@ -234,8 +286,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(lhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `<=` had no left hand side".to_string())) + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `<=` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -256,15 +313,20 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::Not(loc, lhs) => { self.parse_ctx_expr(lhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `NOT` had no left hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `NOT` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - let cnode = - ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(false)))); + let cnode = ConcreteNode::from( + analyzer.add_node(Node::Concrete(Concrete::Bool(false))), + ); let tmp_false = Node::ContextVar( ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) .into_expr_err(loc)?, @@ -285,8 +347,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::And(loc, lhs, rhs) => { self.parse_ctx_expr(lhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `&&` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { @@ -296,8 +362,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(rhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `&&` had no left hand side".to_string())) + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `&&` had no left hand side".to_string(), + )); }; if matches!(rhs_paths, ExprRet::CtxKilled(_)) { @@ -305,7 +376,9 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { return Ok(()); } - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let cnode = ConcreteNode::from( + analyzer.add_node(Node::Concrete(Concrete::Bool(true))), + ); let tmp_true = Node::ContextVar( ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) .into_expr_err(loc)?, @@ -315,29 +388,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); let tmp_rhs_paths = ExprRet::Single(node); - analyzer.handle_require_inner( - ctx, - loc, - &lhs_paths, - &tmp_rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - )?; - - analyzer.handle_require_inner( - ctx, - loc, - &rhs_paths, - &tmp_rhs_paths, - RangeOp::Eq, - RangeOp::Neq, - (RangeOp::Neq, RangeOp::Eq), - )?; - + // NOTE: the following is *sequence dependent* + // we want to update the parts *before* the `And` op + // to ensure the ctx_dep is correct // update the part's bounds - let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + let lhs_cvar = + ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); let underlying = lhs_cvar.underlying(analyzer).into_expr_err(loc)?; if let Some(tmp) = underlying.tmp_of { if let Some((op, inv_op, pair)) = tmp.op.require_parts() { @@ -354,7 +411,8 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { } // update the part's bounds - let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); + let rhs_cvar = + ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); let underlying = rhs_cvar.underlying(analyzer).into_expr_err(loc)?; if let Some(tmp) = underlying.tmp_of { if let Some((op, inv_op, pair)) = tmp.op.require_parts() { @@ -369,6 +427,27 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { )?; } } + + analyzer.handle_require_inner( + ctx, + loc, + &lhs_paths, + &tmp_rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + )?; + + analyzer.handle_require_inner( + ctx, + loc, + &rhs_paths, + &tmp_rhs_paths, + RangeOp::Eq, + RangeOp::Neq, + (RangeOp::Neq, RangeOp::Eq), + )?; + Ok(()) }) }) @@ -376,8 +455,12 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Expression::Or(loc, lhs, rhs) => { self.parse_ctx_expr(lhs, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `||` had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -386,8 +469,13 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { analyzer.parse_ctx_expr(rhs, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation `||` had no left hand side".to_string())) + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation `||` had no left hand side".to_string(), + )); }; if matches!(rhs_paths, ExprRet::CtxKilled(_)) { @@ -395,10 +483,16 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { return Ok(()); } - let lhs_cvar = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - let rhs_cvar = ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); + let lhs_cvar = + ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); + let rhs_cvar = + ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); - let elem = Elem::Expr(RangeExpr::new(lhs_cvar.into(), RangeOp::Or, rhs_cvar.into())); + let elem = Elem::Expr(RangeExpr::new( + lhs_cvar.into(), + RangeOp::Or, + rhs_cvar.into(), + )); let range = SolcRange::new(elem.clone(), elem, vec![]); let new_lhs_underlying = ContextVar { @@ -421,11 +515,22 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { is_symbolic: lhs_cvar.is_symbolic(analyzer).into_expr_err(loc)? || rhs_cvar.is_symbolic(analyzer).into_expr_err(loc)?, is_return: false, - tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Or, Some(rhs_cvar))), - ty: VarType::BuiltIn(analyzer.builtin_or_add(Builtin::Bool).into(), Some(range)) + tmp_of: Some(TmpConstruction::new( + lhs_cvar, + RangeOp::Or, + Some(rhs_cvar), + )), + ty: VarType::BuiltIn( + analyzer.builtin_or_add(Builtin::Bool).into(), + Some(range), + ), }; - let or_var = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_lhs_underlying))); - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let or_var = ContextVarNode::from( + analyzer.add_node(Node::ContextVar(new_lhs_underlying)), + ); + let cnode = ConcreteNode::from( + analyzer.add_node(Node::Concrete(Concrete::Bool(true))), + ); let tmp_true = Node::ContextVar( ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) .into_expr_err(loc)?, @@ -449,14 +554,19 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { other => { self.parse_ctx_expr(other, ctx)?; self.apply_to_edges(ctx, other.loc(), &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Require operation had no left hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Require operation had no left hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - let cnode = ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); + let cnode = + ConcreteNode::from(analyzer.add_node(Node::Concrete(Concrete::Bool(true)))); let tmp_true = Node::ContextVar( ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, analyzer) .into_expr_err(other.loc())?, @@ -586,7 +696,7 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { loc: Loc, op: RangeOp, rhs_op: RangeOp, - recursion_ops: (RangeOp, RangeOp), + _recursion_ops: (RangeOp, RangeOp), ) -> Result, ExprErr> { tracing::trace!( "require: {} {} {}", @@ -732,7 +842,26 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { } } - let tmp_var = ContextVar { + let rhs_display_name = new_rhs.display_name(self).into_expr_err(loc)?; + let display_name = if rhs_display_name == "true" { + (new_lhs.display_name(self).into_expr_err(loc)?).to_string() + } else { + format!( + "({} {} {rhs_display_name})", + new_lhs.display_name(self).into_expr_err(loc)?, + op.to_string(), + ) + }; + + // we take the previous version because for the solver we actually dont want the updated range + let base = Elem::Expr(RangeExpr::new( + new_lhs.previous_version(self).unwrap_or(new_lhs).into(), + op, + new_rhs.previous_version(self).unwrap_or(new_rhs).into(), + )); + + // construct a temporary variable that represent the conditional we just checked + let conditional_var = ContextVar { loc: Some(loc), name: format!( "tmp{}({} {} {})", @@ -741,21 +870,65 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { op.to_string(), new_rhs.name(self).into_expr_err(loc)?, ), - display_name: format!( - "({} {} {})", - new_lhs.display_name(self).into_expr_err(loc)?, + display_name: display_name.clone(), + storage: None, + is_tmp: true, + tmp_of: Some(TmpConstruction::new(new_lhs, op, Some(new_rhs))), + is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? + || new_rhs.is_symbolic(self).into_expr_err(loc)?, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + // we set the minimum to `true` so that if `elem` evaluates to false, + // we can discover the unsatisifiability + Some(SolcRange::new(base.clone(), base, vec![])), + ), + }; + + let conditional_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(conditional_var))); + ctx.add_var(conditional_cvar, self).into_expr_err(loc)?; + self.add_edge(conditional_cvar, ctx, Edge::Context(ContextEdge::Variable)); + + let cnode = ConcreteNode::from(self.add_node(Node::Concrete(Concrete::Bool(true)))); + let tmp_true = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode, self) + .into_expr_err(loc)?, + ); + + // construct a temporary `true` node + let tmp_true = ContextVarNode::from(self.add_node(tmp_true)); + + // construct a temporary var that will be used as the ctx dependency + let tmp_var = ContextVar { + loc: Some(loc), + name: format!( + "tmp{}(({} {} {}) == true)", + ctx.new_tmp(self).into_expr_err(loc)?, + new_lhs.name(self).into_expr_err(loc)?, op.to_string(), - new_rhs.display_name(self).into_expr_err(loc)?, + new_rhs.name(self).into_expr_err(loc)?, ), + display_name: format!("{display_name} == true"), storage: None, is_tmp: true, - tmp_of: Some(TmpConstruction::new(new_lhs, op, Some(new_rhs))), + tmp_of: Some(TmpConstruction::new( + tmp_true, + RangeOp::Eq, + Some(conditional_cvar), + )), is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? || new_rhs.is_symbolic(self).into_expr_err(loc)?, is_return: false, ty: VarType::BuiltIn( BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), + // we set the minimum to `true` so that if `elem` evaluates to false, + // we can discover the unsatisifiability + Some(SolcRange::new( + Elem::from(Concrete::from(true)), + Elem::from(conditional_cvar), + vec![], + )), ), }; @@ -783,7 +956,7 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { ); if let Some(tmp) = new_lhs.tmp_of(self).into_expr_err(loc)? { if tmp.op.inverse().is_some() && !matches!(op, RangeOp::Eq | RangeOp::Neq) { - self.range_recursion(tmp, recursion_ops, new_rhs, ctx, loc, &mut any_unsat)?; + // self.range_recursion(tmp, recursion_ops, new_rhs, ctx, loc, &mut any_unsat)?; } else { match tmp.op { RangeOp::Not => {} @@ -891,8 +1064,7 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { { // mins are equivalent, add 1 instead of adding an exclusion let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; - let Some(min) = min - .maybe_concrete() else { + let Some(min) = min.maybe_concrete() else { return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); }; let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); @@ -1081,6 +1253,10 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { Ok(false) } RangeOp::Neq => { + if new_rhs == new_lhs { + return Ok(true); + } + let rhs_elem = Elem::from(new_rhs.latest_version(self)); // just add as an exclusion lhs_range.add_range_exclusion(rhs_elem); @@ -1262,9 +1438,7 @@ pub trait Require: AnalyzerLike + Variable + BinOp + Sized { ) -> Result<(), ExprErr> { tracing::trace!("Recursing through range"); // handle lhs - let Some(inverse) = tmp_construction - .op - .inverse() else { + let Some(inverse) = tmp_construction.op.inverse() else { return Ok(()); }; diff --git a/crates/solc_expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs similarity index 84% rename from crates/solc_expressions/src/variable.rs rename to crates/solc-expressions/src/variable.rs index d77dc4a2..2e8896b4 100644 --- a/crates/solc_expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -69,11 +69,13 @@ pub trait Variable: AnalyzerLike + Sized { None }; + let mut storage_idx = None; let var = if let Some(con) = const_var { con } else { match self.node(idx) { - Node::Var(_) | Node::Enum(_) => { + Node::Var(_) => { + storage_idx = Some(idx); match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { Some(v) => v, None => { @@ -87,6 +89,18 @@ pub trait Variable: AnalyzerLike + Sized { } } } + Node::Enum(_) => match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + ident.loc, + format!( + "Could not create context variable from user type: {:?}", + self.node(idx) + ), + )) + } + }, _ => { return target_ctx .push_expr(ExprRet::Single(idx), self) @@ -99,6 +113,14 @@ pub trait Variable: AnalyzerLike + Sized { ctx.add_var(new_cvarnode.into(), self) .into_expr_err(ident.loc)?; + + if let Some(store_idx) = storage_idx { + self.add_edge( + new_cvarnode, + store_idx, + Edge::Context(ContextEdge::InheritedStorageVariable), + ); + } self.add_edge( new_cvarnode, target_ctx, diff --git a/crates/solc_expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs similarity index 100% rename from crates/solc_expressions/src/yul/mod.rs rename to crates/solc-expressions/src/yul/mod.rs diff --git a/crates/solc_expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs similarity index 100% rename from crates/solc_expressions/src/yul/yul_cond_op.rs rename to crates/solc-expressions/src/yul/yul_cond_op.rs diff --git a/crates/solc_expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs similarity index 100% rename from crates/solc_expressions/src/yul/yul_funcs.rs rename to crates/solc-expressions/src/yul/yul_funcs.rs From da79a6399a6a017c0f87567b77c1f0258c433aeb Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 7 Dec 2023 19:51:47 -0800 Subject: [PATCH 10/71] progress on moving structure over --- Cargo.lock | 1 + TODO.md | 2 +- crates/graph/src/lib.rs | 3 - crates/graph/src/nodes/context/context_tys.rs | 6 + crates/graph/src/nodes/context/expr_ret.rs | 6 +- crates/graph/src/nodes/context/mod.rs | 5 +- crates/graph/src/nodes/context/node.rs | 10 + crates/graph/src/nodes/context/querying.rs | 3 +- crates/graph/src/nodes/context/solving.rs | 3 +- crates/graph/src/nodes/context/typing.rs | 6 +- crates/graph/src/nodes/context/underlying.rs | 13 + crates/graph/src/nodes/context/var/ranging.rs | 5 + crates/graph/src/nodes/context/variables.rs | 8 + crates/graph/src/nodes/context/versioning.rs | 6 + crates/graph/src/range_impl/elem/concrete.rs | 9 + crates/graph/src/range_impl/elem/elem_enum.rs | 8 + crates/graph/src/range_impl/elem/expr.rs | 7 + .../graph/src/range_impl/elem/map_or_array.rs | 7 + crates/graph/src/range_impl/elem/mod.rs | 11 + crates/graph/src/range_impl/elem/reference.rs | 8 + crates/graph/src/range_impl/exec/add.rs | 5 + crates/graph/src/range_impl/exec/bitwise.rs | 4 + crates/graph/src/range_impl/exec/cast.rs | 6 + crates/graph/src/range_impl/exec/concat.rs | 6 + crates/graph/src/range_impl/exec/div.rs | 5 + crates/graph/src/range_impl/exec/exec_op.rs | 1254 ++++++++++++++++ crates/graph/src/range_impl/exec/exp.rs | 4 + crates/graph/src/range_impl/exec/logical.rs | 3 + crates/graph/src/range_impl/exec/max.rs | 3 + crates/graph/src/range_impl/exec/min.rs | 3 + crates/graph/src/range_impl/exec/mod.rs | 1261 +---------------- crates/graph/src/range_impl/exec/modulo.rs | 5 + crates/graph/src/range_impl/exec/mul.rs | 7 + crates/graph/src/range_impl/exec/ord.rs | 5 + crates/graph/src/range_impl/exec/shift.rs | 5 + crates/graph/src/range_impl/exec/sub.rs | 5 + crates/graph/src/range_impl/range_string.rs | 6 + crates/graph/src/range_impl/solc_range.rs | 13 +- crates/graph/src/solvers/atoms.rs | 346 +++++ crates/graph/src/solvers/dl.rs | 8 +- crates/graph/src/solvers/mod.rs | 341 +---- crates/range/src/elem/concrete.rs | 139 +- crates/range/src/elem/elem_enum.rs | 23 +- crates/range/src/elem/expr.rs | 3 +- crates/range/src/elem/map_or_array.rs | 7 + crates/range/src/elem/mod.rs | 19 +- crates/range/src/elem/reference.rs | 3 + crates/range/src/exec.rs | 20 +- crates/range/src/lib.rs | 24 +- crates/range/src/range_string.rs | 3 +- crates/shared/Cargo.toml | 1 + crates/shared/src/analyzer_like.rs | 111 +- crates/shared/src/graph_like.rs | 520 +++---- crates/shared/src/lib.rs | 5 + 54 files changed, 2228 insertions(+), 2072 deletions(-) create mode 100644 crates/graph/src/range_impl/elem/mod.rs create mode 100644 crates/graph/src/range_impl/exec/exec_op.rs create mode 100644 crates/graph/src/solvers/atoms.rs diff --git a/Cargo.lock b/Cargo.lock index bb486a2a..db1ad92d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,6 +1456,7 @@ version = "0.2.0" dependencies = [ "ethers-core", "hex", + "petgraph", "solang-parser", "tracing", "tracing-subscriber", diff --git a/TODO.md b/TODO.md index 450b4281..c63b9fb8 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,7 @@ - [x] Cleanup repo (remove unnecessary files, automate testing, etc.) - [x] Graceful error handling - [ ] `join` operations between contexts - - [ ] Trait/Lang separation cleanup + - [x] Trait/Lang separation cleanup - [ ] Propogate requirements across variables (i.e. `y = x;` & `x != 0;` therefore `y != 0;`) - [ ] Language - [x] Better import handling (`foundry.toml` reading?) diff --git a/crates/graph/src/lib.rs b/crates/graph/src/lib.rs index 596e7a43..52b4a584 100644 --- a/crates/graph/src/lib.rs +++ b/crates/graph/src/lib.rs @@ -1,9 +1,7 @@ mod graph_elements; -mod graph_like; mod search; mod range_impl; mod var_type; -mod solvers; pub mod nodes; pub mod solvers; @@ -11,6 +9,5 @@ pub mod solvers; pub use var_type::*; pub use graph_elements::*; -pub use graph_like::*; pub use range_impl::*; pub use search::*; diff --git a/crates/graph/src/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs index c8bc81a0..0d625c72 100644 --- a/crates/graph/src/nodes/context/context_tys.rs +++ b/crates/graph/src/nodes/context/context_tys.rs @@ -1,3 +1,9 @@ +use crate::nodes::{ContextNode, ContextVarNode, FunctionNode, ContractNode}; +use shared::NodeIdx; + +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; /// An enum that denotes either a call or a fork of a context #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index 61e33362..7aaeade5 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -1,6 +1,6 @@ -use crate::analyzer::AsDotStr; -use crate::context::GraphError; -use crate::{ContextVarNode, GraphLike, Node, NodeIdx, VarType}; +use crate::{GraphError, Node, VarType, nodes::context::ContextVarNode,}; +use shared::{NodeIdx, GraphLike, AsDotStr}; + /// The reason a context was killed #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] diff --git a/crates/graph/src/nodes/context/mod.rs b/crates/graph/src/nodes/context/mod.rs index 8f239016..9f2e07cf 100644 --- a/crates/graph/src/nodes/context/mod.rs +++ b/crates/graph/src/nodes/context/mod.rs @@ -2,10 +2,13 @@ mod context_tys; mod expr_ret; mod node; mod underlying; +mod var; pub use node::ContextNode; pub use underlying::Context; -pub mod var; +pub use var::ContextVarNode; +pub use expr_ret::{KilledKind, ExprRet}; +pub use context_tys::{ ModifierState, ContextCache, CallFork }; // ContextNode implementations are split to ease in maintainability diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 5f7662fa..34c3f460 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,3 +1,13 @@ +use crate::{ + nodes::{ FunctionParamNode, ContextVarNode, Context, FunctionNode, KilledKind }, + GraphError, Node +}; + +use shared::{AsDotStr, NodeIdx, AnalyzerLike, GraphLike}; + +use solang_parser::pt::Loc; +use std::collections::BTreeMap; + #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] /// A wrapper of a node index that corresponds to a [`Context`] pub struct ContextNode(pub usize); diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 852da7db..56160620 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -1,4 +1,5 @@ - +use crate::GraphError; +use shared::{AnalyzerLike, GraphLike}; impl ContextNode { /// Gets the associated contract for the function for the context diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index f25e93a3..a9b7119a 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,4 +1,5 @@ - +use crate::GraphError; +use shared::{AnalyzerLike, GraphLike}; impl ContextNode { /// Use a Difference Logic solver to see if it is unreachable diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index c0d997f7..b5fb1ec8 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -1,4 +1,8 @@ - +use crate::{ + GraphError, + nodes::{ContextNode, FunctionNode} +}; +use shared::{AnalyzerLike, GraphLike}; impl ContextNode { /// Returns whether this context is killed or returned diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 37c84a35..0180ceb9 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -1,3 +1,16 @@ +use crate::{ + GraphError, + solvers::dl::DLSolver, + nodes::{ + ExprRet, KilledKind, ContextCache, + FunctionNode, ContextVarNode, ContextNode + } +}; +use shared::AnalyzerLike; + +use solang_parser::pt::Loc; + + #[derive(Debug, Clone, Eq, PartialEq)] pub struct Context { /// The function associated with this context diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 93ccc3ff..5a565d85 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,4 +1,9 @@ +use crate::{ + GraphError, SolcRange, + nodes::{ContextVarNode, ContextNode}, +}; +use shared::{AnalyzerLike, GraphLike}; impl ContextVarNode { #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 0a1ecb28..51785424 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -1,4 +1,12 @@ +use crate::{ + Node, Edge, GraphError, ContextEdge, + nodes::{ContextVarNode, ContextNode, ExprRet}, +}; +use shared::{AnalyzerLike, GraphLike}; +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; impl ContextNode { /// Add a variable to this context diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index f073ef2e..89b94af8 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,4 +1,10 @@ +use crate::{ + Node, GraphError, + nodes::{ContextNode, CallFork, KilledKind, FunctionNode} +}; +use shared::{AnalyzerLike, GraphLike}; +use solang_parser::pt::Loc; impl ContextNode { /// Query whether this context has a parent diff --git a/crates/graph/src/range_impl/elem/concrete.rs b/crates/graph/src/range_impl/elem/concrete.rs index 45439072..a8683ab5 100644 --- a/crates/graph/src/range_impl/elem/concrete.rs +++ b/crates/graph/src/range_impl/elem/concrete.rs @@ -1,3 +1,12 @@ +use crate::{GraphError, nodes::{Concrete}}; + +use range::elem::{RangeElem, RangeConcrete, RangeOp, Elem}; +use shared::{NodeIdx, GraphLike}; + +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; + impl From for RangeConcrete { fn from(c: Concrete) -> Self { Self { diff --git a/crates/graph/src/range_impl/elem/elem_enum.rs b/crates/graph/src/range_impl/elem/elem_enum.rs index bb8ed9e8..8356c156 100644 --- a/crates/graph/src/range_impl/elem/elem_enum.rs +++ b/crates/graph/src/range_impl/elem/elem_enum.rs @@ -1,4 +1,12 @@ +use crate::{GraphError, nodes::{ContextVarNode, Concrete}}; +use range::elem::{RangeElem, RangeConcrete, RangeOp, RangeDyn, Elem, Reference, RangeExpr}; +use shared::{NodeIdx, GraphLike}; + +use ethers_core::types::I256; +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; impl std::fmt::Display for Elem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/graph/src/range_impl/elem/expr.rs b/crates/graph/src/range_impl/elem/expr.rs index bc535473..21984d9e 100644 --- a/crates/graph/src/range_impl/elem/expr.rs +++ b/crates/graph/src/range_impl/elem/expr.rs @@ -1,4 +1,11 @@ +use crate::{GraphError, nodes::{Concrete}}; +use range::{ exec::*, elem::{RangeElem, RangeOp, Elem, RangeExpr, MinMaxed}}; +use shared::{NodeIdx, GraphLike}; + +use ethers_core::types::{U256}; + +use std::collections::BTreeMap; static SINGLETON_EQ_OPS: &[RangeOp] = &[ RangeOp::Eq, diff --git a/crates/graph/src/range_impl/elem/map_or_array.rs b/crates/graph/src/range_impl/elem/map_or_array.rs index 129f4af9..d8919ae2 100644 --- a/crates/graph/src/range_impl/elem/map_or_array.rs +++ b/crates/graph/src/range_impl/elem/map_or_array.rs @@ -1,3 +1,10 @@ +use crate::{GraphError, nodes::{ContextVarNode, Concrete}}; + +use range::elem::{RangeElem, RangeOp, RangeDyn, MinMaxed, Elem}; +use shared::{NodeIdx, GraphLike}; + +use std::collections::BTreeMap; + impl RangeElem for RangeDyn { fn range_eq(&self, _other: &Self) -> bool { false diff --git a/crates/graph/src/range_impl/elem/mod.rs b/crates/graph/src/range_impl/elem/mod.rs new file mode 100644 index 00000000..eba17406 --- /dev/null +++ b/crates/graph/src/range_impl/elem/mod.rs @@ -0,0 +1,11 @@ +mod concrete; +mod elem_enum; +mod expr; +mod map_or_array; +mod reference; + +pub use concrete::*; +pub use elem_enum::*; +pub use expr::*; +pub use map_or_array::*; +pub use reference::*; diff --git a/crates/graph/src/range_impl/elem/reference.rs b/crates/graph/src/range_impl/elem/reference.rs index 287297ad..69a0b524 100644 --- a/crates/graph/src/range_impl/elem/reference.rs +++ b/crates/graph/src/range_impl/elem/reference.rs @@ -1,3 +1,11 @@ +use crate::{GraphError, nodes::{ContextVarNode, Concrete}, TypeNode, VarType}; + +use range::elem::{RangeElem, RangeConcrete, RangeOp, MinMaxed, Elem, Reference}; +use shared::{NodeIdx, GraphLike}; + +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; impl RangeElem for Reference { fn range_eq(&self, _other: &Self) -> bool { false diff --git a/crates/graph/src/range_impl/exec/add.rs b/crates/graph/src/range_impl/exec/add.rs index bcb4c717..0999fbfc 100644 --- a/crates/graph/src/range_impl/exec/add.rs +++ b/crates/graph/src/range_impl/exec/add.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{I256, U256}; + impl RangeAdd for RangeConcrete { fn range_add(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/bitwise.rs b/crates/graph/src/range_impl/exec/bitwise.rs index 33d2e7aa..097e4f07 100644 --- a/crates/graph/src/range_impl/exec/bitwise.rs +++ b/crates/graph/src/range_impl/exec/bitwise.rs @@ -1,3 +1,7 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; +use ethers_core::types::{H256, U256}; + impl RangeBitwise for RangeConcrete { fn range_bit_and(&self, other: &Self) -> Option> { match (&self.val, &other.val) { diff --git a/crates/graph/src/range_impl/exec/cast.rs b/crates/graph/src/range_impl/exec/cast.rs index 2c0f7803..11f4658b 100644 --- a/crates/graph/src/range_impl/exec/cast.rs +++ b/crates/graph/src/range_impl/exec/cast.rs @@ -1,3 +1,9 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{H256, U256}; +use std::collections::BTreeMap; + impl RangeCast for RangeConcrete { fn range_cast(&self, other: &Self) -> Option> { Some(Elem::Concrete(RangeConcrete { diff --git a/crates/graph/src/range_impl/exec/concat.rs b/crates/graph/src/range_impl/exec/concat.rs index 96c5e759..e2e14815 100644 --- a/crates/graph/src/range_impl/exec/concat.rs +++ b/crates/graph/src/range_impl/exec/concat.rs @@ -1,3 +1,9 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{H256, U256}; +use std::collections::BTreeMap; + impl RangeConcat for RangeConcrete { fn range_concat(&self, other: &Self) -> Option> { Some(Elem::Concrete(RangeConcrete { diff --git a/crates/graph/src/range_impl/exec/div.rs b/crates/graph/src/range_impl/exec/div.rs index c3f0e91b..ebbd16f8 100644 --- a/crates/graph/src/range_impl/exec/div.rs +++ b/crates/graph/src/range_impl/exec/div.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{H256, I256, U256}; + impl RangeDiv for RangeConcrete { fn range_div(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/exec_op.rs b/crates/graph/src/range_impl/exec/exec_op.rs new file mode 100644 index 00000000..a44d8edf --- /dev/null +++ b/crates/graph/src/range_impl/exec/exec_op.rs @@ -0,0 +1,1254 @@ +use crate::{GraphError, nodes::Concrete}; + +use shared::{NodeIdx, GraphLike}; +use range::{elem::*, exec::*}; + +use ethers_core::types::{ I256, U256 }; +use solang_parser::pt::Loc; + +impl ExecOp for RangeExpr { + fn cache_exec_op( + &mut self, + maximize: bool, + analyzer: &impl GraphLike, + ) -> Result<(), GraphError> { + self.lhs.cache_minimize(analyzer)?; + self.lhs.cache_maximize(analyzer)?; + self.rhs.cache_minimize(analyzer)?; + self.rhs.cache_maximize(analyzer)?; + let res = self.exec_op(maximize, analyzer)?; + if maximize { + self.maximized = Some(MinMaxed::Maximized(Box::new(res))); + } else { + self.minimized = Some(MinMaxed::Minimized(Box::new(res))); + } + Ok(()) + } + + fn uncache_exec(&mut self) { + self.lhs.uncache(); + self.rhs.uncache(); + } + + fn simplify_exec_op( + &self, + maximize: bool, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result, GraphError> { + let (parts, lhs_is_conc) = self.simplify_spread(exclude, analyzer)?; + if self.op == RangeOp::Cast { + // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete + if lhs_is_conc { + return self.exec_op(maximize, analyzer); + } else { + // we can drop the cast if the max of the dynamic lhs is less than the cast + let concretized_lhs = self.lhs.maximize(analyzer)?; + if matches!( + concretized_lhs.range_ord(&self.rhs), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ) { + return Ok(*self.lhs.clone()); + } + } + } + self.exec(parts, maximize) + } + + fn spread( + &self, + analyzer: &impl GraphLike, + ) -> Result< + ( + Elem, + Elem, + Elem, + Elem, + ), + GraphError, + > { + let lhs_min = self.lhs.minimize(analyzer)?; + let lhs_max = self.lhs.maximize(analyzer)?; + let rhs_min = self.rhs.minimize(analyzer)?; + let rhs_max = self.rhs.maximize(analyzer)?; + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) + } + + fn simplify_spread( + &self, + exclude: &mut Vec, + analyzer: &impl GraphLike, + ) -> Result< + ( + ( + Elem, + Elem, + Elem, + Elem, + ), + bool, + ), + GraphError, + > { + let lhs_min = self.lhs.simplify_minimize(exclude, analyzer)?; + let lhs_max = self.lhs.simplify_maximize(exclude, analyzer)?; + let rhs_min = self.rhs.simplify_minimize(exclude, analyzer)?; + let rhs_max = self.rhs.simplify_maximize(exclude, analyzer)?; + let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); + Ok(((lhs_min, lhs_max, rhs_min, rhs_max), lhs_is_conc)) + } + + fn exec( + &self, + (lhs_min, lhs_max, rhs_min, rhs_max): ( + Elem, + Elem, + Elem, + Elem, + ), + maximize: bool, + ) -> Result, GraphError> { + tracing::trace!( + "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", + self.lhs, + self.op.to_string(), + self.rhs, + lhs_min, + lhs_max, + rhs_min, + rhs_max + ); + + let lhs_min_neg = lhs_min.pre_evaled_is_negative(); + let lhs_max_neg = lhs_max.pre_evaled_is_negative(); + let rhs_min_neg = rhs_min.pre_evaled_is_negative(); + let rhs_max_neg = rhs_max.pre_evaled_is_negative(); + + let consts = ( + matches!(lhs_min.range_ord(&lhs_max), Some(std::cmp::Ordering::Equal)), + matches!(rhs_min.range_ord(&rhs_max), Some(std::cmp::Ordering::Equal)), + ); + + fn fallback( + this: &RangeExpr, + lhs: Elem, + rhs: Elem, + consts: (bool, bool), + ) -> Elem { + // println!("fallback exec: {} {} {}", this.lhs, this.op.to_string(), this.rhs); + match consts { + (true, true) => { + // println!("true true: {} {} {}", lhs, this.op.to_string(), rhs); + Elem::Expr(RangeExpr::new(lhs, this.op, rhs)) + } + (false, true) => { + // println!("false true: {} {} {}", this.lhs, this.op.to_string(), rhs); + Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)) + } + (true, false) => { + // println!("true false: {} {} {}", lhs, this.op.to_string(), this.rhs); + Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())) + } + (false, false) => { + // println!("false false: {} {} {}", this.lhs, this.op.to_string(), this.rhs); + Elem::Expr(this.clone()) + } + } + } + + let res = match self.op { + RangeOp::Add(unchecked) => { + if unchecked { + let mut candidates = vec![ + lhs_min.range_wrapping_add(&rhs_min), + lhs_min.range_wrapping_add(&rhs_max), + lhs_max.range_wrapping_add(&rhs_min), + lhs_max.range_wrapping_add(&rhs_max), + ]; + + // if they arent constants, we can test a normal add + if !matches!(consts, (true, true)) { + candidates.push(lhs_max.range_add(&rhs_max)); + candidates.push(lhs_min.range_add(&rhs_min)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value + the largest value + lhs_max + .range_add(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_min + .range_add(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Sub(unchecked) => { + if unchecked { + let candidates = vec![ + lhs_min.range_wrapping_sub(&rhs_min), + lhs_min.range_wrapping_sub(&rhs_max), + lhs_max.range_wrapping_sub(&rhs_min), + lhs_max.range_wrapping_sub(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value - the smallest value + lhs_max + .range_sub(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + // if we are minimizing, the smallest value will always be smallest value - largest value + lhs_min + .range_sub(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Mul(unchecked) => { + if unchecked { + let candidates = vec![ + lhs_min.range_wrapping_mul(&rhs_min), + lhs_min.range_wrapping_mul(&rhs_max), + lhs_max.range_wrapping_mul(&rhs_min), + lhs_max.range_wrapping_mul(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } else if maximize { + // if we are maximizing, and both mins are negative and both maxes are positive, + // we dont know which will be larger of the two (i.e. -1*2**255 * -1*2**255 > 100*100) + match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + (true, true, true, true) => { + // all negative, will be min * min because those are furthest from 0 resulting in the + // largest positive value + lhs_min + .range_mul(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (true, false, true, false) => { + // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller + match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { + (Some(min_expr), Some(max_expr)) => { + match min_expr.range_ord(&max_expr) { + Some(std::cmp::Ordering::Less) => max_expr, + Some(std::cmp::Ordering::Greater) => min_expr, + _ => max_expr, + } + } + (None, Some(max_expr)) => max_expr, + (Some(min_expr), None) => min_expr, + (None, None) => fallback(self, lhs_min, rhs_min, consts), + } + } + (_, false, _, false) => { + // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value + lhs_max + .range_mul(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (false, false, true, true) => { + // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + lhs_min + .range_mul(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (true, true, false, false) => { + // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + lhs_max + .range_mul(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (true, _, true, _) => lhs_min + .range_mul(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), + (false, true, _, _) | (_, _, false, true) => { + panic!("unsatisfiable range") + } + } + } else { + match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + (false, false, false, false) => { + // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value + lhs_min + .range_mul(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (true, true, true, true) => { + // all negative, will be max * max because those are closest to 0 resulting in the + // smallest positive value + lhs_max + .range_mul(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (true, false, true, false) => { + // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller + match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { + (Some(min_expr), Some(max_expr)) => { + match min_expr.range_ord(&max_expr) { + Some(std::cmp::Ordering::Less) => min_expr, + Some(std::cmp::Ordering::Greater) => max_expr, + _ => min_expr, + } + } + (None, Some(max_expr)) => max_expr, + (Some(min_expr), None) => min_expr, + (None, None) => fallback(self, lhs_min, rhs_min, consts), + } + } + (true, _, _, false) => { + // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value + lhs_min + .range_mul(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (_, false, _, true) => { + // just lhs has a positive value, most negative will be lhs_max, rhs_max + lhs_max + .range_mul(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + (false, false, true, false) => lhs_max + .range_mul(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), + (false, true, _, _) | (_, _, false, true) => { + panic!("unsatisfiable range") + } + } + } + } + RangeOp::Div(_unchecked) => { + let mut candidates = vec![ + lhs_min.range_div(&rhs_min), + lhs_min.range_div(&rhs_max), + lhs_max.range_div(&rhs_min), + lhs_max.range_div(&rhs_max), + ]; + + let one = Elem::from(Concrete::from(U256::from(1))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_div(&one)); + candidates.push(lhs_max.range_div(&one)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_div(&negative_one)); + candidates.push(lhs_max.range_div(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger + // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // max_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // min_expr + // } + // _ => { + // max_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (false, false, true, true) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, false, false) => { + // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, false, _) => { + // // lhs is positive, rhs min is positive, guaranteed to give largest + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, false) => { + // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, true, _) => { + // // at this point, its either all trues, or a single false + // // given that, to maximize, the only way to get a positive value is to use the most negative values + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (false, false, false, false) => { + // // smallest number will be lhs_min / rhs_min since both are positive + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, true) => { + // // smallest number will be lhs_max / rhs_min since both are negative + // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, true, false) => { + // // The way to maintain most negative value is lhs_min / rhs_max, all others would go + // // positive or guaranteed to be closer to 0 + // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, false, true, false) => { + // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger + // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { + // (Some(min_expr), Some(max_expr)) => { + // match min_expr.range_ord(&max_expr) { + // Some(std::cmp::Ordering::Less) => { + // min_expr + // } + // Some(std::cmp::Ordering::Greater) => { + // max_expr + // } + // _ => { + // min_expr + // } + // } + // } + // (None, Some(max_expr)) => { + // max_expr + // } + // (Some(min_expr), None) => { + // min_expr + // } + // (None, None) => Elem::Expr(self.clone()) + // } + // } + // (_, false, true, _) => { + // // We are going negative here, so it will be most positive / least negative + // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, _) => { + // // We are going negative here, so it will be most negative / least positive + // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + // RangeOp::Mod => { + // lhs.range_mod(&rhs).unwrap_or(Elem::Expr(self.clone())) + // } + RangeOp::Min => { + let candidates = vec![ + lhs_min.range_min(&rhs_min), + lhs_min.range_min(&rhs_max), + lhs_max.range_min(&rhs_min), + lhs_max.range_min(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // // counter-intuitively, we want the maximum value from a call to minimum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the minimum values but getting the larger of the minimum + // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + RangeOp::Max => { + let candidates = vec![ + lhs_min.range_max(&rhs_min), + lhs_min.range_max(&rhs_max), + lhs_max.range_max(&rhs_min), + lhs_max.range_max(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + // if maximize { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (true, _, true, _) | (false, _, false, _) => { + // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, _, false, false) => { + // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, false, true, _) => { + // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } else { + // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { + // (_, true, _, true) | (_, false, _, false) => { + // // counter-intuitively, we want the minimum value from a call to maximum + // // this is due to the symbolic nature of the evaluation. We are still + // // using the maximum values but getting the smaller of the maximum + // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) + // } + // (_, false, true, true) => { + // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (true, true, _, false) => { + // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) + // } + // (false, true, _, _) | (_, _, false, true)=> { + // panic!("unsatisfiable range") + // } + // } + // } + } + RangeOp::Gt => { + if maximize { + lhs_max + .range_gt(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_min + .range_gt(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Lt => { + if maximize { + lhs_min + .range_lt(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_max + .range_lt(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Gte => { + if maximize { + lhs_max + .range_gte(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_min + .range_gte(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Lte => { + if maximize { + lhs_min + .range_lte(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_max + .range_lte(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::Eq => { + // prevent trying to eval when we have dependents + if !lhs_min.dependent_on().is_empty() + || !lhs_max.dependent_on().is_empty() + || !rhs_min.dependent_on().is_empty() + || !rhs_max.dependent_on().is_empty() + { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + let loc = if let Some(c) = lhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = lhs_max.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_max.maybe_concrete() { + c.loc + } else { + Loc::Implicit + }; + + if maximize { + // check for any overlap + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + + // if lhs max is less than the rhs min, it has to be false + if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + + // if lhs min is greater than the rhs max, it has to be false + if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + + // lhs_max >= rhs_min + // lhs_min <= rhs_max + // therefore its possible to set some value to true here + if lhs_max_rhs_min_ord.is_some() && lhs_min_rhs_max_ord.is_some() { + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }) + } else { + fallback(self, lhs_min, rhs_min, consts) + } + } else { + // check if either lhs element is *not* contained by rhs + match ( + // check if lhs is constant + lhs_min.range_ord(&lhs_max), + // check if rhs is constant + rhs_min.range_ord(&rhs_max), + // check if lhs is equal to rhs + lhs_min.range_ord(&rhs_min), + ) { + ( + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + ) => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }), + // if any of those are not equal, we can construct + // an element that is true + _ => Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + }), + } + } + } + RangeOp::Neq => { + // prevent trying to eval when we have dependents + if !lhs_min.dependent_on().is_empty() + || !lhs_max.dependent_on().is_empty() + || !rhs_min.dependent_on().is_empty() + || !rhs_max.dependent_on().is_empty() + { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + let loc = if let Some(c) = lhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = lhs_max.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_max.maybe_concrete() { + c.loc + } else { + Loc::Implicit + }; + + if maximize { + // the only case here in which we can't assert that + // true is the maximum is when they are both consts and equal + if matches!(consts, (true, true)) { + // both are consts, check if they are equal + if matches!(lhs_min.range_ord(&rhs_min), Some(std::cmp::Ordering::Equal)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + })); + } + } + + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + }) + } else { + // we *want* to produce false + if matches!(consts, (true, true)) { + // both are consts, check if we are forced to return true + if matches!( + lhs_min.range_ord(&rhs_min), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Less) + ) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + })); + } + } + + // check for any overlap + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + + // if lhs max is less than the rhs min, it has to be != (true) + if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + })); + } + + // if lhs min is greater than the rhs max, it has to be != (true) + if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { + return Ok(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(true), + loc, + })); + } + + // we can force an equal value if needed + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(false), + loc, + }) + // fallback(self, lhs_min, rhs_min, consts) + } + } + RangeOp::Shl => { + let candidates = vec![ + lhs_min.range_shl(&rhs_min), + lhs_min.range_shl(&rhs_max), + lhs_max.range_shl(&rhs_min), + lhs_max.range_shl(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Shr => { + let candidates = vec![ + lhs_min.range_shr(&rhs_min), + lhs_min.range_shr(&rhs_max), + lhs_max.range_shr(&rhs_min), + lhs_max.range_shr(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::And => { + let candidates = vec![ + lhs_min.range_and(&rhs_min), + lhs_min.range_and(&rhs_max), + lhs_max.range_and(&rhs_min), + lhs_max.range_and(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Or => { + let candidates = vec![ + lhs_min.range_or(&rhs_min), + lhs_min.range_or(&rhs_max), + lhs_max.range_or(&rhs_min), + lhs_max.range_or(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Not => { + assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); + let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Cast => { + // the weird thing about cast is that we really dont know until after the cast due to sizing things + // so we should just try them all then compare + let candidates = vec![ + lhs_min.range_cast(&rhs_min), + lhs_min.range_cast(&rhs_max), + lhs_max.range_cast(&rhs_min), + lhs_max.range_cast(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Exp => { + // TODO: improve with smarter stuff + let candidates = vec![ + lhs_min.range_exp(&rhs_min), + lhs_min.range_exp(&rhs_max), + lhs_max.range_exp(&rhs_min), + lhs_max.range_exp(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitAnd => { + let mut candidates = vec![ + lhs_min.range_bit_and(&rhs_min), + lhs_min.range_bit_and(&rhs_max), + lhs_max.range_bit_and(&rhs_min), + lhs_max.range_bit_and(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_and(&zero)); + candidates.push(lhs_max.range_bit_and(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_and(&negative_one)); + candidates.push(lhs_max.range_bit_and(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitOr => { + let mut candidates = vec![ + lhs_min.range_bit_or(&rhs_min), + lhs_min.range_bit_or(&rhs_max), + lhs_max.range_bit_or(&rhs_min), + lhs_max.range_bit_or(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_or(&zero)); + candidates.push(lhs_max.range_bit_or(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_or(&negative_one)); + candidates.push(lhs_max.range_bit_or(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitXor => { + let mut candidates = vec![ + lhs_min.range_bit_xor(&rhs_min), + lhs_min.range_bit_xor(&rhs_max), + lhs_max.range_bit_xor(&rhs_min), + lhs_max.range_bit_xor(&rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + // if the rhs contains zero, in xor, thats just itself + candidates.push(lhs_max.range_bit_xor(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_xor(&negative_one)); + candidates.push(lhs_max.range_bit_xor(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::BitNot => { + let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + + let min_contains = matches!( + lhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + lhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + match lhs_min { + Elem::Concrete( + ref r @ RangeConcrete { + val: Concrete::Uint(..), + .. + }, + ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), + Elem::Concrete( + ref r @ RangeConcrete { + val: Concrete::Int(..), + .. + }, + ) => candidates.push(Some(Elem::from(Concrete::min(&r.val).unwrap()))), + _ => {} + } + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + RangeOp::Concat => { + // TODO: improve with smarter stuff + let candidates = vec![ + lhs_min.range_concat(&rhs_min), + lhs_min.range_concat(&rhs_max), + lhs_max.range_concat(&rhs_min), + lhs_max.range_concat(&rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Ok(fallback(self, lhs_min, rhs_min, consts)); + } + + if maximize { + candidates[candidates.len() - 1].clone() + } else { + candidates[0].clone() + } + } + _ => fallback(self, lhs_min, rhs_min, consts), + }; + Ok(res) + } +} diff --git a/crates/graph/src/range_impl/exec/exp.rs b/crates/graph/src/range_impl/exec/exp.rs index 0ecc95a0..c89d1697 100644 --- a/crates/graph/src/range_impl/exec/exp.rs +++ b/crates/graph/src/range_impl/exec/exp.rs @@ -1,3 +1,7 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; +use ethers_core::types::{H256, U256}; + impl RangeExp for RangeConcrete { fn range_exp(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/logical.rs b/crates/graph/src/range_impl/exec/logical.rs index 40b0035f..f3f57ed1 100644 --- a/crates/graph/src/range_impl/exec/logical.rs +++ b/crates/graph/src/range_impl/exec/logical.rs @@ -1,3 +1,6 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + impl RangeUnary for RangeConcrete { fn range_not(&self) -> Option> { match self.val { diff --git a/crates/graph/src/range_impl/exec/max.rs b/crates/graph/src/range_impl/exec/max.rs index 079a96f3..ae0676d8 100644 --- a/crates/graph/src/range_impl/exec/max.rs +++ b/crates/graph/src/range_impl/exec/max.rs @@ -1,3 +1,6 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + impl RangeMax for RangeConcrete { fn range_max(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/min.rs b/crates/graph/src/range_impl/exec/min.rs index 87a857c3..a350532c 100644 --- a/crates/graph/src/range_impl/exec/min.rs +++ b/crates/graph/src/range_impl/exec/min.rs @@ -1,3 +1,6 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + impl RangeMin for RangeConcrete { fn range_min(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/mod.rs b/crates/graph/src/range_impl/exec/mod.rs index f329167c..9efed125 100644 --- a/crates/graph/src/range_impl/exec/mod.rs +++ b/crates/graph/src/range_impl/exec/mod.rs @@ -1,1246 +1,15 @@ -impl ExecOp for RangeExpr { - fn cache_exec_op( - &mut self, - maximize: bool, - analyzer: &impl GraphLike, - ) -> Result<(), GraphError> { - self.lhs.cache_minimize(analyzer)?; - self.lhs.cache_maximize(analyzer)?; - self.rhs.cache_minimize(analyzer)?; - self.rhs.cache_maximize(analyzer)?; - let res = self.exec_op(maximize, analyzer)?; - if maximize { - self.maximized = Some(MinMaxed::Maximized(Box::new(res))); - } else { - self.minimized = Some(MinMaxed::Minimized(Box::new(res))); - } - Ok(()) - } - - fn uncache_exec(&mut self) { - self.lhs.uncache(); - self.rhs.uncache(); - } - - fn simplify_exec_op( - &self, - maximize: bool, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, GraphError> { - let (parts, lhs_is_conc) = self.simplify_spread(exclude, analyzer)?; - if self.op == RangeOp::Cast { - // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete - if lhs_is_conc { - return self.exec_op(maximize, analyzer); - } else { - // we can drop the cast if the max of the dynamic lhs is less than the cast - let concretized_lhs = self.lhs.maximize(analyzer)?; - if matches!( - concretized_lhs.range_ord(&self.rhs), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ) { - return Ok(*self.lhs.clone()); - } - } - } - self.exec(parts, maximize) - } - - fn spread( - &self, - analyzer: &impl GraphLike, - ) -> Result< - ( - Elem, - Elem, - Elem, - Elem, - ), - GraphError, - > { - let lhs_min = self.lhs.minimize(analyzer)?; - let lhs_max = self.lhs.maximize(analyzer)?; - let rhs_min = self.rhs.minimize(analyzer)?; - let rhs_max = self.rhs.maximize(analyzer)?; - Ok((lhs_min, lhs_max, rhs_min, rhs_max)) - } - - fn simplify_spread( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result< - ( - ( - Elem, - Elem, - Elem, - Elem, - ), - bool, - ), - GraphError, - > { - let lhs_min = self.lhs.simplify_minimize(exclude, analyzer)?; - let lhs_max = self.lhs.simplify_maximize(exclude, analyzer)?; - let rhs_min = self.rhs.simplify_minimize(exclude, analyzer)?; - let rhs_max = self.rhs.simplify_maximize(exclude, analyzer)?; - let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); - Ok(((lhs_min, lhs_max, rhs_min, rhs_max), lhs_is_conc)) - } - - fn exec( - &self, - (lhs_min, lhs_max, rhs_min, rhs_max): ( - Elem, - Elem, - Elem, - Elem, - ), - maximize: bool, - ) -> Result, GraphError> { - tracing::trace!( - "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", - self.lhs, - self.op.to_string(), - self.rhs, - lhs_min, - lhs_max, - rhs_min, - rhs_max - ); - - let lhs_min_neg = lhs_min.pre_evaled_is_negative(); - let lhs_max_neg = lhs_max.pre_evaled_is_negative(); - let rhs_min_neg = rhs_min.pre_evaled_is_negative(); - let rhs_max_neg = rhs_max.pre_evaled_is_negative(); - - let consts = ( - matches!(lhs_min.range_ord(&lhs_max), Some(std::cmp::Ordering::Equal)), - matches!(rhs_min.range_ord(&rhs_max), Some(std::cmp::Ordering::Equal)), - ); - - fn fallback( - this: &RangeExpr, - lhs: Elem, - rhs: Elem, - consts: (bool, bool), - ) -> Elem { - // println!("fallback exec: {} {} {}", this.lhs, this.op.to_string(), this.rhs); - match consts { - (true, true) => { - // println!("true true: {} {} {}", lhs, this.op.to_string(), rhs); - Elem::Expr(RangeExpr::new(lhs, this.op, rhs)) - } - (false, true) => { - // println!("false true: {} {} {}", this.lhs, this.op.to_string(), rhs); - Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)) - } - (true, false) => { - // println!("true false: {} {} {}", lhs, this.op.to_string(), this.rhs); - Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())) - } - (false, false) => { - // println!("false false: {} {} {}", this.lhs, this.op.to_string(), this.rhs); - Elem::Expr(this.clone()) - } - } - } - - let res = match self.op { - RangeOp::Add(unchecked) => { - if unchecked { - let mut candidates = vec![ - lhs_min.range_wrapping_add(&rhs_min), - lhs_min.range_wrapping_add(&rhs_max), - lhs_max.range_wrapping_add(&rhs_min), - lhs_max.range_wrapping_add(&rhs_max), - ]; - - // if they arent constants, we can test a normal add - if !matches!(consts, (true, true)) { - candidates.push(lhs_max.range_add(&rhs_max)); - candidates.push(lhs_min.range_add(&rhs_min)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value + the largest value - lhs_max - .range_add(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_add(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Sub(unchecked) => { - if unchecked { - let candidates = vec![ - lhs_min.range_wrapping_sub(&rhs_min), - lhs_min.range_wrapping_sub(&rhs_max), - lhs_max.range_wrapping_sub(&rhs_min), - lhs_max.range_wrapping_sub(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value - the smallest value - lhs_max - .range_sub(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - // if we are minimizing, the smallest value will always be smallest value - largest value - lhs_min - .range_sub(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Mul(unchecked) => { - if unchecked { - let candidates = vec![ - lhs_min.range_wrapping_mul(&rhs_min), - lhs_min.range_wrapping_mul(&rhs_max), - lhs_max.range_wrapping_mul(&rhs_min), - lhs_max.range_wrapping_mul(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, and both mins are negative and both maxes are positive, - // we dont know which will be larger of the two (i.e. -1*2**255 * -1*2**255 > 100*100) - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (true, true, true, true) => { - // all negative, will be min * min because those are furthest from 0 resulting in the - // largest positive value - lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller - match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { - Some(std::cmp::Ordering::Less) => max_expr, - Some(std::cmp::Ordering::Greater) => min_expr, - _ => max_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => fallback(self, lhs_min, rhs_min, consts), - } - } - (_, false, _, false) => { - // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (false, false, true, true) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_min - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, true, false, false) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_max - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, _, true, _) => lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), - (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") - } - } - } else { - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (false, false, false, false) => { - // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value - lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, true, true, true) => { - // all negative, will be max * max because those are closest to 0 resulting in the - // smallest positive value - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller - match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { - Some(std::cmp::Ordering::Less) => min_expr, - Some(std::cmp::Ordering::Greater) => max_expr, - _ => min_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => fallback(self, lhs_min, rhs_min, consts), - } - } - (true, _, _, false) => { - // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value - lhs_min - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (_, false, _, true) => { - // just lhs has a positive value, most negative will be lhs_max, rhs_max - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (false, false, true, false) => lhs_max - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), - (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") - } - } - } - } - RangeOp::Div(_unchecked) => { - let mut candidates = vec![ - lhs_min.range_div(&rhs_min), - lhs_min.range_div(&rhs_max), - lhs_max.range_div(&rhs_min), - lhs_max.range_div(&rhs_max), - ]; - - let one = Elem::from(Concrete::from(U256::from(1))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&one)); - candidates.push(lhs_max.range_div(&one)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&negative_one)); - candidates.push(lhs_max.range_div(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger - // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // max_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // min_expr - // } - // _ => { - // max_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (false, false, true, true) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, false, false) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, false, _) => { - // // lhs is positive, rhs min is positive, guaranteed to give largest - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, false) => { - // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, true, _) => { - // // at this point, its either all trues, or a single false - // // given that, to maximize, the only way to get a positive value is to use the most negative values - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (false, false, false, false) => { - // // smallest number will be lhs_min / rhs_min since both are positive - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, true) => { - // // smallest number will be lhs_max / rhs_min since both are negative - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, false) => { - // // The way to maintain most negative value is lhs_min / rhs_max, all others would go - // // positive or guaranteed to be closer to 0 - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger - // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // min_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // max_expr - // } - // _ => { - // min_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (_, false, true, _) => { - // // We are going negative here, so it will be most positive / least negative - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, _) => { - // // We are going negative here, so it will be most negative / least positive - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - // RangeOp::Mod => { - // lhs.range_mod(&rhs).unwrap_or(Elem::Expr(self.clone())) - // } - RangeOp::Min => { - let candidates = vec![ - lhs_min.range_min(&rhs_min), - lhs_min.range_min(&rhs_max), - lhs_max.range_min(&rhs_min), - lhs_max.range_min(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // // counter-intuitively, we want the maximum value from a call to minimum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the minimum values but getting the larger of the minimum - // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Max => { - let candidates = vec![ - lhs_min.range_max(&rhs_min), - lhs_min.range_max(&rhs_max), - lhs_max.range_max(&rhs_min), - lhs_max.range_max(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (_, true, _, true) | (_, false, _, false) => { - // // counter-intuitively, we want the minimum value from a call to maximum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the maximum values but getting the smaller of the maximum - // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, true) => { - // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, _, false) => { - // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Gt => { - if maximize { - lhs_max - .range_gt(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_gt(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Lt => { - if maximize { - lhs_min - .range_lt(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_max - .range_lt(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Gte => { - if maximize { - lhs_max - .range_gte(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_gte(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Lte => { - if maximize { - lhs_min - .range_lte(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_max - .range_lte(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Eq => { - // prevent trying to eval when we have dependents - if !lhs_min.dependent_on().is_empty() - || !lhs_max.dependent_on().is_empty() - || !rhs_min.dependent_on().is_empty() - || !rhs_max.dependent_on().is_empty() - { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - - if maximize { - // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); - - // if lhs max is less than the rhs min, it has to be false - if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // if lhs min is greater than the rhs max, it has to be false - if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // lhs_max >= rhs_min - // lhs_min <= rhs_max - // therefore its possible to set some value to true here - if lhs_max_rhs_min_ord.is_some() && lhs_min_rhs_max_ord.is_some() { - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }) - } else { - fallback(self, lhs_min, rhs_min, consts) - } - } else { - // check if either lhs element is *not* contained by rhs - match ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max), - // check if rhs is constant - rhs_min.range_ord(&rhs_max), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), - ) { - ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }), - // if any of those are not equal, we can construct - // an element that is true - _ => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }), - } - } - } - RangeOp::Neq => { - // prevent trying to eval when we have dependents - if !lhs_min.dependent_on().is_empty() - || !lhs_max.dependent_on().is_empty() - || !rhs_min.dependent_on().is_empty() - || !rhs_max.dependent_on().is_empty() - { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - - if maximize { - // the only case here in which we can't assert that - // true is the maximum is when they are both consts and equal - if matches!(consts, (true, true)) { - // both are consts, check if they are equal - if matches!(lhs_min.range_ord(&rhs_min), Some(std::cmp::Ordering::Equal)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - } - - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }) - } else { - // we *want* to produce false - if matches!(consts, (true, true)) { - // both are consts, check if we are forced to return true - if matches!( - lhs_min.range_ord(&rhs_min), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Less) - ) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - } - - // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); - - // if lhs max is less than the rhs min, it has to be != (true) - if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - - // if lhs min is greater than the rhs max, it has to be != (true) - if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - - // we can force an equal value if needed - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }) - // fallback(self, lhs_min, rhs_min, consts) - } - } - RangeOp::Shl => { - let candidates = vec![ - lhs_min.range_shl(&rhs_min), - lhs_min.range_shl(&rhs_max), - lhs_max.range_shl(&rhs_min), - lhs_max.range_shl(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Shr => { - let candidates = vec![ - lhs_min.range_shr(&rhs_min), - lhs_min.range_shr(&rhs_max), - lhs_max.range_shr(&rhs_min), - lhs_max.range_shr(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::And => { - let candidates = vec![ - lhs_min.range_and(&rhs_min), - lhs_min.range_and(&rhs_max), - lhs_max.range_and(&rhs_min), - lhs_max.range_and(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Or => { - let candidates = vec![ - lhs_min.range_or(&rhs_min), - lhs_min.range_or(&rhs_max), - lhs_max.range_or(&rhs_min), - lhs_max.range_or(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Not => { - assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); - let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Cast => { - // the weird thing about cast is that we really dont know until after the cast due to sizing things - // so we should just try them all then compare - let candidates = vec![ - lhs_min.range_cast(&rhs_min), - lhs_min.range_cast(&rhs_max), - lhs_max.range_cast(&rhs_min), - lhs_max.range_cast(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Exp => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_exp(&rhs_min), - lhs_min.range_exp(&rhs_max), - lhs_max.range_exp(&rhs_min), - lhs_max.range_exp(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitAnd => { - let mut candidates = vec![ - lhs_min.range_bit_and(&rhs_min), - lhs_min.range_bit_and(&rhs_max), - lhs_max.range_bit_and(&rhs_min), - lhs_max.range_bit_and(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&zero)); - candidates.push(lhs_max.range_bit_and(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&negative_one)); - candidates.push(lhs_max.range_bit_and(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitOr => { - let mut candidates = vec![ - lhs_min.range_bit_or(&rhs_min), - lhs_min.range_bit_or(&rhs_max), - lhs_max.range_bit_or(&rhs_min), - lhs_max.range_bit_or(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&zero)); - candidates.push(lhs_max.range_bit_or(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&negative_one)); - candidates.push(lhs_max.range_bit_or(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitXor => { - let mut candidates = vec![ - lhs_min.range_bit_xor(&rhs_min), - lhs_min.range_bit_xor(&rhs_max), - lhs_max.range_bit_xor(&rhs_min), - lhs_max.range_bit_xor(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - // if the rhs contains zero, in xor, thats just itself - candidates.push(lhs_max.range_bit_xor(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_xor(&negative_one)); - candidates.push(lhs_max.range_bit_xor(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitNot => { - let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - - let min_contains = matches!( - lhs_min.range_ord(&zero), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - lhs_max.range_ord(&zero), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - match lhs_min { - Elem::Concrete( - ref r @ RangeConcrete { - val: Concrete::Uint(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), - Elem::Concrete( - ref r @ RangeConcrete { - val: Concrete::Int(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::min(&r.val).unwrap()))), - _ => {} - } - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Concat => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_concat(&rhs_min), - lhs_min.range_concat(&rhs_max), - lhs_max.range_concat(&rhs_min), - lhs_max.range_concat(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - _ => fallback(self, lhs_min, rhs_min, consts), - }; - Ok(res) - } -} +mod add; +mod bitwise; +mod cast; +mod concat; +mod div; +mod exp; +mod exec_op; +mod logical; +mod max; +mod min; +mod modulo; +mod mul; +mod ord; +mod shift; +mod sub; diff --git a/crates/graph/src/range_impl/exec/modulo.rs b/crates/graph/src/range_impl/exec/modulo.rs index 5fb6fa0c..7080c027 100644 --- a/crates/graph/src/range_impl/exec/modulo.rs +++ b/crates/graph/src/range_impl/exec/modulo.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{I256}; + impl RangeMod for RangeConcrete { fn range_mod(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/mul.rs b/crates/graph/src/range_impl/exec/mul.rs index 91a6a6c2..f07a704a 100644 --- a/crates/graph/src/range_impl/exec/mul.rs +++ b/crates/graph/src/range_impl/exec/mul.rs @@ -1,3 +1,10 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{I256, U256}; + + + impl RangeMul for RangeConcrete { fn range_mul(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/ord.rs b/crates/graph/src/range_impl/exec/ord.rs index 8feb9795..1d45a259 100644 --- a/crates/graph/src/range_impl/exec/ord.rs +++ b/crates/graph/src/range_impl/exec/ord.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + + + impl RangeOrd for RangeConcrete { fn range_ord_eq(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/shift.rs b/crates/graph/src/range_impl/exec/shift.rs index 92636dc6..ccb2d414 100644 --- a/crates/graph/src/range_impl/exec/shift.rs +++ b/crates/graph/src/range_impl/exec/shift.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{I256, U256}; + impl RangeShift for RangeConcrete { fn range_shl(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/exec/sub.rs b/crates/graph/src/range_impl/exec/sub.rs index 6a6f8293..4fe990b6 100644 --- a/crates/graph/src/range_impl/exec/sub.rs +++ b/crates/graph/src/range_impl/exec/sub.rs @@ -1,3 +1,8 @@ +use crate::nodes::Concrete; +use range::{elem::*, exec::*}; + +use ethers_core::types::{I256, U256}; + impl RangeSub for RangeConcrete { fn range_sub(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { diff --git a/crates/graph/src/range_impl/range_string.rs b/crates/graph/src/range_impl/range_string.rs index f89c4f1c..94c8abfa 100644 --- a/crates/graph/src/range_impl/range_string.rs +++ b/crates/graph/src/range_impl/range_string.rs @@ -1,5 +1,11 @@ +use crate::nodes::{Concrete, ContextVarNode}; +use range::{elem::*, range_string::*}; +use shared::GraphLike; +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; impl ToRangeString for Elem { fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { diff --git a/crates/graph/src/range_impl/solc_range.rs b/crates/graph/src/range_impl/solc_range.rs index ce5e0f12..3d55dbe6 100644 --- a/crates/graph/src/range_impl/solc_range.rs +++ b/crates/graph/src/range_impl/solc_range.rs @@ -1,11 +1,14 @@ -use ethers_core::types::Address; -use ethers_core::types::H256; -use ethers_core::types::I256; -use ethers_core::types::U256; -use std::collections::BTreeMap; +use crate::nodes::{Builtin, Concrete}; +use crate::{GraphError, nodes::{ContextVarNode, ContextNode}}; + +use shared::{AsDotStr, GraphLike, NodeIdx}; +use range::{RangeEval, Range, elem::*, range_string::*}; +use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; +use std::collections::BTreeMap; + #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct SolcRange { pub min: Elem, diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs new file mode 100644 index 00000000..a20f7e35 --- /dev/null +++ b/crates/graph/src/solvers/atoms.rs @@ -0,0 +1,346 @@ +use crate::nodes::Concrete; +use crate::nodes::ContextVarNode; + +use range::{ + elem::{ + RangeElem, + RangeOp, + Elem, + RangeExpr, + Reference + }, + range_string::{ToRangeString, RangeElemString} +}; + + +use shared::GraphLike; + +use ethers_core::types::U256; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum AtomOrPart { + Part(Elem), + Atom(SolverAtom), +} + +impl AtomOrPart { + pub fn into_elem(&self) -> Elem { + match self { + AtomOrPart::Part(part) => part.clone(), + AtomOrPart::Atom(atom) => atom.into_expr_elem(), + } + } + + pub fn as_solver_atom(&self) -> SolverAtom { + match self { + AtomOrPart::Part(_) => SolverAtom { + ty: OpType::DL, + lhs: Box::new(self.clone()), + op: RangeOp::Sub(false), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), + }, + AtomOrPart::Atom(atom) => atom.clone(), + } + } + + pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + match self { + AtomOrPart::Part(part) => { + let mut new_part = part.clone(); + solves.iter().for_each(|(dep, replacement)| { + new_part.replace_dep(dep.0.into(), replacement.clone()) + }); + AtomOrPart::Part(new_part) + } + AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves)), + } + } + + pub fn maybe_max_ty(&self) -> Option { + match self { + AtomOrPart::Part(_part) => None, + AtomOrPart::Atom(atom) => Some(atom.max_ty()), + } + } + + pub fn is_part(&self) -> bool { + if let AtomOrPart::Part(_) = self { + true + } else { + false + } + } + + pub fn is_atom(&self) -> bool { + if let AtomOrPart::Atom(_) = self { + true + } else { + false + } + } + + pub fn expect_atom(&self) -> SolverAtom { + if let AtomOrPart::Atom(atom) = self { + atom.clone() + } else { + panic!("Expected atom, was part: {self:?}") + } + } + + pub fn dependent_on(&self) -> Vec { + match self { + AtomOrPart::Part(e) => e.dependent_on(), + AtomOrPart::Atom(a) => a.dependent_on(), + } + } +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum OpType { + Const, + DL, + Linear, + Other, +} + +impl OpType { + pub fn new(op: RangeOp) -> Self { + if LIA_OPS.contains(&op) { + OpType::Linear + } else if DL_OPS.contains(&op) { + OpType::DL + } else if CONST_OPS.contains(&op) { + OpType::Const + } else { + OpType::Other + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct SolverAtom { + pub ty: OpType, + pub lhs: Box, + pub op: RangeOp, + pub rhs: Box, +} + +impl ToRangeString for SolverAtom { + fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + self.into_expr_elem().def_string(analyzer) + } + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + self.into_expr_elem().to_range_string(maximize, analyzer) + } +} + +impl SolverAtom { + pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + SolverAtom { + ty: self.ty, + lhs: Box::new(self.lhs.clone().replace_deps(solves)), + op: self.op, + rhs: Box::new(self.rhs.clone().replace_deps(solves)), + } + } + + pub fn max_ty(&self) -> OpType { + let mut max = OpType::new(self.op); + if let Some(lhs_max_ty) = self.lhs.maybe_max_ty() { + if lhs_max_ty > max { + max = lhs_max_ty; + } + } + if let Some(rhs_max_ty) = self.rhs.maybe_max_ty() { + if rhs_max_ty > max { + max = rhs_max_ty; + } + } + max + } + + pub fn update_max_ty(&mut self) { + self.ty = self.max_ty(); + } + + pub fn dependent_on(&self) -> Vec { + let mut deps = self.lhs.dependent_on(); + deps.extend(self.rhs.dependent_on()); + deps + } + + pub fn into_expr_elem(&self) -> Elem { + Elem::Expr(RangeExpr::new( + self.lhs.into_elem(), + self.op, + self.rhs.into_elem(), + )) + } + + pub fn add_rhs(&self, op: RangeOp, rhs: AtomOrPart) -> Self { + let new_ty = OpType::new(op); + if self.ty >= new_ty { + // keep ty + Self { + ty: self.ty, + lhs: Box::new(AtomOrPart::Atom(self.clone())), + op, + rhs: Box::new(rhs), + } + } else { + Self { + ty: new_ty, + lhs: Box::new(AtomOrPart::Atom(self.clone())), + op, + rhs: Box::new(rhs), + } + } + } + + pub fn add_lhs(&self, op: RangeOp, lhs: AtomOrPart) -> Self { + let new_ty = OpType::new(op); + + if self.ty >= new_ty { + // keep ty + Self { + ty: self.ty, + lhs: Box::new(lhs), + op, + rhs: Box::new(AtomOrPart::Atom(self.clone())), + } + } else { + Self { + ty: new_ty, + lhs: Box::new(lhs), + op, + rhs: Box::new(AtomOrPart::Atom(self.clone())), + } + } + } +} + +pub static CONST_OPS: &[RangeOp] = &[RangeOp::Eq]; +pub static DL_OPS: &[RangeOp] = &[ + RangeOp::Neq, + RangeOp::Add(true), + RangeOp::Add(false), + RangeOp::Sub(true), + RangeOp::Sub(false), + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::And, + RangeOp::Or, +]; +pub static LIA_OPS: &[RangeOp] = &[ + RangeOp::Mul(true), + RangeOp::Mul(false), + RangeOp::Div(true), + RangeOp::Div(false), + RangeOp::Mod, + RangeOp::Exp, +]; + +pub trait Atomize { + fn atoms_or_part(&self) -> AtomOrPart; + fn atomize(&self) -> Option; +} + +impl Atomize for Elem { + fn atoms_or_part(&self) -> AtomOrPart { + match self { + Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), + Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), + Elem::Expr(expr) => { + // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); + match (expr.lhs.atoms_or_part(), expr.rhs.atoms_or_part()) { + (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { + match (l, r) { + (Elem::Reference(Reference { .. }), Elem::Concrete(_)) + | (Elem::Concrete(_), Elem::Reference(Reference { .. })) => { + let ty = OpType::new(expr.op); + let atom = SolverAtom { + ty, + lhs: Box::new(lp.clone()), + op: expr.op, + rhs: Box::new(rp.clone()), + }; + AtomOrPart::Atom(atom) + } + (Elem::Reference(Reference { .. }), Elem::Reference(Reference { .. })) => { + let ty = if DL_OPS.contains(&expr.op) { + OpType::DL + } else if CONST_OPS.contains(&expr.op) { + OpType::Const + } else { + OpType::Other + }; + let atom = SolverAtom { + ty, + lhs: Box::new(lp.clone()), + op: expr.op, + rhs: Box::new(rp.clone()), + }; + AtomOrPart::Atom(atom) + } + (Elem::Expr(_), Elem::Expr(_)) => { + todo!("here"); + } + (Elem::Expr(_), Elem::Reference(Reference { .. })) => { + todo!("here1"); + } + (Elem::Reference(Reference { .. }), Elem::Expr(_)) => { + todo!("here2"); + } + (Elem::Expr(_), Elem::Concrete(_)) => { + todo!("here3"); + } + (Elem::Concrete(_), Elem::Expr(_)) => { + todo!("here4"); + } + (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => { + todo!("Should have simplified? {l} {r}") + } + (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), + (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), + (Elem::Null, _) => AtomOrPart::Part(Elem::Null), + (_, Elem::Null) => AtomOrPart::Part(Elem::Null), + } + } + (AtomOrPart::Atom(l_atom), r @ AtomOrPart::Part(_)) => { + AtomOrPart::Atom(l_atom.add_rhs(expr.op, r)) + } + (l @ AtomOrPart::Part(_), AtomOrPart::Atom(r_atom)) => { + AtomOrPart::Atom(r_atom.add_lhs(expr.op, l)) + } + (AtomOrPart::Atom(l_atoms), AtomOrPart::Atom(r_atoms)) => { + AtomOrPart::Atom(r_atoms.add_lhs(expr.op, AtomOrPart::Atom(l_atoms))) + } + } + } + Elem::Null => AtomOrPart::Part(self.clone()), + } + } + + fn atomize(&self) -> Option { + use Elem::*; + + match self { + Reference(_) => None, //{ println!("was dyn"); None}, + Null => None, //{ println!("was null"); None}, + Concrete(_c) => None, //{ println!("was conc: {}", c.val.as_human_string()); None }, + ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, + Expr(_) => { + // println!("atomized: was expr"); + let AtomOrPart::Atom(mut a) = self.atoms_or_part() else { + return None; + }; + a.update_max_ty(); + Some(a) + } + } + } +} diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 428a99b8..d1e8b740 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -1,9 +1,9 @@ use petgraph::stable_graph::StableGraph; -use crate::analyzer::GraphError; -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; -use crate::range::elem_ty::Elem; +use crate::GraphError; +use range::elem::RangeElem; +use range::elem::; +use range::elem_ty::Elem; use crate::solvers::AtomOrPart; use crate::solvers::Atomize; use crate::solvers::OpType; diff --git a/crates/graph/src/solvers/mod.rs b/crates/graph/src/solvers/mod.rs index 0f82879d..3da078a9 100644 --- a/crates/graph/src/solvers/mod.rs +++ b/crates/graph/src/solvers/mod.rs @@ -1,341 +1,4 @@ -use crate::range::elem::RangeElem; -use crate::range::elem::RangeOp; -use crate::range::elem_ty::Dynamic; -use crate::range::elem_ty::Elem; -use crate::range::elem_ty::RangeExpr; -use crate::range::range_string::RangeElemString; -use crate::range::range_string::ToRangeString; -use crate::Concrete; -use crate::ContextVarNode; -use crate::GraphLike; -use ethers_core::types::U256; -use std::collections::BTreeMap; - pub mod dl; +mod atoms; -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub enum AtomOrPart { - Part(Elem), - Atom(SolverAtom), -} - -impl AtomOrPart { - pub fn into_elem(&self) -> Elem { - match self { - AtomOrPart::Part(part) => part.clone(), - AtomOrPart::Atom(atom) => atom.into_expr_elem(), - } - } - - pub fn as_solver_atom(&self) -> SolverAtom { - match self { - AtomOrPart::Part(_) => SolverAtom { - ty: OpType::DL, - lhs: Box::new(self.clone()), - op: RangeOp::Sub(false), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), - }, - AtomOrPart::Atom(atom) => atom.clone(), - } - } - - pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { - match self { - AtomOrPart::Part(part) => { - let mut new_part = part.clone(); - solves.iter().for_each(|(dep, replacement)| { - new_part.replace_dep(dep.0.into(), replacement.clone()) - }); - AtomOrPart::Part(new_part) - } - AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves)), - } - } - - pub fn maybe_max_ty(&self) -> Option { - match self { - AtomOrPart::Part(_part) => None, - AtomOrPart::Atom(atom) => Some(atom.max_ty()), - } - } - - pub fn is_part(&self) -> bool { - if let AtomOrPart::Part(_) = self { - true - } else { - false - } - } - - pub fn is_atom(&self) -> bool { - if let AtomOrPart::Atom(_) = self { - true - } else { - false - } - } - - pub fn expect_atom(&self) -> SolverAtom { - if let AtomOrPart::Atom(atom) = self { - atom.clone() - } else { - panic!("Expected atom, was part: {self:?}") - } - } - - pub fn dependent_on(&self) -> Vec { - match self { - AtomOrPart::Part(e) => e.dependent_on(), - AtomOrPart::Atom(a) => a.dependent_on(), - } - } -} - -#[repr(u8)] -#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum OpType { - Const, - DL, - Linear, - Other, -} - -impl OpType { - pub fn new(op: RangeOp) -> Self { - if LIA_OPS.contains(&op) { - OpType::Linear - } else if DL_OPS.contains(&op) { - OpType::DL - } else if CONST_OPS.contains(&op) { - OpType::Const - } else { - OpType::Other - } - } -} - -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct SolverAtom { - pub ty: OpType, - pub lhs: Box, - pub op: RangeOp, - pub rhs: Box, -} - -impl ToRangeString for SolverAtom { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { - self.into_expr_elem().def_string(analyzer) - } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { - self.into_expr_elem().to_range_string(maximize, analyzer) - } -} - -impl SolverAtom { - pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { - SolverAtom { - ty: self.ty, - lhs: Box::new(self.lhs.clone().replace_deps(solves)), - op: self.op, - rhs: Box::new(self.rhs.clone().replace_deps(solves)), - } - } - - pub fn max_ty(&self) -> OpType { - let mut max = OpType::new(self.op); - if let Some(lhs_max_ty) = self.lhs.maybe_max_ty() { - if lhs_max_ty > max { - max = lhs_max_ty; - } - } - if let Some(rhs_max_ty) = self.rhs.maybe_max_ty() { - if rhs_max_ty > max { - max = rhs_max_ty; - } - } - max - } - - pub fn update_max_ty(&mut self) { - self.ty = self.max_ty(); - } - - pub fn dependent_on(&self) -> Vec { - let mut deps = self.lhs.dependent_on(); - deps.extend(self.rhs.dependent_on()); - deps - } - - pub fn into_expr_elem(&self) -> Elem { - Elem::Expr(RangeExpr::new( - self.lhs.into_elem(), - self.op, - self.rhs.into_elem(), - )) - } - - pub fn add_rhs(&self, op: RangeOp, rhs: AtomOrPart) -> Self { - let new_ty = OpType::new(op); - if self.ty >= new_ty { - // keep ty - Self { - ty: self.ty, - lhs: Box::new(AtomOrPart::Atom(self.clone())), - op, - rhs: Box::new(rhs), - } - } else { - Self { - ty: new_ty, - lhs: Box::new(AtomOrPart::Atom(self.clone())), - op, - rhs: Box::new(rhs), - } - } - } - - pub fn add_lhs(&self, op: RangeOp, lhs: AtomOrPart) -> Self { - let new_ty = OpType::new(op); - - if self.ty >= new_ty { - // keep ty - Self { - ty: self.ty, - lhs: Box::new(lhs), - op, - rhs: Box::new(AtomOrPart::Atom(self.clone())), - } - } else { - Self { - ty: new_ty, - lhs: Box::new(lhs), - op, - rhs: Box::new(AtomOrPart::Atom(self.clone())), - } - } - } -} - -pub static CONST_OPS: &[RangeOp] = &[RangeOp::Eq]; -pub static DL_OPS: &[RangeOp] = &[ - RangeOp::Neq, - RangeOp::Add(true), - RangeOp::Add(false), - RangeOp::Sub(true), - RangeOp::Sub(false), - RangeOp::Lt, - RangeOp::Lte, - RangeOp::Gt, - RangeOp::Gte, - RangeOp::And, - RangeOp::Or, -]; -pub static LIA_OPS: &[RangeOp] = &[ - RangeOp::Mul(true), - RangeOp::Mul(false), - RangeOp::Div(true), - RangeOp::Div(false), - RangeOp::Mod, - RangeOp::Exp, -]; - -pub trait Atomize { - fn atoms_or_part(&self) -> AtomOrPart; - fn atomize(&self) -> Option; -} - -impl Atomize for Elem { - fn atoms_or_part(&self) -> AtomOrPart { - match self { - Elem::Concrete(_) | Elem::Dynamic(_) => AtomOrPart::Part(self.clone()), - Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), - Elem::Expr(expr) => { - // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); - match (expr.lhs.atoms_or_part(), expr.rhs.atoms_or_part()) { - (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { - match (l, r) { - (Elem::Dynamic(Dynamic { .. }), Elem::Concrete(_)) - | (Elem::Concrete(_), Elem::Dynamic(Dynamic { .. })) => { - let ty = OpType::new(expr.op); - let atom = SolverAtom { - ty, - lhs: Box::new(lp.clone()), - op: expr.op, - rhs: Box::new(rp.clone()), - }; - AtomOrPart::Atom(atom) - } - (Elem::Dynamic(Dynamic { .. }), Elem::Dynamic(Dynamic { .. })) => { - let ty = if DL_OPS.contains(&expr.op) { - OpType::DL - } else if CONST_OPS.contains(&expr.op) { - OpType::Const - } else { - OpType::Other - }; - let atom = SolverAtom { - ty, - lhs: Box::new(lp.clone()), - op: expr.op, - rhs: Box::new(rp.clone()), - }; - AtomOrPart::Atom(atom) - } - (Elem::Expr(_), Elem::Expr(_)) => { - todo!("here"); - } - (Elem::Expr(_), Elem::Dynamic(Dynamic { .. })) => { - todo!("here1"); - } - (Elem::Dynamic(Dynamic { .. }), Elem::Expr(_)) => { - todo!("here2"); - } - (Elem::Expr(_), Elem::Concrete(_)) => { - todo!("here3"); - } - (Elem::Concrete(_), Elem::Expr(_)) => { - todo!("here4"); - } - (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => { - todo!("Should have simplified? {l} {r}") - } - (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), - (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), - (Elem::Null, _) => AtomOrPart::Part(Elem::Null), - (_, Elem::Null) => AtomOrPart::Part(Elem::Null), - } - } - (AtomOrPart::Atom(l_atom), r @ AtomOrPart::Part(_)) => { - AtomOrPart::Atom(l_atom.add_rhs(expr.op, r)) - } - (l @ AtomOrPart::Part(_), AtomOrPart::Atom(r_atom)) => { - AtomOrPart::Atom(r_atom.add_lhs(expr.op, l)) - } - (AtomOrPart::Atom(l_atoms), AtomOrPart::Atom(r_atoms)) => { - AtomOrPart::Atom(r_atoms.add_lhs(expr.op, AtomOrPart::Atom(l_atoms))) - } - } - } - Elem::Null => AtomOrPart::Part(self.clone()), - } - } - - fn atomize(&self) -> Option { - use Elem::*; - - match self { - Dynamic(_) => None, //{ println!("was dyn"); None}, - Null => None, //{ println!("was null"); None}, - Concrete(_c) => None, //{ println!("was conc: {}", c.val.as_human_string()); None }, - ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, - Expr(_) => { - // println!("atomized: was expr"); - let AtomOrPart::Atom(mut a) = self.atoms_or_part() else { - return None; - }; - a.update_max_ty(); - Some(a) - } - } - } -} +pub use atoms::*; diff --git a/crates/range/src/elem/concrete.rs b/crates/range/src/elem/concrete.rs index fb088871..fc599b05 100644 --- a/crates/range/src/elem/concrete.rs +++ b/crates/range/src/elem/concrete.rs @@ -1,143 +1,8 @@ +use solang_parser::pt::Loc; + /// A concrete value for a range element #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeConcrete { pub val: T, pub loc: Loc, -} - -impl From for RangeConcrete { - fn from(c: Concrete) -> Self { - Self { - val: c, - loc: Loc::Implicit, - } - } -} - -impl RangeElem for RangeConcrete { - // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { - // Elem::Concrete(self.clone()) - // } - - fn flatten( - &self, - _maximize: bool, - _analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - - fn range_eq(&self, other: &Self) -> bool { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(self_val), Some(other_val)) => self_val == other_val, - _ => match (&self.val, &other.val) { - (Concrete::Int(_, s), Concrete::Int(_, o)) => s == o, - (Concrete::DynBytes(s), Concrete::DynBytes(o)) => s == o, - (Concrete::String(s), Concrete::String(o)) => s == o, - (Concrete::DynBytes(s), Concrete::String(o)) => s == o.as_bytes(), - (Concrete::String(s), Concrete::DynBytes(o)) => s.as_bytes() == o, - (Concrete::Array(a), Concrete::Array(b)) => { - if a.len() == b.len() { - a.iter().zip(b.iter()).all(|(a, b)| { - let a = RangeConcrete { - val: a.clone(), - loc: self.loc, - }; - - let b = RangeConcrete { - val: b.clone(), - loc: other.loc, - }; - - a.range_eq(&b) - }) - } else { - false - } - } - _ => false, - }, - } - } - - fn range_ord(&self, other: &Self) -> Option { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), - (Some(_), _) => { - match other.val { - Concrete::Int(_, _) => { - // if we couldnt convert an int to uint, its negative - // so self must be > other - Some(std::cmp::Ordering::Greater) - } - _ => None, - } - } - (_, Some(_)) => { - match self.val { - Concrete::Int(_, _) => { - // if we couldnt convert an int to uint, its negative - // so self must be < other - Some(std::cmp::Ordering::Less) - } - _ => None, - } - } - _ => { - match (&self.val, &other.val) { - // two negatives - (Concrete::Int(_, s), Concrete::Int(_, o)) => Some(s.cmp(o)), - (Concrete::DynBytes(b0), Concrete::DynBytes(b1)) => Some(b0.cmp(b1)), - _ => None, - } - } - } - } - - fn dependent_on(&self) -> Vec { - vec![] - } - fn update_deps(&mut self, _mapping: &BTreeMap) {} - - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - - fn maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - fn minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - - fn simplify_maximize( - &self, - _exclude: &mut Vec, - _analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - fn simplify_minimize( - &self, - _exclude: &mut Vec, - _analyzer: &impl GraphLike, - ) -> Result, GraphError> { - Ok(Elem::Concrete(self.clone())) - } - - fn cache_maximize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { - Ok(()) - } - - fn cache_minimize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { - Ok(()) - } - fn uncache(&mut self) {} - - fn contains_op_set( - &self, - _: bool, - _op_set: &[RangeOp], - _analyzer: &impl GraphLike, - ) -> Result { - Ok(false) - } } \ No newline at end of file diff --git a/crates/range/src/elem/elem_enum.rs b/crates/range/src/elem/elem_enum.rs index 5f774e31..aeb7d49b 100644 --- a/crates/range/src/elem/elem_enum.rs +++ b/crates/range/src/elem/elem_enum.rs @@ -1,3 +1,22 @@ +use crate::elem::{RangeOp, Reference, RangeDyn, RangeConcrete, RangeExpr}; +use shared::NodeIdx; + +use std::{ + collections::BTreeMap, + ops::{ + Add, + Sub, + Mul, + Div, + Shl, + Shr, + Rem, + BitAnd, + BitOr, + BitXor, + } +}; + /// A core range element. #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Elem { @@ -88,8 +107,8 @@ impl Elem { } } -impl From for Elem { - fn from(dy: Reference) -> Self { +impl From> for Elem { + fn from(dy: Reference) -> Self { Elem::Reference(dy) } } diff --git a/crates/range/src/elem/expr.rs b/crates/range/src/elem/expr.rs index 37d38801..e9929f12 100644 --- a/crates/range/src/elem/expr.rs +++ b/crates/range/src/elem/expr.rs @@ -1,4 +1,5 @@ - +use crate::elem::{RangeOp, Elem, MinMaxed}; +use shared::NodeIdx; /// A range expression composed of other range [`Elem`] #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] diff --git a/crates/range/src/elem/map_or_array.rs b/crates/range/src/elem/map_or_array.rs index 54c094c0..60391e42 100644 --- a/crates/range/src/elem/map_or_array.rs +++ b/crates/range/src/elem/map_or_array.rs @@ -1,3 +1,10 @@ +use crate::elem::{Elem, MinMaxed }; +use shared::NodeIdx; + +use solang_parser::pt::Loc; + +use std::collections::BTreeMap; + /// A concrete value for a range element #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeDyn { diff --git a/crates/range/src/elem/mod.rs b/crates/range/src/elem/mod.rs index d376f30b..47d6dff4 100644 --- a/crates/range/src/elem/mod.rs +++ b/crates/range/src/elem/mod.rs @@ -1,3 +1,5 @@ +use shared::NodeIdx; +use shared::GraphLike; use std::collections::BTreeMap; mod concrete; @@ -163,16 +165,17 @@ impl ToString for RangeOp { } pub trait RangeElem { + type GraphError; /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables - fn flatten(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError>; + fn flatten(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn maximize(&self, analyzer: &impl GraphLike) -> Result, Self::GraphError>; /// Maximizes the element and caches the result for quicker use later - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError>; + fn minimize(&self, analyzer: &impl GraphLike) -> Result, Self::GraphError>; /// Minimizes the element and caches the result for quicker use later - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; /// Uncaches the minimum and maximum fn uncache(&mut self); /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) @@ -180,13 +183,13 @@ pub trait RangeElem { &self, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result, GraphError>; + ) -> Result, Self::GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) fn simplify_minimize( &self, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result, GraphError>; + ) -> Result, Self::GraphError>; /// Checks if two range elements are equal fn range_eq(&self, other: &Self) -> bool; /// Tries to compare the ordering of two range elements @@ -223,5 +226,5 @@ pub trait RangeElem { max: bool, op_set: &[RangeOp], analyzer: &impl GraphLike, - ) -> Result; + ) -> Result; } diff --git a/crates/range/src/elem/reference.rs b/crates/range/src/elem/reference.rs index 6ff39b21..d4d6931a 100644 --- a/crates/range/src/elem/reference.rs +++ b/crates/range/src/elem/reference.rs @@ -1,3 +1,6 @@ +use crate::elem::MinMaxed; +use shared::NodeIdx; + /// A dynamic range element value #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct Reference { diff --git a/crates/range/src/exec.rs b/crates/range/src/exec.rs index 2c3bd3ac..fae51a64 100644 --- a/crates/range/src/exec.rs +++ b/crates/range/src/exec.rs @@ -1,8 +1,14 @@ +use shared::NodeIdx; +use shared::GraphLike; + +use crate::elem::Elem; + /// For execution of operations to be performed on range expressions pub trait ExecOp { + type GraphError; /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side /// and right-hand-side - fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, GraphError> { + fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, Self::GraphError> { self.exec(self.spread(analyzer)?, maximize) } @@ -10,24 +16,24 @@ pub trait ExecOp { &self, parts: (Elem, Elem, Elem, Elem), maximize: bool, - ) -> Result, GraphError>; + ) -> Result, Self::GraphError>; /// Cache execution fn cache_exec_op( &mut self, maximize: bool, analyzer: &impl GraphLike, - ) -> Result<(), GraphError>; + ) -> Result<(), Self::GraphError>; fn spread( &self, analyzer: &impl GraphLike, - ) -> Result<(Elem, Elem, Elem, Elem), GraphError>; + ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; fn simplify_spread( &self, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result<((Elem, Elem, Elem, Elem), bool), GraphError>; + ) -> Result<((Elem, Elem, Elem, Elem), bool), Self::GraphError>; fn uncache_exec(&mut self); @@ -36,14 +42,14 @@ pub trait ExecOp { maximize: bool, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result, GraphError>; + ) -> Result, Self::GraphError>; /// Attempts to simplify an expression (i.e. just apply constant folding) fn simplify_exec( &self, parts: (Elem, Elem, Elem, Elem), maximize: bool, - ) -> Result, GraphError> { + ) -> Result, Self::GraphError> { self.exec(parts, maximize) } } diff --git a/crates/range/src/lib.rs b/crates/range/src/lib.rs index da36dd38..3139410d 100644 --- a/crates/range/src/lib.rs +++ b/crates/range/src/lib.rs @@ -1,32 +1,32 @@ -mod elem; -mod exec; -mod solc_range; -mod range_string; +use crate::elem::RangeElem; +use shared::{ NodeIdx, GraphLike }; + +pub mod elem; +pub mod exec; +pub mod range_string; -pub use elem::*; -pub use exec::*; -pub use range_string::*; pub trait Range { + type GraphError; type ElemTy: RangeElem + Clone; /// Evaluate both the minimum and the maximum - cache along the way - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError>; + fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; /// Evaluate the range minimum - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; + fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; /// Evaluate the range maximum - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; + fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; /// Simplify the minimum, leaving references in place fn simplified_range_min( &self, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result; + ) -> Result; /// Simplify the maximum, leaving references in place fn simplified_range_max( &self, exclude: &mut Vec, analyzer: &impl GraphLike, - ) -> Result; + ) -> Result; /// Return the range minimum fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; /// Return the range maximum diff --git a/crates/range/src/range_string.rs b/crates/range/src/range_string.rs index 49004f0b..f23ef91f 100644 --- a/crates/range/src/range_string.rs +++ b/crates/range/src/range_string.rs @@ -1,5 +1,4 @@ - -use std::collections::BTreeMap; +use crate::GraphLike; use solang_parser::pt::Loc; diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index aa1e2a3c..d5aa9c59 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -11,6 +11,7 @@ homepage.workspace = true repository.workspace = true [dependencies] +petgraph.workspace = true solang-parser.workspace = true ethers-core.workspace = true hex.workspace = true diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 99d41f82..417383a2 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -1,10 +1,30 @@ -use graph::GraphLike; +use crate::{GraphLike, NodeIdx}; +use std::collections::HashMap; pub trait AnalyzerLike: GraphLike { + /// The expression type type Expr; + /// An error when parsing an expression type ExprErr; + + /// Type of the `msg` node + type MsgNode; + /// Type of the `block` node + type BlockNode; + + /// Type of a function input parameter + type FunctionParam; + /// Type of a function return paramter + type FunctionReturn; + + /// Type of a builtin + type Builtin; + + /// Type of a function + type Function; + /// Gets the builtin functions map - fn builtin_fns(&self) -> &HashMap; + fn builtin_fns(&self) -> &HashMap; /// Mutably gets the builtin functions map fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap; /// Gets the builtin function nodes mapping @@ -16,58 +36,59 @@ pub trait AnalyzerLike: GraphLike { fn user_types(&self) -> &HashMap; fn user_types_mut(&mut self) -> &mut HashMap; fn parse_expr(&mut self, expr: &Self::Expr, parent: Option) -> NodeIdx; - fn msg(&mut self) -> MsgNode; - fn block(&mut self) -> BlockNode; + fn msg(&mut self) -> Self::MsgNode; + fn block(&mut self) -> Self::BlockNode; fn entry(&self) -> NodeIdx; fn add_expr_err(&mut self, err: Self::ExprErr); fn expr_errs(&self) -> Vec; - fn builtin_fn_inputs(&self) -> &HashMap, Vec)>; - fn builtins(&self) -> &HashMap; - fn builtins_mut(&mut self) -> &mut HashMap; + fn builtin_fn_inputs(&self) -> &HashMap, Vec)>; + fn builtins(&self) -> &HashMap; + fn builtins_mut(&mut self) -> &mut HashMap; - fn builtin_or_add(&mut self, builtin: Builtin) -> NodeIdx { - if let Some(idx) = self.builtins().get(&builtin) { - *idx - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins_mut().insert(builtin, idx); - idx - } - } + fn builtin_or_add(&mut self, builtin: Self::Builtin) -> NodeIdx; + // { + // if let Some(idx) = self.builtins().get(&builtin) { + // *idx + // } else { + // let idx = self.add_node(Node::Builtin(builtin.clone())); + // self.builtins_mut().insert(builtin, idx); + // idx + // } + // } fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option where - Self: std::marker::Sized, - { - if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { - Some(*idx) - } else if let Some(func) = self.builtin_fns().get(builtin_name) { - let (inputs, outputs) = self - .builtin_fn_inputs() - .get(builtin_name) - .expect("builtin func but no inputs") - .clone(); - let func_node = self.add_node(Node::Function(func.clone())); - let mut params_strs = vec![]; - inputs.into_iter().for_each(|input| { - let input_node = self.add_node(input); - params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); - self.add_edge(input_node, func_node, Edge::FunctionParam); - }); - outputs.into_iter().for_each(|output| { - let output_node = self.add_node(output); - self.add_edge(output_node, func_node, Edge::FunctionReturn); - }); + Self: std::marker::Sized; + // { + // if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { + // Some(*idx) + // } else if let Some(func) = self.builtin_fns().get(builtin_name) { + // let (inputs, outputs) = self + // .builtin_fn_inputs() + // .get(builtin_name) + // .expect("builtin func but no inputs") + // .clone(); + // let func_node = self.add_node(Node::Function(func.clone())); + // let mut params_strs = vec![]; + // inputs.into_iter().for_each(|input| { + // let input_node = self.add_node(input); + // params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); + // self.add_edge(input_node, func_node, Edge::FunctionParam); + // }); + // outputs.into_iter().for_each(|output| { + // let output_node = self.add_node(output); + // self.add_edge(output_node, func_node, Edge::FunctionReturn); + // }); - self.add_edge(func_node, self.entry(), Edge::Func); + // self.add_edge(func_node, self.entry(), Edge::Func); - self.builtin_fn_nodes_mut() - .insert(builtin_name.to_string(), func_node); - Some(func_node) - } else { - None - } - } + // self.builtin_fn_nodes_mut() + // .insert(builtin_name.to_string(), func_node); + // Some(func_node) + // } else { + // None + // } + // } fn add_if_err(&mut self, err: Result) -> Option { diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 3303bf0c..88cb082c 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,3 +1,14 @@ +use crate::AnalyzerLike; + +use std::{ + sync::{Arc, Mutex}, + collections::BTreeSet +}; +use petgraph::{ + Directed, + graph::{Graph, EdgeIndex, NodeIndex} +}; + pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; @@ -8,22 +19,24 @@ pub trait AsDotStr { /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphLike { + type Node; + type Edge; /// Get a mutable reference to the graph - fn graph_mut(&mut self) -> &mut Graph; + fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph - fn graph(&self) -> &Graph; + fn graph(&self) -> &Graph; /// Add a node to the graph - fn add_node(&mut self, node: impl Into) -> NodeIdx { + fn add_node(&mut self, node: impl Into) -> NodeIdx { self.graph_mut().add_node(node.into()) } /// Get a reference to a node in the graph - fn node(&self, node: impl Into) -> &Node { + fn node(&self, node: impl Into) -> &Self::Node { self.graph() .node_weight(node.into()) .expect("Index not in graph") } /// Get a mutable reference to a node in the graph - fn node_mut(&mut self, node: impl Into) -> &mut Node { + fn node_mut(&mut self, node: impl Into) -> &mut Self::Node { self.graph_mut() .node_weight_mut(node.into()) .expect("Index not in graph") @@ -33,22 +46,20 @@ pub trait GraphLike { &mut self, from_node: impl Into, to_node: impl Into, - edge: impl Into, + edge: impl Into, ) { self.graph_mut() .add_edge(from_node.into(), to_node.into(), edge.into()); } } -impl GraphDot for T {} - /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphDot: GraphLike { /// Open a dot using graphviz fn open_dot(&self) where Self: std::marker::Sized, - Self: AnalyzerLike, + Self: AnalyzerLike { use std::env::temp_dir; use std::fs; @@ -83,271 +94,274 @@ pub trait GraphDot: GraphLike { is_killed: bool, handled_nodes: Arc>>, handled_edges: Arc>>>, - ) -> String { - if self - .graph() - .edges_directed(node, Direction::Outgoing) - .collect::>() - .is_empty() - { - return "".to_string(); - } - let new_graph = self.graph().filter_map( - |_idx, node| match node { - Node::ContextVar(_cvar) => { - // if !cvar.is_symbolic { - // None - // } else { - Some(node.clone()) - // } - } - _ => Some(node.clone()), - }, - |_idx, edge| Some(*edge), - ); + ) -> String; + // { + // if self + // .graph() + // .edges_directed(node, Direction::Outgoing) + // .collect::>() + // .is_empty() + // { + // return "".to_string(); + // } + // let new_graph = self.graph().filter_map( + // |_idx, node| match node { + // Node::ContextVar(_cvar) => { + // // if !cvar.is_symbolic { + // // None + // // } else { + // Some(node.clone()) + // // } + // } + // _ => Some(node.clone()), + // }, + // |_idx, edge| Some(*edge), + // ); - let g = &G { graph: &new_graph }; - let children = g.children(node); - let children_edges = g.children_edges(node); - let mut cn = cluster_num + 1; - let child_node_str = children - .iter() - .map(|child| { - { - handled_nodes.lock().unwrap().insert(*child); - } + // let g = &G { graph: &new_graph }; + // let children = g.children(node); + // let children_edges = g.children_edges(node); + // let mut cn = cluster_num + 1; + // let child_node_str = children + // .iter() + // .map(|child| { + // { + // handled_nodes.lock().unwrap().insert(*child); + // } - if g.graph - .edges_directed(*child, Direction::Outgoing) - .collect::>() - .is_empty() - { - return "".to_string(); - } - let post_str = match self.node(*child) { - Node::Context(c) => { - cn += 2; - self.cluster_str( - *child, - cn, - c.killed.is_some(), - handled_nodes.clone(), - handled_edges.clone(), - ) - } - _ => "".to_string(), - }; + // if g.graph + // .edges_directed(*child, Direction::Outgoing) + // .collect::>() + // .is_empty() + // { + // return "".to_string(); + // } + // let post_str = match self.node(*child) { + // Node::Context(c) => { + // cn += 2; + // self.cluster_str( + // *child, + // cn, + // c.killed.is_some(), + // handled_nodes.clone(), + // handled_edges.clone(), + // ) + // } + // _ => "".to_string(), + // }; - format!( - " {} [label = \"{}\", color = \"{}\"]\n{}\n", - petgraph::graph::GraphIndex::index(child), - as_dot_str(*child, g).replace('\"', "\'"), - self.node(*child).dot_str_color(), - post_str - ) - }) - .collect::>() - .join(""); + // format!( + // " {} [label = \"{}\", color = \"{}\"]\n{}\n", + // petgraph::graph::GraphIndex::index(child), + // child.as_dot_str(g).replace('\"', "\'"), + // self.node(*child).dot_str_color(), + // post_str + // ) + // }) + // .collect::>() + // .join(""); - let edge_str = children_edges - .iter() - .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) - .map(|(from, to, edge, idx)| { - handled_edges.lock().unwrap().insert(*idx); - let from = petgraph::graph::GraphIndex::index(from); - let to = petgraph::graph::GraphIndex::index(to); - format!(" {from:} -> {to:} [label = \"{edge:?}\"]\n",) - }) - .collect::>() - .join(""); - format!( - " subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", - cluster_num, - if is_killed && cluster_num % 2 == 0 { - " bgcolor=\"#7a0b0b\"" - } else if is_killed { - " bgcolor=\"#e04646\"" - } else if cluster_num % 2 == 0 { - " bgcolor=\"#545e87\"" - } else { - " bgcolor=\"#1a1b26\"" - }, - format!( - " {} [label = \"{}\", color = \"{}\"]\n", - node.index(), - as_dot_str(node, g).replace('\"', "\'"), - self.node(node).dot_str_color() - ), - child_node_str, - edge_str, - ) - } + // let edge_str = children_edges + // .iter() + // .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) + // .map(|(from, to, edge, idx)| { + // handled_edges.lock().unwrap().insert(*idx); + // let from = petgraph::graph::GraphIndex::index(from); + // let to = petgraph::graph::GraphIndex::index(to); + // format!(" {from:} -> {to:} [label = \"{edge:?}\"]\n",) + // }) + // .collect::>() + // .join(""); + // format!( + // " subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", + // cluster_num, + // if is_killed && cluster_num % 2 == 0 { + // " bgcolor=\"#7a0b0b\"" + // } else if is_killed { + // " bgcolor=\"#e04646\"" + // } else if cluster_num % 2 == 0 { + // " bgcolor=\"#545e87\"" + // } else { + // " bgcolor=\"#1a1b26\"" + // }, + // format!( + // " {} [label = \"{}\", color = \"{}\"]\n", + // node.index(), + // node.as_dot_str(g).replace('\"', "\'"), + // self.node(node).dot_str_color() + // ), + // child_node_str, + // edge_str, + // ) + // } /// Constructs a dot string fn dot_str(&self) -> String where Self: std::marker::Sized, - Self: AnalyzerLike, - { - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26"; rankdir="BT""##; - dot_str.push(raw_start_str.to_string()); - let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); - let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); - let (nodes, edges) = ( - self.graph().node_indices().collect::>(), - self.graph().edge_indices().collect::>(), - ); - let mut cluster_num = 0; - let mut skip = BTreeSet::default(); - let nodes_str = nodes - .iter() - .filter_map(|node| { - if self - .graph() - .edges_directed(*node, Direction::Outgoing) - .collect::>() - .is_empty() - && !matches!(self.node(*node), Node::Entry) - { - skip.insert(*node); - return None; - } - if !handled_nodes.lock().unwrap().contains(node) { - match self.node(*node) { - Node::Function(_) => { - cluster_num += 2; - Some(self.cluster_str( - *node, - cluster_num, - false, - handled_nodes.clone(), - handled_edges.clone(), - )) - } - n => Some(format!( - "{} [label = \"{}\", color = \"{}\"]", - petgraph::graph::GraphIndex::index(node), - as_dot_str(*node, self).replace('\"', "\'"), - n.dot_str_color() - )), - } - } else { - None - } - }) - .collect::>() - .join("\n "); - let edges_str = edges - .into_iter() - .filter_map(|edge| { - if !handled_edges.lock().unwrap().contains(&edge) { - let (from, to) = self.graph().edge_endpoints(edge).unwrap(); - if skip.contains(&from) || skip.contains(&to) { - return None; - } - let from = from.index(); - let to = to.index(); - Some(format!( - "{from:} -> {to:} [label = \"{:?}\"]", - self.graph().edge_weight(edge).unwrap() - )) - } else { - None - } - }) - .collect::>() - .join("\n "); + Self: AnalyzerLike; + // { + // let mut dot_str = Vec::new(); + // let raw_start_str = r##"digraph G { + // node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + // edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + // bgcolor="#1a1b26"; rankdir="BT""##; + // dot_str.push(raw_start_str.to_string()); + // let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); + // let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); + // let (nodes, edges) = ( + // self.graph().node_indices().collect::>(), + // self.graph().edge_indices().collect::>(), + // ); + // let mut cluster_num = 0; + // let mut skip = BTreeSet::default(); + // let nodes_str = nodes + // .iter() + // .filter_map(|node| { + // if self + // .graph() + // .edges_directed(*node, Direction::Outgoing) + // .collect::>() + // .is_empty() + // && !matches!(self.node(*node), Node::Entry) + // { + // skip.insert(*node); + // return None; + // } + // if !handled_nodes.lock().unwrap().contains(node) { + // match self.node(*node) { + // Node::Function(_) => { + // cluster_num += 2; + // Some(self.cluster_str( + // *node, + // cluster_num, + // false, + // handled_nodes.clone(), + // handled_edges.clone(), + // )) + // } + // n => Some(format!( + // "{} [label = \"{}\", color = \"{}\"]", + // petgraph::graph::GraphIndex::index(node), + // node.as_dot_str(self).replace('\"', "\'"), + // n.dot_str_color() + // )), + // } + // } else { + // None + // } + // }) + // .collect::>() + // .join("\n "); + // let edges_str = edges + // .into_iter() + // .filter_map(|edge| { + // if !handled_edges.lock().unwrap().contains(&edge) { + // let (from, to) = self.graph().edge_endpoints(edge).unwrap(); + // if skip.contains(&from) || skip.contains(&to) { + // return None; + // } + // let from = from.index(); + // let to = to.index(); + // Some(format!( + // "{from:} -> {to:} [label = \"{:?}\"]", + // self.graph().edge_weight(edge).unwrap() + // )) + // } else { + // None + // } + // }) + // .collect::>() + // .join("\n "); - dot_str.push(nodes_str); - dot_str.push(edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - dot_str.join("\n") - } + // dot_str.push(nodes_str); + // dot_str.push(edges_str); + // let raw_end_str = r#"}"#; + // dot_str.push(raw_end_str.to_string()); + // dot_str.join("\n") + // } /// Construct a dot string while filtering temporary variables fn dot_str_no_tmps(&self) -> String where Self: std::marker::Sized, - Self: GraphLike + AnalyzerLike, - { - let new_graph = self.graph().filter_map( - |_idx, node| match node { - Node::ContextVar(cvar) => { - if !cvar.is_symbolic || cvar.tmp_of.is_some() { - None - } else { - Some(node.clone()) - } - } - _ => Some(node.clone()), - }, - |_idx, edge| Some(*edge), - ); - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &new_graph, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - match edge_ref.weight() { - Edge::Context(edge) => format!("label = \"{edge:?}\""), - e => format!("label = \"{e:?}\""), - } - }, - &|_graph, (idx, node_ref)| { - let inner = match node_ref { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { - r.as_dot_str(self) - // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - } else { - "".to_string() - }; + Self: GraphLike + AnalyzerLike; + // { + // let new_graph = self.graph().filter_map( + // |_idx, node| match node { + // Node::ContextVar(cvar) => { + // if !cvar.is_symbolic || cvar.tmp_of.is_some() { + // None + // } else { + // Some(node.clone()) + // } + // } + // _ => Some(node.clone()), + // }, + // |_idx, edge| Some(*edge), + // ); + // let mut dot_str = Vec::new(); + // let raw_start_str = r##"digraph G { + // node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + // edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + // bgcolor="#1a1b26";"##; + // dot_str.push(raw_start_str.to_string()); + // let nodes_and_edges_str = format!( + // "{:?}", + // Dot::with_attr_getters( + // &new_graph, + // &[ + // petgraph::dot::Config::GraphContentOnly, + // petgraph::dot::Config::NodeNoLabel, + // petgraph::dot::Config::EdgeNoLabel + // ], + // &|_graph, edge_ref| { + // match edge_ref.weight() { + // Edge::Context(edge) => format!("label = \"{edge:?}\""), + // e => format!("label = \"{e:?}\""), + // } + // }, + // &|_graph, (idx, node_ref)| { + // let inner = match node_ref { + // Node::ContextVar(cvar) => { + // let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { + // r.as_dot_str(self) + // // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) + // } else { + // "".to_string() + // }; - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(self).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, &G { graph: &new_graph }), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - node_ref.dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - dot_str.join("\n") - } + // format!( + // "{} -- {} -- range: {}", + // cvar.display_name, + // cvar.ty.as_string(self).unwrap(), + // range_str + // ) + // } + // _ => idx.as_dot_str(&G { graph: &new_graph }), + // }; + // format!( + // "label = \"{}\", color = \"{}\"", + // inner.replace('\"', "\'"), + // node_ref.dot_str_color() + // ) + // } + // ) + // ); + // dot_str.push(nodes_and_edges_str); + // let raw_end_str = r#"}"#; + // dot_str.push(raw_end_str.to_string()); + // dot_str.join("\n") + // } } -struct G<'a> { +struct G<'a, Node, Edge> { pub graph: &'a Graph, } -impl GraphLike for G<'_> { +impl GraphLike for G<'_, Node, Edge> { + type Node = Node; + type Edge = Edge; fn graph_mut(&mut self) -> &mut Graph { panic!("Should call this") } diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index e69de29b..c2fa7ebf 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -0,0 +1,5 @@ +mod graph_like; +mod analyzer_like; + +pub use graph_like::*; +pub use analyzer_like::*; \ No newline at end of file From 286ed90d39949a12d41983c068eb234b6d01979a Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 10:50:45 -0800 Subject: [PATCH 11/71] bring range into graph, get graph and analyzers compiling --- Cargo.lock | 18 +- Cargo.toml | 2 - crates/analyzers/Cargo.toml | 2 +- crates/analyzers/src/bounds.rs | 48 +- crates/analyzers/src/func_analyzer/mod.rs | 115 ++-- .../src/func_analyzer/report_display.rs | 27 +- crates/analyzers/src/lib.rs | 20 +- crates/analyzers/src/var_analyzer/mod.rs | 29 +- .../src/var_analyzer/report_display.rs | 26 +- crates/graph/Cargo.toml | 2 +- crates/graph/src/graph_elements.rs | 32 +- crates/graph/src/lib.rs | 6 +- crates/graph/src/nodes/block.rs | 15 +- crates/graph/src/nodes/builtin.rs | 36 +- crates/graph/src/nodes/concrete.rs | 22 +- crates/graph/src/nodes/context/expr_ret.rs | 10 +- crates/graph/src/nodes/context/mod.rs | 2 +- crates/graph/src/nodes/context/node.rs | 29 +- crates/graph/src/nodes/context/querying.rs | 29 +- crates/graph/src/nodes/context/solving.rs | 27 +- crates/graph/src/nodes/context/typing.rs | 21 +- crates/graph/src/nodes/context/underlying.rs | 8 +- crates/graph/src/nodes/context/var/node.rs | 54 +- crates/graph/src/nodes/context/var/ranging.rs | 51 +- crates/graph/src/nodes/context/var/typing.rs | 72 ++- .../graph/src/nodes/context/var/underlying.rs | 43 +- .../graph/src/nodes/context/var/versioning.rs | 38 +- crates/graph/src/nodes/context/variables.rs | 35 +- crates/graph/src/nodes/context/versioning.rs | 41 +- crates/graph/src/nodes/contract_ty.rs | 52 +- crates/graph/src/nodes/enum_ty.rs | 23 +- crates/graph/src/nodes/err_ty.rs | 13 +- crates/graph/src/nodes/func_ty.rs | 101 ++-- crates/graph/src/nodes/msg.rs | 21 +- crates/graph/src/nodes/struct_ty.rs | 32 +- crates/graph/src/nodes/ty_ty.rs | 18 +- crates/graph/src/nodes/var_ty.rs | 35 +- .../{range_impl => range}/elem/concrete.rs | 40 +- .../{range_impl => range}/elem/elem_enum.rs | 425 ++++++++++---- crates/graph/src/range/elem/elem_trait.rs | 70 +++ .../src/{range_impl => range}/elem/expr.rs | 67 ++- .../elem/map_or_array.rs | 60 +- .../src => graph/src/range}/elem/mod.rs | 71 +-- .../{range_impl => range}/elem/reference.rs | 55 +- .../src/{range_impl => range}/exec/add.rs | 2 +- .../src/{range_impl => range}/exec/bitwise.rs | 2 +- .../src/{range_impl => range}/exec/cast.rs | 2 +- .../src/{range_impl => range}/exec/concat.rs | 2 +- .../src/{range_impl => range}/exec/div.rs | 4 +- .../src/{range_impl => range}/exec/exec_op.rs | 14 +- .../src/{range_impl => range}/exec/exp.rs | 4 +- .../src/{range_impl => range}/exec/logical.rs | 2 +- .../src/{range_impl => range}/exec/max.rs | 2 +- .../src/{range_impl => range}/exec/min.rs | 2 +- .../src/{range_impl => range}/exec/mod.rs | 0 .../src/{range_impl => range}/exec/modulo.rs | 2 +- .../src/{range_impl => range}/exec/mul.rs | 2 +- .../src/{range_impl => range}/exec/ord.rs | 2 +- .../src/{range_impl => range}/exec/shift.rs | 2 +- .../src/{range_impl => range}/exec/sub.rs | 2 +- .../src/range/exec_traits.rs} | 14 +- crates/graph/src/range/mod.rs | 11 + .../src/{range_impl => range}/range_string.rs | 58 +- .../lib.rs => graph/src/range/range_trait.rs} | 29 +- .../src/{range_impl => range}/solc_range.rs | 47 +- crates/graph/src/range_impl/elem/mod.rs | 11 - crates/graph/src/range_impl/mod.rs | 6 - crates/graph/src/search.rs | 267 --------- crates/graph/src/solvers/atoms.rs | 28 +- crates/graph/src/solvers/dl.rs | 51 +- crates/graph/src/var_type.rs | 89 +-- crates/pyrometer/Cargo.toml | 1 - crates/pyrometer/src/lib.rs | 2 +- crates/queries/Cargo.toml | 1 - crates/range/Cargo.toml | 19 - crates/range/src/elem/concrete.rs | 8 - crates/range/src/elem/elem_enum.rs | 210 ------- crates/range/src/elem/expr.rs | 31 - crates/range/src/elem/map_or_array.rs | 34 -- crates/range/src/elem/reference.rs | 23 - crates/range/src/range_string.rs | 39 -- crates/shared/src/graph_like.rs | 9 +- crates/shared/src/lib.rs | 2 + crates/shared/src/search.rs | 537 ++++++++++++++++++ 84 files changed, 1913 insertions(+), 1603 deletions(-) rename crates/graph/src/{range_impl => range}/elem/concrete.rs (78%) rename crates/graph/src/{range_impl => range}/elem/elem_enum.rs (61%) create mode 100644 crates/graph/src/range/elem/elem_trait.rs rename crates/graph/src/{range_impl => range}/elem/expr.rs (92%) rename crates/graph/src/{range_impl => range}/elem/map_or_array.rs (72%) rename crates/{range/src => graph/src/range}/elem/mod.rs (53%) rename crates/graph/src/{range_impl => range}/elem/reference.rs (78%) rename crates/graph/src/{range_impl => range}/exec/add.rs (99%) rename crates/graph/src/{range_impl => range}/exec/bitwise.rs (99%) rename crates/graph/src/{range_impl => range}/exec/cast.rs (99%) rename crates/graph/src/{range_impl => range}/exec/concat.rs (99%) rename crates/graph/src/{range_impl => range}/exec/div.rs (98%) rename crates/graph/src/{range_impl => range}/exec/exec_op.rs (99%) rename crates/graph/src/{range_impl => range}/exec/exp.rs (97%) rename crates/graph/src/{range_impl => range}/exec/logical.rs (97%) rename crates/graph/src/{range_impl => range}/exec/max.rs (97%) rename crates/graph/src/{range_impl => range}/exec/min.rs (97%) rename crates/graph/src/{range_impl => range}/exec/mod.rs (100%) rename crates/graph/src/{range_impl => range}/exec/modulo.rs (97%) rename crates/graph/src/{range_impl => range}/exec/mul.rs (99%) rename crates/graph/src/{range_impl => range}/exec/ord.rs (99%) rename crates/graph/src/{range_impl => range}/exec/shift.rs (99%) rename crates/graph/src/{range_impl => range}/exec/sub.rs (99%) rename crates/{range/src/exec.rs => graph/src/range/exec_traits.rs} (93%) create mode 100644 crates/graph/src/range/mod.rs rename crates/graph/src/{range_impl => range}/range_string.rs (83%) rename crates/{range/src/lib.rs => graph/src/range/range_trait.rs} (73%) rename crates/graph/src/{range_impl => range}/solc_range.rs (94%) delete mode 100644 crates/graph/src/range_impl/elem/mod.rs delete mode 100644 crates/graph/src/range_impl/mod.rs delete mode 100644 crates/graph/src/search.rs delete mode 100644 crates/range/Cargo.toml delete mode 100644 crates/range/src/elem/concrete.rs delete mode 100644 crates/range/src/elem/elem_enum.rs delete mode 100644 crates/range/src/elem/expr.rs delete mode 100644 crates/range/src/elem/map_or_array.rs delete mode 100644 crates/range/src/elem/reference.rs delete mode 100644 crates/range/src/range_string.rs create mode 100644 crates/shared/src/search.rs diff --git a/Cargo.lock b/Cargo.lock index db1ad92d..7e4a2eee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ version = "0.2.0" dependencies = [ "ariadne", "graph", - "range", + "shared", "solang-parser", ] @@ -589,9 +589,9 @@ version = "0.2.0" dependencies = [ "ethers-core", "hex", + "itertools", "lazy_static", "petgraph", - "range", "shared", "solang-parser", "tracing", @@ -1139,7 +1139,6 @@ dependencies = [ "ariadne", "ethers-core", "graph", - "range", "solang-parser", "solc-expressions", "tracing", @@ -1154,7 +1153,6 @@ dependencies = [ "ariadne", "ethers-core", "graph", - "range", "solang-parser", "solc-expressions", "tracing", @@ -1215,18 +1213,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "range" -version = "0.2.0" -dependencies = [ - "ethers-core", - "hex", - "shared", - "solang-parser", - "tracing", - "tracing-subscriber", -] - [[package]] name = "redox_syscall" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 32b1b778..06fd6f5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ members = [ "crates/graph", "crates/pyrometer", "crates/queries", - "crates/range", "crates/shared", "crates/solc-expressions", ] @@ -36,7 +35,6 @@ analyzers = { path = "crates/analyzers" } graph = { path = "crates/graph" } pyrometer = { path = "crates/pyrometer" } queries = { path = "crates/queries" } -range = { path = "crates/range" } shared = { path = "crates/shared" } solc-expressions = { path = "crates/solc-expressions" } diff --git a/crates/analyzers/Cargo.toml b/crates/analyzers/Cargo.toml index 18eacaf6..136ace93 100644 --- a/crates/analyzers/Cargo.toml +++ b/crates/analyzers/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true [dependencies] graph.workspace = true -range.workspace = true +shared.workspace = true solang-parser.workspace = true ariadne.workspace = true \ No newline at end of file diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index 2ea3d72a..de485d00 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -1,13 +1,9 @@ -use crate::analyzers::FunctionVarsBoundAnalysis; -use crate::analyzers::VarBoundAnalysis; +use crate::{LocSpan, LocStrSpan, ReportConfig, VarBoundAnalysis, FunctionVarsBoundAnalysis}; -use crate::analyzers::LocSpan; -use crate::analyzers::{LocStrSpan, ReportConfig}; - -use shared::analyzer::GraphLike; -use shared::{ - context::*, - range::{range_string::*, Range, RangeEval, SolcRange}, +use graph::{ + GraphBackend, Range, RangeEval, SolcRange, + range_string::ToRangeString, + nodes::ContextNode, }; use ariadne::{Color, Fmt, Label, Span}; @@ -77,7 +73,7 @@ pub struct OrderedAnalysis { } impl OrderedAnalysis { - pub fn from_bound_analysis(ba: VarBoundAnalysis, analyzer: &impl GraphLike) -> Self { + pub fn from_bound_analysis(ba: VarBoundAnalysis, analyzer: &impl GraphBackend) -> Self { let mut analyses: BTreeMap> = Default::default(); if let Some(init) = ba.init_item(analyzer) { let source: usize = *LocSpan(init.loc.1).source(); @@ -110,7 +106,7 @@ impl OrderedAnalysis { Self { analyses } } - pub fn from_func_analysis(fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphLike) -> Self { + pub fn from_func_analysis(fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphBackend) -> Self { let mut analyses = Self::default(); fvba.vars_by_ctx.iter().for_each(|(_ctx, bas)| { bas.iter().for_each(|ba| { @@ -164,39 +160,39 @@ impl RangePart { } } -impl Into> for AnalysisItem { - fn into(self) -> ariadne::Label { - let (color, order, priority) = if self.init { - (Color::Magenta, self.order, -1) +impl From for Label { + fn from(val: AnalysisItem) -> Self { + let (color, order, priority) = if val.init { + (Color::Magenta, val.order, -1) } else { ( - match self.storage { + match val.storage { Some(StorageLocation::Memory(..)) => Color::Blue, Some(StorageLocation::Storage(..)) => Color::Green, Some(StorageLocation::Calldata(..)) => Color::White, None => Color::Cyan, }, - self.order, + val.order, 0, ) }; - Label::new(self.loc) + Label::new(val.loc) .with_message(format!( "{}\"{}\"{}{}", - match self.storage { + match val.storage { Some(StorageLocation::Memory(..)) => "Memory var ", Some(StorageLocation::Storage(..)) => "Storage var ", Some(StorageLocation::Calldata(..)) => "Calldata var ", None => "", }, - self.name, - self.parts + val.name, + val.parts .into_iter() .map(|part| part.to_cli_string()) .collect::>() .join(" "), - if self.unsat { + if val.unsat { " - unsatisfiable range, unreachable".fg(Color::Red) } else { "".fg(Color::Red) @@ -252,7 +248,7 @@ impl ToString for RangePart { /// Creates an Vec<[RangePart]> from a range based on the current [ReportConfig] pub fn range_parts( - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, report_config: &ReportConfig, range: &SolcRange, ) -> (Vec, bool) { @@ -264,8 +260,9 @@ pub fn range_parts( .to_range_string(false, analyzer) .s } else if report_config.simplify_bounds { + let mut exclude = vec![]; range - .simplified_range_min(analyzer) + .simplified_range_min(&mut exclude, analyzer) .unwrap() .to_range_string(false, analyzer) .s @@ -279,8 +276,9 @@ pub fn range_parts( .to_range_string(true, analyzer) .s } else if report_config.simplify_bounds { + let mut exclude = vec![]; range - .simplified_range_max(analyzer) + .simplified_range_max(&mut exclude, analyzer) .unwrap() .to_range_string(true, analyzer) .s diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index 3ff556b1..560954a8 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -1,20 +1,20 @@ -use crate::analyzers::range_parts; -use crate::analyzers::VarBoundAnalysis; -use crate::analyzers::VarBoundAnalyzer; - -use crate::analyzers::{LocStrSpan, ReportConfig, ReportDisplay}; -use ariadne::ReportKind; -use std::collections::BTreeSet; +use crate::{ + bounds::range_parts, + VarBoundAnalysis, VarBoundAnalyzer, LocStrSpan, ReportConfig, + ReportKind, ReportDisplay, +}; -use shared::analyzer::GraphLike; -use shared::{ - analyzer::{AnalyzerLike, Search}, - context::*, +use graph::{ + GraphBackend, AnalyzerBackend, + nodes::{ContextNode, KilledKind}, + range_string::ToRangeString, + solvers::{SolverAtom, Atomize} }; +use shared::Search; use ariadne::{Color, Config, Fmt, Label, Report, Span}; -use solang_parser::pt::CodeLocation; -use std::collections::BTreeMap; +use solang_parser::pt::{CodeLocation}; +use std::collections::{BTreeMap, BTreeSet}; mod report_display; pub use report_display::*; @@ -48,7 +48,7 @@ impl<'a> FunctionVarsBoundAnalysis { pub fn reports_for_forks( &self, file_mapping: &'a BTreeMap, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Vec> { let mut handled_ctx_switches = BTreeSet::default(); let reports = self @@ -58,27 +58,55 @@ impl<'a> FunctionVarsBoundAnalysis { // sort by display name instead of normal name let deps = ctx.ctx_deps(analyzer).unwrap(); let deps = deps - .values() + .iter() .map(|var| (var.display_name(analyzer).unwrap(), var)) .collect::>(); // create the bound strings - let bounds_string = deps + let mut ranges = BTreeMap::default(); + deps.iter().for_each(|(_, dep)| { + let range = dep.ref_range(analyzer).unwrap().unwrap(); + let r = range.into_flattened_range(analyzer).unwrap(); + ranges.insert(*dep, r); + }); + let atoms = ranges .iter() - .enumerate() - .filter_map(|(i, (name, cvar))| { - let range = cvar.ref_range(analyzer).unwrap()?; - let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); - let ret = parts.into_iter().fold( - format!("{}. {name}", i + 1), - |mut acc, part| { - acc = format!("{acc}{}", part.to_cli_string()); - acc - }, - ); - Some(format!("{ret}\n")) + .filter_map(|(_dep, range)| { + if let Some(atom) = range.min.atomize() { + Some(atom) + } else { + range.max.atomize() + } }) - .collect::>() - .join(""); + .collect::>(); + let mut handled_atom = vec![]; + let mut bounds_string: Vec = vec![]; + atoms.iter().enumerate().for_each(|(i, atom)| { + let atom_str = atom.to_range_string(true, analyzer).s; + if !handled_atom.contains(&atom_str) { + handled_atom.push(atom_str.clone()); + bounds_string.push(format!("{}. {}", i + 1, atom_str)) + } + }); + let bounds_string = bounds_string.into_iter().collect::>().join("\n"); + + // let bounds_string = deps + // .iter() + // .enumerate() + // .filter_map(|(i, (name, cvar))| { + // let range = cvar.ref_range(analyzer).unwrap()?; + + // let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); + // let ret = parts.into_iter().fold( + // format!("{}. {name}", i + 1), + // |mut acc, part| { + // acc = acc.to_string(); + // acc + // }, + // ); + // Some(format!("{ret}\n")) + // }) + // .collect::>() + // .join(""); let mut report = Report::build( self.report_kind(), self.ctx_loc.source(), @@ -291,18 +319,15 @@ impl<'a> FunctionVarsBoundAnalysis { } } -impl FunctionVarsBoundAnalyzer for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - fn bounds_for_all<'a>( +impl FunctionVarsBoundAnalyzer for T where T: VarBoundAnalyzer + Search + AnalyzerBackend + Sized {} +pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerBackend + Sized { + fn bounds_for_lineage<'a>( &'a self, file_mapping: &'a BTreeMap, ctx: ContextNode, + edges: Vec, report_config: ReportConfig, ) -> FunctionVarsBoundAnalysis { - let mut edges = ctx.all_edges(self).unwrap(); - if edges.is_empty() { - edges.push(ctx); - } let lineage_analyses = edges .iter() .filter_map(|fork| { @@ -314,8 +339,7 @@ pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerLike + { return None; } - if !report_config.show_nonreverts - && matches!(fork.underlying(self).unwrap().killed, None) + if !report_config.show_nonreverts && fork.underlying(self).unwrap().killed.is_none() { return None; } @@ -375,4 +399,17 @@ pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerLike + report_config, } } + + fn bounds_for_all<'a>( + &'a self, + file_mapping: &'a BTreeMap, + ctx: ContextNode, + report_config: ReportConfig, + ) -> FunctionVarsBoundAnalysis { + let mut edges = ctx.all_edges(self).unwrap(); + if edges.is_empty() { + edges.push(ctx); + } + self.bounds_for_lineage(file_mapping, ctx, edges, report_config) + } } diff --git a/crates/analyzers/src/func_analyzer/report_display.rs b/crates/analyzers/src/func_analyzer/report_display.rs index 0f54d0c1..4df1c53e 100644 --- a/crates/analyzers/src/func_analyzer/report_display.rs +++ b/crates/analyzers/src/func_analyzer/report_display.rs @@ -1,7 +1,16 @@ -use crate::analyzers::func_analyzer::*; -use crate::analyzers::{LocStrSpan, ReportDisplay}; -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use shared::analyzer::GraphLike; +use crate::{ + LocStrSpan, + ReportKind, + FunctionVarsBoundAnalysis, + ReportDisplay +}; + +use graph::{ + GraphBackend, +}; + +use ariadne::{Color, Config, Fmt, Label, Report, Span, Cache}; + use std::collections::BTreeMap; pub struct CLIFunctionVarsBoundAnalysis<'a> { @@ -25,7 +34,7 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { fn report_kind(&self) -> ReportKind { ReportKind::Custom("Bounds", Color::Cyan) } - fn msg(&self, analyzer: &impl GraphLike) -> String { + fn msg(&self, analyzer: &impl GraphBackend) -> String { format!( "Bounds for function: {}", format!( @@ -39,11 +48,11 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { ) } - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { + fn labels(&self, _analyzer: &impl GraphBackend) -> Vec> { vec![] } - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + fn reports(&self, analyzer: &impl GraphBackend) -> Vec> { let mut report = Report::build( self.report_kind(), self.func_var_bound_analysis.ctx_loc.source(), @@ -76,14 +85,14 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { reports } - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { let reports = &self.reports(analyzer); for report in reports.iter() { report.print(&mut src).unwrap(); } } - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { let reports = &self.reports(analyzer); reports.iter().for_each(|report| { report.eprint(&mut src).unwrap(); diff --git a/crates/analyzers/src/lib.rs b/crates/analyzers/src/lib.rs index 9414cbc3..ed1d00e4 100644 --- a/crates/analyzers/src/lib.rs +++ b/crates/analyzers/src/lib.rs @@ -1,10 +1,8 @@ pub mod bounds; -use crate::AnalyzerLike; -use crate::GraphLike; +use graph::{GraphBackend, AnalyzerBackend}; use ariadne::{Cache, Label, Report, ReportKind, Span}; -use bounds::*; -use shared::analyzer::Search; +use shared::Search; use solang_parser::pt::Loc; use std::collections::BTreeMap; @@ -14,11 +12,11 @@ mod var_analyzer; pub use var_analyzer::*; pub trait ContextAnalyzer: - AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer + AnalyzerBackend + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer { } impl ContextAnalyzer for T where - T: AnalyzerLike + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer + T: AnalyzerBackend + Search + VarBoundAnalyzer + FunctionVarsBoundAnalyzer { } @@ -168,9 +166,9 @@ impl Default for ReportConfig { pub trait ReportDisplay { fn report_kind(&self) -> ReportKind; - fn msg(&self, analyzer: &impl GraphLike) -> String; - fn labels(&self, analyzer: &impl GraphLike) -> Vec>; - fn reports(&self, analyzer: &impl GraphLike) -> Vec>; - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); - fn eprint_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike); + fn msg(&self, analyzer: &impl GraphBackend) -> String; + fn labels(&self, analyzer: &impl GraphBackend) -> Vec>; + fn reports(&self, analyzer: &impl GraphBackend) -> Vec>; + fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphBackend); + fn eprint_reports(&self, src: &mut impl Cache, analyzer: &impl GraphBackend); } diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 0f0fb23f..5141ce5a 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -1,13 +1,14 @@ -use crate::analyzers::range_parts; -use crate::analyzers::AnalysisItem; -use crate::analyzers::RangePart; -use crate::analyzers::{LocStrSpan, ReportConfig}; -use shared::analyzer::GraphLike; -use shared::{ - analyzer::{AnalyzerLike, Search}, - context::*, - range::{Range, SolcRange}, +use crate::{ + bounds::{range_parts, AnalysisItem, RangePart}, + LocStrSpan, ReportConfig }; + +use graph::{ + GraphBackend, AnalyzerBackend, Range, SolcRange, + nodes::{ContextVarNode, ContextNode, KilledKind}, +}; +use shared::Search; + use std::collections::BTreeSet; use solang_parser::pt::{CodeLocation, StorageLocation}; @@ -66,10 +67,10 @@ impl Default for VarBoundAnalysis { } impl VarBoundAnalysis { - pub fn conditionals(&self, analyzer: &impl GraphLike) -> Vec<(String, Vec)> { + pub fn conditionals(&self, analyzer: &impl GraphBackend) -> Vec<(String, Vec)> { let deps = self.ctx.ctx_deps(analyzer).unwrap(); let deps = deps - .values() + .iter() .map(|var| (var.display_name(analyzer).unwrap(), var)) .collect::>(); // create the bound strings @@ -84,7 +85,7 @@ impl VarBoundAnalysis { } /// Creates an [AnalysisItem] if there is a initial bound for a variable - pub fn init_item(&self, analyzer: &impl GraphLike) -> Option { + pub fn init_item(&self, analyzer: &impl GraphBackend) -> Option { let mut parts = vec![]; let mut unsat = false; if let Some(init_range) = &self.var_def.1 { @@ -108,8 +109,8 @@ impl VarBoundAnalysis { } } -impl VarBoundAnalyzer for T where T: Search + AnalyzerLike + Sized {} -pub trait VarBoundAnalyzer: Search + AnalyzerLike + Sized { +impl VarBoundAnalyzer for T where T: Search + AnalyzerBackend + Sized {} +pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { /// Given a lineage of a context (first element being the youngest, last element being the oldest), /// generate a bound analysis for a variable throughout the lineage fn bounds_for_var_in_family_tree( diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index 66210180..cf826e57 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -1,21 +1,29 @@ -use crate::analyzers::{LocStrSpan, ReportDisplay}; -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use shared::analyzer::GraphLike; +use crate::{ + LocStrSpan, + ReportKind, + ReportDisplay, + VarBoundAnalysis, + bounds::{range_parts, AnalysisItem} +}; -use crate::analyzers::var_analyzer::*; +use graph::{ + GraphBackend, +}; + +use ariadne::{Color, Config, Fmt, Label, Report, Span, Cache}; impl ReportDisplay for VarBoundAnalysis { fn report_kind(&self) -> ReportKind { ReportKind::Custom("Bounds", Color::Cyan) } - fn msg(&self, analyzer: &impl GraphLike) -> String { + fn msg(&self, analyzer: &impl GraphBackend) -> String { format!( "Bounds for {} in {}:", self.var_display_name, self.ctx.underlying(analyzer).unwrap().path ) } - fn labels(&self, analyzer: &impl GraphLike) -> Vec> { + fn labels(&self, analyzer: &impl GraphBackend) -> Vec> { let mut labels = if self.report_config.show_initial_bounds { if let Some(init_item) = self.init_item(analyzer) { vec![init_item.into()] @@ -52,7 +60,7 @@ impl ReportDisplay for VarBoundAnalysis { labels } - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { + fn reports(&self, analyzer: &impl GraphBackend) -> Vec> { let mut report = Report::build( self.report_kind(), self.var_def.0.source(), @@ -90,14 +98,14 @@ impl ReportDisplay for VarBoundAnalysis { reports } - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { let reports = self.reports(analyzer); reports.into_iter().for_each(|report| { report.print(&mut src).unwrap(); }); } - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { + fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { let reports = self.reports(analyzer); reports.into_iter().for_each(|report| { report.eprint(&mut src).unwrap(); diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml index 57913b6d..6bc26f70 100644 --- a/crates/graph/Cargo.toml +++ b/crates/graph/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true [dependencies] shared.workspace = true -range.workspace = true solang-parser.workspace = true petgraph.workspace = true @@ -21,4 +20,5 @@ hex.workspace = true tracing.workspace = true tracing-subscriber.workspace = true +itertools = "0.10.5" lazy_static = "1.4.0" \ No newline at end of file diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 46a3d4cd..68a5af24 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -1,17 +1,23 @@ -use crate::graph::GraphLike; -use crate::context::ContextVarNode; -use std::collections::HashMap; +use crate::{VarType, nodes::*}; + +use shared::{ NodeIdx, AnalyzerLike, GraphLike, Heirarchical}; -use crate::analyzer::AsDotStr; -use crate::context::ContextNode; -use crate::{ - context::{Context, ContextEdge, ContextVar}, - nodes::*, -}; use lazy_static::lazy_static; -use petgraph::graph::*; use solang_parser::pt::Identifier; +use std::collections::HashMap; + +pub trait GraphBackend: GraphLike< + Edge = Edge, + Node = Node, + +> {} +pub trait AnalyzerBackend: AnalyzerLike + GraphBackend {} + +pub trait AsDotStr { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String; +} + #[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] pub enum GraphError { /// The analyzer thought the node was suppose to be one type, but it was a different one @@ -86,7 +92,7 @@ pub enum Node { Block(Block), } -pub fn as_dot_str(idx: NodeIdx, analyzer: &impl GraphLike) -> String { +pub fn as_dot_str(idx: NodeIdx, analyzer: &impl GraphBackend) -> String { use crate::Node::*; match analyzer.node(idx) { Context(_) => ContextNode::from(idx).as_dot_str(analyzer), @@ -252,8 +258,8 @@ pub enum Edge { BuiltinFunction, } -impl Edge { - pub fn heirarchical_num(&self) -> usize { +impl Heirarchical for Edge { + fn heirarchical_num(&self) -> usize { use crate::Edge::*; match self { Source => 0, diff --git a/crates/graph/src/lib.rs b/crates/graph/src/lib.rs index 52b4a584..08006b17 100644 --- a/crates/graph/src/lib.rs +++ b/crates/graph/src/lib.rs @@ -1,7 +1,6 @@ mod graph_elements; -mod search; -mod range_impl; mod var_type; +mod range; pub mod nodes; pub mod solvers; @@ -9,5 +8,4 @@ pub mod solvers; pub use var_type::*; pub use graph_elements::*; -pub use range_impl::*; -pub use search::*; +pub use range::*; diff --git a/crates/graph/src/nodes/block.rs b/crates/graph/src/nodes/block.rs index e5cd8201..0e09c2f9 100644 --- a/crates/graph/src/nodes/block.rs +++ b/crates/graph/src/nodes/block.rs @@ -1,12 +1,7 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; +use crate::{GraphBackend, AsDotStr, Node, GraphError}; +use shared::NodeIdx; -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::H256; -use ethers_core::types::U256; +use ethers_core::types::{Address, H256, U256}; /// An index in the graph that references a Block node #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -14,7 +9,7 @@ pub struct BlockNode(pub usize); impl BlockNode { /// Gets the underlying node data for the block environment - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Block, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Block, GraphError> { match analyzer.node(*self) { Node::Block(st) => Ok(st), e => Err(GraphError::NodeConfusion(format!( @@ -25,7 +20,7 @@ impl BlockNode { } impl AsDotStr for BlockNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { format!("block {{ {:?} }}", self.underlying(analyzer).unwrap()) } } diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 722d5e61..876fc282 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -1,10 +1,18 @@ +use crate::{AnalyzerBackend, GraphBackend, SolcRange, VarType, Node, GraphError, nodes::Concrete}; + +use shared::NodeIdx; +use crate::range::elem::*; + +use solang_parser::pt::{Type, Expression, Loc}; +use ethers_core::types::{Address, H256, U256, I256}; + /// A builtin node #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct BuiltInNode(pub usize); impl BuiltInNode { /// Gets the underlying builtin from the graph - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Builtin, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Builtin, GraphError> { match analyzer.node(*self) { Node::Builtin(b) => Ok(b), e => Err(GraphError::NodeConfusion(format!( @@ -14,7 +22,7 @@ impl BuiltInNode { } /// Gets the size of the builtin - pub fn num_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn num_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; Ok(underlying.num_size()) } @@ -23,7 +31,7 @@ impl BuiltInNode { pub fn implicitly_castable_to( &self, other: &Self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { Ok(self .underlying(analyzer)? @@ -33,7 +41,7 @@ impl BuiltInNode { /// Gets the maximum size version of this builtin, i.e. uint16 -> uint256 pub fn max_size( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let m = self.underlying(analyzer)?.max_size(); Ok(analyzer.builtin_or_add(m).into()) @@ -42,7 +50,7 @@ impl BuiltInNode { /// Gets the underlying type of the dynamic builtin backing it. i.e. uint256[] -> uint256 pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match self.underlying(analyzer)? { Builtin::Array(v_ty) | Builtin::SizedArray(_, v_ty) => { @@ -64,12 +72,12 @@ impl BuiltInNode { } /// Returns whether the builtin is a mapping - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { Ok(matches!(self.underlying(analyzer)?, Builtin::Mapping(_, _))) } /// Returns whether the builtin is a sized array - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_sized_array(&self, analyzer: &impl GraphBackend) -> Result { Ok(matches!( self.underlying(analyzer)?, Builtin::SizedArray(_, _) @@ -77,7 +85,7 @@ impl BuiltInNode { } /// Returns whether the builtin is a sized array or bytes - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { match self.underlying(analyzer)? { Builtin::SizedArray(s, _) => Ok(Some(*s)), Builtin::Bytes(s) => Ok(Some(U256::from(*s))), @@ -86,17 +94,17 @@ impl BuiltInNode { } /// Returns whether the builtin is a dynamic type - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_dyn(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_dyn()) } /// Returns whether the builtin is indexable - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_indexable(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_indexable()) } /// Returns the zero range for this builtin type, i.e. uint256 -> [0, 0] - pub fn zero_range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn zero_range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(self.underlying(analyzer)?.zero_range()) } } @@ -151,7 +159,7 @@ impl Builtin { /// `mapping (uint => MyType)`, we may not have parsed `MyType`, so we now try to resolve it pub fn unresolved_as_resolved( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match self { Builtin::Array(n) => Ok(Builtin::Array(n.unresolved_as_resolved(analyzer)?)), @@ -236,7 +244,7 @@ impl Builtin { /// Try to convert from a [`Type`] to a Builtin pub fn try_from_ty( ty: Type, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { use Type::*; match ty { @@ -374,7 +382,7 @@ impl Builtin { } /// Converts the builtin to a string - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_string(&self, analyzer: &impl GraphBackend) -> Result { use Builtin::*; match self { Address => Ok("address".to_string()), diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 2c55c41b..fb38973f 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -1,8 +1,6 @@ -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::Builtin; -use crate::VarType; -use crate::{Node, NodeIdx}; +use crate::{AnalyzerBackend, GraphBackend, Node, GraphError, nodes::Builtin, VarType}; +use shared::NodeIdx; + use ethers_core::types::{Address, H256, I256, U256}; /// An index in the graph that references a [`Concrete`] node @@ -11,7 +9,7 @@ pub struct ConcreteNode(pub usize); impl ConcreteNode { /// Gets the underlying node data for the [`Concrete`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Concrete, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Concrete, GraphError> { match analyzer.node(*self) { Node::Concrete(c) => Ok(c), e => Err(GraphError::NodeConfusion(format!( @@ -23,7 +21,7 @@ impl ConcreteNode { /// Creates a version of this concrete that is max size pub fn max_size( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let c = self.underlying(analyzer)?.max_size(); Ok(analyzer.add_node(Node::Concrete(c)).into()) @@ -32,7 +30,7 @@ impl ConcreteNode { /// Gets the internal type of the dynamic that backs this. Panics if this is not a dynamic concrete pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let builtin = self.underlying(analyzer)?.dynamic_underlying_ty().unwrap(); let bn = analyzer.builtin_or_add(builtin); @@ -41,22 +39,22 @@ impl ConcreteNode { } /// Returns whether this is a dynamic concrete - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_dyn(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_dyn()) } /// Returns whether this is a concrete sized array - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_sized_array(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_sized_array()) } /// Returns the size of the array size if it is an array-like concrete - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(self.underlying(analyzer)?.maybe_array_size()) } /// Returns whether this concrete is indexable - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_indexable(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_indexable()) } } diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index 7aaeade5..9e1cf80a 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -1,5 +1,5 @@ -use crate::{GraphError, Node, VarType, nodes::context::ContextVarNode,}; -use shared::{NodeIdx, GraphLike, AsDotStr}; +use crate::{GraphBackend, AsDotStr, GraphError, Node, VarType, nodes::context::ContextVarNode,}; +use shared::NodeIdx; /// The reason a context was killed @@ -45,7 +45,7 @@ pub enum ExprRet { impl ExprRet { /// Converts the expression return into a debug string - pub fn debug_str(&self, analyzer: &impl GraphLike) -> String { + pub fn debug_str(&self, analyzer: &impl GraphBackend) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => match analyzer.node(*inner) { Node::ContextVar(_) => ContextVarNode::from(*inner).display_name(analyzer).unwrap(), @@ -199,7 +199,7 @@ impl ExprRet { } /// Try to convert to a solidity-like function input string, i.e. `(uint256, uint256, bytes32)` - pub fn try_as_func_input_str(&self, analyzer: &impl GraphLike) -> String { + pub fn try_as_func_input_str(&self, analyzer: &impl GraphBackend) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { let idx = inner; @@ -214,7 +214,7 @@ impl ExprRet { None => "".to_string(), } } - ExprRet::Multi(inner) if !self.has_fork() => { + ExprRet::Multi(inner) => { let mut strs = vec![]; for ret in inner.iter() { strs.push(ret.try_as_func_input_str(analyzer).replace(['(', ')'], "")); diff --git a/crates/graph/src/nodes/context/mod.rs b/crates/graph/src/nodes/context/mod.rs index 9f2e07cf..cebf990c 100644 --- a/crates/graph/src/nodes/context/mod.rs +++ b/crates/graph/src/nodes/context/mod.rs @@ -6,7 +6,7 @@ mod var; pub use node::ContextNode; pub use underlying::Context; -pub use var::ContextVarNode; +pub use var::{ContextVarNode, TmpConstruction, ContextVar}; pub use expr_ret::{KilledKind, ExprRet}; pub use context_tys::{ ModifierState, ContextCache, CallFork }; diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 34c3f460..a23e2fd7 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,9 +1,10 @@ use crate::{ + AsDotStr, AnalyzerBackend, nodes::{ FunctionParamNode, ContextVarNode, Context, FunctionNode, KilledKind }, - GraphError, Node + GraphError, Node, GraphBackend }; -use shared::{AsDotStr, NodeIdx, AnalyzerLike, GraphLike}; +use shared::NodeIdx; use solang_parser::pt::Loc; use std::collections::BTreeMap; @@ -13,7 +14,7 @@ use std::collections::BTreeMap; pub struct ContextNode(pub usize); impl AsDotStr for ContextNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { format!("Context {{ {} }}", self.path(analyzer)) } } @@ -23,7 +24,7 @@ impl ContextNode { &self, _func: FunctionNode, _mapping: &BTreeMap, - _analyzer: &mut (impl GraphLike + AnalyzerLike), + _analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) { todo!("Joining not supported yet"); } @@ -31,26 +32,26 @@ impl ContextNode { /// Gets the total context width pub fn total_width( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { self.first_ancestor(analyzer)? .number_of_live_edges(analyzer) } /// Gets the total context depth - pub fn depth(&self, analyzer: &impl GraphLike) -> usize { + pub fn depth(&self, analyzer: &impl GraphBackend) -> usize { self.underlying(analyzer).unwrap().depth } /// The path of the underlying context - pub fn path(&self, analyzer: &impl GraphLike) -> String { + pub fn path(&self, analyzer: &impl GraphBackend) -> String { self.underlying(analyzer).unwrap().path.clone() } /// Gets a mutable reference to the underlying context in the graph pub fn underlying_mut<'a>( &self, - analyzer: &'a mut (impl GraphLike + AnalyzerLike), + analyzer: &'a mut (impl GraphBackend + AnalyzerBackend), ) -> Result<&'a mut Context, GraphError> { match analyzer.node_mut(*self) { Node::Context(c) => Ok(c), @@ -61,7 +62,7 @@ impl ContextNode { } /// Gets an immutable reference to the underlying context in the graph - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Context, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Context, GraphError> { match analyzer.node(*self) { Node::Context(c) => Ok(c), e => Err(GraphError::NodeConfusion(format!( @@ -73,7 +74,7 @@ impl ContextNode { /// Returns an option to where the context was killed pub fn killed_loc( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(self.underlying(analyzer)?.killed) } @@ -83,7 +84,7 @@ impl ContextNode { &self, ret_stmt_loc: Loc, ret: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { self.underlying_mut(analyzer)? .ret @@ -96,7 +97,7 @@ impl ContextNode { pub fn add_empty_return( &self, ret_stmt_loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { self.underlying_mut(analyzer)? .ret @@ -108,7 +109,7 @@ impl ContextNode { /// Propogate that this context has ended up the context graph pub fn propogate_end( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let underlying = &mut self.underlying_mut(analyzer)?; let curr_live = underlying.number_of_live_edges; @@ -124,7 +125,7 @@ impl ContextNode { /// Gets the return nodes for this context pub fn return_nodes( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let rets = &self.underlying(analyzer)?.ret.clone(); let all_good = rets.iter().all(|(_, node)| node.is_some()); diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 56160620..1bedb637 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -1,11 +1,16 @@ -use crate::GraphError; -use shared::{AnalyzerLike, GraphLike}; +use crate::{ + AnalyzerBackend, GraphBackend, GraphError, Edge, ContextEdge, + nodes::{ContextNode, StructNode, ContractNode, FunctionNode}, +}; + +use shared::{NodeIdx, Search}; +use std::collections::{BTreeSet, BTreeMap}; impl ContextNode { /// Gets the associated contract for the function for the context pub fn associated_contract( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { Ok(self .associated_fn(analyzer)? @@ -16,7 +21,7 @@ impl ContextNode { /// Tries to get the associated function for the context pub fn maybe_associated_contract( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { Ok(self .associated_fn(analyzer)? @@ -26,7 +31,7 @@ impl ContextNode { /// Tries to get the associated source for the context pub fn maybe_associated_source( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { let context = self.underlying(analyzer).unwrap(); if let Some(src) = context.cache.associated_source { @@ -47,7 +52,7 @@ impl ContextNode { /// Tries to get the associated source unit part for the context pub fn associated_source_unit_part( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { if let Some(sup) = self .associated_fn(analyzer)? @@ -64,7 +69,7 @@ impl ContextNode { /// Gets visible functions pub fn visible_modifiers( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { // TODO: filter privates let Some(source) = self.maybe_associated_source(analyzer) else { @@ -136,7 +141,7 @@ impl ContextNode { /// Gets visible functions pub fn visible_funcs( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { // TODO: filter privates if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { @@ -182,7 +187,7 @@ impl ContextNode { /// Gets all visible functions pub fn source_funcs( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Vec { // TODO: filter privates let Some(source) = self.maybe_associated_source(analyzer) else { @@ -205,7 +210,7 @@ impl ContextNode { /// Gets all visible structs pub fn visible_structs( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Vec { // TODO: filter privates let Some(source) = self.maybe_associated_source(analyzer) else { @@ -220,7 +225,7 @@ impl ContextNode { } /// Gets the associated function for the context - pub fn associated_fn(&self, analyzer: &impl GraphLike) -> Result { + pub fn associated_fn(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; if let Some(fn_call) = underlying.fn_call { Ok(fn_call) @@ -232,7 +237,7 @@ impl ContextNode { } /// Gets the associated function name for the context - pub fn associated_fn_name(&self, analyzer: &impl GraphLike) -> Result { + pub fn associated_fn_name(&self, analyzer: &impl GraphBackend) -> Result { self.associated_fn(analyzer)?.name(analyzer) } } \ No newline at end of file diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index a9b7119a..7cd18697 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,9 +1,20 @@ -use crate::GraphError; -use shared::{AnalyzerLike, GraphLike}; +use crate::{ + solvers::{SolverAtom, Atomize, dl::{SolveStatus, DLSolver}}, + range::{elem::RangeOp, RangeEval}, + nodes::{ContextVarNode, ContextNode}, + Node, GraphError, GraphBackend, AnalyzerBackend, AsDotStr, + as_dot_str +}; + +use shared::NodeIdx; + +use petgraph::dot::Dot; + +use std::collections::BTreeMap; impl ContextNode { /// Use a Difference Logic solver to see if it is unreachable - pub fn unreachable(&self, analyzer: &impl GraphLike) -> Result { + pub fn unreachable(&self, analyzer: &impl GraphBackend) -> Result { let mut solver = self.dl_solver(analyzer)?.clone(); match solver.solve_partial(analyzer)? { SolveStatus::Unsat => Ok(true), @@ -12,7 +23,7 @@ impl ContextNode { } /// Get the dependencies as normalized solver atoms - pub fn dep_atoms(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn dep_atoms(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { let deps: Vec<_> = self.ctx_deps(analyzer)?; let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { @@ -44,12 +55,12 @@ impl ContextNode { } /// Get the difference logic solver associated with this context - pub fn dl_solver<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a DLSolver, GraphError> { + pub fn dl_solver<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a DLSolver, GraphError> { Ok(&self.underlying(analyzer)?.dl_solver) } /// Returns a map of variable dependencies for this context - pub fn ctx_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn ctx_deps(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(self.underlying(analyzer)?.ctx_deps.clone()) } @@ -57,7 +68,7 @@ impl ContextNode { pub fn add_ctx_dep( &self, dep: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); if dep.is_controllable(analyzer)? { @@ -79,7 +90,7 @@ impl ContextNode { } /// Creates a DAG of the context dependencies and opens it with graphviz - pub fn deps_dag(&self, g: &impl GraphLike) -> Result<(), GraphError> { + pub fn deps_dag(&self, g: &impl GraphBackend) -> Result<(), GraphError> { let deps = self.ctx_deps(g)?; // #[derive(Debug, Copy, Clone)] // pub enum DepEdge { diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index b5fb1ec8..ad3d3d2c 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -1,35 +1,34 @@ use crate::{ - GraphError, + GraphError, GraphBackend, AnalyzerBackend, nodes::{ContextNode, FunctionNode} }; -use shared::{AnalyzerLike, GraphLike}; impl ContextNode { /// Returns whether this context is killed or returned - pub fn killed_or_ret(&self, analyzer: &impl GraphLike) -> Result { + pub fn killed_or_ret(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; Ok(underlying.killed.is_some() || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) } /// Returns whether the context is killed - pub fn is_returned(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_returned(&self, analyzer: &impl GraphBackend) -> Result { Ok(!self.underlying(analyzer)?.ret.is_empty()) } /// Returns whether the context is killed - pub fn is_killed(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_killed(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.killed.is_some()) } /// Returns whether the context is killed - pub fn is_ended(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_ended(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) } /// Check if this context is in an external function call - pub fn is_ext_fn(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_ext_fn(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) } @@ -37,7 +36,7 @@ impl ContextNode { pub fn is_fn_ext( &self, fn_node: FunctionNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match fn_node.maybe_associated_contract(analyzer) { None => Ok(false), @@ -60,14 +59,14 @@ impl ContextNode { } /// Returns whether this context *currently* uses unchecked math - pub fn unchecked(&self, analyzer: &impl GraphLike) -> Result { + pub fn unchecked(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.unchecked) } /// Sets the context to use unchecked math pub fn set_unchecked( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.unchecked = true; Ok(()) @@ -76,7 +75,7 @@ impl ContextNode { /// Sets the context to use checked math pub fn unset_unchecked( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.unchecked = false; Ok(()) diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 0180ceb9..aa3344d0 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -1,12 +1,12 @@ use crate::{ - GraphError, + GraphError, AnalyzerBackend, solvers::dl::DLSolver, nodes::{ ExprRet, KilledKind, ContextCache, - FunctionNode, ContextVarNode, ContextNode + FunctionNode, ContextVarNode, ContextNode, CallFork, + ModifierState, } }; -use shared::AnalyzerLike; use solang_parser::pt::Loc; @@ -97,7 +97,7 @@ impl Context { fork_expr: Option<&str>, fn_call: Option, fn_ext: bool, - analyzer: &mut impl AnalyzerLike, + analyzer: &mut impl AnalyzerBackend, modifier_state: Option, ) -> Result { let mut depth = diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 8ce0b48a..ef691f92 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -1,8 +1,22 @@ +use crate::{ + GraphBackend, AsDotStr, + GraphError, Node, ContextEdge, Edge, + nodes::{VarNode, ContextNode, ContextVar, TmpConstruction}, + range::{Range, range_string::ToRangeString, elem::RangeElem}, +}; + +use shared::{NodeIdx, Search}; + +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::pt::{StorageLocation, Loc}; + +use std::collections::BTreeMap; + #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct ContextVarNode(pub usize); impl AsDotStr for ContextVarNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); let range_str = if let Some(r) = underlying.ty.ref_range(analyzer).unwrap() { @@ -46,7 +60,7 @@ impl From for ContextVarNode { impl ContextVarNode { pub fn underlying<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> Result<&'a ContextVar, GraphError> { match analyzer.node(*self) { Node::ContextVar(c) => Ok(c), @@ -58,7 +72,7 @@ impl ContextVarNode { pub fn underlying_mut<'a>( &self, - analyzer: &'a mut impl GraphLike, + analyzer: &'a mut impl GraphBackend, ) -> Result<&'a mut ContextVar, GraphError> { match analyzer.node_mut(*self) { Node::ContextVar(c) => Ok(c), @@ -70,20 +84,20 @@ impl ContextVarNode { pub fn storage<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> Result<&'a Option, GraphError> { Ok(&self.underlying(analyzer)?.storage) } - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .loc .expect("No loc for ContextVar")) } - pub fn ctx(&self, analyzer: &impl GraphLike) -> ContextNode { + pub fn ctx(&self, analyzer: &impl GraphBackend) -> ContextNode { ContextNode::from( analyzer .search_for_ancestor(self.0.into(), &Edge::Context(ContextEdge::Variable)) @@ -94,7 +108,7 @@ impl ContextVarNode { ) } - pub fn maybe_ctx(&self, analyzer: &impl GraphLike) -> Option { + pub fn maybe_ctx(&self, analyzer: &impl GraphBackend) -> Option { let first = self.first_version(analyzer); analyzer .graph() @@ -105,7 +119,7 @@ impl ContextVarNode { .next() } - pub fn maybe_storage_var(&self, analyzer: &impl GraphLike) -> Option { + pub fn maybe_storage_var(&self, analyzer: &impl GraphBackend) -> Option { Some( analyzer .graph() @@ -118,11 +132,11 @@ impl ContextVarNode { ) } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.name.clone()) } - pub fn as_controllable_name(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_controllable_name(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ref_range) = self.ref_range(analyzer)? { let mut exclude = vec![]; let min_name = ref_range @@ -146,11 +160,11 @@ impl ContextVarNode { } } - pub fn display_name(&self, analyzer: &impl GraphLike) -> Result { + pub fn display_name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.display_name.clone()) } - pub fn return_assignments(&self, analyzer: &impl GraphLike) -> Vec { + pub fn return_assignments(&self, analyzer: &impl GraphBackend) -> Vec { let latest = self.latest_version(analyzer); let mut earlier = latest; let mut return_assignments = vec![]; @@ -163,7 +177,7 @@ impl ContextVarNode { return_assignments } - pub fn ext_return_assignments(&self, analyzer: &impl GraphLike) -> Vec { + pub fn ext_return_assignments(&self, analyzer: &impl GraphBackend) -> Vec { let latest = self.latest_version(analyzer); let mut earlier = latest; let mut return_assignments = vec![]; @@ -179,13 +193,13 @@ impl ContextVarNode { return_assignments } - pub fn tmp_of(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn tmp_of(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(self.underlying(analyzer)?.tmp_of()) } pub fn len_var_to_array( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { if self.name(analyzer)?.ends_with(".length") { if let Some(arr) = analyzer.search_for_ancestor( @@ -201,7 +215,7 @@ impl ContextVarNode { } } - pub fn index_to_array(&self, analyzer: &impl GraphLike) -> Option { + pub fn index_to_array(&self, analyzer: &impl GraphBackend) -> Option { let arr = analyzer .graph() .edges_directed(self.first_version(analyzer).into(), Direction::Outgoing) @@ -212,7 +226,7 @@ impl ContextVarNode { Some(ContextVarNode::from(arr).latest_version(analyzer)) } - pub fn index_access_to_index(&self, analyzer: &impl GraphLike) -> Option { + pub fn index_access_to_index(&self, analyzer: &impl GraphBackend) -> Option { let index = analyzer.find_child_exclude_via( self.first_version(analyzer).into(), &Edge::Context(ContextEdge::Index), @@ -222,7 +236,7 @@ impl ContextVarNode { Some(ContextVarNode::from(index)) } - pub fn index_or_attr_access(&self, analyzer: &impl GraphLike) -> Vec { + pub fn index_or_attr_access(&self, analyzer: &impl GraphBackend) -> Vec { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -237,7 +251,7 @@ impl ContextVarNode { pub fn dependent_on( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, return_self: bool, ) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; @@ -256,7 +270,7 @@ impl ContextVarNode { pub fn graph_dependent_on( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; let mut tree = BTreeMap::default(); diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 5a565d85..0569cad2 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,16 +1,19 @@ use crate::{ - GraphError, SolcRange, - nodes::{ContextVarNode, ContextNode}, + AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, + nodes::{ContextVarNode, ContextNode, Concrete}, + range::{range_string::ToRangeString, Range}, }; -use shared::{AnalyzerLike, GraphLike}; +use crate::range::elem::*; + +use solang_parser::pt::Loc; impl ContextVarNode { #[tracing::instrument(level = "trace", skip_all)] pub fn update_deps( &mut self, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { if let Some(mut range) = self.range(analyzer)? { range.update_deps(*self, ctx, analyzer); @@ -20,11 +23,11 @@ impl ContextVarNode { Ok(()) } - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { self.underlying(analyzer)?.ty.range(analyzer) } - pub fn range_string(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn range_string(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { Ok(Some(format!( "[ {}, {} ]", @@ -44,14 +47,14 @@ impl ContextVarNode { pub fn ref_range<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> Result>, GraphError> { self.underlying(analyzer)?.ty.ref_range(analyzer) } pub fn range_min( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { Ok(Some(r.range_min().into_owned())) @@ -62,7 +65,7 @@ impl ContextVarNode { pub fn range_max( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { Ok(Some(r.range_max().into_owned())) @@ -73,7 +76,7 @@ impl ContextVarNode { pub fn evaled_range_min( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { Ok(Some(r.evaled_range_min(analyzer)?)) @@ -84,7 +87,7 @@ impl ContextVarNode { pub fn evaled_range_max( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { Ok(Some(r.evaled_range_max(analyzer)?)) @@ -95,7 +98,7 @@ impl ContextVarNode { pub fn as_range_elem( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, loc: Loc, ) -> Result, GraphError> { match self.underlying(analyzer)?.ty { @@ -107,7 +110,7 @@ impl ContextVarNode { } } - pub fn cache_range(&self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { + pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if let Some(mut range) = self.range(analyzer)? { range.cache_eval(analyzer)?; self.set_range(analyzer, range)?; @@ -117,7 +120,7 @@ impl ContextVarNode { pub fn set_range( &self, - analyzer: &mut impl GraphLike, + analyzer: &mut impl GraphBackend, new_range: SolcRange, ) -> Result<(), GraphError> { let underlying = self.underlying_mut(analyzer)?; @@ -127,19 +130,19 @@ impl ContextVarNode { pub fn fallback_range( &self, - analyzer: &mut impl GraphLike, + analyzer: &mut impl GraphBackend, ) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; underlying.fallback_range(analyzer) } - pub fn needs_fallback(&self, analyzer: &impl GraphLike) -> Result { + pub fn needs_fallback(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.needs_fallback()) } // #[tracing::instrument(level = "trace", skip_all)] pub fn set_range_min( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_min: Elem, ) -> Result<(), GraphError> { if new_min.contains_node((*self).into()) { @@ -179,7 +182,7 @@ impl ContextVarNode { // #[tracing::instrument(level = "trace", skip_all)] pub fn set_range_max( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_max: Elem, ) -> Result<(), GraphError> { if new_max.contains_node((*self).into()) { @@ -218,7 +221,7 @@ impl ContextVarNode { pub fn set_range_exclusions( &self, - analyzer: &mut impl GraphLike, + analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result<(), GraphError> { let fallback = if self.needs_fallback(analyzer)? { @@ -233,7 +236,7 @@ impl ContextVarNode { pub fn try_set_range_min( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_min: Elem, ) -> Result { if new_min.contains_node((*self).into()) { @@ -261,7 +264,7 @@ impl ContextVarNode { pub fn try_set_range_max( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_max: Elem, ) -> Result { if new_max.contains_node((*self).into()) { @@ -289,7 +292,7 @@ impl ContextVarNode { pub fn try_set_range_exclusions( &self, - analyzer: &mut impl GraphLike, + analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result { let fallback = if self.needs_fallback(analyzer)? { @@ -302,7 +305,7 @@ impl ContextVarNode { .try_set_range_exclusions(new_exclusions, fallback)) } - pub fn range_deps(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn range_deps(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { Ok(range.dependent_on()) } else { @@ -310,7 +313,7 @@ impl ContextVarNode { } } - pub fn sol_delete_range(&mut self, analyzer: &mut impl GraphLike) -> Result<(), GraphError> { + pub fn sol_delete_range(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { let ty = self.ty(analyzer)?; if let Some(delete_range) = ty.delete_range_result(analyzer)? { self.set_range(analyzer, delete_range)?; diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 0db11a1b..8aee4e98 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,28 +1,38 @@ +use crate::{ + AnalyzerBackend, GraphBackend, GraphError, VarType, Node, Edge, ContextEdge, + nodes::{ContextVarNode, ContextNode, Concrete, Builtin}, +}; + +use shared::Search; + +use petgraph::Direction; +use solang_parser::pt::{StorageLocation, Loc}; + impl ContextVarNode { - pub fn ty<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a VarType, GraphError> { + pub fn ty<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a VarType, GraphError> { Ok(&self.underlying(analyzer)?.ty) } - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_mapping(analyzer) } - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_dyn(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_dyn(analyzer) } - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_indexable(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_indexable(analyzer) } - pub fn is_storage(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_storage(&self, analyzer: &impl GraphBackend) -> Result { Ok(matches!( self.underlying(analyzer)?.storage, Some(StorageLocation::Storage(..)) )) } - pub fn is_return_assignment(&self, analyzer: &impl GraphLike) -> bool { + pub fn is_return_assignment(&self, analyzer: &impl GraphBackend) -> bool { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -32,7 +42,7 @@ impl ContextVarNode { }) } - pub fn is_ext_return_assignment(&self, analyzer: &impl GraphLike) -> bool { + pub fn is_ext_return_assignment(&self, analyzer: &impl GraphBackend) -> bool { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -41,7 +51,7 @@ impl ContextVarNode { pub fn is_storage_or_calldata_input( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let global_first = self.global_first_version(analyzer); Ok(global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer)) @@ -49,7 +59,7 @@ impl ContextVarNode { pub fn is_independent_and_storage_or_calldata( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let global_first = self.global_first_version(analyzer); let is_independent = self.is_independent(analyzer)?; @@ -69,11 +79,11 @@ impl ContextVarNode { && is_independent) } - pub fn is_independent(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_independent(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.dependent_on(analyzer, false)?.is_empty() && self.tmp_of(analyzer)?.is_none()) } - pub fn is_controllable(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result { if self.is_storage_or_calldata_input(analyzer)? { Ok(true) } else if let Some(tmp) = self.tmp_of(analyzer)? { @@ -89,7 +99,7 @@ impl ContextVarNode { } } - pub fn is_calldata_input(&self, analyzer: &impl GraphLike) -> bool { + pub fn is_calldata_input(&self, analyzer: &impl GraphBackend) -> bool { let global_first = self.global_first_version(analyzer); analyzer .graph() @@ -97,7 +107,7 @@ impl ContextVarNode { .any(|edge| Edge::Context(ContextEdge::CalldataVariable) == *edge.weight()) } - pub fn is_func_input(&self, analyzer: &impl GraphLike) -> bool { + pub fn is_func_input(&self, analyzer: &impl GraphBackend) -> bool { let first = self.first_version(analyzer); analyzer .graph() @@ -108,21 +118,21 @@ impl ContextVarNode { }) } - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; underlying.ty.is_const(analyzer) } - pub fn is_symbolic(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_symbolic(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.is_symbolic) } - pub fn is_tmp(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_tmp(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; Ok(underlying.is_tmp()) } - pub fn is_return_node(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_return_node(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ctx) = self.maybe_ctx(analyzer) { return Ok(ctx.underlying(analyzer)?.ret.iter().any(|(_, node)| { if let Some(node) = node { @@ -135,7 +145,7 @@ impl ContextVarNode { Ok(false) } - pub fn is_return_node_in_any(&self, ctxs: &[ContextNode], analyzer: &impl GraphLike) -> bool { + pub fn is_return_node_in_any(&self, ctxs: &[ContextNode], analyzer: &impl GraphBackend) -> bool { ctxs.iter().any(|ctx| { ctx.underlying(analyzer) .unwrap() @@ -151,7 +161,7 @@ impl ContextVarNode { }) } - pub fn is_len_var(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_len_var(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.name(analyzer)?.ends_with(".length") && analyzer .search_for_ancestor( @@ -161,7 +171,7 @@ impl ContextVarNode { .is_some()) } - pub fn is_array_index_access(&self, analyzer: &impl GraphLike) -> bool { + pub fn is_array_index_access(&self, analyzer: &impl GraphBackend) -> bool { analyzer .search_for_ancestor( self.first_version(analyzer).into(), @@ -170,11 +180,11 @@ impl ContextVarNode { .is_some() } - pub fn is_concrete(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_concrete(&self, analyzer: &impl GraphBackend) -> Result { Ok(matches!(self.ty(analyzer)?, VarType::Concrete(_))) } - pub fn as_concrete(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_concrete(&self, analyzer: &impl GraphBackend) -> Result { match &self.ty(analyzer)? { VarType::Concrete(c) => Ok(c.underlying(analyzer)?.clone()), e => Err(GraphError::NodeConfusion(format!( @@ -188,7 +198,7 @@ impl ContextVarNode { loc: Loc, ctx: ContextNode, cast_ty: Builtin, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let new_underlying = self .underlying(analyzer)? @@ -204,7 +214,7 @@ impl ContextVarNode { &self, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let new_underlying = self .underlying(analyzer)? @@ -213,14 +223,14 @@ impl ContextVarNode { Ok(analyzer.add_node(Node::ContextVar(new_underlying)).into()) } - pub fn ty_eq(&self, other: &Self, analyzer: &mut impl GraphLike) -> Result { + pub fn ty_eq(&self, other: &Self, analyzer: &mut impl GraphBackend) -> Result { self.ty(analyzer)?.ty_eq(other.ty(analyzer)?, analyzer) } pub fn cast_from( &self, other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let to_ty = other.ty(analyzer)?.clone(); self.cast_from_ty(to_ty, analyzer)?; @@ -230,7 +240,7 @@ impl ContextVarNode { pub fn literal_cast_from( &self, other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let to_ty = other.ty(analyzer)?.clone(); self.literal_cast_from_ty(to_ty, analyzer)?; @@ -240,7 +250,7 @@ impl ContextVarNode { pub fn cast_from_ty( &self, to_ty: VarType, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { @@ -266,7 +276,7 @@ impl ContextVarNode { pub fn literal_cast_from_ty( &self, to_ty: VarType, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { @@ -286,14 +296,14 @@ impl ContextVarNode { pub fn try_increase_size( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer)?; Ok(()) } - pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_int(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_int(analyzer) } } \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 532ead5a..69bdf92a 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -1,3 +1,14 @@ +use crate::{ + AnalyzerBackend, GraphBackend, GraphError, VarType, Node, SolcRange, TypeNode, + range::Range, + nodes::{ContextVarNode, ContextNode, Concrete, Builtin, ContractNode, FunctionNode, FunctionParam, FunctionReturn, BuiltInNode, EnumNode, Field, TyNode, StructNode, ConcreteNode}, +}; + +use crate::range::elem::*; +use shared::NodeIdx; + +use solang_parser::pt::{StorageLocation, Loc}; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct ContextVar { pub loc: Option, @@ -48,7 +59,7 @@ impl ContextVar { loc: Loc, ctx: ContextNode, concrete_node: ConcreteNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let name = format!( "tmp_{}({})", @@ -73,7 +84,7 @@ impl ContextVar { loc: Loc, ctx: ContextNode, cast_ty: Builtin, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let mut new_tmp = self.clone(); new_tmp.loc = Some(loc); @@ -92,7 +103,7 @@ impl ContextVar { &self, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let mut new_tmp = self.clone(); new_tmp.loc = Some(loc); @@ -105,7 +116,7 @@ impl ContextVar { pub fn new_from_contract( loc: Loc, contract_node: ContractNode, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -127,7 +138,7 @@ impl ContextVar { loc: Loc, struct_node: StructNode, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -150,7 +161,7 @@ impl ContextVar { loc: Loc, ty_node: TyNode, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -172,7 +183,7 @@ impl ContextVar { pub fn new_from_builtin( loc: Loc, bn_node: BuiltInNode, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -189,7 +200,7 @@ impl ContextVar { pub fn fallback_range( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { match &self.ty { VarType::User(TypeNode::Contract(_), ref maybe_range) => { @@ -390,7 +401,7 @@ impl ContextVar { } pub fn maybe_from_user_ty( - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, loc: Loc, node_idx: NodeIdx, ) -> Option { @@ -451,7 +462,7 @@ impl ContextVar { } pub fn maybe_new_from_field( - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, loc: Loc, parent_var: &ContextVar, field: Field, @@ -478,7 +489,7 @@ impl ContextVar { } pub fn new_from_enum_variant( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ctx: ContextNode, loc: Loc, enum_node: EnumNode, @@ -502,7 +513,7 @@ impl ContextVar { } pub fn new_from_index( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), loc: Loc, parent_name: String, parent_display_name: String, @@ -524,7 +535,7 @@ impl ContextVar { } pub fn new_from_func( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), func: FunctionNode, ) -> Result { Ok(ContextVar { @@ -541,7 +552,7 @@ impl ContextVar { } pub fn maybe_new_from_func_param( - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, param: FunctionParam, ) -> Option { if let Some(name) = param.name { @@ -565,7 +576,7 @@ impl ContextVar { } } - pub fn maybe_new_from_func_ret(analyzer: &impl GraphLike, ret: FunctionReturn) -> Option { + pub fn maybe_new_from_func_ret(analyzer: &impl GraphBackend, ret: FunctionReturn) -> Option { if let Some(name) = ret.name { if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { Some(ContextVar { @@ -589,7 +600,7 @@ impl ContextVar { pub fn new_from_func_ret( ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ret: FunctionReturn, ) -> Result, GraphError> { let (is_tmp, name) = if let Some(name) = ret.name { diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index 4867bc5c..f3b4a9c0 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -1,7 +1,15 @@ +use crate::{ + GraphBackend, GraphError, Edge, ContextEdge, + nodes::{ContextVarNode, ContextNode}, +}; + +use shared::NodeIdx; + +use petgraph::{visit::EdgeRef, Direction}; impl ContextVarNode { - pub fn latest_version(&self, analyzer: &impl GraphLike) -> Self { + pub fn latest_version(&self, analyzer: &impl GraphBackend) -> Self { let mut latest = *self; while let Some(next) = latest.next_version(analyzer) { latest = next; @@ -9,7 +17,7 @@ impl ContextVarNode { latest } - pub fn latest_version_less_than(&self, idx: NodeIdx, analyzer: &impl GraphLike) -> Self { + pub fn latest_version_less_than(&self, idx: NodeIdx, analyzer: &impl GraphBackend) -> Self { let mut latest = *self; while let Some(next) = latest.next_version(analyzer) { if next.0 <= idx.index() { @@ -24,7 +32,7 @@ impl ContextVarNode { pub fn latest_version_in_ctx( &self, ctx: ContextNode, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { Ok(cvar.latest_version(analyzer)) @@ -37,7 +45,7 @@ impl ContextVarNode { &self, idx: NodeIdx, ctx: ContextNode, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { if let Some(cvar) = ctx.var_by_name(analyzer, &self.name(analyzer)?) { Ok(cvar.latest_version_less_than(idx, analyzer)) @@ -46,7 +54,7 @@ impl ContextVarNode { } } - pub fn global_first_version(&self, analyzer: &impl GraphLike) -> Self { + pub fn global_first_version(&self, analyzer: &impl GraphBackend) -> Self { let first = self.first_version(analyzer); if let Some(inherited_from) = analyzer .graph() @@ -71,7 +79,7 @@ impl ContextVarNode { } } - pub fn first_version(&self, analyzer: &impl GraphLike) -> Self { + pub fn first_version(&self, analyzer: &impl GraphBackend) -> Self { let mut earlier = *self; while let Some(prev) = earlier.previous_version(analyzer) { earlier = prev; @@ -79,7 +87,7 @@ impl ContextVarNode { earlier } - pub fn num_versions(&self, analyzer: &impl GraphLike) -> usize { + pub fn num_versions(&self, analyzer: &impl GraphBackend) -> usize { let mut count = 1; let mut earlier = self.latest_version(analyzer); while let Some(prev) = earlier.previous_version(analyzer) { @@ -89,7 +97,7 @@ impl ContextVarNode { count } - pub fn curr_version_num(&self, analyzer: &impl GraphLike) -> usize { + pub fn curr_version_num(&self, analyzer: &impl GraphBackend) -> usize { let mut count = 0; let mut earlier = self.first_version(analyzer); while let Some(next) = earlier.next_version(analyzer) { @@ -102,7 +110,7 @@ impl ContextVarNode { count } - pub fn global_curr_version_num(&self, analyzer: &impl GraphLike) -> usize { + pub fn global_curr_version_num(&self, analyzer: &impl GraphBackend) -> usize { let mut curr_num = self.curr_version_num(analyzer); if let Some(inherited_from) = analyzer .graph() @@ -126,7 +134,7 @@ impl ContextVarNode { curr_num } - pub fn all_versions(&self, analyzer: &impl GraphLike) -> Vec { + pub fn all_versions(&self, analyzer: &impl GraphBackend) -> Vec { let mut versions = vec![]; let mut earlier = self.latest_version(analyzer); while let Some(prev) = earlier.previous_version(analyzer) { @@ -136,7 +144,7 @@ impl ContextVarNode { versions } - pub fn next_version(&self, analyzer: &impl GraphLike) -> Option { + pub fn next_version(&self, analyzer: &impl GraphBackend) -> Option { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -146,7 +154,7 @@ impl ContextVarNode { .next() } - pub fn next_version_or_inheriteds(&self, analyzer: &impl GraphLike) -> Vec { + pub fn next_version_or_inheriteds(&self, analyzer: &impl GraphBackend) -> Vec { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -158,11 +166,11 @@ impl ContextVarNode { .collect() } - pub fn other_is_version(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + pub fn other_is_version(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { self.all_versions(analyzer).contains(other) } - pub fn previous_version(&self, analyzer: &impl GraphLike) -> Option { + pub fn previous_version(&self, analyzer: &impl GraphBackend) -> Option { analyzer .graph() .edges_directed(self.0.into(), Direction::Outgoing) @@ -172,7 +180,7 @@ impl ContextVarNode { .next() } - pub fn previous_or_inherited_version(&self, analyzer: &impl GraphLike) -> Option { + pub fn previous_or_inherited_version(&self, analyzer: &impl GraphBackend) -> Option { if let Some(prev) = self.previous_version(analyzer) { Some(prev) } else { diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 51785424..0dae0097 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -1,8 +1,7 @@ use crate::{ - Node, Edge, GraphError, ContextEdge, + AnalyzerBackend, GraphBackend, Node, Edge, GraphError, ContextEdge, nodes::{ContextVarNode, ContextNode, ExprRet}, }; -use shared::{AnalyzerLike, GraphLike}; use solang_parser::pt::Loc; @@ -13,7 +12,7 @@ impl ContextNode { pub fn add_var( &self, var: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let name = var.name(analyzer)?; let vars = &mut self.underlying_mut(analyzer)?.cache.vars; @@ -22,7 +21,7 @@ impl ContextNode { } /// Gets a variable by name in the context - pub fn var_by_name(&self, analyzer: &impl GraphLike, name: &str) -> Option { + pub fn var_by_name(&self, analyzer: &impl GraphBackend, name: &str) -> Option { self.underlying(analyzer) .unwrap() .cache @@ -34,7 +33,7 @@ impl ContextNode { /// Gets a variable by name or recurses up the relevant scopes/contexts until it is found pub fn var_by_name_or_recurse( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, name: &str, ) -> Result, GraphError> { if let Some(var) = self.var_by_name(analyzer, name) { @@ -47,14 +46,14 @@ impl ContextNode { } /// Gets all variables associated with a context - pub fn vars<'a>(&self, analyzer: &'a impl GraphLike) -> &'a BTreeMap { + pub fn vars<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a BTreeMap { &self.underlying(analyzer).unwrap().cache.vars } /// Gets all variables associated with a context pub fn local_vars<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> &'a BTreeMap { self.vars(analyzer) } @@ -62,7 +61,7 @@ impl ContextNode { /// Gets the latest version of a variable associated with a context pub fn latest_var_by_name( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, name: &str, ) -> Option { self.var_by_name(analyzer, name) @@ -72,7 +71,7 @@ impl ContextNode { /// Reads the current temporary counter and increments the counter pub fn new_tmp( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let context = self.underlying_mut(analyzer)?; let ret = context.tmp_var_ctr; @@ -84,7 +83,7 @@ impl ContextNode { pub fn push_tmp_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; underlying_mut.tmp_expr.push(Some(expr_ret)); @@ -96,7 +95,7 @@ impl ContextNode { pub fn append_tmp_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; match underlying_mut.tmp_expr.pop() { @@ -136,7 +135,7 @@ impl ContextNode { pub fn pop_tmp_expr( &self, loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { @@ -151,7 +150,7 @@ impl ContextNode { pub fn push_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { tracing::trace!( "pushing: {}, existing: {:?}, path: {}", @@ -173,7 +172,7 @@ impl ContextNode { &self, expr: ExprRet, loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match expr { ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( @@ -197,7 +196,7 @@ impl ContextNode { &self, var: ContextVarNode, loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { if let Some(ctx) = var.maybe_ctx(analyzer) { if ctx != *self { @@ -225,7 +224,7 @@ impl ContextNode { pub fn pop_expr_latest( &self, loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; if let Some(elem) = underlying_mut.expr_ret_stack.pop() { @@ -241,7 +240,7 @@ impl ContextNode { } /// Gets local vars that were assigned from a function return - pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + pub fn vars_assigned_from_fn_ret(&self, analyzer: &impl GraphBackend) -> Vec { self.local_vars(analyzer) .iter() .flat_map(|(_name, var)| var.return_assignments(analyzer)) @@ -249,7 +248,7 @@ impl ContextNode { } /// Gets local vars that were assigned from an external function return - pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphLike) -> Vec { + pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphBackend) -> Vec { self.local_vars(analyzer) .iter() .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 89b94af8..a19aab1f 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,21 +1,20 @@ use crate::{ - Node, GraphError, + AnalyzerBackend, GraphBackend, Node, GraphError, nodes::{ContextNode, CallFork, KilledKind, FunctionNode} }; -use shared::{AnalyzerLike, GraphLike}; use solang_parser::pt::Loc; impl ContextNode { /// Query whether this context has a parent - pub fn has_parent(&self, analyzer: &impl GraphLike) -> Result { + pub fn has_parent(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.parent_ctx.is_some()) } /// Gets the first ancestor of this context pub fn first_ancestor( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { Ok(first_ancestor) @@ -29,7 +28,7 @@ impl ContextNode { } /// Gets the subcontexts of this context - pub fn subcontexts(&self, analyzer: &impl GraphLike) -> Vec { + pub fn subcontexts(&self, analyzer: &impl GraphBackend) -> Vec { let underlying = self.underlying(analyzer).unwrap(); match underlying.child { Some(CallFork::Call(c)) => vec![c], @@ -41,7 +40,7 @@ impl ContextNode { /// Get the first ancestor context that is in the same function pub fn ancestor_in_fn( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, associated_fn: FunctionNode, ) -> Result, GraphError> { if let Some(ret) = self.underlying(analyzer)?.returning_ctx { @@ -68,7 +67,7 @@ impl ContextNode { } /// Returns all forks associated with the context - pub fn calls(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn calls(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { let descendents = self.descendents(analyzer)?; Ok(descendents .into_iter() @@ -77,7 +76,7 @@ impl ContextNode { } /// Returns tail contexts associated with the context - pub fn live_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn live_edges(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; match child { @@ -112,7 +111,7 @@ impl ContextNode { } /// Gets all reverted descendents - pub fn reverted_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn reverted_edges(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; match child { @@ -147,7 +146,7 @@ impl ContextNode { } /// Gets all successful descendents - pub fn successful_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn successful_edges(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; match child { @@ -182,12 +181,12 @@ impl ContextNode { } /// Returns the current number of live edges - pub fn number_of_live_edges(&self, analyzer: &impl GraphLike) -> Result { + pub fn number_of_live_edges(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.number_of_live_edges) } /// Returns tail contexts associated with the context - pub fn all_edges(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn all_edges(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; match child { @@ -222,7 +221,7 @@ impl ContextNode { } /// Gets all descendents recursively - pub fn descendents(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn descendents(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut descendents = vec![child]; match child { @@ -243,7 +242,7 @@ impl ContextNode { &self, w1: ContextNode, w2: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { assert!(matches!(analyzer.node(w1), Node::Context(_))); assert!(matches!(analyzer.node(w2), Node::Context(_))); @@ -273,7 +272,7 @@ impl ContextNode { pub fn set_child_call( &self, call: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { assert!(matches!(analyzer.node(call), Node::Context(_))); assert!(*self != call, "Tried to set child to self"); @@ -302,7 +301,7 @@ impl ContextNode { /// Removes the child of this context pub fn delete_child( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { if let Some(child) = self.underlying(analyzer)?.child { match child { @@ -324,7 +323,7 @@ impl ContextNode { /// parent contexts if all subcontexts of that context are killed pub fn kill( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), kill_loc: Loc, kill_kind: KilledKind, ) -> Result<(), GraphError> { @@ -370,7 +369,7 @@ impl ContextNode { /// Kills if and only if all subcontexts are killed pub fn end_if_all_forks_ended( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), kill_loc: Loc, kill_kind: KilledKind, ) -> Result<(), GraphError> { @@ -392,7 +391,7 @@ impl ContextNode { } /// Gets parent list - pub fn parent_list(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn parent_list(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { let context = self.underlying(analyzer)?; let mut parents = vec![]; if let Some(parent_ctx) = context.parent_ctx { @@ -405,7 +404,7 @@ impl ContextNode { /// Gets all calls recursively pub fn recursive_calls( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { // Ok( let calls = self.calls(analyzer)?; @@ -424,7 +423,7 @@ impl ContextNode { /// gives the user a full picture of control flow pub fn lineage( &self, - _analyzer: &impl GraphLike, + _analyzer: &impl GraphBackend, _entry: bool, ) -> Result, GraphError> { todo!() diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 6fdd4ebb..3afd79de 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -1,15 +1,9 @@ -use crate::analyzer::GraphError; -use crate::analyzer::Search; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::AsDotStr; -use crate::Edge; -use crate::FunctionNode; -use crate::Node; -use crate::NodeIdx; -use crate::StructNode; -use crate::VarNode; +use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, Edge, nodes::{StructNode, FunctionNode, VarNode}}; +use shared::{NodeIdx, Search}; + use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{ContractDefinition, ContractTy, Identifier, Loc}; + use std::collections::BTreeMap; /// An index in the graph that references a [`Contract`] node @@ -17,7 +11,7 @@ use std::collections::BTreeMap; pub struct ContractNode(pub usize); impl AsDotStr for ContractNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", @@ -33,7 +27,7 @@ impl AsDotStr for ContractNode { impl ContractNode { /// Gets the underlying node data for the [`Contract`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Contract, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Contract, GraphError> { match analyzer.node(*self) { Node::Contract(contract) => Ok(contract), e => Err(GraphError::NodeConfusion(format!( @@ -42,7 +36,7 @@ impl ContractNode { } } - pub fn super_contracts(&self, analyzer: &impl GraphLike) -> Vec { + pub fn super_contracts(&self, analyzer: &impl GraphBackend) -> Vec { analyzer .graph() .edges_directed((*self).into(), Direction::Incoming) @@ -51,7 +45,7 @@ impl ContractNode { .collect() } - pub fn inherit(&self, inherits: Vec, analyzer: &mut (impl GraphLike + AnalyzerLike)) { + pub fn inherit(&self, inherits: Vec, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) { let src = self.associated_source(analyzer); let all_contracts = analyzer.search_children_include_via( src, @@ -80,11 +74,11 @@ impl ContractNode { }); } - pub fn direct_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { + pub fn direct_inherited_contracts(&self, analyzer: &impl GraphBackend) -> Vec { self.underlying(analyzer).unwrap().inherits.clone() } - pub fn all_inherited_contracts(&self, analyzer: &impl GraphLike) -> Vec { + pub fn all_inherited_contracts(&self, analyzer: &impl GraphBackend) -> Vec { let mut inherits = self.direct_inherited_contracts(analyzer); inherits.extend( inherits @@ -96,7 +90,7 @@ impl ContractNode { } /// Gets the name from the underlying node data for the [`Contract`] - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -106,7 +100,7 @@ impl ContractNode { } /// Tries to Get the name from the underlying node data for the [`Contract`] - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_name(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(ident) = self.underlying(analyzer)?.name.clone() { Ok(Some(ident.name)) } else { @@ -115,12 +109,12 @@ impl ContractNode { } /// Gets the sourcecode location from the underlying node data for the [`Contract`] - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.loc) } /// Gets all associated functions from the underlying node data for the [`Contract`] - pub fn funcs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + pub fn funcs(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer .search_children_depth(self.0.into(), &Edge::Func, 1, 0) .into_iter() @@ -129,7 +123,7 @@ impl ContractNode { } /// Gets all associated storage vars from the underlying node data for the [`Contract`] - pub fn direct_storage_vars(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + pub fn direct_storage_vars(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer .search_children_depth(self.0.into(), &Edge::Var, 1, 0) .into_iter() @@ -138,7 +132,7 @@ impl ContractNode { } /// Gets all associated storage vars from the underlying node data for the [`Contract`] - pub fn all_storage_vars(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + pub fn all_storage_vars(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { let mut ret = self .all_inherited_contracts(analyzer) .iter() @@ -150,7 +144,7 @@ impl ContractNode { pub fn funcs_mapping( &self, - analyzer: &(impl GraphLike + Search + AnalyzerLike), + analyzer: &(impl GraphBackend + Search + AnalyzerBackend), ) -> BTreeMap { analyzer .search_children_depth(self.0.into(), &Edge::Func, 1, 0) @@ -164,7 +158,7 @@ impl ContractNode { pub fn linearized_functions( &self, - analyzer: &(impl GraphLike + Search + AnalyzerLike), + analyzer: &(impl GraphBackend + Search + AnalyzerBackend), ) -> BTreeMap { let mut mapping = self.funcs_mapping(analyzer); self.direct_inherited_contracts(analyzer) @@ -182,7 +176,7 @@ impl ContractNode { mapping } - pub fn structs(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + pub fn structs(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer .search_children_depth(self.0.into(), &Edge::Struct, 1, 0) .into_iter() @@ -191,7 +185,7 @@ impl ContractNode { } /// Gets all associated modifiers from the underlying node data for the [`Contract`] - pub fn modifiers(&self, analyzer: &(impl GraphLike + Search)) -> Vec { + pub fn modifiers(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer .search_children_depth(self.0.into(), &Edge::Modifier, 1, 0) .into_iter() @@ -199,13 +193,13 @@ impl ContractNode { .collect() } - pub fn associated_source_unit_part(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { + pub fn associated_source_unit_part(&self, analyzer: &(impl GraphBackend + Search)) -> NodeIdx { analyzer .search_for_ancestor(self.0.into(), &Edge::Contract) .expect("detached contract") } - pub fn associated_source(&self, analyzer: &(impl GraphLike + Search)) -> NodeIdx { + pub fn associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> NodeIdx { let sup = self.associated_source_unit_part(analyzer); analyzer .search_for_ancestor(sup, &Edge::Part) @@ -250,7 +244,7 @@ impl Contract { con: ContractDefinition, source: NodeIdx, imports: &[Option], - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> (Contract, Vec) { let mut inherits = vec![]; let mut unhandled_inherits = vec![]; diff --git a/crates/graph/src/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs index eaf55308..6ca7041d 100644 --- a/crates/graph/src/nodes/enum_ty.rs +++ b/crates/graph/src/nodes/enum_ty.rs @@ -1,10 +1,7 @@ -use crate::analyzer::GraphError; -use crate::analyzer::GraphLike; -use crate::range::SolcRange; -use crate::AsDotStr; -use crate::Concrete; -use crate::Node; -use crate::NodeIdx; +use crate::{AsDotStr, GraphBackend, SolcRange, GraphError, Node, nodes::Concrete}; + +use shared::NodeIdx; + use ethers_core::types::U256; use solang_parser::pt::{EnumDefinition, Identifier, Loc}; @@ -13,7 +10,7 @@ use solang_parser::pt::{EnumDefinition, Identifier, Loc}; pub struct EnumNode(pub usize); impl AsDotStr for EnumNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "enum {} {{ {} }}", @@ -29,7 +26,7 @@ impl AsDotStr for EnumNode { impl EnumNode { /// Gets the underlying node data for the [`Enum`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Enum, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Enum, GraphError> { match analyzer.node(*self) { Node::Enum(e) => Ok(e), e => Err(GraphError::NodeConfusion(format!( @@ -39,7 +36,7 @@ impl EnumNode { } /// Gets the name of the enum from the underlying node data for the [`Enum`] - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -48,13 +45,13 @@ impl EnumNode { .name) } - pub fn variants(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn variants(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(self.underlying(analyzer)?.variants()) } pub fn maybe_default_range( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let variants = self.variants(analyzer)?; if !variants.is_empty() { @@ -69,7 +66,7 @@ impl EnumNode { pub fn range_from_variant( &self, variant: String, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let variants = self.variants(analyzer)?; assert!(variants.contains(&variant)); diff --git a/crates/graph/src/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs index 1830035d..af98f7d3 100644 --- a/crates/graph/src/nodes/err_ty.rs +++ b/crates/graph/src/nodes/err_ty.rs @@ -1,13 +1,12 @@ -use crate::analyzer::GraphError; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::AsDotStr; -use crate::{Node, NodeIdx}; +use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node}; + +use shared::NodeIdx; use solang_parser::pt::{ErrorDefinition, ErrorParameter, Expression, Identifier, Loc}; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct ErrorNode(pub usize); impl ErrorNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Error, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Error, GraphError> { match analyzer.node(*self) { Node::Error(err) => Ok(err), e => Err(GraphError::NodeConfusion(format!( @@ -17,7 +16,7 @@ impl ErrorNode { } } impl AsDotStr for ErrorNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "error {}", @@ -93,7 +92,7 @@ impl From for Node { impl ErrorParam { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), param: ErrorParameter, ) -> Self { ErrorParam { diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index cbcd9f12..efbae343 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -1,31 +1,22 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::GraphError; -use crate::analyzer::Search; -use crate::context::{ContextEdge, ContextNode}; -use crate::nodes::ContractNode; -use crate::range::SolcRange; -use crate::Edge; -use crate::VarType; -use crate::{ - analyzer::{AnalyzerLike, GraphLike}, - Node, NodeIdx, -}; +use crate::{AnalyzerBackend, GraphBackend, AsDotStr, SolcRange, Edge, VarType, GraphError, Node, ContextEdge, nodes::{ContextNode, ContractNode}}; + +use shared::{NodeIdx, Search}; + use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::ParameterList; -use solang_parser::pt::Statement; -use solang_parser::pt::Type; -use solang_parser::pt::VariableDefinition; -use solang_parser::pt::{ - Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, - Parameter, StorageLocation, Visibility, +use solang_parser::{ + helpers::CodeLocation, + pt::{ + ParameterList, Statement, Type, VariableDefinition, + Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, + Loc, Parameter, StorageLocation, Visibility, + }, }; use std::collections::BTreeMap; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct FunctionNode(pub usize); impl FunctionNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Function, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Function, GraphError> { match analyzer.node(*self) { Node::Function(func) => Ok(func), e => Err(GraphError::NodeConfusion(format!( @@ -34,7 +25,7 @@ impl FunctionNode { } } - pub fn body_loc(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn body_loc(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(body_stmt) = &self.underlying(analyzer)?.body { Ok(Some(body_stmt.loc())) } else { @@ -42,13 +33,13 @@ impl FunctionNode { } } - pub fn definition_loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn definition_loc(&self, analyzer: &impl GraphBackend) -> Result { let underlying = &self.underlying(analyzer)?; Ok(underlying.loc) } /// Gets an ordered list of modifiers for a given function - pub fn modifiers(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> Vec { + pub fn modifiers(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> Vec { if let Some(mods) = &self.underlying(analyzer).unwrap().cache.modifiers { mods.values().copied().collect() } else { @@ -68,14 +59,14 @@ impl FunctionNode { } } - pub fn modifiers_set(&self, analyzer: &impl GraphLike) -> Result { + pub fn modifiers_set(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.modifiers_set) } pub fn modifier_input_vars( &self, mod_num: usize, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let modifiers = self.underlying(analyzer)?.modifiers_as_base(); if let Some(modifier) = modifiers.get(mod_num) { @@ -91,7 +82,7 @@ impl FunctionNode { pub fn underlying_mut<'a>( &self, - analyzer: &'a mut (impl GraphLike + AnalyzerLike), + analyzer: &'a mut (impl GraphBackend + AnalyzerBackend), ) -> Result<&'a mut Function, GraphError> { match analyzer.node_mut(*self) { Node::Function(func) => Ok(func), @@ -101,7 +92,7 @@ impl FunctionNode { } } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { match self.underlying(analyzer)?.ty { FunctionTy::Constructor => Ok(format!( "constructor({})", @@ -124,7 +115,7 @@ impl FunctionNode { pub fn loc_specified_name( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { if let Some(con) = self.maybe_associated_contract(analyzer) { Ok(format!("{}.{}", con.name(analyzer)?, self.name(analyzer)?)) @@ -133,7 +124,7 @@ impl FunctionNode { } } - pub fn body_ctx(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> ContextNode { + pub fn body_ctx(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> ContextNode { if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { body_ctx } else { @@ -153,7 +144,7 @@ impl FunctionNode { pub fn maybe_body_ctx( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { Some(body_ctx) @@ -175,7 +166,7 @@ impl FunctionNode { pub fn maybe_associated_contract( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { if let Some(maybe_contract) = self .underlying(analyzer) @@ -217,7 +208,7 @@ impl FunctionNode { pub fn maybe_associated_source_unit_part( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { if let Some(sup) = self .underlying(analyzer) @@ -258,7 +249,7 @@ impl FunctionNode { } } - pub fn associated_source(&self, analyzer: &mut (impl GraphLike + AnalyzerLike)) -> NodeIdx { + pub fn associated_source(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> NodeIdx { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { src } else { @@ -278,7 +269,7 @@ impl FunctionNode { pub fn maybe_associated_source( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Option { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { Some(src) @@ -293,7 +284,7 @@ impl FunctionNode { } } - pub fn params(&self, analyzer: &impl GraphLike) -> Vec { + pub fn params(&self, analyzer: &impl GraphBackend) -> Vec { if let Some(params) = &self.underlying(analyzer).unwrap().cache.params { params.to_vec() } else { @@ -315,7 +306,7 @@ impl FunctionNode { pub fn set_params_and_ret( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { let underlying = self.underlying(analyzer)?.clone(); let mut params_strs = vec![]; @@ -365,7 +356,7 @@ impl FunctionNode { pub fn returns<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> impl Iterator + 'a { analyzer .graph() @@ -374,7 +365,7 @@ impl FunctionNode { .map(|edge| FunctionReturnNode::from(edge.source())) } - pub fn is_public_or_ext(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_public_or_ext(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.attributes.iter().any(|attr| { matches!( attr, @@ -387,7 +378,7 @@ impl FunctionNode { pub fn get_overriding( &self, other: &Self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let self_attrs = &self.underlying(analyzer)?.attributes; let other_attrs = &other.underlying(analyzer)?.attributes; @@ -422,7 +413,7 @@ impl FunctionNode { } impl AsDotStr for FunctionNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let inputs = self .params(analyzer) .iter() @@ -670,7 +661,7 @@ impl From for Function { pub struct FunctionParamNode(pub usize); impl AsDotStr for FunctionParamNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) .expect("Non-typeable as type"); format!( @@ -693,7 +684,7 @@ impl AsDotStr for FunctionParamNode { impl FunctionParamNode { pub fn underlying<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> Result<&'a FunctionParam, GraphError> { match analyzer.node(*self) { Node::FunctionParam(param) => Ok(param), @@ -703,7 +694,7 @@ impl FunctionParamNode { } } - pub fn name(&self, analyzer: &'_ impl GraphLike) -> Result { + pub fn name(&self, analyzer: &'_ impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -712,7 +703,7 @@ impl FunctionParamNode { .name) } - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_name(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(ident) = self.underlying(analyzer)?.name.clone() { Ok(Some(ident.name)) } else { @@ -720,7 +711,7 @@ impl FunctionParamNode { } } - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { let ty_node = self.underlying(analyzer)?.ty; if let Some(var_ty) = VarType::try_from_idx(analyzer, ty_node) { Ok(var_ty.range(analyzer)?) @@ -729,18 +720,18 @@ impl FunctionParamNode { } } - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.loc) } - pub fn ty_str(&self, analyzer: &impl GraphLike) -> Result { + pub fn ty_str(&self, analyzer: &impl GraphBackend) -> Result { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer)?.ty).ok_or( GraphError::NodeConfusion("Non-typeable as type".to_string()), )?; Ok(var_ty.as_dot_str(analyzer)) } - pub fn ty(&self, analyzer: &impl GraphLike) -> Result { + pub fn ty(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.ty) } } @@ -774,7 +765,7 @@ impl From for Node { impl FunctionParam { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), param: Parameter, order: usize, ) -> Self { @@ -792,7 +783,7 @@ impl FunctionParam { pub struct FunctionReturnNode(pub usize); impl AsDotStr for FunctionReturnNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) .expect("Non-typeable as type"); format!( @@ -815,7 +806,7 @@ impl AsDotStr for FunctionReturnNode { impl FunctionReturnNode { pub fn underlying<'a>( &self, - analyzer: &'a impl GraphLike, + analyzer: &'a impl GraphBackend, ) -> Result<&'a FunctionReturn, GraphError> { match analyzer.node(*self) { Node::FunctionReturn(ret) => Ok(ret), @@ -825,7 +816,7 @@ impl FunctionReturnNode { } } - pub fn maybe_name(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_name(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(ident) = self.underlying(analyzer)?.name.clone() { Ok(Some(ident.name)) } else { @@ -833,7 +824,7 @@ impl FunctionReturnNode { } } - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.loc) } } @@ -866,7 +857,7 @@ pub struct FunctionReturn { impl FunctionReturn { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), param: Parameter, ) -> Self { FunctionReturn { diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index b7f24095..de4e0600 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -1,22 +1,15 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Builtin; -use crate::Concrete; -use crate::ContextNode; -use crate::ContextVar; +use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, nodes::{Concrete, Builtin, ContextNode, ContextVar}}; -use crate::Node; -use crate::NodeIdx; -use ethers_core::types::Address; -use ethers_core::types::U256; +use shared::NodeIdx; + +use ethers_core::types::{U256, Address}; use solang_parser::pt::Loc; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct MsgNode(pub usize); impl MsgNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Msg, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Msg, GraphError> { match analyzer.node(*self) { Node::Msg(st) => Ok(st), e => Err(GraphError::NodeConfusion(format!( @@ -27,7 +20,7 @@ impl MsgNode { } impl AsDotStr for MsgNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { format!("msg {{ {:?} }}", self.underlying(analyzer).unwrap()) } } @@ -61,7 +54,7 @@ impl Msg { elem: &str, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { let (node, name) = match elem { "data" => { diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index 2ede9a0f..f7fbdf64 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -1,11 +1,7 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Edge; - -use crate::Node; -use crate::NodeIdx; -use crate::VarType; +use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, Edge, VarType}; + +use shared::NodeIdx; + use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableDeclaration}; @@ -13,7 +9,7 @@ use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableD pub struct StructNode(pub usize); impl StructNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Struct, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Struct, GraphError> { match analyzer.node(*self) { Node::Struct(st) => Ok(st), e => Err(GraphError::NodeConfusion(format!( @@ -22,11 +18,11 @@ impl StructNode { } } - pub fn loc(&self, analyzer: &impl GraphLike) -> Result { + pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.loc) } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -35,7 +31,7 @@ impl StructNode { .to_string()) } - pub fn fields(&self, analyzer: &impl GraphLike) -> Vec { + pub fn fields(&self, analyzer: &impl GraphBackend) -> Vec { let mut fields: Vec<_> = analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -46,7 +42,7 @@ impl StructNode { fields } - pub fn find_field(&self, analyzer: &impl GraphLike, ident: &Identifier) -> Option { + pub fn find_field(&self, analyzer: &impl GraphBackend, ident: &Identifier) -> Option { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -57,7 +53,7 @@ impl StructNode { } impl AsDotStr for StructNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "struct {} {{ {} }}", @@ -121,7 +117,7 @@ impl From for Struct { pub struct FieldNode(pub usize); impl FieldNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Field, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Field, GraphError> { match analyzer.node(*self) { Node::Field(field) => Ok(field), e => Err(GraphError::NodeConfusion(format!( @@ -130,7 +126,7 @@ impl FieldNode { } } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -141,7 +137,7 @@ impl FieldNode { } impl AsDotStr for FieldNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", @@ -186,7 +182,7 @@ impl From for Node { impl Field { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), var_def: VariableDeclaration, ) -> Field { let ty_idx = analyzer.parse_expr(&var_def.ty, None); diff --git a/crates/graph/src/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs index 83b76527..ceb30563 100644 --- a/crates/graph/src/nodes/ty_ty.rs +++ b/crates/graph/src/nodes/ty_ty.rs @@ -1,15 +1,13 @@ -use crate::analyzer::AsDotStr; -use crate::analyzer::{AnalyzerLike, GraphLike}; -use crate::nodes::GraphError; -use crate::Node; -use crate::NodeIdx; -use crate::VarType; +use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, VarType}; + +use shared::NodeIdx; + use solang_parser::pt::{Expression, Identifier, Loc, TypeDefinition}; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct TyNode(pub usize); impl TyNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Ty, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Ty, GraphError> { match analyzer.node(*self) { Node::Ty(ty) => Ok(ty), e => Err(GraphError::NodeConfusion(format!( @@ -18,7 +16,7 @@ impl TyNode { } } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.name.to_string()) } } @@ -36,7 +34,7 @@ impl From for TyNode { } impl AsDotStr for TyNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", @@ -65,7 +63,7 @@ impl From for Node { impl Ty { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ty: TypeDefinition, ) -> Ty { Ty { diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 704d1212..9c985e2a 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,16 +1,7 @@ -use crate::analyzer::Search; -use crate::nodes::GraphError; -use crate::ContextEdge; +use crate::{AsDotStr, AnalyzerBackend, GraphBackend, Node, Edge, VarType, ContextEdge, nodes::{ContextVar, ContractNode, ContextVarNode}, GraphError}; -use crate::ContextVarNode; +use shared::{NodeIdx, Search}; -use crate::ContractNode; -use crate::VarType; -use crate::{ - analyzer::{AnalyzerLike, AsDotStr, GraphLike}, - Node, NodeIdx, -}; -use crate::{ContextVar, Edge}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{ Expression, Identifier, Loc, VariableAttribute, VariableDefinition, Visibility, @@ -20,7 +11,7 @@ use solang_parser::pt::{ pub struct VarNode(pub usize); impl VarNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphLike) -> Result<&'a Var, GraphError> { + pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Var, GraphError> { match analyzer.node(*self) { Node::Var(func) => Ok(func), e => Err(GraphError::NodeConfusion(format!( @@ -31,7 +22,7 @@ impl VarNode { pub fn underlying_mut<'a>( &self, - analyzer: &'a mut impl GraphLike, + analyzer: &'a mut impl GraphBackend, ) -> Result<&'a mut Var, GraphError> { match analyzer.node_mut(*self) { Node::Var(func) => Ok(func), @@ -43,7 +34,7 @@ impl VarNode { pub fn parse_initializer( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), parent: NodeIdx, ) -> Result<(), GraphError> { if let Some(expr) = self.underlying(analyzer)?.initializer_expr.clone() { @@ -67,7 +58,7 @@ impl VarNode { Ok(()) } - pub fn maybe_associated_contract(&self, analyzer: &impl GraphLike) -> Option { + pub fn maybe_associated_contract(&self, analyzer: &impl GraphBackend) -> Option { analyzer .graph() .edges_directed(self.0.into(), Direction::Outgoing) @@ -84,7 +75,7 @@ impl VarNode { .map(ContractNode::from) } - pub fn maybe_associated_source_unit_part(&self, analyzer: &impl GraphLike) -> Option { + pub fn maybe_associated_source_unit_part(&self, analyzer: &impl GraphBackend) -> Option { if let Some(con) = self.maybe_associated_contract(analyzer) { Some(con.associated_source_unit_part(analyzer)) } else { @@ -104,12 +95,12 @@ impl VarNode { } } - pub fn maybe_associated_source(&self, analyzer: &(impl GraphLike + Search)) -> Option { + pub fn maybe_associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> Option { let sup = self.maybe_associated_source_unit_part(analyzer)?; analyzer.search_for_ancestor(sup, &Edge::Part) } - pub fn name(&self, analyzer: &impl GraphLike) -> Result { + pub fn name(&self, analyzer: &impl GraphBackend) -> Result { Ok(self .underlying(analyzer)? .name @@ -121,7 +112,7 @@ impl VarNode { pub fn const_value( &self, loc: Loc, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let attrs = &self.underlying(analyzer)?.attrs; if attrs @@ -147,7 +138,7 @@ impl VarNode { Ok(None) } - pub fn inherited_into(&self, analyzer: &impl GraphLike) -> Vec { + pub fn inherited_into(&self, analyzer: &impl GraphBackend) -> Vec { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) @@ -163,7 +154,7 @@ impl VarNode { } impl AsDotStr for VarNode { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{}{} {}", @@ -225,7 +216,7 @@ impl From for Node { impl Var { pub fn new( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), var: VariableDefinition, in_contract: bool, ) -> Var { diff --git a/crates/graph/src/range_impl/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs similarity index 78% rename from crates/graph/src/range_impl/elem/concrete.rs rename to crates/graph/src/range/elem/concrete.rs index a8683ab5..d86a85e4 100644 --- a/crates/graph/src/range_impl/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,11 +1,20 @@ -use crate::{GraphError, nodes::{Concrete}}; +use crate::{ + GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, + range::elem::{RangeElem, RangeOp, Elem} +}; -use range::elem::{RangeElem, RangeConcrete, RangeOp, Elem}; -use shared::{NodeIdx, GraphLike}; +use shared::NodeIdx; + +use std::collections::BTreeMap; use solang_parser::pt::Loc; -use std::collections::BTreeMap; +/// A concrete value for a range element +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeConcrete { + pub val: T, + pub loc: Loc, +} impl From for RangeConcrete { fn from(c: Concrete) -> Self { @@ -17,14 +26,15 @@ impl From for RangeConcrete { } impl RangeElem for RangeConcrete { - // fn simplify(&self, _analyzer: &impl GraphLike) -> Elem { + type GraphError = GraphError; + // fn simplify(&self, _analyzer: &impl GraphBackend) -> Elem { // Elem::Concrete(self.clone()) // } fn flatten( &self, _maximize: bool, - _analyzer: &impl GraphLike, + _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } @@ -96,40 +106,40 @@ impl RangeElem for RangeConcrete { } } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self) -> Vec { vec![] } - fn update_deps(&mut self, _mapping: &BTreeMap) {} + fn update_deps(&mut self, _mapping: &BTreeMap) {} fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - fn maximize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + fn maximize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn minimize(&self, _analyzer: &impl GraphLike) -> Result, GraphError> { + fn minimize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_maximize( &self, _exclude: &mut Vec, - _analyzer: &impl GraphLike, + _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_minimize( &self, _exclude: &mut Vec, - _analyzer: &impl GraphLike, + _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn cache_maximize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_maximize(&mut self, _g: &impl GraphBackend) -> Result<(), GraphError> { Ok(()) } - fn cache_minimize(&mut self, _g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_minimize(&mut self, _g: &impl GraphBackend) -> Result<(), GraphError> { Ok(()) } fn uncache(&mut self) {} @@ -138,7 +148,7 @@ impl RangeElem for RangeConcrete { &self, _: bool, _op_set: &[RangeOp], - _analyzer: &impl GraphLike, + _analyzer: &impl GraphBackend, ) -> Result { Ok(false) } diff --git a/crates/graph/src/range_impl/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs similarity index 61% rename from crates/graph/src/range_impl/elem/elem_enum.rs rename to crates/graph/src/range/elem/elem_enum.rs index 8356c156..5b7015ef 100644 --- a/crates/graph/src/range_impl/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,125 +1,288 @@ -use crate::{GraphError, nodes::{ContextVarNode, Concrete}}; +use solang_parser::pt::Loc; +use crate::{ + GraphBackend, GraphError, + nodes::{Concrete, ContextVarNode}, + range::elem::{RangeElem, RangeOp, Reference, RangeDyn, RangeConcrete, RangeExpr}, +}; -use range::elem::{RangeElem, RangeConcrete, RangeOp, RangeDyn, Elem, Reference, RangeExpr}; -use shared::{NodeIdx, GraphLike}; +use shared::NodeIdx; use ethers_core::types::I256; -use solang_parser::pt::Loc; -use std::collections::BTreeMap; +use std::{ + collections::BTreeMap, + ops::{ + Add, + Sub, + Mul, + Div, + Shl, + Shr, + Rem, + BitAnd, + BitOr, + BitXor, + } +}; + +/// A core range element. +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub enum Elem { + /// A range element that is a reference to another node + Reference(Reference), + /// A concrete range element of type `T`. e.g.: some number like `10` + ConcreteDyn(Box>), + /// A concrete range element of type `T`. e.g.: some number like `10` + Concrete(RangeConcrete), + /// A range element that is an expression composed of other range elements + Expr(RangeExpr), + /// A null range element useful in range expressions that dont have a rhs + Null, +} -impl std::fmt::Display for Elem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Elem { + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { match self { - Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), - Elem::ConcreteDyn(..) => write!(f, "range_elem"), - Elem::Concrete(RangeConcrete { val, .. }) => { - write!(f, "{}", val.as_string()) - } - Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { - RangeOp::Min | RangeOp::Max => { - write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) - } - RangeOp::Cast => match &**rhs { - Elem::Concrete(RangeConcrete { val, .. }) => { - write!( - f, - "{}({}, {})", - op.to_string(), - lhs, - val.as_builtin().basic_as_string() - ) - } - _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), - }, - RangeOp::BitNot => { - write!(f, "~{}", lhs) + Elem::Reference(Reference { idx, .. }) => { + if *idx == to_replace { + *self = replacement; } - _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), - }, - _ => write!(f, ""), + } + Elem::Concrete(_) => {} + Elem::Expr(expr) => { + expr.lhs.replace_dep(to_replace, replacement.clone()); + expr.rhs.replace_dep(to_replace, replacement); + expr.maximized = None; + expr.minimized = None; + } + Elem::ConcreteDyn(_d) => todo!(), + Elem::Null => {} } } -} -impl From for Elem { - fn from(c: Concrete) -> Self { - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }) + pub fn node_idx(&self) -> Option { + match self { + Self::Reference(Reference { idx, .. }) => Some(*idx), + _ => None, + } } -} -impl From for Elem { - fn from(c: ContextVarNode) -> Self { - Elem::Reference(Reference::new(c.into())) + pub fn concrete(&self) -> Option { + match self { + Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), + _ => None, + } } -} -impl From for Elem { - fn from(idx: NodeIdx) -> Self { - Elem::Reference(Reference::new(idx)) + pub fn maybe_concrete(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } } -} + pub fn maybe_concrete_value(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } -impl Elem { - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { + pub fn maybe_range_dyn(&self) -> Option> { match self { - Self::Reference(Reference { idx, .. }) => { - if *idx == to_replace { - *self = replacement; - } - } - Self::Concrete(_) => {} - Self::Expr(expr) => { - expr.lhs.replace_dep(to_replace, replacement.clone()); - expr.rhs.replace_dep(to_replace, replacement); - expr.maximized = None; - expr.minimized = None; - } - Self::ConcreteDyn(_d) => todo!(), - Self::Null => {} + Elem::ConcreteDyn(a) => Some(*a.clone()), + _ => None, } } +} - pub fn inverse_if_boolean(&self) -> Option { +impl Elem { + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { match self { - Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), - Self::ConcreteDyn(_d) => None, - Self::Null => None, + Self::Reference(d) => d.idx == node_idx, + Self::Concrete(_) => false, + Self::Expr(expr) => expr.contains_node(node_idx), + Self::ConcreteDyn(d) => d.contains_node(node_idx), + Self::Null => false, } } - pub fn node_idx(&self) -> Option { + pub fn expect_into_expr(self) -> RangeExpr { match self { - Self::Reference(Reference { idx, .. }) => Some(*idx), + Self::Expr(expr) => expr, + _ => panic!("Not expression"), + } + } + + pub fn dyn_map(&self) -> Option<&BTreeMap> { + match self { + Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), _ => None, } } - pub fn concrete(&self) -> Option { + pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { match self { - Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), + Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), _ => None, } } + /// Creates a new range element that is a cast from one type to another + pub fn cast(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Cast, other); + Elem::Expr(expr) + } + + pub fn concat(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Concat, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the minimum of two range elements + pub fn min(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Min, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the maximum of two range elements + pub fn max(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Max, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of equality of two range elements + pub fn eq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Eq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of inequality of two range elements + pub fn neq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Neq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is one range element to the power of another + pub fn pow(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Exp, other); + Elem::Expr(expr) + } +} + +impl From> for Elem { + fn from(dy: Reference) -> Self { + Elem::Reference(dy) + } +} + +impl From> for Elem { + fn from(c: RangeConcrete) -> Self { + Elem::Concrete(c) + } +} + +impl Add for Elem { + type Output = Self; + + fn add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(false), other); + Self::Expr(expr) + } +} + +impl Sub for Elem { + type Output = Self; + + fn sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(false), other); + Self::Expr(expr) + } +} + +impl Mul for Elem { + type Output = Self; + + fn mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(false), other); + Self::Expr(expr) + } +} + +impl Div for Elem { + type Output = Self; + + fn div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(false), other); + Self::Expr(expr) + } +} + +impl Shl for Elem { + type Output = Self; + + fn shl(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shl, other); + Self::Expr(expr) + } +} + +impl Shr for Elem { + type Output = Self; + + fn shr(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shr, other); + Self::Expr(expr) + } +} + +impl Rem for Elem { + type Output = Self; + + fn rem(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mod, other); + Self::Expr(expr) + } +} + +impl BitAnd for Elem { + type Output = Self; + + fn bitand(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitAnd, other); + Self::Expr(expr) + } +} + +impl BitOr for Elem { + type Output = Self; + + fn bitor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitOr, other); + Self::Expr(expr) + } +} + +impl BitXor for Elem { + type Output = Self; + + fn bitxor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitXor, other); + Self::Expr(expr) + } +} + +impl From for Elem { + fn from(idx: NodeIdx) -> Self { + Elem::Reference(Reference::new(idx)) + } +} + +impl Elem { pub fn is_negative( &self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let res = match self { Elem::Concrete(RangeConcrete { @@ -149,29 +312,77 @@ impl Elem { matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) } - pub fn maybe_concrete(&self) -> Option> { + pub fn inverse_if_boolean(&self) -> Option { match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, + Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), + Self::ConcreteDyn(_d) => None, + Self::Null => None, } } +} - pub fn maybe_concrete_value(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } +impl From for Elem { + fn from(c: Concrete) -> Self { + Elem::Concrete(RangeConcrete { + val: c, + loc: Loc::Implicit, + }) } +} + +impl From for Elem { + fn from(c: ContextVarNode) -> Self { + Elem::Reference(Reference::new(c.into())) + } +} - pub fn maybe_range_dyn(&self) -> Option> { +impl std::fmt::Display for Elem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Elem::ConcreteDyn(a) => Some(*a.clone()), - _ => None, + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::ConcreteDyn(..) => write!(f, "range_elem"), + Elem::Concrete(RangeConcrete { val, .. }) => { + write!(f, "{}", val.as_string()) + } + Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { + RangeOp::Min | RangeOp::Max => { + write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) + } + RangeOp::Cast => match &**rhs { + Elem::Concrete(RangeConcrete { val, .. }) => { + write!( + f, + "{}({}, {})", + op.to_string(), + lhs, + val.as_builtin().basic_as_string() + ) + } + _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), + }, + RangeOp::BitNot => { + write!(f, "~{}", lhs) + } + _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), + }, + _ => write!(f, ""), } } } impl RangeElem for Elem { + type GraphError = GraphError; + fn range_eq(&self, other: &Self) -> bool { match (self, other) { (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), @@ -190,7 +401,7 @@ impl RangeElem for Elem { fn flatten( &self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { match self { Self::Reference(d) => d.flatten(maximize, analyzer), @@ -201,7 +412,7 @@ impl RangeElem for Elem { } } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self) -> Vec { match self { Self::Reference(d) => d.dependent_on(), Self::Concrete(_) => vec![], @@ -211,7 +422,7 @@ impl RangeElem for Elem { } } - fn update_deps(&mut self, mapping: &BTreeMap) { + fn update_deps(&mut self, mapping: &BTreeMap) { match self { Self::Reference(d) => d.update_deps(mapping), Self::Concrete(_) => {} @@ -235,7 +446,7 @@ impl RangeElem for Elem { } } - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { use Elem::*; let res = match self { Reference(dy) => dy.maximize(analyzer)?, @@ -247,7 +458,7 @@ impl RangeElem for Elem { Ok(res) } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { use Elem::*; let res = match self { Reference(dy) => dy.minimize(analyzer)?, @@ -262,7 +473,7 @@ impl RangeElem for Elem { fn simplify_maximize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { use Elem::*; match self { @@ -277,7 +488,7 @@ impl RangeElem for Elem { fn simplify_minimize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { use Elem::*; match self { @@ -289,7 +500,7 @@ impl RangeElem for Elem { } } - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + fn cache_maximize(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { use Elem::*; match self { Reference(dy) => dy.cache_maximize(analyzer), @@ -300,7 +511,7 @@ impl RangeElem for Elem { } } - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + fn cache_minimize(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { use Elem::*; match self { Reference(dy) => dy.cache_minimize(analyzer), @@ -325,7 +536,7 @@ impl RangeElem for Elem { &self, max: bool, op_set: &[RangeOp], - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { use Elem::*; match self { @@ -358,13 +569,13 @@ impl Elem { /// Creates a logical AND of two range elements pub fn and(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::And, other); + let expr = RangeExpr::::new(self, RangeOp::And, other); Self::Expr(expr) } /// Creates a logical OR of two range elements pub fn or(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Or, other); + let expr = RangeExpr::::new(self, RangeOp::Or, other); Self::Expr(expr) } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs new file mode 100644 index 00000000..e7139743 --- /dev/null +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -0,0 +1,70 @@ +use crate::{GraphBackend, nodes::ContextVarNode, range::elem::{RangeExpr, RangeOp, Elem}}; + +use shared::NodeIdx; + +use std::collections::BTreeMap; + +pub trait RangeElem { + type GraphError; + /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables + fn flatten(&self, maximize: bool, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value + fn maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + /// Maximizes the element and caches the result for quicker use later + fn cache_maximize(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value + fn minimize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + /// Minimizes the element and caches the result for quicker use later + fn cache_minimize(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + /// Uncaches the minimum and maximum + fn uncache(&mut self); + /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) + fn simplify_maximize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError>; + /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) + fn simplify_minimize( + &self, + exclude: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError>; + /// Checks if two range elements are equal + fn range_eq(&self, other: &Self) -> bool; + /// Tries to compare the ordering of two range elements + fn range_ord(&self, other: &Self) -> Option; + /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). + fn range_op(lhs: Elem, rhs: Elem, op: RangeOp) -> Elem + where + Self: Sized, + { + Elem::Expr(RangeExpr::new(lhs, op, rhs)) + } + /// Traverses the range expression and finds all nodes that are dynamically pointed to + /// and returns it in a vector. + fn dependent_on(&self) -> Vec; + /// Traverses the range expression and updates stale pointers from older versions + /// of a variable to a newer version. + /// + /// e.g.: `uint256 z = x + 100`, followed by `require(x < 100)`. Initially, + /// without the `require` statement, `z`'s max is `2**256 - 1`, but with + /// the introduction of the `require` statement, we do a little backtracking + /// and can update `z`'s max to be `200`. + fn update_deps(&mut self, mapping: &BTreeMap); + /// Attempts to replace range elements that form a cyclic dependency by replacing + /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now + /// but in theory it can make sense. + /// + /// e.g.: take the basic expression `x + y`, in normal checked solidity math + /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a + /// cyclic dependency. + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); + + fn contains_op_set( + &self, + max: bool, + op_set: &[RangeOp], + analyzer: &impl GraphBackend, + ) -> Result; +} \ No newline at end of file diff --git a/crates/graph/src/range_impl/elem/expr.rs b/crates/graph/src/range/elem/expr.rs similarity index 92% rename from crates/graph/src/range_impl/elem/expr.rs rename to crates/graph/src/range/elem/expr.rs index 21984d9e..d71d626d 100644 --- a/crates/graph/src/range_impl/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -1,13 +1,15 @@ -use crate::{GraphError, nodes::{Concrete}}; +use crate::{ + GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, + range::{elem::{RangeElem, RangeOp, Elem, MinMaxed}, exec_traits::*} +}; -use range::{ exec::*, elem::{RangeElem, RangeOp, Elem, RangeExpr, MinMaxed}}; -use shared::{NodeIdx, GraphLike}; - -use ethers_core::types::{U256}; +use shared::{NodeIdx}; +use ethers_core::types::U256; use std::collections::BTreeMap; -static SINGLETON_EQ_OPS: &[RangeOp] = &[ + +pub static SINGLETON_EQ_OPS: &[RangeOp] = &[ RangeOp::Eq, RangeOp::Neq, RangeOp::Lt, @@ -16,7 +18,7 @@ static SINGLETON_EQ_OPS: &[RangeOp] = &[ RangeOp::Gte, ]; -static EQ_OPS: &[RangeOp] = &[ +pub static EQ_OPS: &[RangeOp] = &[ RangeOp::Eq, RangeOp::Neq, RangeOp::Lt, @@ -27,7 +29,18 @@ static EQ_OPS: &[RangeOp] = &[ RangeOp::Or, ]; -static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; +pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; + + +/// A range expression composed of other range [`Elem`] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeExpr { + pub maximized: Option>, + pub minimized: Option>, + pub lhs: Box>, + pub op: RangeOp, + pub rhs: Box>, +} impl RangeExpr { pub fn inverse_if_boolean(&self) -> Option { @@ -56,8 +69,25 @@ impl RangeExpr { } } +impl RangeExpr { + /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. + pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { + RangeExpr { + maximized: None, + minimized: None, + lhs: Box::new(lhs), + op, + rhs: Box::new(rhs), + } + } + + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) + } +} impl RangeElem for RangeExpr { + type GraphError = GraphError; fn range_eq(&self, _other: &Self) -> bool { false } @@ -65,7 +95,7 @@ impl RangeElem for RangeExpr { fn flatten( &self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Expr(RangeExpr::new( self.lhs.flatten(maximize, analyzer)?, @@ -78,13 +108,13 @@ impl RangeElem for RangeExpr { todo!() } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self) -> Vec { let mut deps = self.lhs.dependent_on(); deps.extend(self.rhs.dependent_on()); deps } - fn update_deps(&mut self, mapping: &BTreeMap) { + fn update_deps(&mut self, mapping: &BTreeMap) { self.lhs.update_deps(mapping); self.rhs.update_deps(mapping); } @@ -94,14 +124,14 @@ impl RangeElem for RangeExpr { self.rhs.filter_recursion(node_idx, new_idx); } - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { Ok(*cached) } else { self.exec_op(true, analyzer) } } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { Ok(*cached) } else { @@ -112,7 +142,7 @@ impl RangeElem for RangeExpr { fn simplify_maximize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let l = self.lhs.simplify_maximize(exclude, analyzer)?; let r = self.rhs.simplify_maximize(exclude, analyzer)?; @@ -128,7 +158,7 @@ impl RangeElem for RangeExpr { fn simplify_minimize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let l = self.lhs.simplify_minimize(exclude, analyzer)?; let r = self.rhs.simplify_minimize(exclude, analyzer)?; @@ -140,14 +170,14 @@ impl RangeElem for RangeExpr { } } - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { self.cache_exec_op(true, g)?; } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { self.cache_exec_op(false, g)?; } @@ -162,7 +192,7 @@ impl RangeElem for RangeExpr { &self, max: bool, op_set: &[RangeOp], - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { if op_set.contains(&self.op) { Ok(true) @@ -173,6 +203,7 @@ impl RangeElem for RangeExpr { } } + enum MaybeCollapsed { Collapsed(Elem), Not(Elem, Elem), diff --git a/crates/graph/src/range_impl/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs similarity index 72% rename from crates/graph/src/range_impl/elem/map_or_array.rs rename to crates/graph/src/range/elem/map_or_array.rs index d8919ae2..cbacbf12 100644 --- a/crates/graph/src/range_impl/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -1,11 +1,43 @@ -use crate::{GraphError, nodes::{ContextVarNode, Concrete}}; +use crate::{GraphBackend, GraphError, nodes::{ContextVarNode, Concrete}, range::elem::{RangeElem, RangeOp, MinMaxed, Elem}}; -use range::elem::{RangeElem, RangeOp, RangeDyn, MinMaxed, Elem}; -use shared::{NodeIdx, GraphLike}; +use shared::NodeIdx; + +use solang_parser::pt::Loc; use std::collections::BTreeMap; +/// A concrete value for a range element +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RangeDyn { + /// Cached minimized value + pub minimized: Option>, + /// Cached maximized value + pub maximized: Option>, + /// Length of the dynamic variable + pub len: Elem, + /// Values of the dynamic variable + pub val: BTreeMap, Elem>, + /// Sourcecode location + pub loc: Loc, +} +impl RangeDyn { + /// Set the length + pub fn set_len(&mut self, new_len: Elem) { + self.len = new_len; + } + + /// Check if the node contains a reference to a node index + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + self.len.contains_node(node_idx) + // || self.val.iter().any(|(k, v)| k.contains_node(node_idx) || v.contains_node(node_idx)) + } +} + + + impl RangeElem for RangeDyn { + type GraphError = GraphError; + fn range_eq(&self, _other: &Self) -> bool { false } @@ -14,7 +46,7 @@ impl RangeElem for RangeDyn { None } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self) -> Vec { let mut deps: Vec = self.len.dependent_on(); deps.extend( self.val @@ -28,7 +60,7 @@ impl RangeElem for RangeDyn { fn flatten( &self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, @@ -45,7 +77,7 @@ impl RangeElem for RangeDyn { }))) } - fn update_deps(&mut self, mapping: &BTreeMap) { + fn update_deps(&mut self, mapping: &BTreeMap) { self.len.update_deps(mapping); self.val .iter_mut() @@ -66,7 +98,7 @@ impl RangeElem for RangeDyn { .collect(); } - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { return Ok(*cached); } @@ -86,7 +118,7 @@ impl RangeElem for RangeDyn { }))) } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { return Ok(*cached); } @@ -109,7 +141,7 @@ impl RangeElem for RangeDyn { fn simplify_maximize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, @@ -128,7 +160,7 @@ impl RangeElem for RangeDyn { fn simplify_minimize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, @@ -145,14 +177,14 @@ impl RangeElem for RangeDyn { }))) } - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); } @@ -168,9 +200,9 @@ impl RangeElem for RangeDyn { &self, _max: bool, _op_set: &[RangeOp], - _: &impl GraphLike, + _: &impl GraphBackend, ) -> Result { // TODO: reevaluate this Ok(false) } -} \ No newline at end of file +} diff --git a/crates/range/src/elem/mod.rs b/crates/graph/src/range/elem/mod.rs similarity index 53% rename from crates/range/src/elem/mod.rs rename to crates/graph/src/range/elem/mod.rs index 47d6dff4..06a596e3 100644 --- a/crates/range/src/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -1,18 +1,16 @@ -use shared::NodeIdx; -use shared::GraphLike; -use std::collections::BTreeMap; - mod concrete; mod elem_enum; mod expr; mod map_or_array; mod reference; +mod elem_trait; pub use concrete::*; pub use elem_enum::*; pub use expr::*; pub use map_or_array::*; pub use reference::*; +pub use elem_trait::*; #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -163,68 +161,3 @@ impl ToString for RangeOp { } } } - -pub trait RangeElem { - type GraphError; - /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables - fn flatten(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, Self::GraphError>; - /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value - fn maximize(&self, analyzer: &impl GraphLike) -> Result, Self::GraphError>; - /// Maximizes the element and caches the result for quicker use later - fn cache_maximize(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; - /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value - fn minimize(&self, analyzer: &impl GraphLike) -> Result, Self::GraphError>; - /// Minimizes the element and caches the result for quicker use later - fn cache_minimize(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; - /// Uncaches the minimum and maximum - fn uncache(&mut self); - /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) - fn simplify_maximize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, Self::GraphError>; - /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) - fn simplify_minimize( - &self, - exclude: &mut Vec, - analyzer: &impl GraphLike, - ) -> Result, Self::GraphError>; - /// Checks if two range elements are equal - fn range_eq(&self, other: &Self) -> bool; - /// Tries to compare the ordering of two range elements - fn range_ord(&self, other: &Self) -> Option; - /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). - fn range_op(lhs: Elem, rhs: Elem, op: RangeOp) -> Elem - where - Self: Sized, - { - Elem::Expr(RangeExpr::new(lhs, op, rhs)) - } - /// Traverses the range expression and finds all nodes that are dynamically pointed to - /// and returns it in a vector. - fn dependent_on(&self) -> Vec; - /// Traverses the range expression and updates stale pointers from older versions - /// of a variable to a newer version. - /// - /// e.g.: `uint256 z = x + 100`, followed by `require(x < 100)`. Initially, - /// without the `require` statement, `z`'s max is `2**256 - 1`, but with - /// the introduction of the `require` statement, we do a little backtracking - /// and can update `z`'s max to be `200`. - fn update_deps(&mut self, mapping: &BTreeMap); - /// Attempts to replace range elements that form a cyclic dependency by replacing - /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now - /// but in theory it can make sense. - /// - /// e.g.: take the basic expression `x + y`, in normal checked solidity math - /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a - /// cyclic dependency. - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphLike, - ) -> Result; -} diff --git a/crates/graph/src/range_impl/elem/reference.rs b/crates/graph/src/range/elem/reference.rs similarity index 78% rename from crates/graph/src/range_impl/elem/reference.rs rename to crates/graph/src/range/elem/reference.rs index 69a0b524..88131d37 100644 --- a/crates/graph/src/range_impl/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -1,12 +1,35 @@ -use crate::{GraphError, nodes::{ContextVarNode, Concrete}, TypeNode, VarType}; +use crate::{GraphBackend, GraphError, nodes::{ContextVarNode, Concrete}, TypeNode, VarType, range::{Range, elem::{RangeElem, RangeConcrete, RangeOp, MinMaxed, Elem}}}; -use range::elem::{RangeElem, RangeConcrete, RangeOp, MinMaxed, Elem, Reference}; -use shared::{NodeIdx, GraphLike}; +use shared::NodeIdx; use solang_parser::pt::Loc; use std::collections::BTreeMap; + +/// A dynamic range element value +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct Reference { + /// Index of the node that is referenced + pub idx: NodeIdx, + /// Cached minimized value + pub minimized: Option>, + /// Cached maximized value + pub maximized: Option>, +} + +impl Reference { + pub fn new(idx: NodeIdx) -> Self { + Self { + idx, + minimized: None, + maximized: None, + } + } +} + impl RangeElem for Reference { + type GraphError = GraphError; + fn range_eq(&self, _other: &Self) -> bool { false } @@ -19,20 +42,20 @@ impl RangeElem for Reference { } } - fn dependent_on(&self) -> Vec { - vec![self.idx] + fn dependent_on(&self) -> Vec { + vec![self.idx.into()] } - fn update_deps(&mut self, mapping: &BTreeMap) { - if let Some(new) = mapping.get(self.idx) { - self.idx = new; + fn update_deps(&mut self, mapping: &BTreeMap) { + if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { + self.idx = new.0.into(); } } fn flatten( &self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); if cvar.is_independent_and_storage_or_calldata(analyzer)? { @@ -55,7 +78,7 @@ impl RangeElem for Reference { fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} - fn maximize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { return Ok(*cached); } @@ -80,7 +103,7 @@ impl RangeElem for Reference { } } - fn minimize(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { return Ok(*cached); } @@ -108,7 +131,7 @@ impl RangeElem for Reference { fn simplify_maximize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); @@ -126,7 +149,7 @@ impl RangeElem for Reference { fn simplify_minimize( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); if cvar.is_independent_and_storage_or_calldata(analyzer)? { @@ -139,14 +162,14 @@ impl RangeElem for Reference { } } - fn cache_maximize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphLike) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); } @@ -162,7 +185,7 @@ impl RangeElem for Reference { &self, max: bool, op_set: &[RangeOp], - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; match &cvar.ty { diff --git a/crates/graph/src/range_impl/exec/add.rs b/crates/graph/src/range/exec/add.rs similarity index 99% rename from crates/graph/src/range_impl/exec/add.rs rename to crates/graph/src/range/exec/add.rs index 0999fbfc..571d4788 100644 --- a/crates/graph/src/range_impl/exec/add.rs +++ b/crates/graph/src/range/exec/add.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256, U256}; diff --git a/crates/graph/src/range_impl/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs similarity index 99% rename from crates/graph/src/range_impl/exec/bitwise.rs rename to crates/graph/src/range/exec/bitwise.rs index 097e4f07..e437439b 100644 --- a/crates/graph/src/range_impl/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{H256, U256}; impl RangeBitwise for RangeConcrete { diff --git a/crates/graph/src/range_impl/exec/cast.rs b/crates/graph/src/range/exec/cast.rs similarity index 99% rename from crates/graph/src/range_impl/exec/cast.rs rename to crates/graph/src/range/exec/cast.rs index 11f4658b..e5da78ed 100644 --- a/crates/graph/src/range_impl/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{H256, U256}; use std::collections::BTreeMap; diff --git a/crates/graph/src/range_impl/exec/concat.rs b/crates/graph/src/range/exec/concat.rs similarity index 99% rename from crates/graph/src/range_impl/exec/concat.rs rename to crates/graph/src/range/exec/concat.rs index e2e14815..75e26c5f 100644 --- a/crates/graph/src/range_impl/exec/concat.rs +++ b/crates/graph/src/range/exec/concat.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{H256, U256}; use std::collections::BTreeMap; diff --git a/crates/graph/src/range_impl/exec/div.rs b/crates/graph/src/range/exec/div.rs similarity index 98% rename from crates/graph/src/range_impl/exec/div.rs rename to crates/graph/src/range/exec/div.rs index ebbd16f8..11c3f32c 100644 --- a/crates/graph/src/range_impl/exec/div.rs +++ b/crates/graph/src/range/exec/div.rs @@ -1,7 +1,7 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; -use ethers_core::types::{H256, I256, U256}; +use ethers_core::types::{I256, U256}; impl RangeDiv for RangeConcrete { fn range_div(&self, other: &Self) -> Option> { diff --git a/crates/graph/src/range_impl/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs similarity index 99% rename from crates/graph/src/range_impl/exec/exec_op.rs rename to crates/graph/src/range/exec/exec_op.rs index a44d8edf..ea50e212 100644 --- a/crates/graph/src/range_impl/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -1,16 +1,16 @@ -use crate::{GraphError, nodes::Concrete}; +use crate::{GraphBackend, GraphError, nodes::Concrete, range::{elem::*, exec_traits::*}}; -use shared::{NodeIdx, GraphLike}; -use range::{elem::*, exec::*}; +use shared::NodeIdx; use ethers_core::types::{ I256, U256 }; use solang_parser::pt::Loc; impl ExecOp for RangeExpr { + type GraphError = GraphError; fn cache_exec_op( &mut self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result<(), GraphError> { self.lhs.cache_minimize(analyzer)?; self.lhs.cache_maximize(analyzer)?; @@ -34,7 +34,7 @@ impl ExecOp for RangeExpr { &self, maximize: bool, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { let (parts, lhs_is_conc) = self.simplify_spread(exclude, analyzer)?; if self.op == RangeOp::Cast { @@ -57,7 +57,7 @@ impl ExecOp for RangeExpr { fn spread( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result< ( Elem, @@ -77,7 +77,7 @@ impl ExecOp for RangeExpr { fn simplify_spread( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result< ( ( diff --git a/crates/graph/src/range_impl/exec/exp.rs b/crates/graph/src/range/exec/exp.rs similarity index 97% rename from crates/graph/src/range_impl/exec/exp.rs rename to crates/graph/src/range/exec/exp.rs index c89d1697..70cb4dd9 100644 --- a/crates/graph/src/range_impl/exec/exp.rs +++ b/crates/graph/src/range/exec/exp.rs @@ -1,6 +1,6 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; -use ethers_core::types::{H256, U256}; +use crate::range::{elem::*, exec_traits::*}; +use ethers_core::types::U256; impl RangeExp for RangeConcrete { fn range_exp(&self, other: &Self) -> Option> { diff --git a/crates/graph/src/range_impl/exec/logical.rs b/crates/graph/src/range/exec/logical.rs similarity index 97% rename from crates/graph/src/range_impl/exec/logical.rs rename to crates/graph/src/range/exec/logical.rs index f3f57ed1..93befcd9 100644 --- a/crates/graph/src/range_impl/exec/logical.rs +++ b/crates/graph/src/range/exec/logical.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; impl RangeUnary for RangeConcrete { fn range_not(&self) -> Option> { diff --git a/crates/graph/src/range_impl/exec/max.rs b/crates/graph/src/range/exec/max.rs similarity index 97% rename from crates/graph/src/range_impl/exec/max.rs rename to crates/graph/src/range/exec/max.rs index ae0676d8..646f7b2d 100644 --- a/crates/graph/src/range_impl/exec/max.rs +++ b/crates/graph/src/range/exec/max.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; impl RangeMax for RangeConcrete { fn range_max(&self, other: &Self) -> Option> { diff --git a/crates/graph/src/range_impl/exec/min.rs b/crates/graph/src/range/exec/min.rs similarity index 97% rename from crates/graph/src/range_impl/exec/min.rs rename to crates/graph/src/range/exec/min.rs index a350532c..761b34d5 100644 --- a/crates/graph/src/range_impl/exec/min.rs +++ b/crates/graph/src/range/exec/min.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; impl RangeMin for RangeConcrete { fn range_min(&self, other: &Self) -> Option> { diff --git a/crates/graph/src/range_impl/exec/mod.rs b/crates/graph/src/range/exec/mod.rs similarity index 100% rename from crates/graph/src/range_impl/exec/mod.rs rename to crates/graph/src/range/exec/mod.rs diff --git a/crates/graph/src/range_impl/exec/modulo.rs b/crates/graph/src/range/exec/modulo.rs similarity index 97% rename from crates/graph/src/range_impl/exec/modulo.rs rename to crates/graph/src/range/exec/modulo.rs index 7080c027..a021a8ac 100644 --- a/crates/graph/src/range_impl/exec/modulo.rs +++ b/crates/graph/src/range/exec/modulo.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256}; diff --git a/crates/graph/src/range_impl/exec/mul.rs b/crates/graph/src/range/exec/mul.rs similarity index 99% rename from crates/graph/src/range_impl/exec/mul.rs rename to crates/graph/src/range/exec/mul.rs index f07a704a..a671ee9e 100644 --- a/crates/graph/src/range_impl/exec/mul.rs +++ b/crates/graph/src/range/exec/mul.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256, U256}; diff --git a/crates/graph/src/range_impl/exec/ord.rs b/crates/graph/src/range/exec/ord.rs similarity index 99% rename from crates/graph/src/range_impl/exec/ord.rs rename to crates/graph/src/range/exec/ord.rs index 1d45a259..04364730 100644 --- a/crates/graph/src/range_impl/exec/ord.rs +++ b/crates/graph/src/range/exec/ord.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; diff --git a/crates/graph/src/range_impl/exec/shift.rs b/crates/graph/src/range/exec/shift.rs similarity index 99% rename from crates/graph/src/range_impl/exec/shift.rs rename to crates/graph/src/range/exec/shift.rs index ccb2d414..f33e473e 100644 --- a/crates/graph/src/range_impl/exec/shift.rs +++ b/crates/graph/src/range/exec/shift.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256, U256}; diff --git a/crates/graph/src/range_impl/exec/sub.rs b/crates/graph/src/range/exec/sub.rs similarity index 99% rename from crates/graph/src/range_impl/exec/sub.rs rename to crates/graph/src/range/exec/sub.rs index 4fe990b6..1a32dd4d 100644 --- a/crates/graph/src/range_impl/exec/sub.rs +++ b/crates/graph/src/range/exec/sub.rs @@ -1,5 +1,5 @@ use crate::nodes::Concrete; -use range::{elem::*, exec::*}; +use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256, U256}; diff --git a/crates/range/src/exec.rs b/crates/graph/src/range/exec_traits.rs similarity index 93% rename from crates/range/src/exec.rs rename to crates/graph/src/range/exec_traits.rs index fae51a64..3fdc67ce 100644 --- a/crates/range/src/exec.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,14 +1,14 @@ +use crate::{GraphBackend, range::elem::Elem}; use shared::NodeIdx; -use shared::GraphLike; -use crate::elem::Elem; + /// For execution of operations to be performed on range expressions pub trait ExecOp { type GraphError; /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side /// and right-hand-side - fn exec_op(&self, maximize: bool, analyzer: &impl GraphLike) -> Result, Self::GraphError> { + fn exec_op(&self, maximize: bool, analyzer: &impl GraphBackend) -> Result, Self::GraphError> { self.exec(self.spread(analyzer)?, maximize) } @@ -21,18 +21,18 @@ pub trait ExecOp { fn cache_exec_op( &mut self, maximize: bool, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result<(), Self::GraphError>; fn spread( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; fn simplify_spread( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result<((Elem, Elem, Elem, Elem), bool), Self::GraphError>; fn uncache_exec(&mut self); @@ -41,7 +41,7 @@ pub trait ExecOp { &self, maximize: bool, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Attempts to simplify an expression (i.e. just apply constant folding) diff --git a/crates/graph/src/range/mod.rs b/crates/graph/src/range/mod.rs new file mode 100644 index 00000000..54932657 --- /dev/null +++ b/crates/graph/src/range/mod.rs @@ -0,0 +1,11 @@ +pub mod exec_traits; +pub mod elem; +pub mod exec; +pub mod range_string; +mod range_trait; +mod solc_range; + +pub use range_trait::*; +pub use solc_range::*; + + diff --git a/crates/graph/src/range_impl/range_string.rs b/crates/graph/src/range/range_string.rs similarity index 83% rename from crates/graph/src/range_impl/range_string.rs rename to crates/graph/src/range/range_string.rs index 94c8abfa..d9941996 100644 --- a/crates/graph/src/range_impl/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -1,14 +1,50 @@ -use crate::nodes::{Concrete, ContextVarNode}; +use crate::{ + GraphBackend, + nodes::{Concrete, ContextVarNode}, + range::elem::*, +}; +use solang_parser::pt::Loc; +use std::collections::BTreeMap; -use range::{elem::*, range_string::*}; -use shared::GraphLike; +/// A range element string consisting of a string and a location +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct RangeElemString { + pub s: String, + pub loc: Loc, +} -use solang_parser::pt::Loc; +impl RangeElemString { + /// Creates a new range element string from a string and a location + pub fn new(s: String, loc: Loc) -> Self { + Self { s, loc } + } +} + +/// A range string consisting of stringified range elements +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct RangeString { + pub min: RangeElemString, + pub max: RangeElemString, +} + +impl RangeString { + /// Creates a new range string from a min and max [`RangeElemString`] + pub fn new(min: RangeElemString, max: RangeElemString) -> Self { + Self { min, max } + } +} + +/// String related functions for ranges +pub trait ToRangeString { + /// Gets the definition string of the range element + fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString; + /// Converts a range to a human string + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString; +} -use std::collections::BTreeMap; impl ToRangeString for Elem { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), Elem::Reference(Reference { idx, .. }) => { @@ -24,7 +60,7 @@ impl ToRangeString for Elem { } } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), Elem::Reference(Reference { idx, .. }) => { @@ -40,7 +76,7 @@ impl ToRangeString for Elem { } impl ToRangeString for RangeDyn { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { let displayed_vals = self .val .iter() @@ -70,7 +106,7 @@ impl ToRangeString for RangeDyn { ) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { let val_str = if self.val.len() > 10 { let displayed_vals = self .val @@ -162,11 +198,11 @@ impl ToRangeString for RangeDyn { } impl ToRangeString for RangeExpr { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { self.lhs.def_string(analyzer) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); let lhs_str = match *self.lhs { Elem::Expr(_) => { diff --git a/crates/range/src/lib.rs b/crates/graph/src/range/range_trait.rs similarity index 73% rename from crates/range/src/lib.rs rename to crates/graph/src/range/range_trait.rs index 3139410d..f4314b9d 100644 --- a/crates/range/src/lib.rs +++ b/crates/graph/src/range/range_trait.rs @@ -1,31 +1,26 @@ -use crate::elem::RangeElem; -use shared::{ NodeIdx, GraphLike }; - -pub mod elem; -pub mod exec; -pub mod range_string; - +use crate::{GraphBackend, range::elem::RangeElem}; +use shared::NodeIdx; pub trait Range { type GraphError; type ElemTy: RangeElem + Clone; /// Evaluate both the minimum and the maximum - cache along the way - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), Self::GraphError>; + fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Evaluate the range minimum - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result; + fn evaled_range_min(&self, analyzer: &impl GraphBackend) -> Result; /// Evaluate the range maximum - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result; + fn evaled_range_max(&self, analyzer: &impl GraphBackend) -> Result; /// Simplify the minimum, leaving references in place fn simplified_range_min( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result; /// Simplify the maximum, leaving references in place fn simplified_range_max( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result; /// Return the range minimum fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; @@ -66,11 +61,11 @@ pub trait Range { } pub trait RangeEval>: Range { - fn sat(&self, analyzer: &impl GraphLike) -> bool; - fn unsat(&self, analyzer: &impl GraphLike) -> bool { + fn sat(&self, analyzer: &impl GraphBackend) -> bool; + fn unsat(&self, analyzer: &impl GraphBackend) -> bool { !self.sat(analyzer) } - fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool; - fn contains_elem(&self, other: &T, analyzer: &impl GraphLike) -> bool; - fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool; + fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; + fn contains_elem(&self, other: &T, analyzer: &impl GraphBackend) -> bool; + fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; } \ No newline at end of file diff --git a/crates/graph/src/range_impl/solc_range.rs b/crates/graph/src/range/solc_range.rs similarity index 94% rename from crates/graph/src/range_impl/solc_range.rs rename to crates/graph/src/range/solc_range.rs index 3d55dbe6..ea499259 100644 --- a/crates/graph/src/range_impl/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -1,8 +1,10 @@ -use crate::nodes::{Builtin, Concrete}; -use crate::{GraphError, nodes::{ContextVarNode, ContextNode}}; +use crate::{ + AsDotStr, GraphBackend, GraphError, + nodes::{ContextVarNode, ContextNode, Builtin, Concrete}, + range::{RangeEval, Range, elem::*, range_string::*} +}; -use shared::{AsDotStr, GraphLike, NodeIdx}; -use range::{RangeEval, Range, elem::*, range_string::*}; +use shared::NodeIdx; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; @@ -19,7 +21,7 @@ pub struct SolcRange { } impl AsDotStr for SolcRange { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { format!( "[{}, {}] excluding: [{}]", self.evaled_range_min(analyzer) @@ -66,21 +68,21 @@ impl SolcRange { } /// Update a particular context variable with the latest version - pub fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphLike) { + pub fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphBackend) { let deps = self.dependent_on(); - let mapping: BTreeMap = deps + let mapping: BTreeMap = deps .into_iter() .filter(|dep| !dep.is_const(analyzer).unwrap()) .map(|dep| { let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); if latest == node { if let Some(prev) = latest.previous_version(analyzer) { - (dep.0.into(), prev.0.into()) + (dep, prev) } else { - (dep.0.into(), dep.0.into()) + (dep, dep) } } else { - (dep.0.into(), latest.0.into()) + (dep, latest) } }) .collect(); @@ -110,13 +112,13 @@ impl SolcRange { self.max_cached = None; } - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { let min = self.evaled_range_min(analyzer)?; let max = self.evaled_range_max(analyzer)?; Ok(min.range_eq(&max)) } - pub fn min_is_negative(&self, analyzer: &impl GraphLike) -> Result { + pub fn min_is_negative(&self, analyzer: &impl GraphBackend) -> Result { self.min.is_negative(false, analyzer) } @@ -551,7 +553,7 @@ impl SolcRange { Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) } - pub fn into_flattened_range(&self, analyzer: &impl GraphLike) -> Result { + pub fn into_flattened_range(&self, analyzer: &impl GraphBackend) -> Result { // println!("----- into flattened range -----"); let flattened_min = self.range_min().flatten(false, analyzer)?; // println!("flattened minimum: {}", flattened_min); @@ -569,6 +571,7 @@ impl SolcRange { } impl Range for SolcRange { + type GraphError = GraphError; type ElemTy = Elem; fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy> { std::borrow::Cow::Borrowed(&self.min) @@ -583,7 +586,7 @@ impl Range for SolcRange { &mut self.max } - fn cache_eval(&mut self, analyzer: &impl GraphLike) -> Result<(), GraphError> { + fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { if self.min_cached.is_none() { let min = self.range_min_mut(); min.cache_minimize(analyzer)?; @@ -597,7 +600,7 @@ impl Range for SolcRange { Ok(()) } - fn evaled_range_min(&self, analyzer: &impl GraphLike) -> Result { + fn evaled_range_min(&self, analyzer: &impl GraphBackend) -> Result { if let Some(cached) = &self.min_cached { Ok(cached.clone()) } else { @@ -605,7 +608,7 @@ impl Range for SolcRange { } } - fn evaled_range_max(&self, analyzer: &impl GraphLike) -> Result { + fn evaled_range_max(&self, analyzer: &impl GraphBackend) -> Result { if let Some(cached) = &self.max_cached { Ok(cached.clone()) } else { @@ -616,7 +619,7 @@ impl Range for SolcRange { fn simplified_range_min( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { self.range_min() .flatten(false, analyzer)? @@ -625,7 +628,7 @@ impl Range for SolcRange { fn simplified_range_max( &self, exclude: &mut Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { self.range_max() .flatten(true, analyzer)? @@ -661,7 +664,7 @@ impl Range for SolcRange { } impl RangeEval> for SolcRange { - fn sat(&self, analyzer: &impl GraphLike) -> bool { + fn sat(&self, analyzer: &impl GraphBackend) -> bool { matches!( self.evaled_range_min(analyzer) .unwrap() @@ -670,7 +673,7 @@ impl RangeEval> for SolcRange { ) } - fn contains(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { let min_contains = matches!( self.evaled_range_min(analyzer) .unwrap() @@ -688,7 +691,7 @@ impl RangeEval> for SolcRange { min_contains && max_contains } - fn contains_elem(&self, other: &Elem, analyzer: &impl GraphLike) -> bool { + fn contains_elem(&self, other: &Elem, analyzer: &impl GraphBackend) -> bool { let min_contains = match self .evaled_range_min(analyzer) .unwrap() @@ -712,7 +715,7 @@ impl RangeEval> for SolcRange { min_contains && max_contains } - fn overlaps(&self, other: &Self, analyzer: &impl GraphLike) -> bool { + fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { let lhs_min = self.evaled_range_min(analyzer).unwrap(); let rhs_max = other.evaled_range_max(analyzer).unwrap(); diff --git a/crates/graph/src/range_impl/elem/mod.rs b/crates/graph/src/range_impl/elem/mod.rs deleted file mode 100644 index eba17406..00000000 --- a/crates/graph/src/range_impl/elem/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod concrete; -mod elem_enum; -mod expr; -mod map_or_array; -mod reference; - -pub use concrete::*; -pub use elem_enum::*; -pub use expr::*; -pub use map_or_array::*; -pub use reference::*; diff --git a/crates/graph/src/range_impl/mod.rs b/crates/graph/src/range_impl/mod.rs deleted file mode 100644 index 89b8850e..00000000 --- a/crates/graph/src/range_impl/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod elem; -mod exec; -mod range_string; -mod solc_range; - -pub use solc_range::SolcRange; \ No newline at end of file diff --git a/crates/graph/src/search.rs b/crates/graph/src/search.rs deleted file mode 100644 index 1f860aa9..00000000 --- a/crates/graph/src/search.rs +++ /dev/null @@ -1,267 +0,0 @@ - -impl Search for T where T: GraphLike {} - - -/// A trait for searching through a graph -pub trait Search: GraphLike { - /// Given a start node, search for an ancestor via an edge type - fn search_for_ancestor(&self, start: NodeIdx, edge_ty: &Edge) -> Option { - let edges = self.graph().edges_directed(start, Direction::Outgoing); - if let Some(edge) = edges.clone().find(|edge| edge.weight() == edge_ty) { - Some(edge.target()) - } else { - edges - .map(|edge| edge.target()) - .filter_map(|node| self.search_for_ancestor(node, edge_ty)) - .take(1) - .next() - } - } - - /// Given a start node, search for an ancestor via a set of edge types - fn search_for_ancestor_multi(&self, start: NodeIdx, edge_tys: &[Edge]) -> Option { - let edges = self.graph().edges_directed(start, Direction::Outgoing); - if let Some(edge) = edges.clone().find(|edge| edge_tys.contains(edge.weight())) { - Some(edge.target()) - } else { - edges - .map(|edge| edge.target()) - .filter_map(|node| self.search_for_ancestor_multi(node, edge_tys)) - .take(1) - .next() - } - } - /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a set of these - /// - /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d - /// - /// This function would build a set { b, d } if we are looking for `my_edge` and start at a. - fn search_children(&self, start: NodeIdx, edge_ty: &Edge) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .flat_map(|edge| self.search_children(edge.source(), edge_ty)) - .collect::>(), - ); - this_children - } - - fn find_child_exclude_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - exclude_edges: &[Edge], - find_fn: &impl Fn(NodeIdx, &Self) -> Option, - ) -> Option { - let edges = self - .graph() - .edges_directed(start, Direction::Incoming) - .filter(|edge| !exclude_edges.contains(edge.weight())); - if let Some(node) = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .find(|node| find_fn(*node, self).is_some()) - { - Some(node) - } else { - edges - .clone() - .map(|edge| edge.source()) - .find_map(|node| self.find_child_exclude_via(node, edge_ty, exclude_edges, find_fn)) - } - } - - fn search_children_exclude_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - exclude_edges: &[Edge], - ) -> BTreeSet { - let edges = self - .graph() - .edges_directed(start, Direction::Incoming) - .filter(|edge| !exclude_edges.contains(edge.weight())); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .flat_map(|edge| { - self.search_children_exclude_via(edge.source(), edge_ty, exclude_edges) - }) - .collect::>(), - ); - this_children - } - - fn search_children_include_via( - &self, - start: NodeIdx, - edge_ty: &Edge, - include_edges: &[Edge], - ) -> BTreeSet { - let mut edges: Vec<_> = self - .graph() - .edges_directed(start, Direction::Incoming) - .collect(); - edges = edges - .into_iter() - .filter(|edge| include_edges.contains(edge.weight())) - .collect::>(); - let mut this_children: BTreeSet = edges - .iter() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - this_children.extend( - edges - .clone() - .iter() - .flat_map(|edge| { - self.search_children_include_via(edge.source(), edge_ty, include_edges) - }) - .collect::>(), - ); - this_children - } - - fn search_children_depth( - &self, - start: NodeIdx, - edge_ty: &Edge, - max_depth: usize, - curr_depth: usize, - ) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - if curr_depth < max_depth { - this_children.extend( - edges - .flat_map(|edge| { - self.search_children_depth( - edge.source(), - edge_ty, - max_depth, - curr_depth + 1, - ) - }) - .collect::>(), - ); - } - this_children - } - - /// Gets all children recursively - fn children(&self, start: NodeIdx) -> BTreeSet { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children: BTreeSet = - edges.clone().map(|edge| edge.source()).collect(); - - this_children.extend( - edges - .flat_map(|edge| self.children(edge.source())) - .collect::>(), - ); - this_children - } - - /// Gets all children edges recursively - fn children_edges( - &self, - start: NodeIdx, - ) -> BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children_edges: BTreeSet<(NodeIdx, NodeIdx, Edge, EdgeIndex)> = edges - .clone() - .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) - .collect(); - - this_children_edges.extend( - edges - .flat_map(|edge| self.children_edges(edge.source())) - .collect::)>>(), - ); - this_children_edges - } - - /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a mapping of these - /// - /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d - /// - /// This function would build a map { a: [b], c: [d] } if we are looking for `my_edge` and start at a. - fn nodes_with_children( - &self, - start: NodeIdx, - edge_ty: &Edge, - ) -> Option>> { - let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut map: BTreeMap> = Default::default(); - - let this_children: BTreeSet = edges - .clone() - .filter_map(|edge| { - if edge.weight() == edge_ty { - Some(edge.source()) - } else { - None - } - }) - .collect(); - - if !this_children.is_empty() { - map.insert(start, this_children); - } - map.extend( - edges - .filter_map(|edge| self.nodes_with_children(edge.source(), edge_ty)) - .flatten() - .collect::>>(), - ); - if map.is_empty() { - None - } else { - Some(map) - } - } -} \ No newline at end of file diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index a20f7e35..a0d70a08 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -1,19 +1,19 @@ -use crate::nodes::Concrete; -use crate::nodes::ContextVarNode; - -use range::{ - elem::{ - RangeElem, - RangeOp, - Elem, - RangeExpr, - Reference +use crate::{ + GraphBackend, + nodes::{Concrete, ContextVarNode}, + range::{ + elem::{ + RangeElem, + RangeOp, + Elem, + RangeExpr, + Reference + }, + range_string::{ToRangeString, RangeElemString}, }, - range_string::{ToRangeString, RangeElemString} }; -use shared::GraphLike; use ethers_core::types::U256; use std::collections::BTreeMap; @@ -128,10 +128,10 @@ pub struct SolverAtom { } impl ToRangeString for SolverAtom { - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString { + fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { self.into_expr_elem().def_string(analyzer) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString { + fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { self.into_expr_elem().to_range_string(maximize, analyzer) } } diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index d1e8b740..83828341 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -1,26 +1,25 @@ -use petgraph::stable_graph::StableGraph; - -use crate::GraphError; -use range::elem::RangeElem; -use range::elem::; -use range::elem_ty::Elem; -use crate::solvers::AtomOrPart; -use crate::solvers::Atomize; -use crate::solvers::OpType; -use crate::solvers::SolverAtom; -use crate::Concrete; -use crate::ContextVarNode; -use crate::GraphLike; -use ethers_core::types::I256; -use ethers_core::types::U256; +use crate::{ + GraphBackend, GraphError, + nodes::{Concrete, ContextVarNode}, + range::elem::*, + solvers::{AtomOrPart, Atomize, OpType, SolverAtom}, +}; + +use ethers_core::types::{U256, I256}; use itertools::Itertools; -use petgraph::graph::NodeIndex; -use petgraph::visit::EdgeRef; -use petgraph::visit::IntoNodeIdentifiers; -use petgraph::visit::NodeIndexable; -use petgraph::visit::VisitMap; -use petgraph::visit::Visitable; -use petgraph::Directed; +use petgraph::{ + stable_graph::StableGraph, + graph::NodeIndex, + visit::{ + EdgeRef, + IntoNodeIdentifiers, + NodeIndexable, + VisitMap, + Visitable, + }, + Directed +}; + use std::collections::BTreeMap; pub type DLGraph = StableGraph; @@ -204,7 +203,7 @@ impl DLSolver { self.normalized_constraints.values().cloned().collect() } - pub fn solve_partial(&mut self, analyzer: &impl GraphLike) -> Result { + pub fn solve_partial(&mut self, analyzer: &impl GraphBackend) -> Result { let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { let deps = constraint.dependent_on(); @@ -364,7 +363,7 @@ impl DLSolver { pub fn dl_solve( &mut self, normalized_constraints: Vec, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { let mut added_atoms = vec![]; let mut added_deps = vec![]; @@ -833,7 +832,7 @@ impl DLSolver { pub fn find_negative_cycle( g: &DLGraph, source: NodeIndex, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Option>> { let ix = |i| g.to_index(i); let mut path = Vec::>::new(); @@ -907,7 +906,7 @@ pub fn find_negative_cycle( fn bellman_ford_initialize_relax( g: &DLGraph, source: NodeIndex, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> (Vec>, Vec>>) { // Step 1: initialize graph let mut predecessor = vec![None; g.node_bound()]; diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index a2678ce1..2b59199c 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -1,5 +1,16 @@ +use crate::{ + AnalyzerBackend, GraphBackend, AsDotStr, + range::{elem::{Elem, Reference, RangeElem}, Range, SolcRange}, + GraphError, Node, + nodes::{ + ContextVarNode, FunctionNode, TyNode, BuiltInNode, + ConcreteNode, Builtin, Concrete, StructNode, EnumNode, ContractNode + } +}; +use shared::NodeIdx; +use ethers_core::types::{Address, U256, H256}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum VarType { @@ -9,7 +20,7 @@ pub enum VarType { } impl AsDotStr for VarType { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { self.as_string(analyzer).unwrap() } } @@ -30,7 +41,7 @@ impl VarType { } } - pub fn possible_builtins_from_ty_inf(&self, analyzer: &impl GraphLike) -> Vec { + pub fn possible_builtins_from_ty_inf(&self, analyzer: &impl GraphBackend) -> Vec { match self { Self::BuiltIn(bn, _) => bn .underlying(analyzer) @@ -52,14 +63,14 @@ impl VarType { } } - pub fn is_dyn_builtin(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_dyn_builtin(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => node.is_dyn(analyzer), _ => Ok(false), } } - pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { + pub fn unresolved_as_resolved(&self, analyzer: &impl GraphBackend) -> Result { match self { VarType::User(TypeNode::Unresolved(n), _) => match analyzer.node(*n) { Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( @@ -82,54 +93,54 @@ impl VarType { pub fn concrete_to_builtin( &mut self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { if let VarType::Concrete(cnode) = self { let c = cnode.underlying(analyzer)?.clone(); match c { - crate::Concrete::Uint(ref size, _) => { + Concrete::Uint(ref size, _) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::Uint(*size))), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::Int(ref size, _) => { + Concrete::Int(ref size, _) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::Int(*size))), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::Bool(_) => { + Concrete::Bool(_) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bool)), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::Address(_) => { + Concrete::Address(_) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::Address)), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::Bytes(ref s, _) => { + Concrete::Bytes(ref s, _) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::Bytes(*s))), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::String(_) => { + Concrete::String(_) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::String)), SolcRange::from(c), ); *self = new_ty; } - crate::Concrete::DynBytes(_) => { + Concrete::DynBytes(_) => { let new_ty = VarType::BuiltIn( BuiltInNode::from(analyzer.builtin_or_add(Builtin::DynamicBytes)), SolcRange::from(c), @@ -143,7 +154,7 @@ impl VarType { Ok(()) } - pub fn try_from_idx(analyzer: &impl GraphLike, node: NodeIdx) -> Option { + pub fn try_from_idx(analyzer: &impl GraphBackend, node: NodeIdx) -> Option { // get node, check if typeable and convert idx into vartype match analyzer.node(node) { Node::VarType(a) => Some(a.clone()), @@ -194,7 +205,7 @@ impl VarType { } } - pub fn requires_input(&self, analyzer: &impl GraphLike) -> Result { + pub fn requires_input(&self, analyzer: &impl GraphBackend) -> Result { match self { VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.requires_input()), _ => Ok(false), @@ -204,7 +215,7 @@ impl VarType { pub fn try_cast( self, other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { match (self, other) { (l, Self::User(TypeNode::Ty(ty), o_r)) => { @@ -261,7 +272,7 @@ impl VarType { pub fn try_literal_cast( self, other: &Self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { match (self, other) { (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Ty(ty), _)) => { @@ -317,7 +328,7 @@ impl VarType { pub fn implicitly_castable_to( &self, other: &Self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result { match (self, other) { (Self::BuiltIn(from_bn, _), Self::BuiltIn(to_bn, _)) => { @@ -332,7 +343,7 @@ impl VarType { pub fn max_size( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match self { Self::BuiltIn(from_bn, _r) => { @@ -347,7 +358,7 @@ impl VarType { } } - pub fn range(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { match self { Self::User(_, Some(range)) => Ok(Some(range.clone())), Self::BuiltIn(_, Some(range)) => Ok(Some(range.clone())), @@ -359,7 +370,7 @@ impl VarType { pub fn ref_range( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result>, GraphError> { match self { Self::User(_, Some(range)) => Ok(Some(std::borrow::Cow::Borrowed(range))), @@ -384,7 +395,7 @@ impl VarType { pub fn delete_range_result( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { match self { Self::User(TypeNode::Contract(_), _) => { @@ -418,7 +429,7 @@ impl VarType { pub fn default_range( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { match self { Self::User(TypeNode::Contract(_), _) => { @@ -434,7 +445,7 @@ impl VarType { } } - pub fn is_const(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::Concrete(_) => Ok(true), Self::User(TypeNode::Func(_), _) => Ok(false), @@ -450,7 +461,7 @@ impl VarType { } } - pub fn func_node(&self, _analyzer: &impl GraphLike) -> Option { + pub fn func_node(&self, _analyzer: &impl GraphBackend) -> Option { match self { Self::User(TypeNode::Func(func_node), _) => Some(*func_node), _ => None, @@ -459,7 +470,7 @@ impl VarType { pub fn evaled_range( &self, - analyzer: &impl GraphLike, + analyzer: &impl GraphBackend, ) -> Result, Elem)>, GraphError> { Ok(self.ref_range(analyzer)?.map(|range| { ( @@ -472,7 +483,7 @@ impl VarType { pub fn try_match_index_dynamic_ty( &self, index: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result, GraphError> { match self { Self::BuiltIn(_node, None) => Ok(None), @@ -588,7 +599,7 @@ impl VarType { pub fn get_index_dynamic_ty( &self, index: ContextVarNode, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) @@ -605,7 +616,7 @@ impl VarType { pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { match self { Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), @@ -616,14 +627,14 @@ impl VarType { } } - pub fn is_mapping(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => Ok(node.is_mapping(analyzer)?), _ => Ok(false), } } - pub fn is_sized_array(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_sized_array(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => node.is_sized_array(analyzer), Self::Concrete(node) => node.is_sized_array(analyzer), @@ -631,7 +642,7 @@ impl VarType { } } - pub fn maybe_array_size(&self, analyzer: &impl GraphLike) -> Result, GraphError> { + pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { match self { Self::BuiltIn(node, _) => node.maybe_array_size(analyzer), Self::Concrete(node) => node.maybe_array_size(analyzer), @@ -639,7 +650,7 @@ impl VarType { } } - pub fn is_dyn(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_dyn(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => Ok(node.is_dyn(analyzer)?), Self::Concrete(node) => Ok(node.is_dyn(analyzer)?), @@ -647,7 +658,7 @@ impl VarType { } } - pub fn is_indexable(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_indexable(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => Ok(node.is_indexable(analyzer)?), Self::Concrete(node) => Ok(node.is_indexable(analyzer)?), @@ -655,7 +666,7 @@ impl VarType { } } - pub fn ty_eq(&self, other: &Self, analyzer: &impl GraphLike) -> Result { + pub fn ty_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> Result { match (self, other) { (VarType::User(s, _), VarType::User(o, _)) => { Ok(s.unresolved_as_resolved(analyzer)? == o.unresolved_as_resolved(analyzer)?) @@ -684,7 +695,7 @@ impl VarType { } } - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_string(&self, analyzer: &impl GraphBackend) -> Result { match self { VarType::User(ty_node, _) => ty_node.as_string(analyzer), VarType::BuiltIn(bn, _) => match analyzer.node(*bn) { @@ -695,7 +706,7 @@ impl VarType { } } - pub fn is_int(&self, analyzer: &impl GraphLike) -> Result { + pub fn is_int(&self, analyzer: &impl GraphBackend) -> Result { match self { VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.is_int()), VarType::Concrete(c) => Ok(c.underlying(analyzer)?.is_int()), @@ -703,7 +714,7 @@ impl VarType { } } - pub fn as_builtin(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_builtin(&self, analyzer: &impl GraphBackend) -> Result { match self { VarType::BuiltIn(bn, _) => Ok(bn.underlying(analyzer)?.clone()), VarType::Concrete(c) => Ok(c.underlying(analyzer)?.as_builtin()), @@ -725,7 +736,7 @@ pub enum TypeNode { } impl TypeNode { - pub fn as_string(&self, analyzer: &impl GraphLike) -> Result { + pub fn as_string(&self, analyzer: &impl GraphBackend) -> Result { match self { TypeNode::Contract(n) => n.name(analyzer), TypeNode::Struct(n) => n.name(analyzer), @@ -736,7 +747,7 @@ impl TypeNode { } } - pub fn unresolved_as_resolved(&self, analyzer: &impl GraphLike) -> Result { + pub fn unresolved_as_resolved(&self, analyzer: &impl GraphBackend) -> Result { match self { TypeNode::Unresolved(n) => match analyzer.node(*n) { Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml index bdf54361..76ef2467 100644 --- a/crates/pyrometer/Cargo.toml +++ b/crates/pyrometer/Cargo.toml @@ -13,7 +13,6 @@ repository.workspace = true [dependencies] analyzers.workspace = true graph.workspace = true -range.workspace = true solc-expressions.workspace = true solang-parser.workspace = true diff --git a/crates/pyrometer/src/lib.rs b/crates/pyrometer/src/lib.rs index 3d67b73b..eb83ba53 100644 --- a/crates/pyrometer/src/lib.rs +++ b/crates/pyrometer/src/lib.rs @@ -155,7 +155,7 @@ impl GraphLike for Analyzer { } } -impl AnalyzerLike for Analyzer { +impl AnalyzerBackend for Analyzer { type Expr = Expression; type ExprErr = ExprErr; diff --git a/crates/queries/Cargo.toml b/crates/queries/Cargo.toml index 746fcc9a..1b58bbfc 100644 --- a/crates/queries/Cargo.toml +++ b/crates/queries/Cargo.toml @@ -13,7 +13,6 @@ repository.workspace = true [dependencies] analyzers.workspace = true graph.workspace = true -range.workspace = true solc-expressions.workspace = true solang-parser.workspace = true diff --git a/crates/range/Cargo.toml b/crates/range/Cargo.toml deleted file mode 100644 index 36bf9983..00000000 --- a/crates/range/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "range" -description = "Pyrometer's trait and generics based representation of a range" - -version.workspace = true -edition.workspace = true -rust-version.workspace = true -authors.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[dependencies] -shared.workspace = true -solang-parser.workspace = true -ethers-core.workspace = true -hex.workspace = true -tracing.workspace = true -tracing-subscriber.workspace = true \ No newline at end of file diff --git a/crates/range/src/elem/concrete.rs b/crates/range/src/elem/concrete.rs deleted file mode 100644 index fc599b05..00000000 --- a/crates/range/src/elem/concrete.rs +++ /dev/null @@ -1,8 +0,0 @@ -use solang_parser::pt::Loc; - -/// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeConcrete { - pub val: T, - pub loc: Loc, -} \ No newline at end of file diff --git a/crates/range/src/elem/elem_enum.rs b/crates/range/src/elem/elem_enum.rs deleted file mode 100644 index aeb7d49b..00000000 --- a/crates/range/src/elem/elem_enum.rs +++ /dev/null @@ -1,210 +0,0 @@ -use crate::elem::{RangeOp, Reference, RangeDyn, RangeConcrete, RangeExpr}; -use shared::NodeIdx; - -use std::{ - collections::BTreeMap, - ops::{ - Add, - Sub, - Mul, - Div, - Shl, - Shr, - Rem, - BitAnd, - BitOr, - BitXor, - } -}; - -/// A core range element. -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub enum Elem { - /// A range element that is a reference to another node - Reference(Reference), - /// A concrete range element of type `T`. e.g.: some number like `10` - ConcreteDyn(Box>), - /// A concrete range element of type `T`. e.g.: some number like `10` - Concrete(RangeConcrete), - /// A range element that is an expression composed of other range elements - Expr(RangeExpr), - /// A null range element useful in range expressions that dont have a rhs - Null, -} - - -impl Elem { - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - match self { - Self::Reference(d) => d.idx == node_idx, - Self::Concrete(_) => false, - Self::Expr(expr) => expr.contains_node(node_idx), - Self::ConcreteDyn(d) => d.contains_node(node_idx), - Self::Null => false, - } - } - - pub fn expect_into_expr(self) -> RangeExpr { - match self { - Self::Expr(expr) => expr, - _ => panic!("Not expression"), - } - } - - pub fn dyn_map(&self) -> Option<&BTreeMap> { - match self { - Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), - _ => None, - } - } - - pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { - match self { - Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), - _ => None, - } - } - - /// Creates a new range element that is a cast from one type to another - pub fn cast(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Cast, other); - Elem::Expr(expr) - } - - pub fn concat(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Concat, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the minimum of two range elements - pub fn min(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Min, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the maximum of two range elements - pub fn max(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Max, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of equality of two range elements - pub fn eq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Eq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of inequality of two range elements - pub fn neq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Neq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is one range element to the power of another - pub fn pow(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Exp, other); - Elem::Expr(expr) - } -} - -impl From> for Elem { - fn from(dy: Reference) -> Self { - Elem::Reference(dy) - } -} - -impl From> for Elem { - fn from(c: RangeConcrete) -> Self { - Elem::Concrete(c) - } -} - -impl Add for Elem { - type Output = Self; - - fn add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(false), other); - Self::Expr(expr) - } -} - -impl Sub for Elem { - type Output = Self; - - fn sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(false), other); - Self::Expr(expr) - } -} - -impl Mul for Elem { - type Output = Self; - - fn mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(false), other); - Self::Expr(expr) - } -} - -impl Div for Elem { - type Output = Self; - - fn div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(false), other); - Self::Expr(expr) - } -} - -impl Shl for Elem { - type Output = Self; - - fn shl(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shl, other); - Self::Expr(expr) - } -} - -impl Shr for Elem { - type Output = Self; - - fn shr(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shr, other); - Self::Expr(expr) - } -} - -impl Rem for Elem { - type Output = Self; - - fn rem(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mod, other); - Self::Expr(expr) - } -} - -impl BitAnd for Elem { - type Output = Self; - - fn bitand(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitAnd, other); - Self::Expr(expr) - } -} - -impl BitOr for Elem { - type Output = Self; - - fn bitor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitOr, other); - Self::Expr(expr) - } -} - -impl BitXor for Elem { - type Output = Self; - - fn bitxor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitXor, other); - Self::Expr(expr) - } -} \ No newline at end of file diff --git a/crates/range/src/elem/expr.rs b/crates/range/src/elem/expr.rs deleted file mode 100644 index e9929f12..00000000 --- a/crates/range/src/elem/expr.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::elem::{RangeOp, Elem, MinMaxed}; -use shared::NodeIdx; - -/// A range expression composed of other range [`Elem`] -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeExpr { - pub maximized: Option>, - pub minimized: Option>, - pub lhs: Box>, - pub op: RangeOp, - pub rhs: Box>, -} - - - -impl RangeExpr { - /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. - pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { - RangeExpr { - maximized: None, - minimized: None, - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - } - } - - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) - } -} diff --git a/crates/range/src/elem/map_or_array.rs b/crates/range/src/elem/map_or_array.rs deleted file mode 100644 index 60391e42..00000000 --- a/crates/range/src/elem/map_or_array.rs +++ /dev/null @@ -1,34 +0,0 @@ -use crate::elem::{Elem, MinMaxed }; -use shared::NodeIdx; - -use solang_parser::pt::Loc; - -use std::collections::BTreeMap; - -/// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct RangeDyn { - /// Cached minimized value - pub minimized: Option>, - /// Cached maximized value - pub maximized: Option>, - /// Length of the dynamic variable - pub len: Elem, - /// Values of the dynamic variable - pub val: BTreeMap, Elem>, - /// Sourcecode location - pub loc: Loc, -} -impl RangeDyn { - /// Set the length - pub fn set_len(&mut self, new_len: Elem) { - self.len = new_len; - } - - /// Check if the node contains a reference to a node index - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - self.len.contains_node(node_idx) - // || self.val.iter().any(|(k, v)| k.contains_node(node_idx) || v.contains_node(node_idx)) - } -} - diff --git a/crates/range/src/elem/reference.rs b/crates/range/src/elem/reference.rs deleted file mode 100644 index d4d6931a..00000000 --- a/crates/range/src/elem/reference.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::elem::MinMaxed; -use shared::NodeIdx; - -/// A dynamic range element value -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] -pub struct Reference { - /// Index of the node that is referenced - pub idx: NodeIdx, - /// Cached minimized value - pub minimized: Option>, - /// Cached maximized value - pub maximized: Option>, -} - -impl Reference { - pub fn new(idx: NodeIdx) -> Self { - Self { - idx, - minimized: None, - maximized: None, - } - } -} \ No newline at end of file diff --git a/crates/range/src/range_string.rs b/crates/range/src/range_string.rs deleted file mode 100644 index f23ef91f..00000000 --- a/crates/range/src/range_string.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::GraphLike; - -use solang_parser::pt::Loc; - -/// A range element string consisting of a string and a location -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct RangeElemString { - pub s: String, - pub loc: Loc, -} - -impl RangeElemString { - /// Creates a new range element string from a string and a location - pub fn new(s: String, loc: Loc) -> Self { - Self { s, loc } - } -} - -/// A range string consisting of stringified range elements -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct RangeString { - pub min: RangeElemString, - pub max: RangeElemString, -} - -impl RangeString { - /// Creates a new range string from a min and max [`RangeElemString`] - pub fn new(min: RangeElemString, max: RangeElemString) -> Self { - Self { min, max } - } -} - -/// String related functions for ranges -pub trait ToRangeString { - /// Gets the definition string of the range element - fn def_string(&self, analyzer: &impl GraphLike) -> RangeElemString; - /// Converts a range to a human string - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphLike) -> RangeElemString; -} diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 88cb082c..01834f60 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,3 +1,4 @@ +use crate::Heirarchical; use crate::AnalyzerLike; use std::{ @@ -13,14 +14,10 @@ use petgraph::{ pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; -pub trait AsDotStr { - fn as_dot_str(&self, analyzer: &impl GraphLike) -> String; -} - /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphLike { type Node; - type Edge; + type Edge: Ord + PartialEq + Heirarchical + Copy; /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph @@ -359,7 +356,7 @@ struct G<'a, Node, Edge> { pub graph: &'a Graph, } -impl GraphLike for G<'_, Node, Edge> { +impl GraphLike for G<'_, Node, Edge> { type Node = Node; type Edge = Edge; fn graph_mut(&mut self) -> &mut Graph { diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index c2fa7ebf..5391d213 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -1,5 +1,7 @@ mod graph_like; mod analyzer_like; +mod search; +pub use search::*; pub use graph_like::*; pub use analyzer_like::*; \ No newline at end of file diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs new file mode 100644 index 00000000..fd5757e4 --- /dev/null +++ b/crates/shared/src/search.rs @@ -0,0 +1,537 @@ +use std::collections::{BTreeSet, BTreeMap}; + +use crate::{NodeIdx, GraphLike}; +use petgraph::{visit::EdgeRef, graph::*, Direction}; + +pub trait Heirarchical { + fn heirarchical_num(&self) -> usize; +} + +impl Search for T where T: GraphLike, ::Edge: Ord + PartialEq + Heirarchical + Copy {} +/// A trait for searching through a graph +pub trait Search: GraphLike + where ::Edge: PartialEq + Heirarchical + Copy +{ + fn search_for_ancestor(&self, start: NodeIdx, edge_ty: &::Edge) -> Option { + tracing::trace!("searching for ancestor"); + let edges = self.graph().edges_directed(start, Direction::Outgoing); + if let Some(edge) = edges.clone().find(|edge| edge.weight() == edge_ty) { + Some(edge.target()) + } else { + edges + .map(|edge| edge.target()) + .filter_map(|node| self.search_for_ancestor(node, edge_ty)) + .take(1) + .next() + } + } + + fn search_for_ancestor_multi(&self, start: NodeIdx, edge_tys: &[::Edge]) -> Option { + tracing::trace!("searching for ancestor_multi"); + let edges = self.graph().edges_directed(start, Direction::Outgoing); + if let Some(edge) = edges.clone().find(|edge| edge_tys.contains(edge.weight())) { + Some(edge.target()) + } else { + edges + .map(|edge| edge.target()) + .filter_map(|node| self.search_for_ancestor_multi(node, edge_tys)) + .take(1) + .next() + } + } + + fn search_children_same_heirarchy(&self, start: NodeIdx, edge_ty: &::Edge) -> BTreeSet { + tracing::trace!("search_children_same_heirarchy"); + let num = edge_ty.heirarchical_num(); + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|e| e.weight().heirarchical_num() == num); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .flat_map(|edge| self.search_children_same_heirarchy(edge.source(), edge_ty)) + .collect::>(), + ); + this_children + } + + /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a set of these + /// + /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d + /// + /// This function would build a set { b, d } if we are looking for `my_edge` and start at a. + fn search_children(&self, start: NodeIdx, edge_ty: &::Edge) -> BTreeSet { + tracing::trace!("search_children"); + let mut seen = Default::default(); + self.search_children_prevent_cycle(start, edge_ty, &mut seen) + } + + fn search_children_prevent_cycle( + &self, + start: NodeIdx, + edge_ty: &::Edge, + seen: &mut BTreeSet, + ) -> BTreeSet { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + if !seen.contains(&edge.source()) { + Some(edge.source()) + } else { + None + } + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .flat_map(|edge| self.search_children_prevent_cycle(edge.source(), edge_ty, seen)) + .collect::>(), + ); + this_children + } + + fn find_child_exclude_via( + &self, + start: NodeIdx, + edge_ty: &::Edge, + exclude_edges: &[::Edge], + find_fn: &impl Fn(NodeIdx, &Self) -> Option, + ) -> Option { + tracing::trace!("find_child_exclude_via"); + let mut seen = Default::default(); + self.find_child_exclude_via_prevent_cycle(start, edge_ty, exclude_edges, find_fn, &mut seen) + } + + fn find_child_exclude_via_prevent_cycle( + &self, + start: NodeIdx, + edge_ty: &::Edge, + exclude_edges: &[::Edge], + find_fn: &impl Fn(NodeIdx, &Self) -> Option, + seen: &mut BTreeSet, + ) -> Option { + if seen.contains(&start) { + return None; + } else { + seen.insert(start); + } + + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|edge| !exclude_edges.contains(edge.weight())); + if let Some(node) = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .find(|node| find_fn(*node, self).is_some()) + { + Some(node) + } else { + edges + .clone() + .map(|edge| edge.source()) + .find_map(|node| self.find_child_exclude_via(node, edge_ty, exclude_edges, find_fn)) + } + } + + fn search_children_exclude_via( + &self, + start: NodeIdx, + edge_ty: &::Edge, + exclude_edges: &[::Edge], + ) -> BTreeSet { + tracing::trace!("search_children_exclude_via"); + let mut seen = Default::default(); + self.search_children_exclude_via_prevent_cycle(start, edge_ty, exclude_edges, &mut seen) + } + + fn search_children_exclude_via_prevent_cycle( + &self, + start: NodeIdx, + edge_ty: &::Edge, + exclude_edges: &[::Edge], + seen: &mut BTreeSet, + ) -> BTreeSet { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|edge| !exclude_edges.contains(edge.weight())); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + seen.insert(start); + + this_children.extend( + edges + .flat_map(|edge| { + self.search_children_exclude_via_prevent_cycle( + edge.source(), + edge_ty, + exclude_edges, + seen, + ) + }) + .collect::>(), + ); + this_children + } + + fn search_children_include_via( + &self, + start: NodeIdx, + edge_ty: &::Edge, + include_edges: &[::Edge], + ) -> BTreeSet { + tracing::trace!("search_children_include_via"); + let mut seen = Default::default(); + self.search_children_include_via_prevent_cycle(start, edge_ty, include_edges, &mut seen) + } + + fn search_children_include_via_prevent_cycle( + &self, + start: NodeIdx, + edge_ty: &::Edge, + include_edges: &[::Edge], + seen: &mut BTreeSet, + ) -> BTreeSet { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let mut edges: Vec<_> = self + .graph() + .edges_directed(start, Direction::Incoming) + .collect(); + edges = edges + .into_iter() + .filter(|edge| include_edges.contains(edge.weight())) + .collect::>(); + let mut this_children: BTreeSet = edges + .iter() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .clone() + .iter() + .flat_map(|edge| { + self.search_children_include_via_prevent_cycle( + edge.source(), + edge_ty, + include_edges, + seen, + ) + }) + .collect::>(), + ); + this_children + } + + fn search_children_depth( + &self, + start: NodeIdx, + edge_ty: &::Edge, + max_depth: usize, + curr_depth: usize, + ) -> BTreeSet { + tracing::trace!("search_children_depth"); + let mut seen = Default::default(); + self.search_children_depth_prevent_cylce(start, edge_ty, max_depth, curr_depth, &mut seen) + } + + fn search_children_depth_prevent_cylce( + &self, + start: NodeIdx, + edge_ty: &::Edge, + max_depth: usize, + curr_depth: usize, + seen: &mut BTreeSet, + ) -> BTreeSet { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + if curr_depth < max_depth { + this_children.extend( + edges + .flat_map(|edge| { + self.search_children_depth_prevent_cylce( + edge.source(), + edge_ty, + max_depth, + curr_depth + 1, + seen, + ) + }) + .collect::>(), + ); + } + this_children + } + + /// Gets all children recursively, removing nodes that are connected via an excluded edge + fn children_exclude( + &self, + start: NodeIdx, + max_depth: usize, + exclude_edges: &[::Edge], + ) -> BTreeSet { + tracing::trace!("children"); + let mut seen = Default::default(); + self.children_exclude_prevent_cycle(start, 0, max_depth, exclude_edges, &mut seen) + } + + /// Gets all children recursively up to a certain depth + fn children_exclude_prevent_cycle( + &self, + start: NodeIdx, + curr_depth: usize, + max_depth: usize, + exclude_edges: &[::Edge], + seen: &mut BTreeSet, + ) -> BTreeSet { + if curr_depth > max_depth { + return Default::default(); + } + + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if !exclude_edges.contains(edge.weight()) { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + this_children.extend( + edges + .flat_map(|edge| { + self.children_exclude_prevent_cycle( + edge.source(), + curr_depth + 1, + max_depth, + exclude_edges, + seen, + ) + }) + .collect::>(), + ); + this_children + } + + /// Gets all children recursively + fn children(&self, start: NodeIdx) -> BTreeSet { + tracing::trace!("children"); + let mut seen = Default::default(); + self.children_prevent_cycle(start, &mut seen) + } + + /// Gets all children recursively + fn children_prevent_cycle( + &self, + start: NodeIdx, + seen: &mut BTreeSet, + ) -> BTreeSet { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children: BTreeSet = + edges.clone().map(|edge| edge.source()).collect(); + + this_children.extend( + edges + .flat_map(|edge| self.children_prevent_cycle(edge.source(), seen)) + .collect::>(), + ); + this_children + } + + /// Gets all children edges recursively + fn edges_for_nodes( + &self, + nodes: &BTreeSet, + ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + tracing::trace!("children_edges"); + + nodes + .iter() + .flat_map(|node| { + self.graph() + .edges_directed(*node, Direction::Incoming) + .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) + .collect::::Edge, EdgeIndex)>>() + }) + .collect() + } + + /// Gets all children edges recursively + fn children_edges( + &self, + start: NodeIdx, + ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + tracing::trace!("children_edges"); + let mut seen = Default::default(); + self.children_edges_prevent_cycle(start, &mut seen) + } + + fn children_edges_prevent_cycle( + &self, + start: NodeIdx, + seen: &mut BTreeSet, + ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + if seen.contains(&start) { + return Default::default(); + } else { + seen.insert(start); + } + + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut this_children_edges: BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> = edges + .clone() + .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) + .collect(); + + this_children_edges.extend( + edges + .flat_map(|edge| self.children_edges_prevent_cycle(edge.source(), seen)) + .collect::::Edge, EdgeIndex)>>(), + ); + this_children_edges + } + + /// Finds any child nodes that have some edge `edge_ty` incoming. Builds up a mapping of these + /// + /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d + /// + /// This function would build a map { a: [b], c: [d] } if we are looking for `my_edge` and start at a. + fn nodes_with_children( + &self, + start: NodeIdx, + edge_ty: &::Edge, + ) -> Option>> { + tracing::trace!("nodes_with_children"); + let mut seen = Default::default(); + self.nodes_with_children_prevent_cycles(start, edge_ty, &mut seen) + } + + fn nodes_with_children_prevent_cycles( + &self, + start: NodeIdx, + edge_ty: &::Edge, + seen: &mut BTreeSet, + ) -> Option>> { + if seen.contains(&start) { + return None; + } else { + seen.insert(start); + } + let edges = self.graph().edges_directed(start, Direction::Incoming); + let mut map: BTreeMap> = Default::default(); + + let this_children: BTreeSet = edges + .clone() + .filter_map(|edge| { + if edge.weight() == edge_ty { + Some(edge.source()) + } else { + None + } + }) + .collect(); + + if !this_children.is_empty() { + map.insert(start, this_children); + } + map.extend( + edges + .filter_map(|edge| { + self.nodes_with_children_prevent_cycles(edge.source(), edge_ty, seen) + }) + .flatten() + .collect::>>(), + ); + if map.is_empty() { + None + } else { + Some(map) + } + } +} \ No newline at end of file From b5b8035bea7a8477617029f541dd21614fc56d32 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 11:54:18 -0800 Subject: [PATCH 12/71] fix up solc-expressions --- Cargo.lock | 2 + crates/graph/src/graph_elements.rs | 9 +- crates/solc-expressions/Cargo.toml | 3 + crates/solc-expressions/src/array.rs | 24 +- crates/solc-expressions/src/bin_op.rs | 44 +- crates/solc-expressions/src/cmp.rs | 23 +- crates/solc-expressions/src/cond_op.rs | 15 +- .../src/context_builder/mod.rs | 1606 +++++++++++++++++ crates/solc-expressions/src/env.rs | 24 +- .../src/func_call/internal_call.rs | 27 +- .../src/func_call/intrinsic_call.rs | 426 +++-- crates/solc-expressions/src/func_call/mod.rs | 199 +- .../src/func_call/modifier.rs | 21 +- .../src/func_call/namespaced_call.rs | 167 +- crates/solc-expressions/src/lib.rs | 45 +- crates/solc-expressions/src/list.rs | 17 +- crates/solc-expressions/src/literal.rs | 29 +- crates/solc-expressions/src/loops.rs | 20 +- .../mod.rs} | 29 +- crates/solc-expressions/src/require.rs | 35 +- crates/solc-expressions/src/variable.rs | 18 +- crates/solc-expressions/src/yul/mod.rs | 155 +- .../solc-expressions/src/yul/yul_cond_op.rs | 87 +- crates/solc-expressions/src/yul/yul_funcs.rs | 284 ++- 24 files changed, 2617 insertions(+), 692 deletions(-) create mode 100644 crates/solc-expressions/src/context_builder/mod.rs rename crates/solc-expressions/src/{member_access.rs => member_access/mod.rs} (98%) diff --git a/Cargo.lock b/Cargo.lock index 7e4a2eee..0431be9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1493,6 +1493,8 @@ dependencies = [ "ethers-core", "graph", "hex", + "petgraph", + "shared", "solang-parser", "tracing", "tracing-subscriber", diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 68a5af24..9e0e99c4 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -12,7 +12,14 @@ pub trait GraphBackend: GraphLike< Node = Node, > {} -pub trait AnalyzerBackend: AnalyzerLike + GraphBackend {} +pub trait AnalyzerBackend: AnalyzerLike< + Builtin = Builtin, + MsgNode = MsgNode, + BlockNode = BlockNode, + FunctionParam = FunctionParam, + FunctionReturn = FunctionReturn, + Function = Function +> + GraphBackend {} pub trait AsDotStr { fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String; diff --git a/crates/solc-expressions/Cargo.toml b/crates/solc-expressions/Cargo.toml index a8cb83f2..a6ed6cf3 100644 --- a/crates/solc-expressions/Cargo.toml +++ b/crates/solc-expressions/Cargo.toml @@ -13,6 +13,9 @@ repository.workspace = true [dependencies] analyzers.workspace = true graph.workspace = true +shared.workspace = true + +petgraph.workspace = true solang-parser.workspace = true ethers-core.workspace = true hex.workspace = true diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 7507af3b..9d51681f 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,15 +1,21 @@ -use crate::context::ExprErr; -use crate::context::IntoExprErr; use crate::{ - context::exprs::{member_access::MemberAccess, require::Require}, - Builtin, ContextBuilder, Edge, Node, VarType, + ContextBuilder, IntoExprErr, + ExprErr, member_access::MemberAccess, require::Require, }; -use shared::{analyzer::AnalyzerLike, context::*, range::elem::RangeOp}; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::{Expression, Loc}; -impl Array for T where T: AnalyzerLike + Sized {} -pub trait Array: AnalyzerLike + Sized { +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{Builtin, ContextVar, ContextVarNode, ContextNode, ExprRet}, + elem::RangeOp +}; + +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc}, +}; + +impl Array for T where T: AnalyzerBackend + Sized {} +pub trait Array: AnalyzerBackend + Sized { /// Gets the array type #[tracing::instrument(level = "trace", skip_all)] fn array_ty(&mut self, ty_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 7c0140e2..117b7f9c 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -1,26 +1,16 @@ -use crate::context::exprs::require::Require; -use crate::context::exprs::IntoExprErr; -use crate::context::{ContextBuilder, ExprErr}; -use ethers_core::types::{I256, U256}; +use crate::{ContextBuilder, IntoExprErr, ExprErr, require::Require}; -use shared::range::elem::RangeElem; -use shared::range::elem_ty::RangeExpr; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::{BuiltInNode, Builtin, Concrete, VarType}, - range::{ - elem::RangeOp, - elem_ty::{Dynamic, Elem}, - Range, RangeEval, SolcRange, - }, - Edge, Node, +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{BuiltInNode, Builtin, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, KilledKind, ExprRet, }, + elem::*, Range, RangeEval, SolcRange }; +use ethers_core::types::{I256, U256}; use solang_parser::pt::{Expression, Loc}; -impl BinOp for T where T: AnalyzerLike + Sized {} -pub trait BinOp: AnalyzerLike + Sized { +impl BinOp for T where T: AnalyzerBackend + Sized {} +pub trait BinOp: AnalyzerBackend + Sized { /// Evaluate and execute a binary operation expression #[tracing::instrument(level = "trace", skip_all)] fn op_expr( @@ -205,9 +195,9 @@ pub trait BinOp: AnalyzerLike + Sized { let mut new_rhs = rhs_cvar.latest_version(self); let expr = Elem::Expr(RangeExpr::::new( - Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), + Elem::from(Reference::new(lhs_cvar.latest_version(self).into())), op, - Elem::from(Dynamic::new(rhs_cvar.latest_version(self).into())), + Elem::from(Reference::new(rhs_cvar.latest_version(self).into())), )); // TODO: change to only hit this path if !uncheck @@ -303,7 +293,7 @@ pub trait BinOp: AnalyzerLike + Sized { } else { // the new min is max(1, rhs.min) let min = Elem::max( - Elem::from(Dynamic::new(new_rhs.into())), + Elem::from(Reference::new(new_rhs.into())), // tmp_rhs // .range_min(self) // .into_expr_err(loc)? @@ -311,7 +301,7 @@ pub trait BinOp: AnalyzerLike + Sized { // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) // }), Elem::from(Concrete::from(U256::from(1))).cast( - Elem::from(Dynamic::new(tmp_rhs.into())), // .range_min(self) + Elem::from(Reference::new(tmp_rhs.into())), // .range_min(self) // .into_expr_err(loc)? // .expect("No range minimum?"), ), @@ -359,7 +349,7 @@ pub trait BinOp: AnalyzerLike + Sized { } // the new min is max(lhs.min, rhs.min) let min = Elem::max( - Elem::from(Dynamic::new(lhs_cvar.into())), + Elem::from(Reference::new(lhs_cvar.into())), // .range_min(self) // .into_expr_err(loc)? // .unwrap_or_else(|| { @@ -411,7 +401,7 @@ pub trait BinOp: AnalyzerLike + Sized { // the new max is min(lhs.max, (2**256 - rhs.min)) let max = Elem::min( - Elem::from(Dynamic::new(lhs_cvar.into())), + Elem::from(Reference::new(lhs_cvar.into())), // .range_max(self) // .into_expr_err(loc)? // .expect("No range max?"), @@ -498,7 +488,7 @@ pub trait BinOp: AnalyzerLike + Sized { // the new max is min(lhs.max, (2**256 / max(1, rhs.min))) let max = Elem::min( - Elem::from(Dynamic::new(lhs_cvar.into())), + Elem::from(Reference::new(lhs_cvar.into())), // .range_max(self) // .into_expr_err(loc)? // .expect("No range max?"), @@ -593,7 +583,7 @@ pub trait BinOp: AnalyzerLike + Sized { let tmp_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; // the new min is max(lhs.min, rhs.min) let min = Elem::max( - Elem::from(Dynamic::new(rhs_cvar.into())), + Elem::from(Reference::new(rhs_cvar.into())), // .range_min(self) // .into_expr_err(loc)? // .expect("No range minimum?"), @@ -772,7 +762,7 @@ pub trait BinOp: AnalyzerLike + Sized { }; let expr = Elem::Expr(RangeExpr::::new( - Elem::from(Dynamic::new(lhs_cvar.latest_version(self).into())), + Elem::from(Reference::new(lhs_cvar.latest_version(self).into())), RangeOp::BitNot, Elem::Null, )); diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index a538a9f0..b3fe62ad 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -1,25 +1,16 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::ContextBuilder; -use shared::analyzer::GraphError; +use crate::{ContextBuilder, IntoExprErr, ExprErr}; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::*, - range::{ - elem::{RangeElem, RangeOp}, - elem_ty::{Elem, RangeConcrete, RangeExpr}, - Range, SolcRange, - }, - Node, +use graph::{ + AnalyzerBackend, Node, VarType, GraphError, + nodes::{BuiltInNode, Builtin, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, ExprRet, }, + elem::*, Range, SolcRange }; use solang_parser::pt::{Expression, Loc}; use std::cmp::Ordering; -impl Cmp for T where T: AnalyzerLike + Sized {} -pub trait Cmp: AnalyzerLike + Sized { +impl Cmp for T where T: AnalyzerBackend + Sized {} +pub trait Cmp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn not(&mut self, loc: Loc, lhs_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { self.parse_ctx_expr(lhs_expr, ctx)?; diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index e0bc9d4a..4b271aed 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -1,13 +1,16 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{exprs::Require, AnalyzerLike, ContextBuilder}; -use shared::{context::*, Edge, Node, NodeIdx}; +use crate::{ContextBuilder, IntoExprErr, ExprErr, require::Require}; + +use graph::{ + AnalyzerBackend, Edge, Node, ContextEdge, + nodes::{Context, ContextNode, } +}; +use shared::NodeIdx; use solang_parser::pt::CodeLocation; use solang_parser::pt::{Expression, Loc, Statement}; -impl CondOp for T where T: AnalyzerLike + Require + Sized {} -pub trait CondOp: AnalyzerLike + Require + Sized { +impl CondOp for T where T: AnalyzerBackend + Require + Sized {} +pub trait CondOp: AnalyzerBackend + Require + Sized { #[tracing::instrument(level = "trace", skip_all)] fn cond_op_stmt( &mut self, diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs new file mode 100644 index 00000000..f49d60b0 --- /dev/null +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -0,0 +1,1606 @@ +use crate::{ + yul::YulBuilder, func_call::FuncCaller, loops::Looper, ExprParser, IntoExprErr, ExprErr +}; + +use graph::{ + GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, GraphError, + nodes::{FunctionReturnNode, FunctionParamNode, Context, KilledKind, Builtin, FunctionNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + elem::*, Range +}; +use shared::NodeIdx; + +use ethers_core::types::{I256, U256}; +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::{ + pt::{VariableDeclaration, YulStatement, Expression, Loc, Statement}, + helpers::CodeLocation +}; + +impl ContextBuilder for T where + T: AnalyzerBackend + Sized + ExprParser +{ +} + +pub trait ContextBuilder: + AnalyzerBackend + Sized + ExprParser +{ + fn parse_ctx_statement( + &mut self, + stmt: &Statement, + unchecked: bool, + parent_ctx: Option + Clone + Copy>, + ) where + Self: Sized, + { + if let Some(parent) = parent_ctx { + match self.node(parent) { + Node::Context(_) => { + let ctx = ContextNode::from(parent.into()); + if !ctx.killed_or_ret(self).unwrap() { + if let Some(live_edges) = + self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) + { + if live_edges.is_empty() { + self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + } else { + live_edges.iter().for_each(|fork_ctx| { + self.parse_ctx_stmt_inner(stmt, unchecked, Some(*fork_ctx)); + }); + } + } + } + } + _ => self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx), + } + } else { + self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn parse_ctx_stmt_inner( + &mut self, + stmt: &Statement, + unchecked: bool, + parent_ctx: Option + Clone + Copy>, + ) where + Self: Sized, + { + use Statement::*; + // println!("stmt: {:#?}, node: {:#?}", stmt, if let Some(node) = parent_ctx { Some(self.node(node.into())) } else { None}); + // if let Some(ctx) = parent_ctx { + // if let Node::Context(_) = self.node(ctx) { + // println!("ctx: {}, {:#?}", ContextNode::from(ctx.into()).path(self), stmt); + // } + // } + + // at the end of a statement we shouldn't have anything in the stack? + if let Some(ctx) = parent_ctx { + if let Node::Context(_) = self.node(ctx) { + let c = ContextNode::from(ctx.into()); + let _ = c.pop_expr_latest(stmt.loc(), self); + if unchecked { + let _ = c.set_unchecked(self); + } else { + let _ = c.unset_unchecked(self); + } + + if c.killed_or_ret(self).unwrap() { + return; + } + } + } + + match stmt { + Block { + loc, + unchecked, + statements, + } => { + tracing::trace!("parsing block"); + let parent = parent_ctx.expect("Free floating contexts shouldn't happen"); + let mut entry_loc = None; + let mut mods_set = false; + let ctx_node = match self.node(parent) { + Node::Function(fn_node) => { + mods_set = fn_node.modifiers_set; + entry_loc = Some(fn_node.loc); + let ctx = Context::new( + FunctionNode::from(parent.into()), + self.add_if_err( + FunctionNode::from(parent.into()) + .name(self) + .into_expr_err(stmt.loc()), + ) + .unwrap(), + *loc, + ); + let ctx_node = self.add_node(Node::Context(ctx)); + self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Context)); + + ctx_node + } + Node::Context(_) => { + // let ctx = Context::new_subctx( + // ContextNode::from(parent.into()), + // *loc, + // false, + // self, + // ); + // let ctx_node = self.add_node(Node::Context(ctx)); + // self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Subcontext)); + // ctx_node + parent.into() + } + e => todo!( + "Expected a context to be created by a function or context but got: {:?}", + e + ), + }; + + // optionally add named input and named outputs into context + let (params, inputs): (Vec<_>, Vec<_>) = self + .graph() + .edges_directed(parent.into(), Direction::Incoming) + .filter(|edge| *edge.weight() == Edge::FunctionParam) + .map(|edge| FunctionParamNode::from(edge.source())) + .collect::>() + .into_iter() + .filter_map(|param_node| { + let res = param_node + .underlying(self) + .into_expr_err(stmt.loc()) + .cloned(); + let func_param = self.add_if_err(res)?; + if let Some(cvar) = ContextVar::maybe_new_from_func_param(self, func_param) + { + let cvar_node = self.add_node(Node::ContextVar(cvar)); + ContextNode::from(ctx_node) + .add_var(cvar_node.into(), self) + .unwrap(); + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::Variable), + ); + + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::CalldataVariable), + ); + + Some((param_node, ContextVarNode::from(cvar_node))) + } else { + None + } + }) + .unzip(); + + self.graph() + .edges_directed(parent.into(), Direction::Incoming) + .filter(|edge| *edge.weight() == Edge::FunctionReturn) + .map(|edge| FunctionReturnNode::from(edge.source())) + .collect::>() + .iter() + .for_each(|ret_node| { + let res = ret_node.underlying(self).into_expr_err(stmt.loc()).cloned(); + let func_ret = self.add_if_err(res).unwrap(); + if let Some(cvar) = ContextVar::maybe_new_from_func_ret(self, func_ret) { + let cvar_node = self.add_node(Node::ContextVar(cvar)); + ContextNode::from(ctx_node) + .add_var(cvar_node.into(), self) + .unwrap(); + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::Variable), + ); + } + }); + + if let Some(fn_loc) = entry_loc { + if !mods_set { + let parent = FunctionNode::from(parent.into()); + let _ = self + .set_modifiers(parent, ctx_node.into()) + .map_err(|e| self.add_expr_err(e)); + } + + let res = self.func_call_inner( + true, + ctx_node.into(), + parent.into().into(), + fn_loc, + inputs, + params, + None, + None, + ); + if self.widen_if_limit_hit(ctx_node.into(), res) { + return; + } + let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad funciton call"); + let res = ContextNode::from(ctx_node) + .kill( + analyzer, + fn_loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(fn_loc); + let _ = analyzer.add_if_err(res); + } + Ok(()) + }); + + if self.widen_if_limit_hit(ctx_node.into(), res) { + return; + } + + return; + } + + let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, _loc| { + statements + .iter() + .for_each(|stmt| analyzer.parse_ctx_statement(stmt, *unchecked, Some(ctx))); + Ok(()) + }); + if self.widen_if_limit_hit(ctx_node.into(), res) {} + } + VariableDefinition(loc, var_decl, maybe_expr) => { + let ctx = ContextNode::from( + parent_ctx + .expect("No context for variable definition?") + .into(), + ); + tracing::trace!( + "parsing variable definition, {:?} {var_decl:?}", + ctx.path(self) + ); + + if let Some(rhs) = maybe_expr { + match self.parse_ctx_expr(rhs, ctx) { + Ok(()) => { + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + format!( + "Variable definition had no right hand side, {}", + ctx.path(analyzer) + ), + )); + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(&var_decl.ty, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side" + .to_string(), + )); + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer) + .into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def( + ctx, + var_decl, + loc, + &lhs_paths, + Some(&rhs_paths), + )?; + Ok(()) + }) + } else { + Ok(()) + } + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + ret => { + let _ = self.widen_if_limit_hit(ctx, ret); + } + } + } else { + let res = self.parse_ctx_expr(&var_decl.ty, ctx); + if self.widen_if_limit_hit(ctx, res) { + return; + } + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side".to_string(), + )); + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, None)?; + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + } + Args(_loc, _args) => { + tracing::trace!("parsing args, {_args:?}"); + } + If(loc, if_expr, true_expr, maybe_false_expr) => { + tracing::trace!("parsing if, {if_expr:?}"); + let ctx = ContextNode::from(parent_ctx.expect("Dangling if statement").into()); + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.cond_op_stmt(loc, if_expr, true_expr, maybe_false_expr, ctx) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + While(loc, cond, body) => { + tracing::trace!("parsing while, {cond:?}"); + if let Some(parent) = parent_ctx { + let res = self.apply_to_edges( + ContextNode::from(parent.into()), + *loc, + &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, cond, body), + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + Expression(loc, expr) => { + tracing::trace!("parsing expr, {expr:?}"); + if let Some(parent) = parent_ctx { + let ctx = parent.into().into(); + match self.parse_ctx_expr(expr, ctx) { + Ok(()) => { + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad expr"); + ContextNode::from(parent.into()) + .kill( + analyzer, + loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(loc)?; + } + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + e => { + let _ = self.widen_if_limit_hit(ctx, e); + } + } + } + } + For(loc, maybe_for_start, maybe_for_middle, maybe_for_end, maybe_for_body) => { + tracing::trace!("parsing for loop"); + if let Some(parent) = parent_ctx { + let res = + self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { + analyzer.for_loop( + loc, + ctx, + maybe_for_start, + maybe_for_middle, + maybe_for_end, + maybe_for_body, + ) + }); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + DoWhile(loc, while_stmt, while_expr) => { + tracing::trace!("parsing `do while`, {while_expr:?}"); + if let Some(parent) = parent_ctx { + let res = self.apply_to_edges( + ContextNode::from(parent.into()), + *loc, + &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, while_expr, while_stmt), + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + Continue(_loc) => { + tracing::trace!("parsing continue"); + // TODO: We cheat in loops by just widening so continues dont matter yet + } + Break(_loc) => { + tracing::trace!("parsing break"); + // TODO: We cheat in loops by just widening so breaks dont matter yet + } + Assembly { + loc, + dialect: _, + flags: _, + block: yul_block, + } => { + tracing::trace!("parsing assembly"); + let ctx = ContextNode::from( + parent_ctx + .expect("No context for variable definition?") + .into(), + ); + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_yul_statement(&YulStatement::Block(yul_block.clone()), ctx); + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + Return(loc, maybe_ret_expr) => { + tracing::trace!("parsing return"); + if let Some(ret_expr) = maybe_ret_expr { + if let Some(parent) = parent_ctx { + let res = self.parse_ctx_expr(ret_expr, parent.into().into()); + if self.widen_if_limit_hit(parent.into().into(), res) { + return; + } + let res = self.apply_to_edges( + parent.into().into(), + *loc, + &|analyzer, ctx, loc| { + let Ok(Some(ret)) = ctx.pop_expr_latest(loc, analyzer) else { + return Err(ExprErr::NoLhs( + loc, + "Return did not have a associated expression".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let paths = ret.flatten(); + if paths.is_killed() { + tracing::trace!("killing due to bad return"); + let res = ContextNode::from(parent.into()) + .kill(analyzer, loc, paths.killed_kind().unwrap()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + return Ok(()); + } + analyzer.return_match(ctx, &loc, &paths); + Ok(()) + }, + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } else if let Some(parent) = parent_ctx { + let res = + self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { + let res = ctx.add_empty_return(loc, analyzer).into_expr_err(loc); + analyzer.add_if_err(res); + Ok(()) + }); + if self.widen_if_limit_hit(parent.into().into(), res) { + return; + } + } + } + Revert(loc, _maybe_err_path, _exprs) => { + tracing::trace!("parsing revert"); + if let Some(parent) = parent_ctx { + let parent = ContextNode::from(parent.into()); + let res = self.apply_to_edges(parent, *loc, &|analyzer, ctx, loc| { + let res = ctx + .kill(analyzer, loc, KilledKind::Revert) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + Ok(()) + }); + let _ = self.add_if_err(res); + } + } + RevertNamedArgs(_loc, _maybe_err_path, _named_args) => { + tracing::trace!("parsing named revert"); + todo!("revert named args") + } + Emit(_loc, _emit_expr) => {} + Try(_loc, _try_expr, _maybe_returns, _clauses) => {} + Error(_loc) => {} + } + } + + fn widen_if_limit_hit(&mut self, ctx: ContextNode, maybe_err: Result<(), ExprErr>) -> bool { + match maybe_err { + Err(ExprErr::FunctionCallBlockTodo(_, _s)) => { + // dont kill for this one + false + } + Err(e @ ExprErr::GraphError(_, GraphError::MaxStackWidthReached(..), ..)) => { + // TODO: we should ideally peak at each if statement body and only widen variables referenced in there + // but for now we just delete the forks, and reset all local variables + self.add_expr_err(e); + true + } + Err(e) => { + let res = ctx + .kill(self, e.loc(), KilledKind::ParseError) + .into_expr_err(e.loc()); + let _ = self.add_if_err(res); + self.add_expr_err(e); + false + } + _ => false, + } + } + + fn return_match(&mut self, ctx: ContextNode, loc: &Loc, paths: &ExprRet) { + match paths { + ExprRet::CtxKilled(kind) => { + let _ = ctx.kill(self, *loc, *kind); + } + ExprRet::Single(expr) | ExprRet::SingleLiteral(expr) => { + let latest = ContextVarNode::from(*expr).latest_version(self); + // let ret = self.advance_var_in_ctx(latest, *loc, *ctx); + let path = ctx.path(self); + let res = latest.underlying_mut(self).into_expr_err(*loc); + match res { + Ok(var) => { + tracing::trace!("Returning: {}, {}", path, var.display_name); + var.is_return = true; + + self.add_edge(latest, ctx, Edge::Context(ContextEdge::Return)); + + let res = ctx.add_return_node(*loc, latest, self).into_expr_err(*loc); + // ctx.kill(self, *loc, KilledKind::Ended); + let _ = self.add_if_err(res); + } + Err(e) => self.add_expr_err(e), + } + } + ExprRet::Multi(rets) => { + rets.iter().for_each(|expr_ret| { + self.return_match(ctx, loc, expr_ret); + }); + } + ExprRet::Null => {} + } + } + + fn match_var_def( + &mut self, + ctx: ContextNode, + var_decl: &VariableDeclaration, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: Option<&ExprRet>, + ) -> Result { + match (lhs_paths, rhs_paths) { + (ExprRet::CtxKilled(kind), _) | (_, Some(ExprRet::CtxKilled(kind))) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(true) + } + (ExprRet::Single(ty), Some(ExprRet::SingleLiteral(rhs))) => { + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + let res = rhs_cvar.literal_cast_from_ty(ty, self).into_expr_err(loc); + let _ = self.add_if_err(res); + self.match_var_def( + ctx, + var_decl, + loc, + lhs_paths, + Some(&ExprRet::Single(rhs_cvar.into())), + ) + } + (ExprRet::Single(ty), Some(ExprRet::Single(rhs))) => { + let name = var_decl.name.clone().expect("Variable wasn't named"); + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let var = ContextVar { + loc: Some(loc), + name: name.to_string(), + display_name: name.to_string(), + storage: var_decl.storage.clone(), + is_tmp: false, + is_symbolic: true, + tmp_of: None, + is_return: false, + ty, + }; + let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); + ctx.add_var(lhs, self).into_expr_err(loc)?; + self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); + let rhs = ContextVarNode::from(*rhs); + + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let _ = analyzer.assign(loc, lhs, rhs, ctx)?; + // match_assign_ret(analyzer, ctx, ret); + Ok(()) + })?; + + Ok(false) + } + (ExprRet::Single(ty), None) => { + let name = var_decl.name.clone().expect("Variable wasn't named"); + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let var = ContextVar { + loc: Some(loc), + name: name.to_string(), + display_name: name.to_string(), + storage: var_decl.storage.clone(), + is_tmp: false, + is_symbolic: true, + tmp_of: None, + is_return: false, + ty, + }; + let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); + ctx.add_var(lhs, self).into_expr_err(loc)?; + self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); + Ok(false) + } + (l @ ExprRet::Single(_lhs), Some(ExprRet::Multi(rhs_sides))) => Ok(rhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, l, Some(expr_ret))) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), r @ Some(ExprRet::Single(_))) => Ok(lhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, r)) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), None) => Ok(lhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, None)) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), Some(ExprRet::Multi(rhs_sides))) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + Ok(lhs_sides + .iter() + .zip(rhs_sides.iter()) + .map(|(lhs_expr_ret, rhs_expr_ret)| { + self.match_var_def(ctx, var_decl, loc, lhs_expr_ret, Some(rhs_expr_ret)) + }) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)) + } else { + Ok(rhs_sides + .iter() + .map(|rhs_expr_ret| { + self.match_var_def(ctx, var_decl, loc, lhs_paths, Some(rhs_expr_ret)) + }) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)) + } + } + (_e, _f) => Err(ExprErr::Todo( + loc, + "Unhandled ExprRet combination in `match_var_def`".to_string(), + )), + } + } + + fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + if !ctx.killed_or_ret(self).unwrap() { + let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; + if edges.is_empty() { + self.parse_ctx_expr_inner(expr, ctx) + } else { + edges + .iter() + .try_for_each(|fork_ctx| self.parse_ctx_expr(expr, *fork_ctx))?; + Ok(()) + } + } else { + Ok(()) + } + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + use Expression::*; + // println!( + // "ctx: {}, current stack: {:?}, \nexpr: {:?}\n", + // ctx.underlying(self).unwrap().path, + // ctx.underlying(self) + // .unwrap() + // .expr_ret_stack + // .iter() + // .map(|i| i.debug_str(self)) + // .collect::>(), + // expr + // ); + match expr { + // literals + NumberLiteral(loc, int, exp, _unit) => self.number_literal(ctx, *loc, int, exp, false), + AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), + StringLiteral(lits) => lits + .iter() + .try_for_each(|lit| self.string_literal(ctx, lit.loc, &lit.string)), + BoolLiteral(loc, b) => self.bool_literal(ctx, *loc, *b), + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), + HexLiteral(hexes) => self.hex_literals(ctx, hexes), + RationalNumberLiteral(loc, integer, fraction, exp, unit) => { + self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) + } + Negate(_loc, expr) => match &**expr { + NumberLiteral(loc, int, exp, _unit) => { + self.number_literal(ctx, *loc, int, exp, true) + } + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), + e => { + self.parse_ctx_expr(e, ctx)?; + self.apply_to_edges(ctx, e.loc(), &|analyzer, ctx, loc| { + tracing::trace!("Negate variable pop"); + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No variable present to negate".to_string(), + )); + }; + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + // Solidity is dumb and used to allow negation of unsigned integers. + // That means we have to cast this as a int256. + let var = rhs_paths.expect_single().into_expr_err(loc)?; + + let zero = + analyzer.add_node(Node::Concrete(Concrete::from(I256::from(0i32)))); + let zero = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + zero.into(), + analyzer, + ) + .into_expr_err(loc)?; + let zero = analyzer.add_node(Node::ContextVar(zero)); + let new_underlying = ContextVarNode::from(var) + .underlying(analyzer) + .into_expr_err(loc)? + .clone() + .as_cast_tmp(loc, ctx, Builtin::Int(256), analyzer) + .into_expr_err(loc)?; + let node = analyzer.add_node(Node::ContextVar(new_underlying)); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + + ContextVarNode::from(node) + .cast_from(&ContextVarNode::from(zero), analyzer) + .into_expr_err(loc)?; + + let lhs_paths = ExprRet::Single(zero); + analyzer.op_match( + ctx, + loc, + &lhs_paths, + &ExprRet::Single( + ContextVarNode::from(node).latest_version(analyzer).into(), + ), + RangeOp::Sub(true), + false, + ) + }) + } // e => todo!("UnaryMinus unexpected rhs: {e:?}"), + }, + UnaryPlus(_loc, e) => todo!("UnaryPlus unexpected rhs: {e:?}"), + + // Binary ops + Power(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) + } + Add(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignAdd(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Subtract(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignSubtract(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Multiply(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignMultiply(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Divide(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), false) + } + AssignDivide(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), true) + } + Modulo(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) + } + AssignModulo(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) + } + ShiftLeft(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) + } + AssignShiftLeft(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) + } + ShiftRight(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) + } + AssignShiftRight(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) + } + ConditionalOperator(loc, if_expr, true_expr, false_expr) => { + self.cond_op_expr(*loc, if_expr, true_expr, false_expr, ctx) + } + + // Bitwise ops + BitwiseAnd(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) + } + AssignAnd(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) + } + BitwiseXor(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) + } + AssignXor(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) + } + BitwiseOr(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) + } + AssignOr(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) + } + BitwiseNot(loc, lhs_expr) => self.bit_not(*loc, lhs_expr, ctx), + + // assign + Assign(loc, lhs_expr, rhs_expr) => self.assign_exprs(*loc, lhs_expr, rhs_expr, ctx), + List(loc, params) => self.list(ctx, *loc, params), + // array + ArraySubscript(_loc, ty_expr, None) => self.array_ty(ty_expr, ctx), + ArraySubscript(loc, ty_expr, Some(index_expr)) => { + self.index_into_array(*loc, ty_expr, index_expr, ctx) + } + ArraySlice(loc, _lhs_expr, _maybe_middle_expr, _maybe_rhs) => Err(ExprErr::Todo( + *loc, + "Array slicing not currently supported".to_string(), + )), + ArrayLiteral(loc, _) => Err(ExprErr::Todo( + *loc, + "Array literal not currently supported".to_string(), + )), + + // Comparator + Equal(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Eq, rhs, ctx), + NotEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Neq, rhs, ctx), + Less(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lt, rhs, ctx), + More(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gt, rhs, ctx), + LessEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lte, rhs, ctx), + MoreEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gte, rhs, ctx), + + // Logical + Not(loc, expr) => self.not(*loc, expr, ctx), + And(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::And, rhs, ctx), + Or(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Or, rhs, ctx), + + // Function calls + FunctionCallBlock(loc, _func_expr, _input_exprs) => { + // TODO: update msg node + Err(ExprErr::Todo( + *loc, + "Function call block is unsupported. We shouldn't have hit this code path" + .to_string(), + )) + } + NamedFunctionCall(loc, func_expr, input_args) => { + self.named_fn_call_expr(ctx, loc, func_expr, input_args) + } + FunctionCall(loc, func_expr, input_exprs) => { + let updated_func_expr = match **func_expr { + FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { + // we dont currently handle the `{value: .. gas: ..}` msg updating + self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take affect".to_string())); + inner_func_expr.clone() + } + _ => func_expr.clone(), + }; + + self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) + } + // member + New(_loc, expr) => self.parse_ctx_expr(expr, ctx), + This(loc) => { + let var = ContextVar::new_from_contract( + *loc, + ctx.associated_contract(self).into_expr_err(*loc)?, + self, + ) + .into_expr_err(*loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(cvar), self) + .into_expr_err(*loc)?; + Ok(()) + } + MemberAccess(loc, member_expr, ident) => { + self.member_access(*loc, member_expr, ident, ctx) + } + + Delete(loc, expr) => { + fn delete_match( + ctx: ContextNode, + loc: &Loc, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ret: ExprRet, + ) { + match ret { + ExprRet::CtxKilled(kind) => { + let _ = ctx.kill(analyzer, *loc, kind); + } + ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { + let mut new_var = + analyzer.advance_var_in_ctx(cvar.into(), *loc, ctx).unwrap(); + let res = new_var.sol_delete_range(analyzer).into_expr_err(*loc); + let _ = analyzer.add_if_err(res); + } + ExprRet::Multi(inner) => { + inner + .iter() + .for_each(|i| delete_match(ctx, loc, analyzer, i.clone())); + } + ExprRet::Null => {} + } + } + + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("Delete variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "Delete operation had no right hand side".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + delete_match(ctx, &loc, analyzer, ret); + Ok(()) + }) + } + + // de/increment stuff + PreIncrement(loc, expr) => { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("PreIncrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PreIncrement operation had no right hand side".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, true, true, loc, &ret) + }) + } + PostIncrement(loc, expr) => { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("PostIncrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PostIncrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, false, true, loc, &ret) + }) + } + PreDecrement(loc, expr) => { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("PreDecrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PreDecrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, true, false, loc, &ret) + }) + } + PostDecrement(loc, expr) => { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("PostDecrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PostDecrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, false, false, loc, &ret) + }) + } + + // Misc. + Variable(ident) => self.variable(ident, ctx, None), + Type(loc, ty) => { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(idx) = self.builtins().get(&builtin) { + ctx.push_expr(ExprRet::Single(*idx), self) + .into_expr_err(*loc)?; + Ok(()) + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins_mut().insert(builtin, idx); + ctx.push_expr(ExprRet::Single(idx), self) + .into_expr_err(*loc)?; + Ok(()) + } + } else { + ctx.push_expr(ExprRet::Null, self).into_expr_err(*loc)?; + Ok(()) + } + } + Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), + } + } + + fn match_in_de_crement( + &mut self, + ctx: ContextNode, + pre: bool, + increment: bool, + loc: Loc, + rhs: &ExprRet, + ) -> Result<(), ExprErr> { + match rhs { + ExprRet::CtxKilled(kind) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(()) + } + ExprRet::SingleLiteral(var) => { + let res = ContextVarNode::from(*var) + .try_increase_size(self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) + } + ExprRet::Single(var) => { + let cvar = ContextVarNode::from(*var); + let elem = Elem::from(cvar); + let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); + // if let Some(r) = cvar.range(self).into_expr_err(loc)? { + if increment { + if pre { + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() + one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + let res = new_cvar.set_range_max(self, elem + one).into_expr_err(loc); + let _ = self.add_if_err(res); + ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() + one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem + one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(dup.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + } else if pre { + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() - one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem - one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() - one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem - one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(dup.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + // } else { + // panic!("No range in post-increment") + // } + } + ExprRet::Multi(inner) => inner + .iter() + .try_for_each(|expr| self.match_in_de_crement(ctx, pre, increment, loc, expr)), + ExprRet::Null => Ok(()), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn assign_exprs( + &mut self, + loc: Loc, + lhs_expr: &Expression, + rhs_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(rhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "Assign operation had no right hand side".to_string(), + )); + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Assign operation had no left hand side".to_string(), + )); + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_assign_sides(ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; + Ok(()) + }) + }) + } + + fn match_assign_sides( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: &ExprRet, + ) -> Result<(), ExprErr> { + match (lhs_paths, rhs_paths) { + (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), + (ExprRet::CtxKilled(kind), _) | (_, ExprRet::CtxKilled(kind)) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + let res = rhs_cvar + .literal_cast_from(&lhs_cvar, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (l @ ExprRet::Single(_), ExprRet::Multi(rhs_sides)) => rhs_sides + .iter() + .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, l, expr_ret)), + (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { + lhs_sides + .iter() + .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, expr_ret, r)) + } + (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( + |(lhs_expr_ret, rhs_expr_ret)| { + self.match_assign_sides(ctx, loc, lhs_expr_ret, rhs_expr_ret) + }, + ) + } else { + rhs_sides.iter().try_for_each(|rhs_expr_ret| { + self.match_assign_sides(ctx, loc, lhs_paths, rhs_expr_ret) + }) + } + } + (e, f) => todo!("any: {:?} {:?}", e, f), + } + } + + fn assign( + &mut self, + loc: Loc, + lhs_cvar: ContextVarNode, + rhs_cvar: ContextVarNode, + ctx: ContextNode, + ) -> Result { + tracing::trace!( + "assigning: {} to {}", + lhs_cvar.display_name(self).unwrap(), + rhs_cvar.display_name(self).unwrap() + ); + + let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( + Elem::from(rhs_cvar.latest_version(self)), + Elem::from(rhs_cvar.latest_version(self)), + ); + + let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; + + if lhs_cvar.is_storage(self).into_expr_err(loc)? { + self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); + } + + if rhs_cvar.underlying(self).into_expr_err(loc)?.is_return { + if let Some(rhs_ctx) = rhs_cvar.maybe_ctx(self) { + self.add_edge( + rhs_cvar, + new_lhs, + Edge::Context(ContextEdge::ReturnAssign( + rhs_ctx.underlying(self).unwrap().ext_fn_call.is_some(), + )), + ); + } else { + return Err(ExprErr::GraphError( + loc, + GraphError::DetachedVariable(format!( + "No context for variable: {}, node idx: {}, curr ctx: {}, lhs ctx: {}", + rhs_cvar.display_name(self).unwrap(), + rhs_cvar.0, + ctx.path(self), + lhs_cvar.ctx(self).path(self) + )), + )); + } + } + if !lhs_cvar.ty_eq(&rhs_cvar, self).into_expr_err(loc)? { + let cast_to_min = match lhs_cvar.range_min(self).into_expr_err(loc)? { + Some(v) => v, + None => { + return Err(ExprErr::BadRange( + loc, + format!( + "No range during cast? {:?}, {:?}", + lhs_cvar.underlying(self).unwrap(), + rhs_cvar.underlying(self).unwrap(), + ), + )) + } + }; + + let cast_to_max = match lhs_cvar.range_max(self).into_expr_err(loc)? { + Some(v) => v, + None => { + return Err(ExprErr::BadRange( + loc, + format!( + "No range during cast? {:?}, {:?}", + lhs_cvar.underlying(self).unwrap(), + rhs_cvar.underlying(self).unwrap(), + ), + )) + } + }; + + let _ = new_lhs.try_set_range_min(self, new_lower_bound.cast(cast_to_min)); + let _ = new_lhs.try_set_range_max(self, new_upper_bound.cast(cast_to_max)); + } else { + let _ = new_lhs.try_set_range_min(self, new_lower_bound); + let _ = new_lhs.try_set_range_max(self, new_upper_bound); + } + if let Some(rhs_range) = rhs_cvar.ref_range(self).into_expr_err(loc)? { + let res = new_lhs + .try_set_range_exclusions(self, rhs_range.exclusions.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(arr) = lhs_cvar.index_to_array(self) { + if let Some(index) = lhs_cvar.index_access_to_index(self) { + let next_arr = self.advance_var_in_ctx(arr, loc, ctx)?; + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + } + } + + Ok(ExprRet::Single(new_lhs.into())) + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + fn advance_var_in_ctx( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result { + tracing::trace!( + "advancing variable: {}", + cvar_node.display_name(self).into_expr_err(loc)? + ); + if let Some(cvar) = cvar_node.next_version(self) { + panic!( + "Not latest version of: {}", + cvar.display_name(self).unwrap() + ); + } + if let Some(child) = ctx.underlying(self).into_expr_err(loc)?.child { + return Err(ExprErr::GraphError( + loc, + GraphError::VariableUpdateInOldContext(format!( + "Variable update of {} in old context: parent: {}, child: {:#?}", + cvar_node.display_name(self).unwrap(), + ctx.path(self), + child + )), + )); + } + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + // get the old context + let new_cvarnode; + + 'a: { + if let Some(old_ctx) = cvar_node.maybe_ctx(self) { + // get the previous version to remove and prevent spurious nodes + if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { + let prev_version = prev.underlying(self).into_expr_err(loc)?; + // check if there was no change between the previous version and the latest version + if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { + // there was no change in the current context, just give them the current variable + new_cvarnode = cvar_node.into(); + break 'a; + } + } + + new_cvar.loc = Some(loc); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + if old_ctx != ctx { + ctx.add_var(new_cvarnode.into(), self).into_expr_err(loc)?; + self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); + self.add_edge( + new_cvarnode, + cvar_node.0, + Edge::Context(ContextEdge::InheritedVariable), + ); + } else { + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } else { + new_cvar.loc = Some(loc); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } + + Ok(ContextVarNode::from(new_cvarnode)) + } + + fn advance_var_in_curr_ctx( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ) -> Result { + tracing::trace!( + "advancing variable: {}", + cvar_node.display_name(self).into_expr_err(loc)? + ); + if let Some(cvar) = cvar_node.next_version(self) { + panic!( + "Not latest version of: {}", + cvar.display_name(self).unwrap() + ); + } + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + new_cvar.loc = Some(loc); + + let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + + Ok(ContextVarNode::from(new_cvarnode)) + } + + fn advance_var_underlying(&mut self, cvar_node: ContextVarNode, loc: Loc) -> &mut ContextVar { + assert_eq!(None, cvar_node.next_version(self)); + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .unwrap() + .clone(); + new_cvar.loc = Some(loc); + let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + ContextVarNode::from(new_cvarnode) + .underlying_mut(self) + .unwrap() + } + + fn apply_to_edges( + &mut self, + ctx: ContextNode, + loc: Loc, + closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result<(), ExprErr>, + ) -> Result<(), ExprErr> { + let live_edges = ctx.live_edges(self).into_expr_err(loc)?; + tracing::trace!( + "Applying to live edges of: {}. edges: {:#?}", + ctx.path(self), + live_edges.iter().map(|i| i.path(self)).collect::>(), + ); + if !ctx.killed_or_ret(self).into_expr_err(loc)? { + if ctx.underlying(self).into_expr_err(loc)?.child.is_some() { + if live_edges.is_empty() { + Ok(()) + } else { + live_edges + .iter() + .try_for_each(|ctx| closure(self, *ctx, loc)) + } + } else if live_edges.is_empty() { + closure(self, ctx, loc) + } else { + live_edges + .iter() + .try_for_each(|ctx| closure(self, *ctx, loc)) + } + } else { + Ok(()) + } + } + + fn take_from_edge( + &mut self, + ctx: ContextNode, + loc: Loc, + closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result, + ) -> Result, ExprErr> { + let live_edges = ctx.live_edges(self).into_expr_err(loc)?; + tracing::trace!( + "Taking from live edges of: {}. edges: {:#?}", + ctx.path(self), + live_edges.iter().map(|i| i.path(self)).collect::>(), + ); + + if live_edges.is_empty() { + Ok(vec![closure(self, ctx, loc)?]) + } else { + live_edges + .iter() + .map(|ctx| closure(self, *ctx, loc)) + .collect::, ExprErr>>() + } + } +} diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index ba36b1c2..ea18f207 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,20 +1,14 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::FuncCaller; -use crate::context::ExprErr; -use crate::{context::ContextNode, AnalyzerLike}; -use shared::context::ExprRet; -use shared::context::{ContextEdge, ContextVar}; -use shared::nodes::Builtin; -use shared::nodes::Concrete; -use shared::Edge; -use shared::Node; -use solang_parser::pt::Expression; -use solang_parser::pt::Loc; +use crate::{func_call::FuncCaller, IntoExprErr, ExprErr}; -use solang_parser::pt::Identifier; +use graph::{ + AnalyzerBackend, Edge, Node, ContextEdge, + nodes::{Builtin, ContextNode, ContextVar, Concrete, ExprRet, } +}; -impl Env for T where T: AnalyzerLike + Sized {} -pub trait Env: AnalyzerLike + Sized { +use solang_parser::pt::{Loc, Expression, Identifier}; + +impl Env for T where T: AnalyzerBackend + Sized {} +pub trait Env: AnalyzerBackend + Sized { fn env_variable( &mut self, ident: &Identifier, diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 9f32b079..443d11d4 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,21 +1,20 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{func_call::FuncCaller, ContextBuilder}; -use shared::context::ExprRet; -use shared::nodes::{Builtin, Concrete, VarType}; -use shared::{ - analyzer::{AnalyzerLike, GraphLike}, - context::{ContextEdge, ContextNode, ContextVar, ContextVarNode}, - Edge, Node, +use crate::{ + ContextBuilder, IntoExprErr, ExprErr, FuncCaller }; + +use graph::{ + GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{Builtin, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, +}; + use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; impl InternalFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + T: AnalyzerBackend + Sized + GraphBackend { } pub trait InternalFuncCaller: - AnalyzerLike + Sized + GraphLike + AnalyzerBackend + Sized + GraphBackend { #[tracing::instrument(level = "trace", skip_all)] fn call_internal_named_func( @@ -121,8 +120,10 @@ pub trait InternalFuncCaller: .expect("No field in struct in struct construction"); self.parse_ctx_expr(&input.expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(assignment) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + let Some(assignment) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); }; if matches!(assignment, ExprRet::CtxKilled(_)) { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index 0804f6b5..d62ce87d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -1,37 +1,25 @@ -use crate::context::func_call::FuncCaller; -use crate::context::{ - exprs::{Array, MemberAccess, Require}, - ContextBuilder, +use crate::{ + ContextBuilder, IntoExprErr, ExprErr, FuncCaller, + require::Require, array::Array, + member_access::MemberAccess, }; -use crate::context::{ExprErr, IntoExprErr}; -use ethers_core::types::U256; -use shared::nodes::BuiltInNode; -use shared::nodes::StructNode; -use shared::nodes::TyNode; - -use shared::analyzer::Search; -use shared::analyzer::{AnalyzerLike, GraphLike}; -use shared::nodes::Concrete; -use shared::{ - context::*, - nodes::{Builtin, VarType}, - range::{ - elem::RangeOp, - elem_ty::{Elem, RangeExpr}, - Range, SolcRange, - }, - Edge, Node, NodeIdx, +use graph::{ + GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{TyNode, StructNode, BuiltInNode, Builtin, Context, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + elem::*, Range, SolcRange }; +use shared::{Search, NodeIdx}; +use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; impl IntrinsicFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + Search + T: AnalyzerBackend + Sized + GraphBackend + Search { } pub trait IntrinsicFuncCaller: - AnalyzerLike + Sized + GraphLike + Search + AnalyzerBackend + Sized + GraphBackend + Search { /// Calls an intrinsic/builtin function call (casts, require, etc.) #[tracing::instrument(level = "trace", skip_all)] @@ -53,7 +41,7 @@ pub trait IntrinsicFuncCaller: ctx: ContextNode, loc: &Loc, ret: ExprRet, - analyzer: &mut impl AnalyzerLike, + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), ExprErr> { match ret { ExprRet::Single(expect_builtin) => { @@ -115,8 +103,14 @@ pub trait IntrinsicFuncCaller: } self.parse_ctx_expr(&input_exprs[1], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -142,6 +136,8 @@ pub trait IntrinsicFuncCaller: Ok(()) } "delegatecall" | "staticcall" | "call" => { + // TODO: Check if we have the code for the address + // if we dont, model it as a unrestricted call that can make other calls ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; // TODO: try to be smarter based on the address input let booln = self.builtin_or_add(Builtin::Bool); @@ -201,8 +197,13 @@ pub trait IntrinsicFuncCaller: assert!(input_exprs.len() == 2); self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].push(..) was not an array to push to".to_string())) + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].push(..) was not an array to push to".to_string(), + )); }; if matches!(array, ExprRet::CtxKilled(_)) { ctx.push_expr(array, analyzer).into_expr_err(loc)?; @@ -210,8 +211,14 @@ pub trait IntrinsicFuncCaller: } analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "array[].push(..) was not given an element to push".to_string())) + let Some(new_elem) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "array[].push(..) was not given an element to push" + .to_string(), + )); }; if matches!(new_elem, ExprRet::CtxKilled(_)) { @@ -224,7 +231,8 @@ pub trait IntrinsicFuncCaller: // get length let len = analyzer.tmp_length(arr, ctx, loc); - let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + let len_as_idx = + len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; // set length as index analyzer.index_into_array_inner( ctx, @@ -232,7 +240,10 @@ pub trait IntrinsicFuncCaller: ExprRet::Single(arr.latest_version(analyzer).into()), ExprRet::Single(len_as_idx.latest_version(analyzer).into()), )?; - let index = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?.unwrap(); + let index = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap(); if matches!(index, ExprRet::CtxKilled(_)) { ctx.push_expr(index, analyzer).into_expr_err(loc)?; return Ok(()); @@ -246,8 +257,13 @@ pub trait IntrinsicFuncCaller: assert!(input_exprs.len() == 1); self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].pop() was not an array to pop from".to_string(), + )); }; if matches!(array, ExprRet::CtxKilled(_)) { ctx.push_expr(array, analyzer).into_expr_err(loc)?; @@ -260,13 +276,28 @@ pub trait IntrinsicFuncCaller: // get length analyzer.match_length(ctx, loc, array, false)?; - let Some(len) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "array[].pop() was not an array to pop from".to_string())) + let Some(len) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].pop() was not an array to pop from".to_string(), + )); }; let len = len.expect_single().into_expr_err(loc)?; let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; - next_len.set_range_min(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; - next_len.set_range_max(analyzer, Elem::from(len) - Elem::from(Concrete::from(U256::from(1)))).into_expr_err(loc)?; + next_len + .set_range_min( + analyzer, + Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), + ) + .into_expr_err(loc)?; + next_len + .set_range_max( + analyzer, + Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), + ) + .into_expr_err(loc)?; // set length as index analyzer.index_into_array_inner( @@ -281,8 +312,14 @@ pub trait IntrinsicFuncCaller: "keccak256" => { self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + let Some(_input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); }; let var = ContextVar::new_from_builtin( loc, @@ -291,15 +328,22 @@ pub trait IntrinsicFuncCaller: ) .into_expr_err(loc)?; let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; Ok(()) }) } "sha256" => { self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); }; if matches!(input, ExprRet::CtxKilled(_)) { ctx.push_expr(input, analyzer).into_expr_err(loc)?; @@ -312,15 +356,22 @@ pub trait IntrinsicFuncCaller: ) .into_expr_err(loc)?; let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; Ok(()) }) } "ripemd160" => { self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "abi.decode was not given the types for decoding".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); }; if matches!(input, ExprRet::CtxKilled(_)) { ctx.push_expr(input, analyzer).into_expr_err(loc)?; @@ -333,15 +384,22 @@ pub trait IntrinsicFuncCaller: ) .into_expr_err(loc)?; let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; Ok(()) }) } "blockhash" => { self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "blockhash function was not provided a block number".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "blockhash function was not provided a block number" + .to_string(), + )); }; if matches!(input, ExprRet::CtxKilled(_)) { ctx.push_expr(input, analyzer).into_expr_err(loc)?; @@ -354,7 +412,8 @@ pub trait IntrinsicFuncCaller: ) .into_expr_err(loc)?; let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; Ok(()) }) } @@ -375,32 +434,43 @@ pub trait IntrinsicFuncCaller: self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let cctx = Context::new_subctx( - ctx, - None, - loc, - None, - Some(func_idx.into()), - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let call_ctx = analyzer.add_node(Node::Context( - cctx - )); + ctx, + None, + loc, + None, + Some(func_idx.into()), + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let call_ctx = analyzer.add_node(Node::Context(cctx)); ctx.set_child_call(call_ctx.into(), analyzer) .into_expr_err(loc)?; let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); - analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); + analyzer.add_edge( + call_node, + func_idx, + Edge::Context(ContextEdge::Call), + ); + analyzer.add_edge( + call_node, + ctx, + Edge::Context(ContextEdge::Subcontext), + ); analyzer.add_edge( call_ctx, call_node, Edge::Context(ContextEdge::Subcontext), ); - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); }; if matches!(input, ExprRet::CtxKilled(_)) { @@ -410,15 +480,17 @@ pub trait IntrinsicFuncCaller: let mut inner_vals = vec![]; match input { - ExprRet::Single(var) - | ExprRet::SingleLiteral(var) => { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { inner_vals.push( - ContextVarNode::from(var).display_name(analyzer).unwrap(), + ContextVarNode::from(var) + .display_name(analyzer) + .unwrap(), ); } _ => inner_vals.push("".to_string()), } - let inner_name = inner_vals.into_iter().collect::>().join(", "); + let inner_name = + inner_vals.into_iter().collect::>().join(", "); let mut var = ContextVar::new_from_builtin( loc, analyzer.builtin_or_add(Builtin::Address).into(), @@ -430,34 +502,47 @@ pub trait IntrinsicFuncCaller: var.is_return = true; let cvar = analyzer.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Return), + ); ContextNode::from(call_ctx) .add_return_node(loc, cvar.into(), analyzer) .into_expr_err(loc)?; let rctx = Context::new_subctx( - call_ctx.into(), - Some(ctx), - loc, - None, - None, - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let ret_ctx = analyzer.add_node(Node::Context( - rctx - )); + call_ctx.into(), + Some(ctx), + loc, + None, + None, + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let ret_ctx = analyzer.add_node(Node::Context(rctx)); ContextNode::from(call_ctx) .set_child_call(ret_ctx.into(), analyzer) .into_expr_err(loc)?; - analyzer.add_edge(ret_ctx, call_ctx, Edge::Context(ContextEdge::Continue)); + analyzer.add_edge( + ret_ctx, + call_ctx, + Edge::Context(ContextEdge::Continue), + ); let tmp_ret = ContextVarNode::from(cvar) .as_tmp( - ContextNode::from(call_ctx).underlying(analyzer).unwrap().loc, + ContextNode::from(call_ctx) + .underlying(analyzer) + .unwrap() + .loc, ret_ctx.into(), analyzer, ) @@ -466,9 +551,15 @@ pub trait IntrinsicFuncCaller: tmp_ret.underlying_mut(analyzer).unwrap().display_name = format!("ecrecover({}).return", inner_name); ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge( + tmp_ret, + ret_ctx, + Edge::Context(ContextEdge::Variable), + ); - ContextNode::from(ret_ctx).push_expr(ExprRet::Single(tmp_ret.into()), analyzer).into_expr_err(loc)?; + ContextNode::from(ret_ctx) + .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) + .into_expr_err(loc)?; Ok(()) }) } @@ -514,8 +605,13 @@ pub trait IntrinsicFuncCaller: self.parse_inputs(ctx, *loc, input_exprs)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); }; input.expect_length(2).into_expr_err(loc)?; let ret = input.as_vec(); @@ -528,10 +624,16 @@ pub trait IntrinsicFuncCaller: ) .into_expr_err(loc)?; let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_wrapped), RangeOp::Cast, Elem::from(cvar))); - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + let expr = Elem::Expr(RangeExpr::new( + Elem::from(to_be_wrapped), + RangeOp::Cast, + Elem::from(cvar), + )); + next.set_range_min(analyzer, expr.clone()) + .into_expr_err(loc)?; next.set_range_max(analyzer, expr).into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) .into_expr_err(loc) @@ -540,32 +642,55 @@ pub trait IntrinsicFuncCaller: "unwrap" => { self.parse_inputs(ctx, *loc, input_exprs)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "ecrecover did not receive inputs".to_string())) + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); }; input.expect_length(2).into_expr_err(loc)?; let ret = input.as_vec(); let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; let mut var = ContextVar::new_from_builtin( loc, - BuiltInNode::from(TyNode::from(wrapping_ty).underlying(analyzer).into_expr_err(loc)?.ty), + BuiltInNode::from( + TyNode::from(wrapping_ty) + .underlying(analyzer) + .into_expr_err(loc)? + .ty, + ), analyzer, ) .into_expr_err(loc)?; let to_be_unwrapped = ret[1].expect_single().into_expr_err(loc)?; - var.display_name = format!("{}.unwrap({})", - TyNode::from(wrapping_ty).name(analyzer).into_expr_err(loc)?, - ContextVarNode::from(to_be_unwrapped).display_name(analyzer).into_expr_err(loc)? + var.display_name = format!( + "{}.unwrap({})", + TyNode::from(wrapping_ty) + .name(analyzer) + .into_expr_err(loc)?, + ContextVarNode::from(to_be_unwrapped) + .display_name(analyzer) + .into_expr_err(loc)? ); - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new(Elem::from(to_be_unwrapped), RangeOp::Cast, Elem::from(cvar))); - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + let expr = Elem::Expr(RangeExpr::new( + Elem::from(to_be_unwrapped), + RangeOp::Cast, + Elem::from(cvar), + )); + next.set_range_min(analyzer, expr.clone()) + .into_expr_err(loc)?; next.set_range_max(analyzer, expr).into_expr_err(loc)?; - cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; - cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)).into_expr_err(loc)?; + cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; + cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) .into_expr_err(loc) }) @@ -583,8 +708,9 @@ pub trait IntrinsicFuncCaller: // create a new list self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); }; if matches!(len_var, ExprRet::CtxKilled(_)) { @@ -661,7 +787,7 @@ pub trait IntrinsicFuncCaller: fn cast_match( ctx: ContextNode, loc: Loc, - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ty: &Builtin, ret: ExprRet, func_idx: NodeIdx, @@ -685,14 +811,36 @@ pub trait IntrinsicFuncCaller: { let curr_range = SolcRange::try_from_builtin(ty).expect("No default range"); - let min = r + let mut min = r .range_min() .into_owned() .cast(curr_range.range_min().into_owned()); - let max = r + + min.cache_minimize(analyzer).into_expr_err(loc)?; + let mut max = r .range_max() .into_owned() .cast(curr_range.range_max().into_owned()); + + max.cache_maximize(analyzer).into_expr_err(loc)?; + + let existing_max = + r.evaled_range_max(analyzer).into_expr_err(loc)?; + // Check if the max value has changed once the cast is applied. + // If it hasnt, then the cast had no effect and we should adjust the naming + // to not muddle the CLI + if let Some(std::cmp::Ordering::Equal) = max + .maximize(analyzer) + .into_expr_err(loc)? + .range_ord(&existing_max) + { + // its a noop, reflect that in the naming + new_var.underlying_mut(analyzer).unwrap().display_name = + ContextVarNode::from(cvar) + .display_name(analyzer) + .into_expr_err(loc)?; + } + new_var.set_range_min(analyzer, min).into_expr_err(loc)?; new_var.set_range_max(analyzer, max).into_expr_err(loc)?; // cast the range exclusions - TODO: verify this is correct @@ -719,7 +867,7 @@ pub trait IntrinsicFuncCaller: self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); }; if matches!(ret, ExprRet::CtxKilled(_)) { @@ -745,22 +893,22 @@ pub trait IntrinsicFuncCaller: Ok(()) } Node::Contract(_) => { - if input_exprs.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - "Invalid number of inputs to a contract instantiation".to_string(), - )); + if !input_exprs.is_empty() { + self.parse_ctx_expr(&input_exprs[0], ctx)?; } - - self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())) - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); + if !input_exprs.is_empty() { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Contract creation failed".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } } let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { @@ -775,15 +923,15 @@ pub trait IntrinsicFuncCaller: )) } }; - let idx = ret.expect_single().into_expr_err(loc)?; + // let idx = ret.expect_single().into_expr_err(loc)?; let contract_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - contract_cvar - .set_range_min(analyzer, Elem::from(idx)) - .into_expr_err(loc)?; - contract_cvar - .set_range_max(analyzer, Elem::from(idx)) - .into_expr_err(loc)?; + // contract_cvar + // .set_range_min(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; + // contract_cvar + // .set_range_max(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) .into_expr_err(loc) }) @@ -832,8 +980,12 @@ pub trait IntrinsicFuncCaller: self.parse_inputs(ctx, *loc, input_exprs)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Struct Function call failed".to_string())) + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Struct Function call failed".to_string(), + )); }; let inputs = inputs.as_vec(); @@ -895,7 +1047,7 @@ pub trait IntrinsicFuncCaller: self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())) + return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())); }; if matches!(inputs, ExprRet::CtxKilled(_)) { ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index 897feec9..bac2a516 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,37 +1,34 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::{ - internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, +use crate::{ + ContextBuilder, IntoExprErr, ExprErr, namespaced_call::NameSpaceFuncCaller, + internal_call::InternalFuncCaller, + intrinsic_call::IntrinsicFuncCaller }; -use crate::context::ContextBuilder; -use crate::context::ExprErr; + +use graph::{ + GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{FunctionNode, ModifierState, FunctionParamNode, FunctionReturnNode, CallFork, Context, ContextNode, ContextVarNode, ContextVar, ExprRet, }, + Range, +}; +use shared::NodeIdx; + use std::cell::RefCell; use std::rc::Rc; - -use shared::analyzer::GraphLike; -use shared::context::ExprRet; -use shared::context::*; use solang_parser::helpers::CodeLocation; use std::collections::BTreeMap; - -use shared::range::Range; use solang_parser::pt::{Expression, Loc, NamedArgument, StorageLocation}; -use crate::VarType; - -use shared::{analyzer::AnalyzerLike, nodes::*, Edge, Node, NodeIdx}; - pub mod internal_call; pub mod intrinsic_call; pub mod modifier; pub mod namespaced_call; impl FuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + T: AnalyzerBackend + Sized + GraphBackend { } pub trait FuncCaller: - GraphLike + AnalyzerLike + Sized + GraphBackend + AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn named_fn_call_expr( @@ -71,7 +68,10 @@ pub trait FuncCaller: self.parse_ctx_expr(func_expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Function call to nonexistent function".to_string())) + return Err(ExprErr::NoLhs( + loc, + "Function call to nonexistent function".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -184,30 +184,34 @@ pub trait FuncCaller: Rc::new(RefCell::new(false)) }; - inputs - .iter() - .try_for_each(|input| { - self.parse_ctx_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) - })?; + inputs.iter().try_for_each(|input| { + self.parse_ctx_expr(input, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + })?; if !inputs.is_empty() { self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); }; ctx.push_expr(ret, analyzer).into_expr_err(loc) }) @@ -730,31 +734,43 @@ pub trait FuncCaller: })?; rets = callee_ctx.underlying(self).unwrap().ret.clone(); } - let ret = rets - .into_iter() - .enumerate() - .map(|(i, (_, node))| { - let tmp_ret = node - .as_tmp(callee_ctx.underlying(self).unwrap().loc, ret_subctx, self) - .unwrap(); - tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; - tmp_ret - .underlying_mut(self) - .into_expr_err(loc)? - .display_name = - format!("{}.{}", callee_ctx.associated_fn_name(self).unwrap(), i); - ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; - self.add_edge( - tmp_ret, - ret_subctx, - Edge::Context(ContextEdge::Variable), - ); - Ok(ExprRet::Single(tmp_ret.into())) - }) - .collect::>()?; - ret_subctx - .push_expr(ExprRet::Multi(ret), self) - .into_expr_err(loc)?; + + let handle_rets = rets.iter().all(|(_, node)| node.is_some()); + if handle_rets { + let ret = rets + .into_iter() + .enumerate() + .map(|(i, (_, node))| { + let tmp_ret = node + .unwrap() + .as_tmp( + callee_ctx.underlying(self).unwrap().loc, + ret_subctx, + self, + ) + .unwrap(); + tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; + tmp_ret + .underlying_mut(self) + .into_expr_err(loc)? + .display_name = format!( + "{}.{}", + callee_ctx.associated_fn_name(self).unwrap(), + i + ); + ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; + self.add_edge( + tmp_ret, + ret_subctx, + Edge::Context(ContextEdge::Variable), + ); + Ok(ExprRet::Single(tmp_ret.into())) + }) + .collect::>()?; + ret_subctx + .push_expr(ExprRet::Multi(ret), self) + .into_expr_err(loc)?; + } Ok(()) } else { let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); @@ -791,16 +807,20 @@ pub trait FuncCaller: })?; rets = callee_ctx.underlying(self).unwrap().ret.clone(); } - callee_ctx - .push_expr( - ExprRet::Multi( - rets.iter() - .map(|(_, node)| ExprRet::Single((*node).into())) - .collect(), - ), - self, - ) - .into_expr_err(loc) + if rets.iter().all(|(_, node)| node.is_some()) { + callee_ctx + .push_expr( + ExprRet::Multi( + rets.iter() + .map(|(_, node)| ExprRet::Single((node.unwrap()).into())) + .collect(), + ), + self, + ) + .into_expr_err(loc) + } else { + Ok(()) + } } } } @@ -833,8 +853,12 @@ pub trait FuncCaller: let input_paths = if input_exprs.is_empty() { ExprRet::Multi(vec![]) } else { - let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, format!("No inputs to modifier, expected: {}", input_exprs.len()))) + let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + format!("No inputs to modifier, expected: {}", input_exprs.len()), + )); }; if matches!(input_paths, ExprRet::CtxKilled(_)) { @@ -862,12 +886,6 @@ pub trait FuncCaller: ctx: ContextNode, modifier_state: ModifierState, ) -> Result<(), ExprErr> { - tracing::trace!( - "resuming from modifier: {}", - ctx.associated_fn_name(self) - .into_expr_err(modifier_state.loc)? - ); - let mods = modifier_state.parent_fn.modifiers(self); self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { if modifier_state.num + 1 < mods.len() { @@ -944,7 +962,7 @@ pub trait FuncCaller: )?; fn inherit_return_from_call( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -1129,11 +1147,16 @@ pub trait FuncCaller: self.parse_ctx_expr(expr, callee_ctx)?; let f: Vec = self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { - let ret = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap(); - Ok(ret.try_as_func_input_str(analyzer)) + if let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + { + Ok(ret.try_as_func_input_str(analyzer)) + } else { + Err(ExprErr::ParseError( + loc, + "Bad modifier parse".to_string(), + )) + } })?; ctx.delete_child(self).into_expr_err(expr.loc())?; diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index a62adda5..8a6e21f5 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -1,21 +1,20 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::func_call::FuncCaller; +use crate::{ + IntoExprErr, ExprErr, FuncCaller +}; -use crate::context::ExprErr; - -use shared::analyzer::GraphLike; -use shared::context::*; +use graph::{ + GraphBackend, AnalyzerBackend, + nodes::{FunctionNode, ContextNode, ExprRet, } +}; use solang_parser::pt::{Expression, Loc}; -use shared::{analyzer::AnalyzerLike, nodes::*}; - impl ModifierCaller for T where - T: AnalyzerLike + Sized + GraphLike + T: AnalyzerBackend + Sized + GraphBackend { } pub trait ModifierCaller: - GraphLike + AnalyzerLike + Sized + GraphBackend + AnalyzerBackend + Sized { fn handle_modifiers( &mut self, @@ -31,4 +30,4 @@ pub trait ModifierCaller: todo!() } -} +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 9a4118d2..8fa6eb7b 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,24 +1,25 @@ -use crate::context::{ - exprs::{IntoExprErr, MemberAccess}, - func_call::intrinsic_call::IntrinsicFuncCaller, - func_call::FuncCaller, - ContextBuilder, ExprErr, +use crate::{ + FuncCaller, + ContextBuilder, IntoExprErr, ExprErr, + member_access::MemberAccess, + intrinsic_call::IntrinsicFuncCaller }; -use shared::nodes::BuiltInNode; -use shared::{ - analyzer::{AnalyzerLike, GraphLike}, - context::{ContextNode, ContextVarNode, ExprRet}, - nodes::FunctionNode, - Node, NodeIdx, + +use graph::{ + AnalyzerBackend, GraphBackend, Node, + nodes::{BuiltInNode, FunctionNode, ContextNode, ContextVarNode, ExprRet, } }; + +use shared::NodeIdx; + use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; impl NameSpaceFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + T: AnalyzerBackend + Sized + GraphBackend { } pub trait NameSpaceFuncCaller: - AnalyzerLike + Sized + GraphLike + AnalyzerBackend + Sized + GraphBackend { #[tracing::instrument(level = "trace", skip_all)] fn call_name_spaced_named_func( @@ -139,7 +140,10 @@ pub trait NameSpaceFuncCaller: self.parse_ctx_expr(member_expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Namespace function call had no namespace".to_string())) + return Err(ExprErr::NoLhs( + loc, + "Namespace function call had no namespace".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { @@ -210,7 +214,10 @@ pub trait NameSpaceFuncCaller: self.parse_inputs(ctx, loc, input_exprs)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Namespace function call had no inputs".to_string())) + return Err(ExprErr::NoLhs( + loc, + "Namespace function call had no inputs".to_string(), + )); }; if matches!(inputs, ExprRet::CtxKilled(_)) { @@ -220,10 +227,14 @@ pub trait NameSpaceFuncCaller: if possible_funcs.is_empty() { // TODO: this is extremely ugly. if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + return ctx + .kill(analyzer, loc, inputs.killed_kind().unwrap()) + .into_expr_err(loc); } let mut inputs = inputs.as_vec(); - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + if let Node::ContextVar(_) = analyzer.node(member) { + inputs.insert(0, ExprRet::Single(member)) + } let inputs = ExprRet::Multi(inputs); let as_input_str = inputs.try_as_func_input_str(analyzer); @@ -232,7 +243,10 @@ pub trait NameSpaceFuncCaller: if lits.iter().any(|i| *i) { // try to disambiguate if lits[0] { - Err(ExprErr::Todo(loc, "First element in function call was literal".to_string())) + Err(ExprErr::Todo( + loc, + "First element in function call was literal".to_string(), + )) } else { let ty = if let Node::ContextVar(cvar) = analyzer.node(member) { cvar.ty.ty_idx() @@ -240,42 +254,69 @@ pub trait NameSpaceFuncCaller: member }; - let possible_builtins: Vec<_> = analyzer.builtin_fn_inputs().iter().filter_map(|(func_name, (inputs, _))| { - if func_name.starts_with(&ident.name) { - if let Some(input) = inputs.first() { - let Ok(implicitly_castable) = BuiltInNode::from(ty).implicitly_castable_to(&BuiltInNode::from(input.ty), analyzer) else { - return None - }; - if implicitly_castable { - Some(func_name.clone()) + let possible_builtins: Vec<_> = analyzer + .builtin_fn_inputs() + .iter() + .filter_map(|(func_name, (inputs, _))| { + if func_name.starts_with(&ident.name) { + if let Some(input) = inputs.first() { + let Ok(implicitly_castable) = BuiltInNode::from(ty) + .implicitly_castable_to( + &BuiltInNode::from(input.ty), + analyzer, + ) + else { + return None; + }; + if implicitly_castable { + Some(func_name.clone()) + } else { + None + } } else { None } } else { None } - } else { - None - } - }).collect::>(); - let possible_builtins: Vec<_> = possible_builtins.into_iter().filter_map(|name| { - analyzer.builtin_fn_or_maybe_add(&name).map(FunctionNode::from) - }).collect(); - if let Some(func) = - analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_builtins) - { + }) + .collect::>(); + let possible_builtins: Vec<_> = possible_builtins + .into_iter() + .filter_map(|name| { + analyzer + .builtin_fn_or_maybe_add(&name) + .map(FunctionNode::from) + }) + .collect(); + if let Some(func) = analyzer.disambiguate_fn_call( + &ident.name, + lits, + &inputs, + &possible_builtins, + ) { let expr = &MemberAccess( loc, Box::new(member_expr.clone()), Identifier { loc: ident.loc, - name: func.name(analyzer).into_expr_err(loc)?.split('(').collect::>()[0].to_string(), + name: func + .name(analyzer) + .into_expr_err(loc)? + .split('(') + .collect::>()[0] + .to_string(), }, ); analyzer.parse_ctx_expr(expr, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Fallback function parse failure".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -283,13 +324,24 @@ pub trait NameSpaceFuncCaller: } let mut modifier_input_exprs = vec![member_expr.clone()]; modifier_input_exprs.extend(input_exprs.to_vec()); - analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + analyzer.match_intrinsic_fallback( + ctx, + &loc, + &modifier_input_exprs, + ret, + ) }) } else { // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) Err(ExprErr::FunctionNotFound( loc, - format!("Could not disambiguate function, possible functions: {:#?}", possible_builtins.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) + format!( + "Could not disambiguate function, possible functions: {:#?}", + possible_builtins + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect::>() + ), )) } } @@ -304,8 +356,12 @@ pub trait NameSpaceFuncCaller: ); analyzer.parse_ctx_expr(expr, ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Fallback function parse failure".to_string())) + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Fallback function parse failure".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -321,19 +377,24 @@ pub trait NameSpaceFuncCaller: let func = possible_funcs[0]; if func.params(analyzer).len() > inputs.len() { // Add the member back in if its a context variable - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + if let Node::ContextVar(_) = analyzer.node(member) { + inputs.insert(0, ExprRet::Single(member)) + } } let inputs = ExprRet::Multi(inputs); if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + return ctx + .kill(analyzer, loc, inputs.killed_kind().unwrap()) + .into_expr_err(loc); } - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) } else { // Add the member back in if its a context variable let mut inputs = inputs.as_vec(); - if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + if let Node::ContextVar(_) = analyzer.node(member) { + inputs.insert(0, ExprRet::Single(member)) + } let inputs = ExprRet::Multi(inputs); // this is the annoying case due to function overloading & type inference on number literals let mut lits = vec![false]; @@ -354,7 +415,9 @@ pub trait NameSpaceFuncCaller: ); if inputs.has_killed() { - return ctx.kill(analyzer, loc, inputs.killed_kind().unwrap()).into_expr_err(loc); + return ctx + .kill(analyzer, loc, inputs.killed_kind().unwrap()) + .into_expr_err(loc); } if let Some(func) = analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_funcs) @@ -363,7 +426,13 @@ pub trait NameSpaceFuncCaller: } else { Err(ExprErr::FunctionNotFound( loc, - format!("Could not disambiguate function, possible functions: {:#?}", possible_funcs.iter().map(|i| i.name(analyzer).unwrap()).collect::>()) + format!( + "Could not disambiguate function, possible functions: {:#?}", + possible_funcs + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect::>() + ), )) } } diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index dbd5ebfa..5b7d450d 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -1,10 +1,10 @@ -use shared::analyzer::GraphError; use solang_parser::pt::Loc; mod array; mod bin_op; mod cmp; mod cond_op; +mod context_builder; mod env; mod func_call; mod list; @@ -19,6 +19,7 @@ pub use array::*; pub use bin_op::*; pub use cmp::*; pub use cond_op::*; +pub use context_builder::*; pub use func_call::*; pub use env::*; pub use list::*; @@ -42,7 +43,7 @@ pub trait IntoExprErr { fn into_expr_err(self, loc: Loc) -> Result; } -impl IntoExprErr for Result { +impl IntoExprErr for Result { fn into_expr_err(self, loc: Loc) -> Result { match self { Ok(v) => Ok(v), @@ -75,12 +76,12 @@ pub enum ExprErr { IntrinsicNamedArgs(Loc, String), InvalidFunctionInput(Loc, String), TakeFromFork(Loc, String), - GraphError(Loc, GraphError), + GraphError(Loc, graph::GraphError), Unresolved(Loc, String), } impl ExprErr { - pub fn from_graph_err(loc: Loc, graph_err: GraphError) -> Self { + pub fn from_graph_err(loc: Loc, graph_err: graph::GraphError) -> Self { Self::GraphError(loc, graph_err) } } @@ -138,17 +139,17 @@ impl ExprErr { InvalidFunctionInput(_, msg, ..) => msg, TakeFromFork(_, msg, ..) => msg, Unresolved(_, msg, ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(msg), ..) => { + GraphError(_loc, graph::GraphError::NodeConfusion(msg), ..) => msg, + GraphError(_loc, graph::GraphError::MaxStackDepthReached(msg), ..) => msg, + GraphError(_loc, graph::GraphError::MaxStackWidthReached(msg), ..) => msg, + GraphError(_loc, graph::GraphError::ChildRedefinition(msg), ..) => msg, + GraphError(_loc, graph::GraphError::DetachedVariable(msg), ..) => msg, + GraphError(_loc, graph::GraphError::VariableUpdateInOldContext(msg), ..) => { msg } - GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(msg), ..) => msg, - GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(msg), ..) => msg, + GraphError(_loc, graph::GraphError::ExpectedSingle(msg), ..) => msg, + GraphError(_loc, graph::GraphError::StackLengthMismatch(msg), ..) => msg, + GraphError(_loc, graph::GraphError::UnbreakableRecursion(msg), ..) => msg, } } @@ -176,15 +177,15 @@ impl ExprErr { IntrinsicNamedArgs(..) => "Arguments in calls to intrinsic functions cannot be named", InvalidFunctionInput(..) => "Arguments to this function call do not match required types", TakeFromFork(..) => "IR Error: Tried to take from an child context that ended up forking", - GraphError(_loc, shared::analyzer::GraphError::NodeConfusion(_), ..) => "Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::MaxStackDepthReached(_), ..) => "Max call depth reached - either recursion or loop", - GraphError(_loc, shared::analyzer::GraphError::MaxStackWidthReached(_), ..) => "TODO: Max fork width reached - Need to widen variables and remove contexts", - GraphError(_loc, shared::analyzer::GraphError::ChildRedefinition(_), ..) => "Graph IR Error: Child redefintion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::DetachedVariable(_), ..) => "Graph IR Error: Detached Variable. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::VariableUpdateInOldContext(_), ..) => "Graph IR Error: Variable update in an old context. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::ExpectedSingle(_), ..) => "Graph IR Error: Expecting single expression return, got multiple. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::StackLengthMismatch(_), ..) => "Graph IR Error: Expected a particular number of elements on the context stack but found a different amount. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", - GraphError(_loc, shared::analyzer::GraphError::UnbreakableRecursion(_), ..) => "Graph IR Error: Unbreakable recursion in variable range. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::NodeConfusion(_), ..) => "Graph IR Error: Node type confusion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::MaxStackDepthReached(_), ..) => "Max call depth reached - either recursion or loop", + GraphError(_loc, graph::GraphError::MaxStackWidthReached(_), ..) => "TODO: Max fork width reached - Need to widen variables and remove contexts", + GraphError(_loc, graph::GraphError::ChildRedefinition(_), ..) => "Graph IR Error: Child redefintion. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::DetachedVariable(_), ..) => "Graph IR Error: Detached Variable. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::VariableUpdateInOldContext(_), ..) => "Graph IR Error: Variable update in an old context. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::ExpectedSingle(_), ..) => "Graph IR Error: Expecting single expression return, got multiple. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::StackLengthMismatch(_), ..) => "Graph IR Error: Expected a particular number of elements on the context stack but found a different amount. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::UnbreakableRecursion(_), ..) => "Graph IR Error: Unbreakable recursion in variable range. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", } } } diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 66ffa16f..5b94b01c 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -1,16 +1,15 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use shared::{analyzer::AnalyzerLike, context::*, nodes::*, Edge, Node}; -use solang_parser::pt::Expression; +use crate::{ContextBuilder, IntoExprErr, ExprErr}; -use solang_parser::pt::{Parameter, ParameterList}; +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{ContextNode, ContextVar, ExprRet, } +}; -use solang_parser::pt::Loc; +use solang_parser::pt::{Parameter, ParameterList, Loc, Expression}; -impl List for T where T: AnalyzerLike + Sized {} +impl List for T where T: AnalyzerBackend + Sized {} -pub trait List: AnalyzerLike + Sized { +pub trait List: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { params.iter().try_for_each(|(loc, input)| { diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index ec8c4b8f..d8c1f25f 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -1,26 +1,19 @@ -use crate::context::exprs::IntoExprErr; -use crate::ExprErr; -use ethers_core::types::H256; -use ethers_core::types::I256; -use shared::context::ExprRet; -use shared::nodes::Builtin; -use shared::range::elem_ty::Elem; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::{Concrete, ConcreteNode}, - Edge, Node, +use crate::{IntoExprErr, ExprErr}; + +use graph::{ + AnalyzerBackend, Edge, Node, ContextEdge, + nodes::{Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + elem::*, }; -use solang_parser::pt::HexLiteral; -use solang_parser::pt::Identifier; -use ethers_core::types::{Address, U256}; -use solang_parser::pt::Loc; +use ethers_core::types::{H256, I256, U256, Address}; +use solang_parser::pt::{Identifier, HexLiteral, Loc}; + use std::str::FromStr; -impl Literal for T where T: AnalyzerLike + Sized {} +impl Literal for T where T: AnalyzerBackend + Sized {} -pub trait Literal: AnalyzerLike + Sized { +pub trait Literal: AnalyzerBackend + Sized { fn number_literal( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index 449b4d6e..dd64713b 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -1,16 +1,14 @@ -use crate::context::exprs::IntoExprErr; -use crate::ExprErr; -use solang_parser::pt::Loc; -use solang_parser::pt::Statement; +use crate::{ContextBuilder, IntoExprErr, ExprErr}; -use crate::context::ContextBuilder; -use shared::analyzer::GraphLike; -use shared::context::*; -use shared::{analyzer::AnalyzerLike, Node}; -use solang_parser::pt::Expression; +use graph::{ + GraphBackend, AnalyzerBackend, Node, + nodes::{Context, ContextNode, }, +}; -impl Looper for T where T: AnalyzerLike + Sized + GraphLike {} -pub trait Looper: GraphLike + AnalyzerLike + Sized { +use solang_parser::pt::{Loc, Expression, Statement}; + +impl Looper for T where T: AnalyzerBackend + Sized + GraphBackend {} +pub trait Looper: GraphBackend + AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn for_loop( &mut self, diff --git a/crates/solc-expressions/src/member_access.rs b/crates/solc-expressions/src/member_access/mod.rs similarity index 98% rename from crates/solc-expressions/src/member_access.rs rename to crates/solc-expressions/src/member_access/mod.rs index 9bab2c39..682768b7 100644 --- a/crates/solc-expressions/src/member_access.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -1,25 +1,20 @@ -use crate::context::exprs::env::Env; -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{context::exprs::variable::Variable, ContextBuilder, NodeIdx}; -use petgraph::{visit::EdgeRef, Direction}; -use shared::range::elem_ty::Elem; -use shared::range::Range; -use shared::{ - analyzer::AnalyzerLike, - context::*, - nodes::*, - range::SolcRange, - {Edge, Node}, +use crate::{ContextBuilder, Variable, Env, IntoExprErr, ExprErr}; + +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, TypeNode, + nodes::{BuiltInNode, Builtin, FunctionNode, StructNode, EnumNode, TyNode, ContractNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + elem::*, Range, SolcRange }; -use std::collections::BTreeSet; +use shared::NodeIdx; use ethers_core::types::{I256, U256}; - +use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{Expression, Identifier, Loc}; -impl MemberAccess for T where T: AnalyzerLike + Sized {} -pub trait MemberAccess: AnalyzerLike + Sized { +use std::collections::BTreeSet; + +impl MemberAccess for T where T: AnalyzerBackend + Sized {} +pub trait MemberAccess: AnalyzerBackend + Sized { fn visible_member_funcs( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 1faefab8..6a6b57df 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,30 +1,21 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::{ - exprs::{BinOp, Variable}, - AnalyzerLike, Concrete, ConcreteNode, ContextBuilder, Node, -}; -use shared::range::elem_ty::RangeExpr; -use shared::range::range_string::ToRangeString; - -use shared::{ - context::*, - nodes::{BuiltInNode, Builtin, VarType}, - range::{ - elem::{RangeElem, RangeOp}, - elem_ty::{Elem, RangeConcrete}, - Range, RangeEval, SolcRange, - }, - Edge, +use crate::{ContextBuilder, BinOp, Variable, IntoExprErr, ExprErr}; + +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{BuiltInNode, Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, KilledKind, ExprRet, }, + elem::*, Range, RangeEval, SolcRange, range_string::ToRangeString, }; -use solang_parser::helpers::CodeLocation; use ethers_core::types::I256; -use solang_parser::pt::{Expression, Loc}; +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc}, +}; + use std::cmp::Ordering; -impl Require for T where T: Variable + BinOp + Sized + AnalyzerLike {} -pub trait Require: AnalyzerLike + Variable + BinOp + Sized { +impl Require for T where T: Variable + BinOp + Sized + AnalyzerBackend {} +pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Inverts a comparator expression fn inverse_expr(&self, expr: Expression) -> Expression { match expr { diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 2e8896b4..502de6b6 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,15 +1,15 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ExprErr; -use crate::context::{exprs::env::Env, ContextBuilder}; -use shared::nodes::VarNode; -use shared::{analyzer::AnalyzerLike, context::*, Edge, Node}; -use solang_parser::pt::Expression; +use crate::{ContextBuilder, env::Env, IntoExprErr, ExprErr}; -use solang_parser::pt::Identifier; +use graph::{ + AnalyzerBackend, Edge, Node, ContextEdge, + nodes::{VarNode, ContextNode, ContextVar, ExprRet, } +}; -impl Variable for T where T: AnalyzerLike + Sized {} +use solang_parser::pt::{Identifier, Expression}; -pub trait Variable: AnalyzerLike + Sized { +impl Variable for T where T: AnalyzerBackend + Sized {} + +pub trait Variable: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn variable( &mut self, diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index 223167de..2a0a98c2 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -1,23 +1,14 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::ContextBuilder; -use crate::context::ExprParser; -use crate::AnalyzerLike; -use crate::ExprErr; -use shared::context::Context; -use shared::context::ContextVar; -use shared::context::ContextVarNode; -use shared::context::ExprRet; -use shared::nodes::Builtin; -use shared::nodes::VarType; -use shared::{ - context::{ContextEdge, ContextNode}, - Edge, Node, +use crate::{ContextBuilder, ExprParser, IntoExprErr, ExprErr}; + +use graph::{ + AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{Builtin, Context, ContextNode, ContextVarNode, ContextVar, ExprRet, }, }; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::Expression; -use solang_parser::pt::Loc; -use solang_parser::pt::{YulExpression, YulFor, YulStatement, YulSwitch}; +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc, YulExpression, YulFor, YulStatement, YulSwitch}, +}; mod yul_cond_op; pub use yul_cond_op::*; @@ -26,11 +17,11 @@ mod yul_funcs; pub use yul_funcs::*; impl YulBuilder for T where - T: AnalyzerLike + Sized + ExprParser + T: AnalyzerBackend + Sized + ExprParser { } pub trait YulBuilder: - AnalyzerLike + Sized + ExprParser + AnalyzerBackend + Sized + ExprParser { #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) @@ -74,36 +65,39 @@ pub trait YulBuilder: .iter() .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) { - Ok(()) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "No left hand side assignments in yul block".to_string())) + Ok(()) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_side) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "No left hand side assignments in yul block".to_string(), + )); + }; + if matches!(lhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_side) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No right hand side assignments in yul block".to_string(), + )); }; - if matches!(lhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; + + if matches!(rhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) - }; - - if matches!(rhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_sides( - ctx, - loc, - &lhs_side, - &rhs_side, - ) - }) + analyzer.match_assign_sides(ctx, loc, &lhs_side, &rhs_side) }) - } + }), Err(e) => Err(e), } } @@ -123,7 +117,8 @@ pub trait YulBuilder: is_return: false, ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), }; - let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); ctx.add_var(cvar, analyzer).unwrap(); analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); analyzer.advance_var_in_ctx(cvar, *loc, ctx).unwrap() @@ -133,8 +128,13 @@ pub trait YulBuilder: if let Some(yul_expr) = maybe_yul_expr { analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No right hand side assignments in yul block".to_string())) + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No right hand side assignments in yul block".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { @@ -143,7 +143,6 @@ pub trait YulBuilder: } analyzer.match_assign_yul(ctx, loc, &nodes, ret) - }) } else { Ok(()) @@ -163,8 +162,9 @@ pub trait YulBuilder: post_block: _, execution_block: _, }) => { - let sctx = Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) - .into_expr_err(*loc)?; + let sctx = + Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) + .into_expr_err(*loc)?; let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { @@ -202,20 +202,27 @@ pub trait YulBuilder: condition, cases, default, - }) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.yul_switch_stmt(loc, condition.clone(), cases.to_vec(), default.clone(), ctx) - }) - } - Leave(loc) => { - Err(ExprErr::Todo(*loc, "Yul `leave` statements are not currently supported".to_string())) - } - Break(loc) => { - Err(ExprErr::Todo(*loc, "Yul `break` statements are not currently supported".to_string())) - } - Continue(loc) => { - Err(ExprErr::Todo(*loc, "Yul `continue` statements are not currently supported".to_string())) - } + }) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.yul_switch_stmt( + loc, + condition.clone(), + cases.to_vec(), + default.clone(), + ctx, + ) + }), + Leave(loc) => Err(ExprErr::Todo( + *loc, + "Yul `leave` statements are not currently supported".to_string(), + )), + Break(loc) => Err(ExprErr::Todo( + *loc, + "Yul `break` statements are not currently supported".to_string(), + )), + Continue(loc) => Err(ExprErr::Todo( + *loc, + "Yul `continue` statements are not currently supported".to_string(), + )), Block(yul_block) => { yul_block .statements @@ -223,15 +230,15 @@ pub trait YulBuilder: .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); Ok(()) } - FunctionDefinition(yul_func_def) => { - Err(ExprErr::Todo(yul_func_def.loc(), "Yul `function` defintions are not currently supported".to_string())) - } - FunctionCall(yul_func_call) => { - analyzer.yul_func_call(yul_func_call, ctx) - } - Error(loc) => { - Err(ExprErr::ParseError(*loc, "Could not parse this yul statement".to_string())) - } + FunctionDefinition(yul_func_def) => Err(ExprErr::Todo( + yul_func_def.loc(), + "Yul `function` defintions are not currently supported".to_string(), + )), + FunctionCall(yul_func_call) => analyzer.yul_func_call(yul_func_call, ctx), + Error(loc) => Err(ExprErr::ParseError( + *loc, + "Could not parse this yul statement".to_string(), + )), } }); let _ = self.add_if_err(ret); diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index 59d35621..2616e18b 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -1,26 +1,21 @@ -use crate::context::exprs::IntoExprErr; -use crate::context::yul::YulBuilder; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use crate::Concrete; -use crate::ConcreteNode; -use crate::{exprs::Require, AnalyzerLike}; -use ethers_core::types::U256; -use shared::context::ExprRet; -use shared::range::elem::RangeOp; -use shared::{context::*, Edge, Node, NodeIdx}; -use solang_parser::pt::Identifier; -use solang_parser::pt::YulBlock; -use solang_parser::pt::YulFunctionCall; -use solang_parser::pt::YulSwitchOptions; +use crate::{YulBuilder, ContextBuilder, IntoExprErr, ExprErr, require::Require}; + +use graph::{ + AnalyzerBackend, Edge, Node, ContextEdge, + nodes::{ConcreteNode, Context, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + elem::* +}; +use shared::NodeIdx; -use solang_parser::pt::CodeLocation; -use solang_parser::pt::{Expression, Loc}; -use solang_parser::pt::{YulExpression, YulStatement}; +use ethers_core::types::U256; +use solang_parser::pt::{ + Identifier, YulBlock, YulFunctionCall, YulSwitchOptions, CodeLocation, + Expression, Loc, YulExpression, YulStatement +}; -impl YulCondOp for T where T: AnalyzerLike + Require + Sized +impl YulCondOp for T where T: AnalyzerBackend + Require + Sized {} -pub trait YulCondOp: AnalyzerLike + Require + Sized { +pub trait YulCondOp: AnalyzerBackend + Require + Sized { #[tracing::instrument(level = "trace", skip_all)] fn yul_cond_op_stmt( &mut self, @@ -56,7 +51,10 @@ pub trait YulCondOp: AnalyzerLike + Requir analyzer.parse_ctx_yul_expr(if_expr, true_subctx)?; analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "True conditional had no lhs".to_string())); + return Err(ExprErr::NoLhs( + loc, + "True conditional had no lhs".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { @@ -79,7 +77,10 @@ pub trait YulCondOp: AnalyzerLike + Requir analyzer.parse_ctx_yul_expr(if_expr, false_subctx)?; analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "False conditional had no lhs".to_string())); + return Err(ExprErr::NoLhs( + loc, + "False conditional had no lhs".to_string(), + )); }; if matches!(ret, ExprRet::CtxKilled(_)) { @@ -100,20 +101,14 @@ pub trait YulCondOp: AnalyzerLike + Requir ctx: ContextNode, ) -> Result<(), ExprErr> { self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) - .into_expr_err(loc)?; - let true_subctx = ContextNode::from( - analyzer.add_node(Node::Context( - tctx - )), - ); - let fctx = Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) - .into_expr_err(loc)?; - let false_subctx = ContextNode::from( - analyzer.add_node(Node::Context( - fctx - )), - ); + let tctx = + Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) + .into_expr_err(loc)?; + let true_subctx = ContextNode::from(analyzer.add_node(Node::Context(tctx))); + let fctx = + Context::new_subctx(ctx, None, loc, Some("false"), None, false, analyzer, None) + .into_expr_err(loc)?; + let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); @@ -129,13 +124,16 @@ pub trait YulCondOp: AnalyzerLike + Requir Edge::Context(ContextEdge::Subcontext), ); - let if_expr_loc = if_else_chain.if_expr.loc(); analyzer.apply_to_edges(true_subctx, if_expr_loc, &|analyzer, ctx, loc| { analyzer.parse_ctx_yul_expr(&if_else_chain.if_expr, true_subctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - let Some(true_vars) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul switch statement was missing a case discriminator".to_string())) + let Some(true_vars) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul switch statement was missing a case discriminator".to_string(), + )); }; if matches!(true_vars, ExprRet::CtxKilled(_)) { @@ -150,7 +148,6 @@ pub trait YulCondOp: AnalyzerLike + Requir }) })?; - if let Some(next) = &if_else_chain.next { match next { ElseOrDefault::Default(default) => { @@ -329,11 +326,17 @@ impl IfElseChain { child = Some(chain_part.into()); }); let Some(child) = child else { - return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) + return Err(ExprErr::NoRhs( + loc, + "No cases or default found for switch statement".to_string(), + )); }; let Some(iec) = IfElseChain::from_child(child) else { - return Err(ExprErr::NoRhs(loc, "No cases or default found for switch statement".to_string())) + return Err(ExprErr::NoRhs( + loc, + "No cases or default found for switch statement".to_string(), + )); }; Ok(iec) } diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 5f151e5f..473bc4f4 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,36 +1,24 @@ -use crate::context::exprs::BinOp; -use crate::context::exprs::Cmp; -use crate::context::exprs::Env; -use crate::context::exprs::IntoExprErr; -use crate::context::yul::YulBuilder; -use crate::context::ContextBuilder; -use crate::context::ExprErr; -use crate::Concrete; -use crate::ConcreteNode; -use crate::Node; +use crate::{ContextBuilder, Cmp, Env, YulBuilder, BinOp, IntoExprErr, ExprErr}; + +use graph::{ + GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, + nodes::{Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, Concrete, KilledKind, ExprRet, }, + elem::*, SolcRange +}; + use ethers_core::types::U256; -use shared::analyzer::AnalyzerLike; -use shared::analyzer::GraphLike; -use shared::context::ExprRet; -use shared::nodes::VarType; -use shared::range::elem_ty::RangeExpr; +use solang_parser::pt::{YulExpression, YulFunctionCall, Expression, Loc, StorageLocation}; -use solang_parser::pt::YulExpression; use std::cell::RefCell; use std::rc::Rc; -use shared::range::{elem_ty::Elem, SolcRange}; -use shared::{context::ContextEdge, nodes::Builtin, Edge}; -use shared::{context::*, range::elem::RangeOp}; -use solang_parser::pt::YulFunctionCall; -use solang_parser::pt::{Expression, Loc, StorageLocation}; impl YulFuncCaller for T where - T: AnalyzerLike + Sized + GraphLike + T: AnalyzerBackend + Sized + GraphBackend { } pub trait YulFuncCaller: - GraphLike + AnalyzerLike + Sized + GraphBackend + AnalyzerBackend + Sized { fn yul_func_call( &mut self, @@ -76,8 +64,9 @@ pub trait YulFuncCaller: "return" => { self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(offset) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Return had no offset".to_string())) + let Some(offset) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs(loc, "Yul Return had no offset".to_string())); }; if matches!(offset, ExprRet::CtxKilled(_)) { ctx.push_expr(offset, analyzer).into_expr_err(loc)?; @@ -85,8 +74,9 @@ pub trait YulFuncCaller: } analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(size) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Return had no size".to_string())) + let Some(size) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs(loc, "Yul Return had no size".to_string())); }; if matches!(size, ExprRet::CtxKilled(_)) { ctx.push_expr(size, analyzer).into_expr_err(loc)?; @@ -115,7 +105,10 @@ pub trait YulFuncCaller: self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Not operation had no element".to_string())) + return Err(ExprErr::NoRhs( + loc, + "Not operation had no element".to_string(), + )); }; if matches!(lhs, ExprRet::CtxKilled(_)) { @@ -162,8 +155,12 @@ pub trait YulFuncCaller: self.parse_inputs(ctx, *loc, &inputs)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no inputs".to_string())) + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul Binary operation had no inputs".to_string(), + )); }; if matches!(inputs, ExprRet::CtxKilled(_)) { ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; @@ -176,12 +173,25 @@ pub trait YulFuncCaller: // we have to cast the inputs into an EVM word, which is effectively a u256. let word_ty = analyzer.builtin_or_add(Builtin::Uint(256)); let cast_ty = VarType::try_from_idx(analyzer, word_ty).unwrap(); - let lhs_paths = ContextVarNode::from(inputs[0].expect_single().into_expr_err(loc)?); - lhs_paths.cast_from_ty(cast_ty.clone(), analyzer).into_expr_err(loc)?; - let rhs_paths = ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); - rhs_paths.cast_from_ty(cast_ty, analyzer).into_expr_err(loc)?; + let lhs_paths = + ContextVarNode::from(inputs[0].expect_single().into_expr_err(loc)?); + lhs_paths + .cast_from_ty(cast_ty.clone(), analyzer) + .into_expr_err(loc)?; + let rhs_paths = + ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); + rhs_paths + .cast_from_ty(cast_ty, analyzer) + .into_expr_err(loc)?; - analyzer.op_match(ctx, loc, &ExprRet::Single(lhs_paths.into()), &ExprRet::Single(rhs_paths.into()), op, false) + analyzer.op_match( + ctx, + loc, + &ExprRet::Single(lhs_paths.into()), + &ExprRet::Single(rhs_paths.into()), + op, + false, + ) }) } "lt" | "gt" | "slt" | "sgt" | "eq" => { @@ -205,8 +215,12 @@ pub trait YulFuncCaller: self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul Binary operation had no right hand side".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul Binary operation had no right hand side".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { @@ -216,8 +230,13 @@ pub trait YulFuncCaller: analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no left hand side".to_string())) + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Yul Binary operation had no left hand side".to_string(), + )); }; if matches!(rhs_paths, ExprRet::CtxKilled(_)) { @@ -225,8 +244,12 @@ pub trait YulFuncCaller: return Ok(()); } analyzer.cmp_inner(ctx, loc, &lhs_paths, op, &rhs_paths)?; - let Some(result) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Yul Binary operation had no return".to_string())) + let Some(result) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Yul Binary operation had no return".to_string(), + )); }; let res = ContextVarNode::from(result.expect_single().into_expr_err(loc)?); @@ -234,16 +257,14 @@ pub trait YulFuncCaller: let expr = Elem::Expr(RangeExpr::new( Elem::from(res), RangeOp::Cast, - Elem::from(Concrete::Uint(1, U256::zero())) + Elem::from(Concrete::Uint(1, U256::zero())), )); - next.set_range_min(analyzer, expr.clone()).into_expr_err(loc)?; + next.set_range_min(analyzer, expr.clone()) + .into_expr_err(loc)?; next.set_range_max(analyzer, expr).into_expr_err(loc)?; - ctx.push_expr( - ExprRet::Single(next.into()), - analyzer, - ) - .into_expr_err(loc) + ctx.push_expr(ExprRet::Single(next.into()), analyzer) + .into_expr_err(loc) }) }) } @@ -260,8 +281,12 @@ pub trait YulFuncCaller: self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `iszero` operation had no input".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `iszero` operation had no input".to_string(), + )); }; if matches!(lhs_paths, ExprRet::CtxKilled(_)) { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; @@ -304,6 +329,16 @@ pub trait YulFuncCaller: // TODO: actually handle this. @MemoryModel Ok(()) } + "calldatasize" => { + // TODO: actually handle this. @MemoryModel + let b = Builtin::Uint(256); + let var = ContextVar::new_from_builtin(*loc, self.builtin_or_add(b).into(), self) + .into_expr_err(*loc)?; + let node = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(*loc)?; + Ok(()) + } "calldataload" => { if arguments.len() != 1 { return Err(ExprErr::InvalidFunctionInput( @@ -317,15 +352,27 @@ pub trait YulFuncCaller: self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `calldataload` operation had no input".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `calldataload` operation had no input".to_string(), + )); }; // TODO: check const version let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("calldata[{}:{}+32]", elem.display_name(analyzer).into_expr_err(loc)?, elem.display_name(analyzer).into_expr_err(loc)?); + var.display_name = format!( + "calldata[{}:{}+32]", + elem.display_name(analyzer).into_expr_err(loc)?, + elem.display_name(analyzer).into_expr_err(loc)? + ); let node = analyzer.add_node(Node::ContextVar(var)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(loc) @@ -436,15 +483,26 @@ pub trait YulFuncCaller: "balance" => { self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `balance` operation had no input".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `balance` operation had no input".to_string(), + )); }; let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("balance({})", elem.display_name(analyzer).into_expr_err(loc)?); + var.display_name = format!( + "balance({})", + elem.display_name(analyzer).into_expr_err(loc)? + ); let node = analyzer.add_node(Node::ContextVar(var)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(loc) @@ -473,15 +531,26 @@ pub trait YulFuncCaller: "extcodesize" => { self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `extcodesize` operation had no input".to_string(), + )); }; let b = Builtin::Uint(256); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("extcodesize({})", elem.display_name(analyzer).into_expr_err(loc)?); + var.display_name = format!( + "extcodesize({})", + elem.display_name(analyzer).into_expr_err(loc)? + ); let node = analyzer.add_node(Node::ContextVar(var)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(loc) @@ -511,8 +580,12 @@ pub trait YulFuncCaller: self.parse_inputs(ctx, *loc, arguments)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `codecopy` operation had no input".to_string())) + let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `codecopy` operation had no input".to_string(), + )); }; ctx.push_expr(ExprRet::Multi(vec![]), analyzer) .into_expr_err(loc) @@ -532,8 +605,12 @@ pub trait YulFuncCaller: self.parse_inputs(ctx, *loc, arguments)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodecopy` operation had no input".to_string())) + let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `extcodecopy` operation had no input".to_string(), + )); }; ctx.push_expr(ExprRet::Multi(vec![]), analyzer) .into_expr_err(loc) @@ -542,15 +619,26 @@ pub trait YulFuncCaller: "extcodehash" => { self.parse_ctx_yul_expr(&arguments[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Yul `extcodesize` operation had no input".to_string())) + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul `extcodesize` operation had no input".to_string(), + )); }; let b = Builtin::Bytes(32); - let mut var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; let elem = ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); - var.display_name = format!("extcodehash({})", elem.display_name(analyzer).into_expr_err(loc)?); + var.display_name = format!( + "extcodehash({})", + elem.display_name(analyzer).into_expr_err(loc)? + ); let node = analyzer.add_node(Node::ContextVar(var)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(loc) @@ -622,30 +710,34 @@ pub trait YulFuncCaller: Rc::new(RefCell::new(false)) }; - inputs - .iter() - .try_for_each(|input| { - self.parse_ctx_yul_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) - })?; + inputs.iter().try_for_each(|input| { + self.parse_ctx_yul_expr(input, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + })?; if !inputs.is_empty() { self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs(loc, "Inputs did not have left hand sides".to_string())); + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); }; ctx.push_expr(ret, analyzer).into_expr_err(loc) }) @@ -653,4 +745,4 @@ pub trait YulFuncCaller: Ok(()) } } -} +} \ No newline at end of file From 60901db023cea1ea1c13eeac6c9b8ae3b98b4147 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 12:20:06 -0800 Subject: [PATCH 13/71] pyrometer lib compiling --- Cargo.lock | 3 + crates/pyrometer/Cargo.toml | 3 + crates/pyrometer/src/analyzer.rs | 1157 ++++++++++++++++++++++ crates/pyrometer/src/analyzer_backend.rs | 235 +++++ crates/pyrometer/src/builtin_fns.rs | 11 +- crates/pyrometer/src/graph_backend.rs | 20 + crates/pyrometer/src/lib.rs | 1134 +-------------------- crates/shared/src/analyzer_like.rs | 5 +- 8 files changed, 1432 insertions(+), 1136 deletions(-) create mode 100644 crates/pyrometer/src/analyzer.rs create mode 100644 crates/pyrometer/src/analyzer_backend.rs create mode 100644 crates/pyrometer/src/graph_backend.rs diff --git a/Cargo.lock b/Cargo.lock index 0431be9f..698ad507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1139,6 +1139,9 @@ dependencies = [ "ariadne", "ethers-core", "graph", + "petgraph", + "serde_json", + "shared", "solang-parser", "solc-expressions", "tracing", diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml index 76ef2467..37f0d37f 100644 --- a/crates/pyrometer/Cargo.toml +++ b/crates/pyrometer/Cargo.toml @@ -14,9 +14,12 @@ repository.workspace = true analyzers.workspace = true graph.workspace = true solc-expressions.workspace = true +shared.workspace = true +petgraph.workspace = true solang-parser.workspace = true ethers-core.workspace = true ariadne.workspace = true tracing.workspace = true tracing-subscriber.workspace = true +serde_json = "1" \ No newline at end of file diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs new file mode 100644 index 00000000..95388ab7 --- /dev/null +++ b/crates/pyrometer/src/analyzer.rs @@ -0,0 +1,1157 @@ +use crate::builtin_fns; + +use analyzers::LocStrSpan; +use solc_expressions::{ContextBuilder,IntoExprErr, ExprErr}; +use graph::{Edge, Node, nodes::*, VarType, ContextEdge}; +use shared::{Search, GraphLike, AnalyzerLike, NodeIdx}; + +use solang_parser::{ + diagnostics::Diagnostic, + helpers::CodeLocation, + pt::{ + ContractDefinition, ContractPart, EnumDefinition, ErrorDefinition, Expression, + FunctionDefinition, FunctionTy, SourceUnit, SourceUnitPart, StructDefinition, TypeDefinition, + Using, UsingList, VariableDefinition, Identifier, Import, + } +}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span, Source}; +use petgraph::{graph::*, Directed}; +use serde_json::Value; + +use std::{path::{PathBuf, Path}, collections::{BTreeMap, HashMap}, fs}; + +/// A path to either a single solidity file or a Solc Standard JSON file +#[derive(Debug, Clone)] +pub enum Root { + /// A path to a single solidity file + SolidityFile(PathBuf), + /// A path to a Solc Standard JSON file + SolcJSON(PathBuf), + /// A path to a directory containing a remappings file + RemappingsDirectory(PathBuf), +} + +impl Default for Root { + fn default() -> Self { + Root::SolidityFile(PathBuf::new()) + } +} + +/// An intermediate representation of a path to a solidity source +/// +/// This is done so that any source can be fetched from the filesystem again if needed +#[derive(Debug, Clone, Ord, PartialEq, PartialOrd, Eq)] +pub enum SourcePath { + /// A path to a solidity file + SolidityFile(PathBuf), + /// A path to a Solc JSON file and the path within pointing to the solidity source + SolcJSON(PathBuf, String), +} + +impl SourcePath { + pub fn path_to_solidity_source(&self) -> PathBuf { + match self { + SourcePath::SolidityFile(path) => path.clone(), + SourcePath::SolcJSON(_path_to_json, path) => path.clone().into(), + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct FinalPassItem { + pub funcs: Vec, + pub usings: Vec<(Using, NodeIdx)>, + pub inherits: Vec<(ContractNode, Vec)>, + pub vars: Vec<(VarNode, NodeIdx)>, +} +impl FinalPassItem { + pub fn new( + funcs: Vec, + usings: Vec<(Using, NodeIdx)>, + inherits: Vec<(ContractNode, Vec)>, + vars: Vec<(VarNode, NodeIdx)>, + ) -> Self { + Self { + funcs, + usings, + inherits, + vars, + } + } +} + +#[derive(Debug, Clone)] +pub struct Analyzer { + /// The root of the path to either the contract or solc json file to be analyzed + pub root: Root, + /// Solidity remappings - as would be passed into the solidity compiler + pub remappings: Vec<(String, String)>, + /// Solidity sources - tuple of SourcePath, solidity string, file number (None until parsed), and entry node (None until parsed) + pub sources: Vec<(SourcePath, String, Option, Option)>, + /// Since we use a staged approach to analysis, we analyze all user types first then go through and patch up any missing or unresolved + /// parts of a contract (i.e. we parsed a struct which is used as an input to a function signature, we have to know about the struct) + pub final_pass_items: Vec, + /// The next file number to use when parsing a new file + pub file_no: usize, + /// The index of the current `msg` node + pub msg: MsgNode, + /// The index of the current `block` node + pub block: BlockNode, + /// The underlying graph holding all of the elements of the contracts + pub graph: Graph, + /// The entry node - this is the root of the dag, all relevant things should eventually point back to this (otherwise can be discarded) + pub entry: NodeIdx, + /// A mapping of a solidity builtin to the index in the graph + pub builtins: HashMap, + /// A mapping of a user type's name to the index in the graph (i.e. `struct A` would mapped `A` -> index) + pub user_types: HashMap, + /// A mapping of solidity builtin function to a [Function] struct, i.e. `ecrecover` -> `Function { name: "ecrecover", ..}` + pub builtin_fns: HashMap, + /// A mapping of solidity builtin functions to their indices in the graph + pub builtin_fn_nodes: HashMap, + /// A mapping of solidity builtin function names to their parameters and returns, i.e. `ecrecover` -> `([hash, r, s, v], [signer])` + pub builtin_fn_inputs: HashMap, Vec)>, + /// Accumulated errors that happened while analyzing + pub expr_errs: Vec, + /// The maximum depth to analyze to (i.e. call depth) + pub max_depth: usize, + /// The maximum number of forks throughout the lifetime of the analysis. + pub max_width: usize, + /// Dummy function used during parsing to attach contexts to for more complex first-pass parsing (i.e. before `final_pass`) + pub parse_fn: FunctionNode, +} + +impl Default for Analyzer { + fn default() -> Self { + let mut a = Self { + root: Default::default(), + remappings: Default::default(), + sources: Default::default(), + final_pass_items: Default::default(), + file_no: 0, + msg: MsgNode(0), + block: BlockNode(0), + graph: Default::default(), + entry: NodeIndex::from(0), + builtins: Default::default(), + user_types: Default::default(), + builtin_fns: builtin_fns::builtin_fns(), + builtin_fn_nodes: Default::default(), + builtin_fn_inputs: Default::default(), + expr_errs: Default::default(), + max_depth: 50, + max_width: 2_i32.pow(14) as usize, + parse_fn: NodeIdx::from(0).into(), + }; + a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); + + let msg = Msg::default(); + let block = Block::default(); + let msg = a.graph.add_node(Node::Msg(msg)).into(); + let block = a.graph.add_node(Node::Block(block)).into(); + a.msg = msg; + a.block = block; + a.entry = a.add_node(Node::Entry); + let pf = Function { + name: Some(Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".into(), + }), + ..Default::default() + }; + let parser_fn = FunctionNode::from(a.add_node(pf)); + a.add_edge(parser_fn, a.entry, Edge::Func); + a.parse_fn = parser_fn; + a + } +} + +impl Analyzer { + pub fn complicated_parse( + &mut self, + expr: &Expression, + parent: Option, + ) -> Option { + tracing::trace!("Parsing required compile-time evaluation"); + + let ctx = if let Some(parent) = parent { + let pf = Function { + name: Some(Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".into(), + }), + ..Default::default() + }; + let parser_fn = FunctionNode::from(self.add_node(pf)); + self.add_edge(parser_fn, parent, Edge::Func); + + let dummy_ctx = Context::new(parser_fn, "".to_string(), expr.loc()); + let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); + self.add_edge(ctx, parser_fn, Edge::Context(ContextEdge::Context)); + ctx + } else { + let dummy_ctx = Context::new(self.parse_fn, "".to_string(), expr.loc()); + let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); + self.add_edge(ctx, self.entry(), Edge::Context(ContextEdge::Context)); + ctx + }; + + let full_stmt = solang_parser::pt::Statement::Return(expr.loc(), Some(expr.clone())); + self.parse_ctx_statement(&full_stmt, false, Some(ctx)); + let edges = self.add_if_err(ctx.successful_edges(self).into_expr_err(expr.loc()))?; + if edges.len() == 1 { + let res = edges[0].return_nodes(self).into_expr_err(expr.loc()); + + let res = self.add_if_err(res); + + if let Some(res) = res { + res.last().map(|last| ExprRet::Single(last.1.into())) + } else { + None + } + } else if edges.is_empty() { + let res = ctx.return_nodes(self).into_expr_err(expr.loc()); + + let res = self.add_if_err(res); + + if let Some(res) = res { + res.last().map(|last| ExprRet::Single(last.1.into())) + } else { + None + } + } else { + self.add_expr_err(ExprErr::ParseError(expr.loc(), "Expected this to be compile-time evaluatable, but it was nondeterministic likely due to an external call via an interface".to_string())); + None + } + } + + pub fn set_remappings_and_root(&mut self, remappings_path: String) { + let parent_path_buf = PathBuf::from(&remappings_path) + .parent() + .unwrap() + .to_path_buf(); + self.root = Root::RemappingsDirectory(parent_path_buf); + + let remappings_file = fs::read_to_string(remappings_path) + .map_err(|err| err.to_string()) + .expect("Remappings file not found"); + + self.remappings = remappings_file + .lines() + .map(|x| x.trim()) + .filter(|x| !x.is_empty()) + .map(|x| x.split_once('=').expect("Invalid remapping")) + .map(|(name, path)| (name.to_owned(), path.to_owned())) + .collect(); + } + + pub fn update_with_solc_json(&mut self, path_to_json: &PathBuf) { + self.root = Root::SolcJSON(path_to_json.clone()); + + // iterate over the Solc JSON and add all the sources + let json_file = fs::read_to_string(path_to_json) + .unwrap_or_else(|_| panic!("Solc JSON file not found: {}", path_to_json.display())); + let solc_json: Value = serde_json::from_str(&json_file).unwrap(); + let sources = solc_json["sources"].as_object().unwrap(); + for (name, value_obj) in sources { + // value_obj is a Value with a `content` field -> save the `content` field's solidity string + let sol_source = value_obj.as_object().unwrap()["content"].as_str().unwrap(); + // create SourcePath with the path to the JSON and the name of the source + let source_path = SourcePath::SolcJSON(path_to_json.clone(), name.to_owned()); + // Don't know the solang file no yet, so set it to None + let source = (source_path.clone(), sol_source.to_owned(), None, None); + self.sources.push(source); + } + + // also iterate over the Solc JSON and add all the remappings + // settings (optional) -> remappings (optional) -> iterate over all remappings + let remappings = solc_json["settings"]["remappings"].as_array(); + if let Some(remappings) = remappings { + // vec of strings + for remapping in remappings { + // split the remapping string into two parts + let remapping = remapping.as_str().unwrap(); + let remapping = remapping.split_once('=').expect("Invalid remapping"); + // remapping.0 is the name of the remapping + // remapping.1 is the path of the remapping + self.remappings.push(( + remapping.0.to_owned().to_string(), + remapping.1.to_owned().to_string(), + )); + } + } + } + + pub fn print_errors( + &self, + file_mapping: &'_ BTreeMap, + mut src: &mut impl Cache, + ) { + if self.expr_errs.is_empty() { + } else { + self.expr_errs.iter().for_each(|error| { + let str_span = LocStrSpan::new(file_mapping, error.loc()); + let report = Report::build(ReportKind::Error, str_span.source(), str_span.start()) + .with_message(error.report_msg()) + .with_config( + Config::default() + .with_cross_gap(false) + .with_underlines(true) + .with_tab_width(4), + ) + .with_label( + Label::new(str_span) + .with_color(Color::Red) + .with_message(format!("{}", error.msg().fg(Color::Red))), + ); + report.finish().print(&mut src).unwrap(); + }); + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse(&mut self, src: &str, current_path: &SourcePath, entry: bool) -> Option { + // tracing::trace!("parsing: {:?}", current_path); + let file_no = self.file_no; + self.sources + .push((current_path.clone(), src.to_string(), Some(file_no), None)); + match solang_parser::parse(src, file_no) { + Ok((source_unit, _comments)) => { + let parent = self.add_node(Node::SourceUnit(file_no)); + self.add_edge(parent, self.entry, Edge::Source); + let final_pass_part = + self.parse_source_unit(source_unit, file_no, parent, current_path); + self.final_pass_items.push(final_pass_part); + if entry { + self.final_pass(); + } + + Some(parent) + } + Err(diagnostics) => { + print_diagnostics_report(src, ¤t_path.path_to_solidity_source(), diagnostics) + .unwrap(); + panic!("Failed to parse Solidity code for {current_path:?}."); + } + } + } + + pub fn final_pass(&mut self) { + let elems = self.final_pass_items.clone(); + elems.iter().for_each(|final_pass_item| { + final_pass_item + .inherits + .iter() + .for_each(|(contract, inherits)| { + contract.inherit(inherits.to_vec(), self); + }); + final_pass_item.funcs.iter().for_each(|func| { + // add params now that parsing is done + func.set_params_and_ret(self).unwrap(); + }); + + final_pass_item + .usings + .iter() + .for_each(|(using, scope_node)| { + self.parse_using(using, *scope_node); + }); + final_pass_item.vars.iter().for_each(|(var, parent)| { + let loc = var.underlying(self).unwrap().loc; + let res = var.parse_initializer(self, *parent).into_expr_err(loc); + let _ = self.add_if_err(res); + }); + }); + + elems.into_iter().for_each(|final_pass_item| { + final_pass_item.funcs.into_iter().for_each(|func| { + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(body, false, Some(func)); + } + }); + }); + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_source_unit( + &mut self, + source_unit: SourceUnit, + file_no: usize, + parent: NodeIdx, + current_path: &SourcePath, + ) -> FinalPassItem { + let mut all_funcs = vec![]; + let mut all_usings = vec![]; + let mut all_inherits = vec![]; + let mut all_vars = vec![]; + source_unit + .0 + .iter() + .enumerate() + .for_each(|(unit_part, source_unit_part)| { + let (_sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( + source_unit_part, + file_no, + unit_part, + parent, + current_path, + ); + all_funcs.extend(funcs); + all_usings.extend(usings); + all_inherits.extend(inherits); + all_vars.extend(vars); + }); + FinalPassItem::new(all_funcs, all_usings, all_inherits, all_vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_source_unit_part( + &mut self, + sup: &SourceUnitPart, + file_no: usize, + unit_part: usize, + parent: NodeIdx, + // imported: &mut Vec<(Option, String, String, usize)>, + current_path: &SourcePath, + ) -> ( + NodeIdx, + Vec, + Vec<(Using, NodeIdx)>, + Vec<(ContractNode, Vec)>, + Vec<(VarNode, NodeIdx)>, + ) { + use SourceUnitPart::*; + + let sup_node = self.add_node(Node::SourceUnitPart(file_no, unit_part)); + self.add_edge(sup_node, parent, Edge::Part); + + let mut func_nodes = vec![]; + let mut usings = vec![]; + let mut inherits = vec![]; + let mut vars = vec![]; + + match sup { + ContractDefinition(def) => { + let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = + self.parse_contract_def(def, parent); + self.add_edge(node, sup_node, Edge::Contract); + func_nodes.extend(funcs); + usings.extend(con_usings); + inherits.push((node, unhandled_inherits)); + vars.extend(unhandled_vars); + } + StructDefinition(def) => { + let node = self.parse_struct_def(def); + self.add_edge(node, sup_node, Edge::Struct); + } + EnumDefinition(def) => { + let node = self.parse_enum_def(def); + self.add_edge(node, sup_node, Edge::Enum); + } + ErrorDefinition(def) => { + let node = self.parse_err_def(def); + self.add_edge(node, sup_node, Edge::Error); + } + VariableDefinition(def) => { + let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); + if let Some(func) = maybe_func { + func_nodes.push(self.handle_func(func, None)); + } + + if needs_final_pass { + vars.push((node, parent)); + } + + self.add_edge(node, sup_node, Edge::Var); + } + FunctionDefinition(def) => { + let node = self.parse_func_def(def, None); + func_nodes.push(node); + self.add_edge(node, sup_node, Edge::Func); + } + TypeDefinition(def) => { + let node = self.parse_ty_def(def); + self.add_edge(node, sup_node, Edge::Ty); + } + EventDefinition(_def) => todo!(), + Annotation(_anno) => todo!(), + Using(using) => usings.push((*using.clone(), parent)), + StraySemicolon(_loc) => todo!(), + PragmaDirective(_, _, _) => {} + ImportDirective(import) => { + self.parse_import(import, current_path, parent); + } + } + (sup_node, func_nodes, usings, inherits, vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_import(&mut self, import: &Import, current_path: &SourcePath, parent: NodeIdx) { + let (import_path, remapping) = match import { + Import::Plain(import_path, _) => { + tracing::trace!("parse_import, path: {:?}", import_path); + // find the longest remapping that the import_path starts with + let remapping = self + .remappings + .iter() + .filter_map(|(name, target)| { + let str_lit = &import_path.string; + if str_lit.starts_with(name) { + Some((name, target)) + } else { + None + } + }) + .max_by(|(name1, _), (name2, _)| name1.len().cmp(&name2.len())); + (import_path, remapping) + } + Import::Rename(import_path, _elems, _) => { + tracing::trace!("parse_import, path: {:?}, Rename", import_path); + // find the longest remapping that the import_path starts with + let remapping = self + .remappings + .iter() + .filter_map(|(name, target)| { + let str_lit = &import_path.string; + if str_lit.starts_with(name) { + Some((name, target)) + } else { + None + } + }) + .max_by(|(name1, _), (name2, _)| name1.len().cmp(&name2.len())); + (import_path, remapping) + } + e => todo!("import {:?}", e), + }; + /* + Cases to handle: + current path SolidityFile, remapping found + - Root is RemappingsDirectory + current path SolidityFile, no remapping found + - Root is SolidityFile + - Root is RemappingsDirectory + current path SolcJSON, remapping found + - Root is SolcJSON + current path SolcJSON, no remapping found + - Root is SolcJSON + */ + let (remapped, sol) = match current_path { + SourcePath::SolidityFile(sol_file_path) => { + // check for remappings found + let remapped = if let Some((name, target)) = remapping { + // Found matching remapping name and target, check for remapping within the root path + match &self.root { + Root::RemappingsDirectory(root_path) => { + let remapped_path = root_path.join(target).join( + import_path + .string + .replacen(name, "", 1) + .trim_start_matches('/'), + ); + SourcePath::SolidityFile(remapped_path) + } + Root::SolcJSON(_) => { + panic!("Please report this as a bug, root is SolcJSON but current path is a SolidityFile w/ remapping found") + } + Root::SolidityFile(_) => { + panic!("Please report this as a bug, root is SolidityFile but remappings are available") + } + } + } else { + // no remapping found, check for import within the root path + match &self.root { + Root::RemappingsDirectory(_) | Root::SolidityFile(_) => { + // _root_path is not used, should be equal to sol_file_path for first level imports, but different for chains of imports + // should be a relative import from sol_file_path + let remapped_path = sol_file_path + .parent() + .unwrap() + .join(import_path.string.trim_start_matches('/')); + SourcePath::SolidityFile(remapped_path) + } + Root::SolcJSON(_) => { + panic!("Please report this as a bug, root is SolcJSON but current path is a SolidityFile w/ no remapping found") + } + } + }; + + let canonical = fs::canonicalize(remapped.path_to_solidity_source()) + .unwrap_or_else(|_| panic!( + "Could not find file: {remapped:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" + } else { "" } + ) + ); + let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { + panic!( + "Could not find file for dependency: {canonical:?}{}", + if self.remappings.is_empty() { + ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input (where `remappings.txt` is the output of `forge remappings > remappings.txt`)" + } else { "" } + ) + }); + let canonical_source = SourcePath::SolidityFile(canonical); + (canonical_source, sol) + } + SourcePath::SolcJSON(_json_path, current_name) => { + // can use the import_path and remappings to find the import amongst self.sources + let (remapped, sol) = match &self.root { + Root::SolcJSON(_solc_path) => { + // check for remappings found + if let Some((name, target)) = remapping { + // First, take the import_path and remove the remapping name + let import_path_str = import_path.string.replacen(name, "", 1); + let remapped_path = import_path_str.trim_start_matches('/'); + // the source that matches should be "{target}/{remapped_path}". Create PathBuf for this + let remapped_path_buf = + PathBuf::from(format!("{}/{}", target, remapped_path)); + // look for this path in self.sources + let normalized_remapped_path_buf = normalize_path(&remapped_path_buf); + if let Some((confirmed_source_path, sol, _file_no, _entry)) = + self.sources.iter().find(|(path, _sol, _file_no, _entry)| { + normalize_path(path.path_to_solidity_source()) + == normalized_remapped_path_buf + }) + { + // found the path, return the source_path + (confirmed_source_path.clone(), sol.clone()) + } else { + // didn't find the path, panic + panic!("Could not find file: {:#?}", remapped_path_buf); + } + } else { + // need to find name of the file in self.sources + // import will be relative to the current_name + let current_path_buf = PathBuf::from(current_name); + let current_name_parent = current_path_buf + .parent() + .expect("no parent found for current file"); + + let import_path_str = import_path.string.as_str(); + // convert to a PathBuf + let import_path_buf = PathBuf::from(import_path_str); + // check if the import_path begins with an '@' + if import_path_str.starts_with('@') { + // if lib, look for this path in self.sources + let normalized_import = normalize_path(&import_path_buf); + if let Some((confirmed_source_path, sol, _file_no, _entry)) = + self.sources.iter().find(|(path, _sol, _file_no, _entry)| { + normalize_path(path.path_to_solidity_source()) + == normalized_import + }) + { + // found the path, return the source_path + (confirmed_source_path.clone(), sol.clone()) + } else { + // didn't find the path, panic + panic!("Could not find file: {:#?}", normalized_import); + } + } else { + tracing::debug!("import_path_buf is relative"); + + // if relative, join to the current_name_parent + let joined = current_name_parent.join(import_path_buf); + // look for this path in self.sources + let normalized_joined = normalize_path(joined); + + if let Some((confirmed_source_path, sol, _file_no, _entry)) = + self.sources.iter().find(|(path, _sol, _file_no, _entry)| { + normalize_path(path.path_to_solidity_source()) + == normalized_joined + }) + { + // found the path, return the source_path + (confirmed_source_path.clone(), sol.clone()) + } else { + // didn't find the path, panic + panic!("Could not find file: {:#?}", normalized_joined); + } + } + } + } + Root::SolidityFile(_) | Root::RemappingsDirectory(_) => { + panic!("Please report this as a bug, root is SolidityFile or RemappingsDirectory but current path is a SolcJSON") + } + }; + + (remapped, sol) + } + }; + + // check for entry in self.sources that has a matching SourcePath + let normalized_remapped = normalize_path(remapped.path_to_solidity_source()); + if let Some((_, _, _, optional_entry)) = self.sources.iter().find(|(path, _, _, _)| { + normalize_path(path.path_to_solidity_source()) == normalized_remapped + }) { + // if found, add an edge from the parent to the entry + if let Some(o_e) = optional_entry { + self.add_edge(*o_e, parent, Edge::Import); + } + } else { + // if not found, add it + self.sources + .push((remapped.clone(), sol.clone(), None, None)); + } + + let normalized_remapped = normalize_path(remapped.path_to_solidity_source()); + // take self.sources entry with the same path as remapped and update the file_no + if let Some((_, _, optional_file_no, _)) = + self.sources.iter_mut().find(|(path, _, _, _)| { + normalize_path(path.path_to_solidity_source()) == normalized_remapped + }) + { + if optional_file_no.is_some() { + // if the file_no is already set, don't recurse, just return + return; + } + self.file_no += 1; + let file_no = self.file_no; + *optional_file_no = Some(file_no); + } + + let maybe_entry = self.parse(&sol, &remapped, false); + + // take self.sources entry with the same path as remapped and update the entry node + if let Some((_, _, _, optional_entry)) = self.sources.iter_mut().find(|(path, _, _, _)| { + normalize_path(path.path_to_solidity_source()) == normalized_remapped + }) { + *optional_entry = maybe_entry; + } + + if let Some(other_entry) = maybe_entry { + self.add_edge(other_entry, parent, Edge::Import); + }; + } + + // #[tracing::instrument(name = "parse_contract_def", skip_all, fields(name = format!("{:?}", contract_def.name)))] + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_contract_def( + &mut self, + contract_def: &ContractDefinition, + source: NodeIdx, + ) -> ( + ContractNode, + Vec, + Vec<(Using, NodeIdx)>, + Vec, + Vec<(VarNode, NodeIdx)>, + ) { + tracing::trace!( + "Parsing contract {}", + if let Some(ident) = &contract_def.name { + ident.name.clone() + } else { + "interface".to_string() + } + ); + use ContractPart::*; + + let import_nodes = self + .sources + .iter() + .map(|(_, _, _, maybe_node)| *maybe_node) + .collect::>(); + // convert vec to slice + let import_nodes = import_nodes.as_slice(); + + let (contract, unhandled_inherits) = + Contract::from_w_imports(contract_def.clone(), source, import_nodes, self); + + let inherits = contract.inherits.clone(); + let con_name = contract.name.clone().unwrap().name; + let con_node: ContractNode = + if let Some(user_ty_node) = self.user_types.get(&con_name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Contract(contract); + user_ty_node.into() + } else { + let node = self.add_node(Node::Contract(contract)); + self.user_types.insert(con_name, node); + node.into() + }; + + inherits.iter().for_each(|contract_node| { + self.add_edge(*contract_node, con_node, Edge::InheritedContract); + }); + let mut usings = vec![]; + let mut func_nodes = vec![]; + let mut vars = vec![]; + contract_def.parts.iter().for_each(|cpart| match cpart { + StructDefinition(def) => { + let node = self.parse_struct_def(def); + self.add_edge(node, con_node, Edge::Struct); + } + EnumDefinition(def) => { + let node = self.parse_enum_def(def); + self.add_edge(node, con_node, Edge::Enum); + } + ErrorDefinition(def) => { + let node = self.parse_err_def(def); + self.add_edge(node, con_node, Edge::Error); + } + VariableDefinition(def) => { + let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, true); + if let Some(func) = maybe_func { + func_nodes.push(self.handle_func(func, Some(con_node))); + } + + if needs_final_pass { + vars.push((node, con_node.into())); + } + + self.add_edge(node, con_node, Edge::Var); + } + FunctionDefinition(def) => { + let node = self.parse_func_def(def, Some(con_node)); + func_nodes.push(node); + } + TypeDefinition(def) => { + let node = self.parse_ty_def(def); + self.add_edge(node, con_node, Edge::Ty); + } + EventDefinition(_def) => {} + Annotation(_anno) => todo!(), + Using(using) => usings.push((*using.clone(), con_node.0.into())), + StraySemicolon(_loc) => todo!(), + }); + (con_node, func_nodes, usings, unhandled_inherits, vars) + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_using(&mut self, using_def: &Using, scope_node: NodeIdx) { + tracing::trace!("Parsing \"using\" {:?}", using_def); + let Some(ref using_def_ty) = using_def.ty else { + self.add_expr_err(ExprErr::Todo( + using_def.loc(), + "Using statements with wildcards currently unsupported".to_string(), + )); + return; + }; + let maybe_cvar_idx = self.parse_expr(using_def_ty, None); + let ty_idx = match VarType::try_from_idx(self, maybe_cvar_idx) { + Some(v_ty) => v_ty.ty_idx(), + None => { + self.add_expr_err(ExprErr::Unresolved( + using_def.loc(), + "Unable to deduce the type for which to apply the `using` statement to" + .to_string(), + )); + return; + } + }; + + match &using_def.list { + UsingList::Library(ident_paths) => { + ident_paths.identifiers.iter().for_each(|ident| { + if let Some(hopefully_contract) = self.user_types.get(&ident.name) { + match self.node(*hopefully_contract) { + Node::Contract(_) => { + let funcs = ContractNode::from(*hopefully_contract).funcs(self); + let relevant_funcs: Vec<_> = funcs + .iter() + .filter_map(|func| { + let first_param: FunctionParamNode = + *func.params(self).iter().take(1).next()?; + let param_ty = first_param.ty(self).unwrap(); + if param_ty == ty_idx { + Some(func) + } else { + None + } + }) + .copied() + .collect(); + relevant_funcs.iter().for_each(|func| { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + }); + } + _ => self.add_expr_err(ExprErr::ParseError( + using_def.loc(), + "Tried to use a non-contract as a contract in a `using` statement" + .to_string(), + )), + } + } else { + panic!("Cannot find library contract {}", ident.name); + } + }); + } + UsingList::Functions(vec_ident_paths) => { + vec_ident_paths.iter().for_each(|ident_paths| { + if ident_paths.path.identifiers.len() == 2 { + if let Some(hopefully_contract) = + self.user_types.get(&ident_paths.path.identifiers[0].name) + { + if let Some(func) = ContractNode::from(*hopefully_contract) + .funcs(self) + .iter() + .find(|func| { + func.name(self) + .unwrap() + .starts_with(&ident_paths.path.identifiers[1].name) + }) + { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + } else { + panic!( + "Cannot find library function {}.{}", + ident_paths.path.identifiers[0].name, + ident_paths.path.identifiers[1].name + ); + } + } else { + panic!( + "Cannot find library contract {}", + ident_paths.path.identifiers[0].name + ); + } + } else { + // looking for free floating function + let funcs = match self.node(scope_node) { + Node::Contract(_) => self.search_children( + ContractNode::from(scope_node).associated_source(self), + &Edge::Func, + ), + Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), + _ => unreachable!(), + }; + if let Some(func) = funcs.iter().find(|func| { + FunctionNode::from(**func) + .name(self) + .unwrap() + .starts_with(&ident_paths.path.identifiers[0].name) + }) { + self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); + } else { + panic!( + "Cannot find library function {}", + ident_paths.path.identifiers[0].name + ); + } + } + }); + } + UsingList::Error => todo!(), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_enum_def(&mut self, enum_def: &EnumDefinition) -> EnumNode { + tracing::trace!("Parsing enum {:?}", enum_def); + let enu = Enum::from(enum_def.clone()); + let name = enu.name.clone().expect("Enum was not named").name; + + // check if we have an unresolved type by the same name + let enu_node: EnumNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Enum(enu); + user_ty_node.into() + } else { + let node = self.add_node(enu); + self.user_types.insert(name, node); + node.into() + }; + + enu_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_struct_def(&mut self, struct_def: &StructDefinition) -> StructNode { + tracing::trace!("Parsing struct {:?}", struct_def.name); + let strukt = Struct::from(struct_def.clone()); + + let name = strukt.name.clone().expect("Struct was not named").name; + + // check if we have an unresolved type by the same name + let strukt_node: StructNode = + if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Struct(strukt); + user_ty_node.into() + } else { + let node = self.add_node(strukt); + self.user_types.insert(name, node); + node.into() + }; + + struct_def.fields.iter().for_each(|field| { + let f = Field::new(self, field.clone()); + let field_node = self.add_node(f); + self.add_edge(field_node, strukt_node, Edge::Field); + }); + strukt_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_err_def(&mut self, err_def: &ErrorDefinition) -> ErrorNode { + tracing::trace!("Parsing error {:?}", err_def); + let err_node = ErrorNode(self.add_node(Error::from(err_def.clone())).index()); + err_def.fields.iter().for_each(|field| { + let param = ErrorParam::new(self, field.clone()); + let field_node = self.add_node(param); + self.add_edge(field_node, err_node, Edge::ErrorParam); + }); + err_node + } + + #[tracing::instrument(level = "trace", skip_all)] + pub fn parse_func_def( + &mut self, + func_def: &FunctionDefinition, + con_node: Option, + ) -> FunctionNode { + let func = Function::from(func_def.clone()); + tracing::trace!( + "Parsing function {:?}", + func.name + .clone() + .unwrap_or_else(|| solang_parser::pt::Identifier { + loc: solang_parser::pt::Loc::Implicit, + name: "".to_string() + }) + .name + ); + self.handle_func(func, con_node) + } + + pub fn handle_func(&mut self, func: Function, con_node: Option) -> FunctionNode { + match func.ty { + FunctionTy::Constructor => { + let node = self.add_node(func); + let func_node = node.into(); + + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::Constructor); + } + func_node + } + FunctionTy::Fallback => { + let node = self.add_node(func); + let func_node = node.into(); + + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::FallbackFunc); + } + + func_node + } + FunctionTy::Receive => { + // receive function cannot have input/output + let node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(node, con_node, Edge::ReceiveFunc); + } + FunctionNode::from(node) + } + FunctionTy::Function => { + let fn_node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(fn_node, con_node, Edge::Func); + } + fn_node.into() + } + FunctionTy::Modifier => { + let fn_node = self.add_node(func); + if let Some(con_node) = con_node { + self.add_edge(fn_node, con_node, Edge::Modifier); + } + fn_node.into() + } + } + } + + pub fn parse_var_def( + &mut self, + var_def: &VariableDefinition, + in_contract: bool, + ) -> (VarNode, Option, bool) { + tracing::trace!("Parsing variable definition: {:?}", var_def.name); + let var = Var::new(self, var_def.clone(), in_contract); + let mut func = None; + if var.is_public() { + func = Some(Function::from(var_def.clone())); + } + let needs_final_pass = var.initializer_expr.is_some(); + let var_node = VarNode::from(self.add_node(var)); + self.user_types + .insert(var_node.name(self).unwrap(), var_node.into()); + (var_node, func, needs_final_pass) + } + + pub fn parse_ty_def(&mut self, ty_def: &TypeDefinition) -> TyNode { + tracing::trace!("Parsing type definition"); + let ty = Ty::new(self, ty_def.clone()); + let name = ty.name.name.clone(); + let ty_node: TyNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { + let unresolved = self.node_mut(user_ty_node); + *unresolved = Node::Ty(ty); + user_ty_node.into() + } else { + let node = self.add_node(Node::Ty(ty)); + self.user_types.insert(name, node); + node.into() + }; + ty_node + } +} + +/// Print the report of parser's diagnostics +pub fn print_diagnostics_report( + content: &str, + path: &Path, + diagnostics: Vec, +) -> std::io::Result<()> { + let filename = path.file_name().unwrap().to_string_lossy().to_string(); + for diag in diagnostics { + let (start, end) = (diag.loc.start(), diag.loc.end()); + let mut report = Report::build(ReportKind::Error, &filename, start) + .with_message(format!("{:?}", diag.ty)) + .with_label( + Label::new((&filename, start..end)) + .with_color(Color::Red) + .with_message(format!("{}", diag.message.fg(Color::Red))), + ); + + for note in diag.notes { + report = report.with_note(note.message); + } + + report.finish().print((&filename, Source::from(content)))?; + } + Ok(()) +} + +/// Normalize the path by resolving the `.` and `..` components in order to do path comparison. +/// +/// This is used instead of `std::fs::canonicalize()` in cases where the path is not present on the filesystem (e.g. in the case of a Solc Standard JSON) +/// +/// ## Examples +/// +/// ``` +/// use std::path::{Path, PathBuf}; +/// use pyrometer::normalize_path; +/// +/// let path = Path::new("/src/contracts/./Main.sol"); +/// assert_eq!(normalize_path(path), PathBuf::from("/src/contracts/Main.sol")); +/// +/// let path = Path::new("/src/contracts/../Main.sol"); +/// assert_eq!(normalize_path(path), PathBuf::from("/src/Main.sol")); +/// ``` +pub fn normalize_path>(path: P) -> PathBuf { + let mut normalized_path = PathBuf::new(); + + for component in path.as_ref().components() { + match component { + std::path::Component::CurDir => {} // Ignore current dir component + std::path::Component::ParentDir => { + // Handle parent dir component + normalized_path.pop(); + } + _ => normalized_path.push(component), + } + } + + normalized_path +} diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs new file mode 100644 index 00000000..610b44ec --- /dev/null +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -0,0 +1,235 @@ +use crate::Analyzer; + +use graph::{ + AnalyzerBackend, Node, Edge, VarType, + nodes::{ + Concrete, + FunctionParamNode, + ConcreteNode, + MsgNode, + BlockNode, + FunctionParam, + FunctionReturn, + Builtin, + Function, + } +}; +use shared::{AnalyzerLike, NodeIdx, GraphLike}; +use solc_expressions::{IntoExprErr, ExprErr}; + +use ethers_core::types::U256; +use solang_parser::{pt::Expression, helpers::CodeLocation}; + +use std::collections::HashMap; + +impl AnalyzerBackend for Analyzer {} + + +impl AnalyzerLike for Analyzer { + type Expr = Expression; + type ExprErr = ExprErr; + type MsgNode = MsgNode; + type BlockNode = BlockNode; + + type Function = Function; + type FunctionParam = FunctionParam; + type FunctionReturn = FunctionReturn; + type Builtin = Builtin; + + + fn builtin_fn_nodes(&self) -> &HashMap { + &self.builtin_fn_nodes + } + + fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap { + &mut self.builtin_fn_nodes + } + + fn max_depth(&self) -> usize { + self.max_depth + } + + fn max_width(&self) -> usize { + self.max_width + } + + fn add_expr_err(&mut self, err: ExprErr) { + if !self.expr_errs.contains(&err) { + self.expr_errs.push(err); + } + } + + fn expr_errs(&self) -> Vec { + self.expr_errs.clone() + } + + fn entry(&self) -> NodeIdx { + self.entry + } + + fn msg(&mut self) -> MsgNode { + self.msg + } + + fn block(&mut self) -> BlockNode { + self.block + } + + fn builtin_fns(&self) -> &HashMap { + &self.builtin_fns + } + + fn builtin_fn_inputs(&self) -> &HashMap, Vec)> { + &self.builtin_fn_inputs + } + + fn builtins(&self) -> &HashMap { + &self.builtins + } + fn builtins_mut(&mut self) -> &mut HashMap { + &mut self.builtins + } + fn user_types(&self) -> &HashMap { + &self.user_types + } + fn user_types_mut(&mut self) -> &mut HashMap { + &mut self.user_types + } + + fn parse_expr(&mut self, expr: &Expression, parent: Option) -> NodeIdx { + use Expression::*; + match expr { + Type(_loc, ty) => { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(idx) = self.builtins.get(&builtin) { + *idx + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins.insert(builtin, idx); + idx + } + } else if let Some(idx) = self.complicated_parse(expr, parent) { + self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) + .unwrap_or(0.into()) + } else { + 0.into() + } + } + Variable(ident) => { + if let Some(idx) = self.user_types.get(&ident.name) { + *idx + } else { + let node = self.add_node(Node::Unresolved(ident.clone())); + self.user_types.insert(ident.name.clone(), node); + node + } + } + ArraySubscript(_loc, ty_expr, None) => { + let inner_ty = self.parse_expr(ty_expr, parent); + if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { + let dyn_b = Builtin::Array(var_type); + if let Some(idx) = self.builtins.get(&dyn_b) { + *idx + } else { + let idx = self.add_node(Node::Builtin(dyn_b.clone())); + self.builtins.insert(dyn_b, idx); + idx + } + } else { + inner_ty + } + } + ArraySubscript(loc, ty_expr, Some(idx_expr)) => { + let inner_ty = self.parse_expr(ty_expr, parent); + let idx = self.parse_expr(idx_expr, parent); + if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { + let res = ConcreteNode::from(idx) + .underlying(self) + .into_expr_err(*loc) + .cloned(); + if let Some(concrete) = self.add_if_err(res) { + if let Some(size) = concrete.uint_val() { + let dyn_b = Builtin::SizedArray(size, var_type); + if let Some(idx) = self.builtins.get(&dyn_b) { + *idx + } else { + let idx = self.add_node(Node::Builtin(dyn_b.clone())); + self.builtins.insert(dyn_b, idx); + idx + } + } else { + inner_ty + } + } else { + inner_ty + } + } else { + inner_ty + } + } + NumberLiteral(_loc, integer, exponent, _unit) => { + let int = U256::from_dec_str(integer).unwrap(); + let val = if !exponent.is_empty() { + let exp = U256::from_dec_str(exponent).unwrap(); + int * U256::from(10).pow(exp) + } else { + int + }; + + self.add_node(Node::Concrete(Concrete::Uint(256, val))) + } + _ => { + if let Some(idx) = self.complicated_parse(expr, parent) { + self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) + .unwrap_or(0.into()) + } else { + 0.into() + } + } + } + } + + fn builtin_or_add(&mut self, builtin: Builtin) -> NodeIdx { + if let Some(idx) = self.builtins().get(&builtin) { + *idx + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins_mut().insert(builtin, idx); + idx + } + } + + fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option + where + Self: std::marker::Sized, + { + if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { + Some(*idx) + } else if let Some(func) = self.builtin_fns().get(builtin_name) { + let (inputs, outputs) = self + .builtin_fn_inputs() + .get(builtin_name) + .expect("builtin func but no inputs") + .clone(); + let func_node = self.add_node(Node::Function(func.clone())); + let mut params_strs = vec![]; + inputs.into_iter().for_each(|input| { + let input_node = self.add_node(input); + params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); + self.add_edge(input_node, func_node, Edge::FunctionParam); + }); + outputs.into_iter().for_each(|output| { + let output_node = self.add_node(output); + self.add_edge(output_node, func_node, Edge::FunctionReturn); + }); + + self.add_edge(func_node, self.entry(), Edge::Func); + + self.builtin_fn_nodes_mut() + .insert(builtin_name.to_string(), func_node); + Some(func_node) + } else { + None + } + } +} \ No newline at end of file diff --git a/crates/pyrometer/src/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs index f6832307..83175f73 100644 --- a/crates/pyrometer/src/builtin_fns.rs +++ b/crates/pyrometer/src/builtin_fns.rs @@ -1,7 +1,10 @@ -use crate::Builtin; -use crate::{Function, FunctionParam, FunctionReturn}; -use shared::analyzer::{AnalyzerLike, GraphLike}; +use graph::nodes::{ + Builtin, Function, FunctionParam, FunctionReturn +}; +use shared::{AnalyzerLike, GraphLike}; + use solang_parser::pt::{FunctionAttribute, Identifier, Loc, StorageLocation, Visibility}; + use std::collections::HashMap; macro_rules! builtin_fn { @@ -324,7 +327,7 @@ pub fn builtin_fns() -> HashMap { } pub fn builtin_fns_inputs( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut (impl GraphLike + AnalyzerLike), ) -> HashMap, Vec)> { let funcs = [ ("wrap", vec![], vec![]), diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs new file mode 100644 index 00000000..2000130f --- /dev/null +++ b/crates/pyrometer/src/graph_backend.rs @@ -0,0 +1,20 @@ +use crate::Analyzer; + +use shared::GraphLike; +use graph::{GraphBackend, Node, Edge}; + +use petgraph::{Graph, Directed}; + +impl GraphLike for Analyzer { + type Node = Node; + type Edge = Edge; + fn graph_mut(&mut self) -> &mut Graph { + &mut self.graph + } + + fn graph(&self) -> &Graph { + &self.graph + } +} + +impl GraphBackend for Analyzer {} \ No newline at end of file diff --git a/crates/pyrometer/src/lib.rs b/crates/pyrometer/src/lib.rs index eb83ba53..0b2a1f42 100644 --- a/crates/pyrometer/src/lib.rs +++ b/crates/pyrometer/src/lib.rs @@ -1,1134 +1,8 @@ -use crate::analyzers::LocStrSpan; -use crate::context::exprs::IntoExprErr; -use crate::exprs::ExprErr; -use ariadne::Source; -use ethers_core::types::U256; -use shared::analyzer::*; -use shared::context::ContextNode; -use shared::context::ExprRet; -use shared::context::{Context, ContextEdge}; -use shared::nodes::*; -use shared::{Edge, Node, NodeIdx}; -use solang_parser::diagnostics::Diagnostic; -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::Identifier; -use solang_parser::pt::Import; -use std::collections::BTreeMap; - -use std::ffi::OsString; -use std::path::Path; - -use solang_parser::pt::{ - ContractDefinition, ContractPart, EnumDefinition, ErrorDefinition, Expression, - FunctionDefinition, FunctionTy, SourceUnit, SourceUnitPart, StructDefinition, TypeDefinition, - Using, UsingList, VariableDefinition, -}; -use std::path::PathBuf; -use std::{collections::HashMap, fs}; - -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use petgraph::{graph::*, Directed}; - +mod analyzer; mod builtin_fns; +mod analyzer_backend; +mod graph_backend; -pub mod context; -// pub mod range; -use context::*; -pub use shared; - -#[derive(Debug, Clone, Default)] -pub struct FinalPassItem { - pub funcs: Vec, - pub usings: Vec<(Using, NodeIdx)>, - pub inherits: Vec<(ContractNode, Vec)>, - pub vars: Vec<(VarNode, NodeIdx)>, -} -impl FinalPassItem { - pub fn new( - funcs: Vec, - usings: Vec<(Using, NodeIdx)>, - inherits: Vec<(ContractNode, Vec)>, - vars: Vec<(VarNode, NodeIdx)>, - ) -> Self { - Self { - funcs, - usings, - inherits, - vars, - } - } -} - -#[derive(Debug, Clone)] -pub struct Analyzer { - /// The root path of the contract to be analyzed - pub root: PathBuf, - /// Solidity remappings - as would be passed into the solidity compiler - pub remappings: Vec<(String, String)>, - /// Imported sources - the canonicalized string to the entry source element index - pub imported_srcs: BTreeMap>, - /// Since we use a staged approach to analysis, we analyze all user types first then go through and patch up any missing or unresolved - /// parts of a contract (i.e. we parsed a struct which is used as an input to a function signature, we have to know about the struct) - pub final_pass_items: Vec, - /// The next file number to use when parsing a new file - pub file_no: usize, - /// The index of the current `msg` node - pub msg: MsgNode, - /// The index of the current `block` node - pub block: BlockNode, - /// The underlying graph holding all of the elements of the contracts - pub graph: Graph, - /// The entry node - this is the root of the dag, all relevant things should eventually point back to this (otherwise can be discarded) - pub entry: NodeIdx, - /// A mapping of a solidity builtin to the index in the graph - pub builtins: HashMap, - /// A mapping of a user type's name to the index in the graph (i.e. `struct A` would mapped `A` -> index) - pub user_types: HashMap, - /// A mapping of solidity builtin function to a [Function] struct, i.e. `ecrecover` -> `Function { name: "ecrecover", ..}` - pub builtin_fns: HashMap, - /// A mapping of solidity builtin functions to their indices in the graph - pub builtin_fn_nodes: HashMap, - /// A mapping of solidity builtin function names to their parameters and returns, i.e. `ecrecover` -> `([hash, r, s, v], [signer])` - pub builtin_fn_inputs: HashMap, Vec)>, - /// Accumulated errors that happened while analyzing - pub expr_errs: Vec, - /// The maximum depth to analyze to (i.e. call depth) - pub max_depth: usize, - /// The maximum number of forks throughout the lifetime of the analysis. - pub max_width: usize, - /// Dummy function used during parsing to attach contexts to for more complex first-pass parsing (i.e. before `final_pass`) - pub parse_fn: FunctionNode, -} - -impl Default for Analyzer { - fn default() -> Self { - let mut a = Self { - root: Default::default(), - remappings: Default::default(), - imported_srcs: Default::default(), - final_pass_items: Default::default(), - file_no: 0, - msg: MsgNode(0), - block: BlockNode(0), - graph: Default::default(), - entry: NodeIndex::from(0), - builtins: Default::default(), - user_types: Default::default(), - builtin_fns: builtin_fns::builtin_fns(), - builtin_fn_nodes: Default::default(), - builtin_fn_inputs: Default::default(), - expr_errs: Default::default(), - max_depth: 1024, - max_width: 2_i32.pow(14) as usize, - parse_fn: NodeIdx::from(0).into(), - }; - a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); - - let msg = Msg::default(); - let block = Block::default(); - let msg = a.graph.add_node(Node::Msg(msg)).into(); - let block = a.graph.add_node(Node::Block(block)).into(); - a.msg = msg; - a.block = block; - a.entry = a.add_node(Node::Entry); - let pf = Function { - name: Some(Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".into(), - }), - ..Default::default() - }; - let parser_fn = FunctionNode::from(a.add_node(pf)); - a.add_edge(parser_fn, a.entry, Edge::Func); - a.parse_fn = parser_fn; - a - } -} - -impl GraphLike for Analyzer { - fn graph_mut(&mut self) -> &mut Graph { - &mut self.graph - } - - fn graph(&self) -> &Graph { - &self.graph - } -} - -impl AnalyzerBackend for Analyzer { - type Expr = Expression; - type ExprErr = ExprErr; - - fn builtin_fn_nodes(&self) -> &HashMap { - &self.builtin_fn_nodes - } - - fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap { - &mut self.builtin_fn_nodes - } - - fn max_depth(&self) -> usize { - self.max_depth - } - - fn max_width(&self) -> usize { - self.max_width - } - - fn add_expr_err(&mut self, err: ExprErr) { - if !self.expr_errs.contains(&err) { - self.expr_errs.push(err); - } - } - - fn expr_errs(&self) -> Vec { - self.expr_errs.clone() - } - - fn entry(&self) -> NodeIdx { - self.entry - } - - fn msg(&mut self) -> MsgNode { - self.msg - } - - fn block(&mut self) -> BlockNode { - self.block - } - - fn builtin_fns(&self) -> &HashMap { - &self.builtin_fns - } - - fn builtin_fn_inputs(&self) -> &HashMap, Vec)> { - &self.builtin_fn_inputs - } - - fn builtins(&self) -> &HashMap { - &self.builtins - } - fn builtins_mut(&mut self) -> &mut HashMap { - &mut self.builtins - } - fn user_types(&self) -> &HashMap { - &self.user_types - } - fn user_types_mut(&mut self) -> &mut HashMap { - &mut self.user_types - } - - fn parse_expr(&mut self, expr: &Expression, parent: Option) -> NodeIdx { - use Expression::*; - match expr { - Type(_loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { - if let Some(idx) = self.builtins.get(&builtin) { - *idx - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins.insert(builtin, idx); - idx - } - } else if let Some(idx) = self.complicated_parse(expr, parent) { - self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) - .unwrap_or(0.into()) - } else { - 0.into() - } - } - Variable(ident) => { - if let Some(idx) = self.user_types.get(&ident.name) { - *idx - } else { - let node = self.add_node(Node::Unresolved(ident.clone())); - self.user_types.insert(ident.name.clone(), node); - node - } - } - ArraySubscript(_loc, ty_expr, None) => { - let inner_ty = self.parse_expr(ty_expr, parent); - if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { - let dyn_b = Builtin::Array(var_type); - if let Some(idx) = self.builtins.get(&dyn_b) { - *idx - } else { - let idx = self.add_node(Node::Builtin(dyn_b.clone())); - self.builtins.insert(dyn_b, idx); - idx - } - } else { - inner_ty - } - } - ArraySubscript(loc, ty_expr, Some(idx_expr)) => { - let inner_ty = self.parse_expr(ty_expr, parent); - let idx = self.parse_expr(idx_expr, parent); - if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { - let res = ConcreteNode::from(idx) - .underlying(self) - .into_expr_err(*loc) - .cloned(); - if let Some(concrete) = self.add_if_err(res) { - if let Some(size) = concrete.uint_val() { - let dyn_b = Builtin::SizedArray(size, var_type); - if let Some(idx) = self.builtins.get(&dyn_b) { - *idx - } else { - let idx = self.add_node(Node::Builtin(dyn_b.clone())); - self.builtins.insert(dyn_b, idx); - idx - } - } else { - inner_ty - } - } else { - inner_ty - } - } else { - inner_ty - } - } - NumberLiteral(_loc, integer, exponent, _unit) => { - let int = U256::from_dec_str(integer).unwrap(); - let val = if !exponent.is_empty() { - let exp = U256::from_dec_str(exponent).unwrap(); - int * U256::from(10).pow(exp) - } else { - int - }; - - self.add_node(Node::Concrete(Concrete::Uint(256, val))) - } - _ => { - if let Some(idx) = self.complicated_parse(expr, parent) { - self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) - .unwrap_or(0.into()) - } else { - 0.into() - } - } - } - } -} - -impl Analyzer { - pub fn complicated_parse( - &mut self, - expr: &Expression, - parent: Option, - ) -> Option { - tracing::trace!("Parsing required compile-time evaluation"); - - let ctx = if let Some(parent) = parent { - let pf = Function { - name: Some(Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".into(), - }), - ..Default::default() - }; - let parser_fn = FunctionNode::from(self.add_node(pf)); - self.add_edge(parser_fn, parent, Edge::Func); - - let dummy_ctx = Context::new(parser_fn, "".to_string(), expr.loc()); - let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); - self.add_edge(ctx, parser_fn, Edge::Context(ContextEdge::Context)); - ctx - } else { - let dummy_ctx = Context::new(self.parse_fn, "".to_string(), expr.loc()); - let ctx = ContextNode::from(self.add_node(Node::Context(dummy_ctx))); - self.add_edge(ctx, self.entry(), Edge::Context(ContextEdge::Context)); - ctx - }; - - let full_stmt = solang_parser::pt::Statement::Return(expr.loc(), Some(expr.clone())); - self.parse_ctx_statement(&full_stmt, false, Some(ctx)); - let edges = self.add_if_err(ctx.all_edges(self).into_expr_err(expr.loc()))?; - if edges.len() == 1 { - let res = edges[0].return_nodes(self).into_expr_err(expr.loc()); - - let res = self.add_if_err(res); - - if let Some(res) = res { - res.last().map(|last| ExprRet::Single(last.1.into())) - } else { - None - } - } else if edges.is_empty() { - let res = ctx.return_nodes(self).into_expr_err(expr.loc()); - - let res = self.add_if_err(res); - - if let Some(res) = res { - res.last().map(|last| ExprRet::Single(last.1.into())) - } else { - None - } - } else { - self.add_expr_err(ExprErr::ParseError(expr.loc(), "Expected this to be compile-time evaluatable, but it was nondeterministic likely due to an external call via an interface".to_string())); - None - } - } - - pub fn set_remappings_and_root(&mut self, remappings_path: String) { - self.root = PathBuf::from(&remappings_path) - .parent() - .unwrap() - .to_path_buf(); - let remappings_file = fs::read_to_string(remappings_path) - .map_err(|err| err.to_string()) - .expect("Remappings file not found"); - - self.remappings = remappings_file - .lines() - .map(|x| x.trim()) - .filter(|x| !x.is_empty()) - .map(|x| x.split_once('=').expect("Invalid remapping")) - .map(|(name, path)| (name.to_owned(), path.to_owned())) - .collect(); - } - - pub fn print_errors( - &self, - file_mapping: &'_ BTreeMap, - mut src: &mut impl Cache, - ) { - if self.expr_errs.is_empty() { - } else { - self.expr_errs.iter().for_each(|error| { - let str_span = LocStrSpan::new(file_mapping, error.loc()); - let report = Report::build(ReportKind::Error, str_span.source(), str_span.start()) - .with_message(error.report_msg()) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ) - .with_label( - Label::new(str_span) - .with_color(Color::Red) - .with_message(format!("{}", error.msg().fg(Color::Red))), - ); - report.finish().print(&mut src).unwrap(); - }); - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse( - &mut self, - src: &str, - current_path: &Path, - entry: bool, - ) -> ( - Option, - Vec<(Option, String, String, usize)>, - ) { - // tracing::trace!("parsing: {:?}", current_path); - let file_no = self.file_no; - let mut imported = vec![]; - match solang_parser::parse(src, file_no) { - Ok((source_unit, _comments)) => { - let parent = self.add_node(Node::SourceUnit(file_no)); - self.add_edge(parent, self.entry, Edge::Source); - let final_pass_part = self.parse_source_unit( - source_unit, - file_no, - parent, - &mut imported, - current_path, - ); - self.final_pass_items.push(final_pass_part); - if entry { - self.final_pass(); - } - - (Some(parent), imported) - } - Err(diagnostics) => { - print_diagnostics_report(src, current_path, diagnostics).unwrap(); - panic!("Failed to parse Solidity code for {current_path:?}."); - } - } - } - - pub fn final_pass(&mut self) { - let elems = self.final_pass_items.clone(); - elems.iter().for_each(|final_pass_item| { - final_pass_item - .inherits - .iter() - .for_each(|(contract, inherits)| { - contract.inherit(inherits.to_vec(), self); - }); - final_pass_item.funcs.iter().for_each(|func| { - // add params now that parsing is done - func.set_params_and_ret(self).unwrap(); - }); - - final_pass_item - .usings - .iter() - .for_each(|(using, scope_node)| { - self.parse_using(using, *scope_node); - }); - final_pass_item.vars.iter().for_each(|(var, parent)| { - let loc = var.underlying(self).unwrap().loc; - let res = var.parse_initializer(self, *parent).into_expr_err(loc); - let _ = self.add_if_err(res); - }); - }); - - elems.into_iter().for_each(|final_pass_item| { - final_pass_item.funcs.into_iter().for_each(|func| { - if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(func)); - } - }); - }); - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_source_unit( - &mut self, - source_unit: SourceUnit, - file_no: usize, - parent: NodeIdx, - imported: &mut Vec<(Option, String, String, usize)>, - current_path: &Path, - ) -> FinalPassItem { - let mut all_funcs = vec![]; - let mut all_usings = vec![]; - let mut all_inherits = vec![]; - let mut all_vars = vec![]; - source_unit - .0 - .iter() - .enumerate() - .for_each(|(unit_part, source_unit_part)| { - let (_sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( - source_unit_part, - file_no, - unit_part, - parent, - imported, - current_path, - ); - all_funcs.extend(funcs); - all_usings.extend(usings); - all_inherits.extend(inherits); - all_vars.extend(vars); - }); - FinalPassItem::new(all_funcs, all_usings, all_inherits, all_vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_source_unit_part( - &mut self, - sup: &SourceUnitPart, - file_no: usize, - unit_part: usize, - parent: NodeIdx, - imported: &mut Vec<(Option, String, String, usize)>, - current_path: &Path, - ) -> ( - NodeIdx, - Vec, - Vec<(Using, NodeIdx)>, - Vec<(ContractNode, Vec)>, - Vec<(VarNode, NodeIdx)>, - ) { - use SourceUnitPart::*; - - let sup_node = self.add_node(Node::SourceUnitPart(file_no, unit_part)); - self.add_edge(sup_node, parent, Edge::Part); - - let mut func_nodes = vec![]; - let mut usings = vec![]; - let mut inherits = vec![]; - let mut vars = vec![]; - - match sup { - ContractDefinition(def) => { - let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = - self.parse_contract_def(def, parent, imported); - self.add_edge(node, sup_node, Edge::Contract); - func_nodes.extend(funcs); - usings.extend(con_usings); - inherits.push((node, unhandled_inherits)); - vars.extend(unhandled_vars); - } - StructDefinition(def) => { - let node = self.parse_struct_def(def); - self.add_edge(node, sup_node, Edge::Struct); - } - EnumDefinition(def) => { - let node = self.parse_enum_def(def); - self.add_edge(node, sup_node, Edge::Enum); - } - ErrorDefinition(def) => { - let node = self.parse_err_def(def); - self.add_edge(node, sup_node, Edge::Error); - } - VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); - if let Some(func) = maybe_func { - func_nodes.push(self.handle_func(func, None)); - } - - if needs_final_pass { - vars.push((node, parent)); - } - - self.add_edge(node, sup_node, Edge::Var); - } - FunctionDefinition(def) => { - let node = self.parse_func_def(def, None); - func_nodes.push(node); - self.add_edge(node, sup_node, Edge::Func); - } - TypeDefinition(def) => { - let node = self.parse_ty_def(def); - self.add_edge(node, sup_node, Edge::Ty); - } - EventDefinition(_def) => todo!(), - Annotation(_anno) => todo!(), - Using(using) => usings.push((*using.clone(), parent)), - StraySemicolon(_loc) => todo!(), - PragmaDirective(_, _, _) => {} - ImportDirective(import) => { - imported.extend(self.parse_import(import, current_path, parent)) - } - } - (sup_node, func_nodes, usings, inherits, vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_import( - &mut self, - import: &Import, - current_path: &Path, - parent: NodeIdx, - ) -> Vec<(Option, String, String, usize)> { - match import { - Import::Plain(import_path, _) => { - tracing::trace!("parse_import, path: {:?}", import_path); - let remapping = self - .remappings - .iter() - .find(|x| import_path.string.starts_with(&x.0)); - - let remapped = if let Some((name, path)) = remapping { - self.root.join(path).join( - import_path - .string - .replacen(name, "", 1) - .trim_start_matches('/'), - ) - } else { - current_path - .parent() - .unwrap() - .join(import_path.string.clone()) - }; - - let canonical = fs::canonicalize(&remapped) - .unwrap_or_else(|_| panic!( - "Could not find file: {remapped:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - ); - let canonical_str_path = canonical.as_os_str(); - if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { - if let Some(o_e) = other_entry { - self.add_edge(*o_e, parent, Edge::Import); - } - return vec![]; - } - - let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { - panic!( - "Could not find file for dependency: {canonical:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input (where `remappings.txt` is the output of `forge remappings > remappings.txt`)" - } else { "" } - ) - }); - self.file_no += 1; - let file_no = self.file_no; - // breaks recursion issues - self.imported_srcs.insert(canonical_str_path.into(), None); - let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); - self.imported_srcs - .insert(canonical_str_path.into(), maybe_entry); - if let Some(other_entry) = maybe_entry { - self.add_edge(other_entry, parent, Edge::Import); - } - - inner_sources.push(( - maybe_entry, - remapped.to_str().unwrap().to_owned(), - sol.to_string(), - file_no, - )); - inner_sources - } - Import::Rename(import_path, _elems, _) => { - tracing::trace!("parse_import, path: {:?}, Rename", import_path); - let remapping = self - .remappings - .iter() - .find(|x| import_path.string.starts_with(&x.0)); - - let remapped = if let Some((name, path)) = remapping { - self.root.join(path).join( - import_path - .string - .replacen(name, "", 1) - .trim_start_matches('/'), - ) - } else { - current_path - .parent() - .unwrap() - .join(import_path.string.clone()) - }; - - let canonical = fs::canonicalize(&remapped).unwrap_or_else(|_| panic!( - "Could not find file: {remapped:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - ); - let canonical_str_path = canonical.as_os_str(); - if let Some(other_entry) = self.imported_srcs.get(canonical_str_path) { - if let Some(o_e) = other_entry { - self.add_edge(*o_e, parent, Edge::Import); - } - return vec![]; - } - - let sol = fs::read_to_string(&canonical).unwrap_or_else(|_| { - panic!( - "Could not find file for dependency: {canonical:?}{}", - if self.remappings.is_empty() { - ". It looks like you didn't pass in any remappings. Try adding the `--remappings ./path/to/remappings.txt` to the command line input" - } else { "" } - ) - }); - self.file_no += 1; - let file_no = self.file_no; - - // breaks recursion issues - self.imported_srcs.insert(canonical_str_path.into(), None); - let (maybe_entry, mut inner_sources) = self.parse(&sol, &remapped, false); - self.imported_srcs - .insert(canonical_str_path.into(), maybe_entry); - if let Some(other_entry) = maybe_entry { - self.add_edge(other_entry, parent, Edge::Import); - } - - inner_sources.push(( - maybe_entry, - remapped.to_str().unwrap().to_owned(), - sol.to_string(), - file_no, - )); - inner_sources - } - e => todo!("import {:?}", e), - } - } - - // #[tracing::instrument(name = "parse_contract_def", skip_all, fields(name = format!("{:?}", contract_def.name)))] - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_contract_def( - &mut self, - contract_def: &ContractDefinition, - source: NodeIdx, - imports: &[(Option, String, String, usize)], - ) -> ( - ContractNode, - Vec, - Vec<(Using, NodeIdx)>, - Vec, - Vec<(VarNode, NodeIdx)>, - ) { - tracing::trace!( - "Parsing contract {}", - if let Some(ident) = &contract_def.name { - ident.name.clone() - } else { - "interface".to_string() - } - ); - use ContractPart::*; - - let (contract, unhandled_inherits) = - Contract::from_w_imports(contract_def.clone(), source, imports, self); - - let inherits = contract.inherits.clone(); - let con_name = contract.name.clone().unwrap().name; - let con_node: ContractNode = - if let Some(user_ty_node) = self.user_types.get(&con_name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Contract(contract); - user_ty_node.into() - } else { - let node = self.add_node(Node::Contract(contract)); - self.user_types.insert(con_name, node); - node.into() - }; - - inherits.iter().for_each(|contract_node| { - self.add_edge(*contract_node, con_node, Edge::InheritedContract); - }); - let mut usings = vec![]; - let mut func_nodes = vec![]; - let mut vars = vec![]; - contract_def.parts.iter().for_each(|cpart| match cpart { - StructDefinition(def) => { - let node = self.parse_struct_def(def); - self.add_edge(node, con_node, Edge::Struct); - } - EnumDefinition(def) => { - let node = self.parse_enum_def(def); - self.add_edge(node, con_node, Edge::Enum); - } - ErrorDefinition(def) => { - let node = self.parse_err_def(def); - self.add_edge(node, con_node, Edge::Error); - } - VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, true); - if let Some(func) = maybe_func { - func_nodes.push(self.handle_func(func, Some(con_node))); - } - - if needs_final_pass { - vars.push((node, con_node.into())); - } - - self.add_edge(node, con_node, Edge::Var); - } - FunctionDefinition(def) => { - let node = self.parse_func_def(def, Some(con_node)); - func_nodes.push(node); - } - TypeDefinition(def) => { - let node = self.parse_ty_def(def); - self.add_edge(node, con_node, Edge::Ty); - } - EventDefinition(_def) => {} - Annotation(_anno) => todo!(), - Using(using) => usings.push((*using.clone(), con_node.0.into())), - StraySemicolon(_loc) => todo!(), - }); - (con_node, func_nodes, usings, unhandled_inherits, vars) - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_using(&mut self, using_def: &Using, scope_node: NodeIdx) { - tracing::trace!("Parsing \"using\" {:?}", using_def); - let Some(ref using_def_ty) = using_def.ty else { - self.add_expr_err(ExprErr::Todo(using_def.loc(), "Using statements with wildcards currently unsupported".to_string())); - return; - }; - let maybe_cvar_idx = self.parse_expr(using_def_ty, None); - let ty_idx = match VarType::try_from_idx(self, maybe_cvar_idx) { - Some(v_ty) => v_ty.ty_idx(), - None => { - self.add_expr_err(ExprErr::Unresolved( - using_def.loc(), - "Unable to deduce the type for which to apply the `using` statement to" - .to_string(), - )); - return; - } - }; - - match &using_def.list { - UsingList::Library(ident_paths) => { - ident_paths.identifiers.iter().for_each(|ident| { - if let Some(hopefully_contract) = self.user_types.get(&ident.name) { - match self.node(*hopefully_contract) { - Node::Contract(_) => { - let funcs = ContractNode::from(*hopefully_contract).funcs(self); - let relevant_funcs: Vec<_> = funcs - .iter() - .filter_map(|func| { - let first_param: FunctionParamNode = - *func.params(self).iter().take(1).next()?; - let param_ty = first_param.ty(self).unwrap(); - if param_ty == ty_idx { - Some(func) - } else { - None - } - }) - .copied() - .collect(); - relevant_funcs.iter().for_each(|func| { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - }); - } - _ => self.add_expr_err(ExprErr::ParseError( - using_def.loc(), - "Tried to use a non-contract as a contract in a `using` statement" - .to_string(), - )), - } - } else { - panic!("Cannot find library contract {}", ident.name); - } - }); - } - UsingList::Functions(vec_ident_paths) => { - vec_ident_paths.iter().for_each(|ident_paths| { - if ident_paths.path.identifiers.len() == 2 { - if let Some(hopefully_contract) = - self.user_types.get(&ident_paths.path.identifiers[0].name) - { - if let Some(func) = ContractNode::from(*hopefully_contract) - .funcs(self) - .iter() - .find(|func| { - func.name(self) - .unwrap() - .starts_with(&ident_paths.path.identifiers[1].name) - }) - { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - } else { - panic!( - "Cannot find library function {}.{}", - ident_paths.path.identifiers[0].name, - ident_paths.path.identifiers[1].name - ); - } - } else { - panic!( - "Cannot find library contract {}", - ident_paths.path.identifiers[0].name - ); - } - } else { - // looking for free floating function - let funcs = match self.node(scope_node) { - Node::Contract(_) => self.search_children( - ContractNode::from(scope_node).associated_source(self), - &Edge::Func, - ), - Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), - _ => unreachable!(), - }; - if let Some(func) = funcs.iter().find(|func| { - FunctionNode::from(**func) - .name(self) - .unwrap() - .starts_with(&ident_paths.path.identifiers[0].name) - }) { - self.add_edge(ty_idx, *func, Edge::LibraryFunction(scope_node)); - } else { - panic!( - "Cannot find library function {}", - ident_paths.path.identifiers[0].name - ); - } - } - }); - } - UsingList::Error => todo!(), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_enum_def(&mut self, enum_def: &EnumDefinition) -> EnumNode { - tracing::trace!("Parsing enum {:?}", enum_def); - let enu = Enum::from(enum_def.clone()); - let name = enu.name.clone().expect("Enum was not named").name; - - // check if we have an unresolved type by the same name - let enu_node: EnumNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Enum(enu); - user_ty_node.into() - } else { - let node = self.add_node(enu); - self.user_types.insert(name, node); - node.into() - }; - - enu_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_struct_def(&mut self, struct_def: &StructDefinition) -> StructNode { - tracing::trace!("Parsing struct {:?}", struct_def.name); - let strukt = Struct::from(struct_def.clone()); - - let name = strukt.name.clone().expect("Struct was not named").name; - - // check if we have an unresolved type by the same name - let strukt_node: StructNode = - if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Struct(strukt); - user_ty_node.into() - } else { - let node = self.add_node(strukt); - self.user_types.insert(name, node); - node.into() - }; - - struct_def.fields.iter().for_each(|field| { - let f = Field::new(self, field.clone()); - let field_node = self.add_node(f); - self.add_edge(field_node, strukt_node, Edge::Field); - }); - strukt_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_err_def(&mut self, err_def: &ErrorDefinition) -> ErrorNode { - tracing::trace!("Parsing error {:?}", err_def); - let err_node = ErrorNode(self.add_node(Error::from(err_def.clone())).index()); - err_def.fields.iter().for_each(|field| { - let param = ErrorParam::new(self, field.clone()); - let field_node = self.add_node(param); - self.add_edge(field_node, err_node, Edge::ErrorParam); - }); - err_node - } - - #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_func_def( - &mut self, - func_def: &FunctionDefinition, - con_node: Option, - ) -> FunctionNode { - let func = Function::from(func_def.clone()); - tracing::trace!( - "Parsing function {:?}", - func.name - .clone() - .unwrap_or_else(|| solang_parser::pt::Identifier { - loc: solang_parser::pt::Loc::Implicit, - name: "".to_string() - }) - .name - ); - self.handle_func(func, con_node) - } - - pub fn handle_func(&mut self, func: Function, con_node: Option) -> FunctionNode { - match func.ty { - FunctionTy::Constructor => { - let node = self.add_node(func); - let func_node = node.into(); - - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::Constructor); - } - func_node - } - FunctionTy::Fallback => { - let node = self.add_node(func); - let func_node = node.into(); - - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::FallbackFunc); - } - - func_node - } - FunctionTy::Receive => { - // receive function cannot have input/output - let node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(node, con_node, Edge::ReceiveFunc); - } - FunctionNode::from(node) - } - FunctionTy::Function => { - let fn_node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(fn_node, con_node, Edge::Func); - } - fn_node.into() - } - FunctionTy::Modifier => { - let fn_node = self.add_node(func); - if let Some(con_node) = con_node { - self.add_edge(fn_node, con_node, Edge::Modifier); - } - fn_node.into() - } - } - } - - pub fn parse_var_def( - &mut self, - var_def: &VariableDefinition, - in_contract: bool, - ) -> (VarNode, Option, bool) { - tracing::trace!("Parsing variable definition: {:?}", var_def.name); - let var = Var::new(self, var_def.clone(), in_contract); - let mut func = None; - if var.is_public() { - func = Some(Function::from(var_def.clone())); - } - let needs_final_pass = var.initializer_expr.is_some(); - let var_node = VarNode::from(self.add_node(var)); - self.user_types - .insert(var_node.name(self).unwrap(), var_node.into()); - (var_node, func, needs_final_pass) - } - - pub fn parse_ty_def(&mut self, ty_def: &TypeDefinition) -> TyNode { - tracing::trace!("Parsing type definition"); - let ty = Ty::new(self, ty_def.clone()); - let name = ty.name.name.clone(); - let ty_node: TyNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { - let unresolved = self.node_mut(user_ty_node); - *unresolved = Node::Ty(ty); - user_ty_node.into() - } else { - let node = self.add_node(Node::Ty(ty)); - self.user_types.insert(name, node); - node.into() - }; - ty_node - } -} - -/// Print the report of parser's diagnostics -pub fn print_diagnostics_report( - content: &str, - path: &Path, - diagnostics: Vec, -) -> std::io::Result<()> { - let filename = path.file_name().unwrap().to_string_lossy().to_string(); - for diag in diagnostics { - let (start, end) = (diag.loc.start(), diag.loc.end()); - let mut report = Report::build(ReportKind::Error, &filename, start) - .with_message(format!("{:?}", diag.ty)) - .with_label( - Label::new((&filename, start..end)) - .with_color(Color::Red) - .with_message(format!("{}", diag.message.fg(Color::Red))), - ); +pub use analyzer::Analyzer; - for note in diag.notes { - report = report.with_note(note.message); - } - report.finish().print((&filename, Source::from(content)))?; - } - Ok(()) -} diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 417383a2..028cd523 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -12,6 +12,8 @@ pub trait AnalyzerLike: GraphLike { /// Type of the `block` node type BlockNode; + /// Type of a function + type Function; /// Type of a function input parameter type FunctionParam; /// Type of a function return paramter @@ -20,8 +22,7 @@ pub trait AnalyzerLike: GraphLike { /// Type of a builtin type Builtin; - /// Type of a function - type Function; + /// Gets the builtin functions map fn builtin_fns(&self) -> &HashMap; From ac945cab7aaf81e1393b3f19aebe5761a1b80743 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 13:13:35 -0800 Subject: [PATCH 14/71] its alive --- Cargo.lock | 27 +- Cargo.toml | 4 +- crates/cli/Cargo.toml | 3 + crates/cli/src/main.rs | 210 +++-- crates/graph/src/solvers/brute.rs | 864 +++++++++++++++++++++ crates/graph/src/solvers/mod.rs | 2 + crates/pyrometer/src/graph_backend.rs | 599 +++++++++++++- crates/pyrometer/src/lib.rs | 2 +- crates/queries/src/lib.rs | 3 +- crates/queries/src/storage_write/access.rs | 93 --- crates/queries/src/storage_write/mod.rs | 5 - crates/queries/src/storage_write/target.rs | 156 ---- crates/queries/src/taint.rs | 68 -- crates/shared/src/graph_like.rs | 273 +------ 14 files changed, 1658 insertions(+), 651 deletions(-) create mode 100644 crates/graph/src/solvers/brute.rs delete mode 100644 crates/queries/src/storage_write/access.rs delete mode 100644 crates/queries/src/storage_write/mod.rs delete mode 100644 crates/queries/src/storage_write/target.rs delete mode 100644 crates/queries/src/taint.rs diff --git a/Cargo.lock b/Cargo.lock index 698ad507..cfbd8fc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,11 +251,14 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" name = "cli" version = "0.1.0" dependencies = [ + "analyzers", "ariadne", "clap", + "ethers-core", "graph", "petgraph", "pyrometer", + "shared", "tracing", "tracing-subscriber", ] @@ -820,6 +823,15 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1244,10 +1256,19 @@ checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.4.3", "regex-syntax 0.8.2", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + [[package]] name = "regex-automata" version = "0.4.3" @@ -1734,10 +1755,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] diff --git a/Cargo.toml b/Cargo.toml index 06fd6f5f..a9b7eced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ "crates/shared", "crates/solc-expressions", ] - +resolver = "2" [workspace.package] version = "0.2.0" @@ -40,7 +40,7 @@ solc-expressions = { path = "crates/solc-expressions" } solang-parser = { version = "0.2.4", features = ["pt-serde"] } tracing = { version = "0.1", features = ["attributes"] } -tracing-subscriber = "0.3" +tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } ethers-core = "*" hex = "0.4.3" ariadne = "0.2.0" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index e3671939..7c14ee7d 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +analyzers.workspace = true +shared.workspace = true pyrometer.workspace = true graph.workspace = true # queries.workspace = true @@ -14,6 +16,7 @@ ariadne.workspace = true tracing.workspace = true tracing-subscriber.workspace = true petgraph.workspace = true +ethers-core.workspace = true clap = { version = "4.1.4", features = ["derive"] } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 5449ab71..9d6ae5ee 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,26 +1,28 @@ -use crate::analyzers::ReportConfig; -use ariadne::sources; -use clap::{ArgAction, Parser, ValueHint}; -use pyrometer::context::analyzers::FunctionVarsBoundAnalyzer; -use pyrometer::{ - context::{analyzers::ReportDisplay, *}, - Analyzer, -}; - -use shared::nodes::FunctionNode; -use shared::Edge; -use shared::{ - analyzer::{GraphLike, Search}, - nodes::ContractNode, +use shared::GraphDot; +use analyzers::{ + ReportDisplay, FunctionVarsBoundAnalyzer, ReportConfig }; -use tracing_subscriber::prelude::*; +use graph::{ + Edge, Range, + nodes::{ContractNode, FunctionNode, Concrete}, + elem::{Elem, RangeElem}, + solvers::{SolcSolver, AtomicSolveStatus, BruteBinSearchSolver}, +}; +use pyrometer::{Root, SourcePath, Analyzer}; +use shared::{Search}; -use std::collections::{BTreeMap, HashMap}; -use std::path::PathBuf; +use ariadne::sources; +use clap::{ArgAction, Parser, ValueHint}; +use tracing_subscriber::prelude::*; +use ethers_core::types::I256; -use std::env::{self}; -use std::fs; +use std::{ + collections::{BTreeMap, HashMap}, + path::PathBuf, + env::{self}, + fs +}; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -58,6 +60,9 @@ struct Args { pub verbosity: u8, /// Whether to print out a dot string of the analyzed contracts #[clap(long, short, default_value = "false")] + pub mermaid: bool, + /// Whether to print out a dot string of the analyzed contracts + #[clap(long, short, default_value = "false")] pub dot: bool, /// Whether to generate and open a dot visualization of the analyzed contracts #[clap(long, short, default_value = "false")] @@ -80,12 +85,6 @@ struct Args { /// Show non-revert paths #[clap(long)] pub show_nonreverts: Option, - // #[clap(long, short)] - // pub access_query: Vec, - // #[clap(long, short)] - // pub query: Vec, - // #[clap(long, short)] - // pub write_query: Vec, /// A debugging command to prevent bound analysis printing. Useful for debugging parse errors during development. Only prints out parse errors /// then ends the program #[clap(long)] @@ -102,7 +101,6 @@ pub fn subscriber() { fn main() { subscriber(); let args = Args::parse(); - let path_str = args.path.to_string(); let verbosity = args.verbosity; let config = match verbosity { 0 => ReportConfig { @@ -202,44 +200,59 @@ fn main() { show_nonreverts: args.show_nonreverts.unwrap_or(true), }, }; + let mut analyzer = Analyzer::default(); + analyzer.root = Root::RemappingsDirectory(env::current_dir().unwrap()); - let sol = fs::read_to_string(args.path.clone()).expect("Could not find file"); + let (current_path, sol) = if args.path.ends_with(".sol") { + let sol = fs::read_to_string(args.path.clone()).expect("Could not find file"); + // Remappings file only required for Solidity files + if args.remappings.is_some() { + let remappings = args.remappings.unwrap(); + analyzer.set_remappings_and_root(remappings); + } - let mut analyzer = Analyzer { - root: env::current_dir().unwrap(), - ..Default::default() + ( + SourcePath::SolidityFile(PathBuf::from(args.path.clone())), + sol, + ) + } else if args.path.ends_with(".json") { + let json_path_buf = PathBuf::from(args.path.clone()); + analyzer.update_with_solc_json(&json_path_buf); + let (current_path, sol, _, _) = analyzer.sources.first().unwrap().clone(); + (current_path, sol) + } else { + panic!("Unsupported file type") }; - if args.remappings.is_some() { - let remappings = args.remappings.unwrap(); - analyzer.set_remappings_and_root(remappings); - } + let t0 = std::time::Instant::now(); - let (maybe_entry, mut all_sources) = - analyzer.parse(&sol, &PathBuf::from(args.path.clone()), true); + let maybe_entry = analyzer.parse(&sol, ¤t_path, true); let parse_time = t0.elapsed().as_millis(); println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); - all_sources.push((maybe_entry, args.path, sol, 0)); - let entry = maybe_entry.unwrap(); + // use self.sources to fill a BTreeMap with the file_no and SourcePath.path_to_solidity_file + let mut file_mapping: BTreeMap = BTreeMap::new(); + let mut src_map: HashMap = HashMap::new(); + for (source_path, sol, o_file_no, _o_entry) in analyzer.sources.iter() { + if let Some(file_no) = o_file_no { + file_mapping.insert( + *file_no, + source_path.path_to_solidity_source().display().to_string(), + ); + } + src_map.insert( + source_path.path_to_solidity_source().display().to_string(), + sol.to_string(), + ); + } + let mut source_map = sources(src_map); - let mut file_mapping: BTreeMap<_, _> = vec![(0usize, path_str)].into_iter().collect(); - file_mapping.extend( - all_sources - .iter() - .map(|(_entry, name, _src, num)| (*num, name.clone())) - .collect::>(), - ); + let entry = maybe_entry.unwrap(); - let mut source_map = sources( - all_sources - .iter() - .map(|(_entry, name, src, _num)| (name.clone(), src)) - .collect::>(), - ); + // analyzer.print_errors(&file_mapping, &mut source_map); // let t = petgraph::algo::toposort(&analyzer.graph, None); - analyzer.print_errors(&file_mapping, &mut source_map); + // analyzer.print_errors(&file_mapping, &mut source_map); if args.open_dot { analyzer.open_dot() @@ -249,15 +262,64 @@ fn main() { println!("{}", analyzer.dot_str_no_tmps()); } + if args.mermaid { + println!("{}", analyzer.mermaid_str()); + } + if args.debug { return; } + // println!("getting contracts"); let all_contracts = analyzer .search_children(entry, &Edge::Contract) .into_iter() .map(ContractNode::from) .collect::>(); + + // TODO: clean this up to actually run on all contracts + // if args.swq { + // println!("Creating SWQ graph for {} contracts", all_contracts.len()); + // let mut cond_graph: Option = None; + // for i in 0..all_contracts.len() { + // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { + // (Some(ref mut existing), Some(new)) => { + // existing.append_graph(new); + // } + // (None, Some(new)) => { + // cond_graph = Some(new); + // } + // _ => {} + // } + // } + + // if let Some(graph) = cond_graph { + // println!("{}", graph.dot_str()); + // graph.open_dot(); + // } else { + // println!("no graph"); + // } + // } else if args.swq_mermaid { + // println!("Creating SWQ graph for {} contracts", all_contracts.len()); + // let mut cond_graph: Option = None; + // for i in 0..all_contracts.len() { + // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { + // (Some(ref mut existing), Some(new)) => { + // existing.append_graph(new); + // } + // (None, Some(new)) => { + // cond_graph = Some(new); + // } + // _ => {} + // } + // } + + // if let Some(graph) = cond_graph { + // println!("{}", graph.mermaid_str()); + // } else { + // println!("no graph"); + // } + // } else { let _t1 = std::time::Instant::now(); if args.contracts.is_empty() { let funcs = analyzer.search_children(entry, &Edge::Func); @@ -270,10 +332,45 @@ fn main() { .starts_with(analyze_for) }) { if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { - let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) - .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); + let mut all_edges = ctx.all_edges(&analyzer).unwrap(); + all_edges.push(ctx); + all_edges.iter().for_each(|c| { + let rets = c.return_nodes(&analyzer).unwrap(); + if c.path(&analyzer).starts_with(r#"step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64)"#) + && rets.iter().take(1).any(|ret| { + let range = ret.1.ref_range(&analyzer).unwrap().unwrap(); + range.evaled_range_min(&analyzer).unwrap().range_eq(&Elem::from(Concrete::from(I256::from(-1)))) + }) + { // step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64).fork{ false }.fork{ true }.fork{ true }.fork{ false }"#.to_string()) { + // println!("{:#?}", c.ctx_deps_as_controllables_str(&analyzer).unwrap()); + if let Some(mut solver) = BruteBinSearchSolver::maybe_new(c.ctx_deps(&analyzer).unwrap(), &analyzer).unwrap() { + println!("created solver"); + match solver.solve(&analyzer).unwrap() { + AtomicSolveStatus::Unsat => { + println!("TRUE UNSAT: {}", c.path(&analyzer)); + } + AtomicSolveStatus::Sat(ranges) => { + println!("-----------------------"); + println!("sat for: {}", c.path(&analyzer)); + ranges.iter().for_each(|(atomic, conc)| { + println!("{}: {}", atomic.idxs[0].display_name(&analyzer).unwrap(), conc.as_human_string()); + }); + } + AtomicSolveStatus::Indeterminate => { + println!("-----------------------"); + println!("sat for: {}", c.path(&analyzer)); + println!("MAYBE UNSAT"); + } + } + } + println!("-----------------------"); + let analysis = analyzer + .bounds_for_lineage(&file_mapping, *c, vec![*c], config) + .as_cli_compat(&file_mapping); + analysis.print_reports(&mut source_map, &analyzer); + // return; + } + }); } } } else if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { @@ -313,6 +410,7 @@ fn main() { } }); } + // } // args.query.iter().for_each(|query| { // analyzer.taint_query(entry, query.to_string()); diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs new file mode 100644 index 00000000..38057178 --- /dev/null +++ b/crates/graph/src/solvers/brute.rs @@ -0,0 +1,864 @@ +use crate::{ + GraphBackend, AnalyzerBackend, GraphError, + SolcRange, Range, RangeEval, + elem::{RangeElem, Elem}, + nodes::{ContextVarNode, Concrete, VarNode}, + solvers::{dl::{SolveStatus, DLSolver}, Atomize, SolverAtom}, +}; + +use ethers_core::types::U256; +use std::collections::BTreeMap; + +pub trait SolcSolver { + fn simplify(&mut self, analyzer: &(impl GraphBackend + AnalyzerBackend)); + fn solve( + &mut self, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result; + fn recurse_check( + &mut self, + idx: usize, + solved_atomics: &mut Vec, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result; + fn check( + &mut self, + solved_for: usize, + lmr: (Elem, Elem, Elem), + solved_atomics: &mut Vec, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result<(bool, Option), GraphError>; +} + +pub enum AtomicSolveStatus { + Unsat, + Sat(AtomicSolveMap), + Indeterminate, +} + +pub type AtomicSolveMap = BTreeMap; + +#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] +pub struct Atomic { + pub idxs: Vec, +} + +#[derive(Clone, Debug)] +pub struct BruteBinSearchSolver { + pub deps: Vec, + pub solves: BTreeMap>, + pub atomics: Vec, + // This is private due to wanting to ensure we construct the ranges correctly via `as_simplified_range` + ranges: BTreeMap, + atomic_ranges: BTreeMap, + pub lmrs: Vec, + pub intermediate_ranges: BTreeMap, + pub intermediate_atomic_ranges: BTreeMap, + pub sat: bool, + pub start_idx: usize, + pub successful_passes: usize, +} + +#[derive(Clone, Debug)] +pub struct LMR { + pub low: Elem, + pub mid: Elem, + pub high: Elem, +} + +impl From<(Elem, Elem, Elem)> for LMR { + fn from((low, mid, high): (Elem, Elem, Elem)) -> Self { + Self { low, mid, high } + } +} + +pub enum HintOrRanges { + Higher, + Lower, + Ranges(BTreeMap), +} + +impl BruteBinSearchSolver { + pub fn maybe_new( + deps: Vec, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + let mut atomic_idxs = vec![]; + + let mut ranges = BTreeMap::default(); + let mut atomic_ranges = BTreeMap::default(); + deps.iter().try_for_each(|dep| { + let range = dep.ref_range(analyzer)?.unwrap(); + if range.unsat(analyzer) { + panic!( + "initial range for {} not sat", + dep.display_name(analyzer).unwrap() + ); + } + let r = range.into_flattened_range(analyzer)?; + atomic_idxs.extend(r.dependent_on()); + ranges.insert(*dep, r); + Ok(()) + })?; + + // Sometimes a storage variable will be split due to a context fork. We recombine them here + atomic_idxs.sort(); + atomic_idxs.dedup(); + atomic_idxs.iter().for_each(|dep| { + println!( + "atomic dep: {} - {}", + dep.display_name(analyzer).unwrap(), + dep.0 + ) + }); + // let atomics = atomic_idxs; + let mut storage_atomics: BTreeMap> = BTreeMap::default(); + let mut calldata_atomics = vec![]; + atomic_idxs.into_iter().try_for_each(|atomic| { + if atomic.is_storage(analyzer)? { + // its a storage variable, get the parent var + if atomic.is_dyn(analyzer)? { + } else { + let entry = storage_atomics + .entry(atomic.maybe_storage_var(analyzer).unwrap()) + .or_default(); + entry.push(atomic); + entry.sort(); + entry.dedup(); + } + } else { + calldata_atomics.push(atomic); + } + Ok(()) + })?; + + let mut atomics: Vec = vec![]; + storage_atomics + .into_iter() + .for_each(|(_k, same_atomics)| atomics.push(Atomic { idxs: same_atomics })); + atomics.extend( + calldata_atomics + .into_iter() + .map(|atomic| Atomic { idxs: vec![atomic] }) + .collect::>(), + ); + + atomics.iter().try_for_each(|atomic| { + let range = atomic.idxs[0].range(analyzer)?.unwrap(); + atomic_ranges.insert(atomic.clone(), range); + Ok(()) + })?; + if let Some((dep, unsat_range)) = ranges.iter().find(|(_, range)| range.unsat(analyzer)) { + panic!( + "Initial ranges not sat for dep {}: {} {}", + dep.display_name(analyzer).unwrap(), + unsat_range.min, + unsat_range.max + ); + } + + if ranges.len() != deps.len() { + panic!("HERE"); + } + + let mut s = Self { + deps, + solves: Default::default(), + atomics, + intermediate_ranges: ranges.clone(), + ranges, + intermediate_atomic_ranges: atomic_ranges.clone(), + atomic_ranges, + lmrs: vec![], + sat: true, + start_idx: 0, + successful_passes: 0, + }; + + s.reset_lmrs(analyzer); + Ok(Some(s)) + } + + pub fn lmr( + &self, + atomic: &Atomic, + analyzer: &impl GraphBackend, + ) -> (Elem, Elem, Elem) { + let range = &self.atomic_ranges[atomic]; + let mut min = range.evaled_range_min(analyzer).unwrap(); + min.cache_minimize(analyzer).unwrap(); + // println!("min: {}", min.minimize(analyzer).unwrap().to_range_string(false, analyzer).s); + let mut max = range.evaled_range_max(analyzer).unwrap(); + max.cache_maximize(analyzer).unwrap(); + let mut mid = (min.clone() + max.clone()) / Elem::from(Concrete::from(U256::from(2))); + mid.cache_maximize(analyzer).unwrap(); + (min, mid, max) + } + + pub fn reset_lmrs(&mut self, analyzer: &impl GraphBackend) { + self.lmrs = vec![]; + (0..self.atomic_ranges.len()).for_each(|i| { + self.lmrs.push(self.lmr(&self.atomics[i], analyzer).into()); + }); + } + + pub fn reset_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) { + self.lmrs[i] = self.lmr(&self.atomics[i], analyzer).into(); + } + + pub fn raise_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) -> bool { + // move the low to low + mid / 2 + // reset the mid + let mut curr_lmr = self.lmrs[i].clone(); + curr_lmr.low = (curr_lmr.low + curr_lmr.mid) + / Elem::from(Concrete::from(U256::from(2))) + .minimize(analyzer) + .unwrap(); + curr_lmr.mid = (curr_lmr.low.clone() + curr_lmr.high.clone()) + / Elem::from(Concrete::from(U256::from(2))) + .minimize(analyzer) + .unwrap(); + + let new_mid_conc = curr_lmr.mid.maximize(analyzer).unwrap(); + let old_mid_conc = self.lmrs[i].mid.maximize(analyzer).unwrap(); + + if matches!( + new_mid_conc.range_ord(&old_mid_conc), + Some(std::cmp::Ordering::Equal) + ) { + return false; + } + self.lmrs[i] = curr_lmr; + true + } + + pub fn lower_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) -> bool { + // println!("lowering mid"); + // move the high to high + mid / 2 + // reset the mid + let mut curr_lmr = self.lmrs[i].clone(); + curr_lmr.high = (curr_lmr.mid.minimize(analyzer).unwrap() + + curr_lmr.high.minimize(analyzer).unwrap()) + / Elem::from(Concrete::from(U256::from(2))) + .minimize(analyzer) + .unwrap(); + curr_lmr.mid = (curr_lmr.low.minimize(analyzer).unwrap() + + curr_lmr.high.minimize(analyzer).unwrap()) + / Elem::from(Concrete::from(U256::from(2))) + .minimize(analyzer) + .unwrap(); + + let new_high_conc = curr_lmr.high.minimize(analyzer).unwrap(); + let old_high_conc = self.lmrs[i].high.minimize(analyzer).unwrap(); + + if matches!( + new_high_conc.range_ord(&old_high_conc), + Some(std::cmp::Ordering::Equal) + ) { + return false; + } + self.lmrs[i] = curr_lmr; + true + } + + pub fn increase_start(&mut self) -> bool { + self.start_idx += 1; + self.start_idx < self.atomic_ranges.len() + } +} + +impl SolcSolver for BruteBinSearchSolver { + fn simplify(&mut self, _analyzer: &(impl GraphBackend + AnalyzerBackend)) {} + + fn solve( + &mut self, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result { + // pick a value for a variable. check if it satisfies all dependendies + // if is sat, try to reduce using bin search? Not sure how that will + // affect other dependencies If it doesnt, + // raise or lower + + println!("-------------------------"); + println!("DL SOLVER CHECK"); + let atoms = self + .ranges + .iter() + .filter_map(|(_dep, range)| { + // println!("dep: {}", dep.display_name(analyzer).unwrap()); + + // println!("atom: {atom:#?}"); + if let Some(atom) = range.min.atomize() { + Some(atom) + } else { + range.max.atomize() + } + }) + .collect::>(); + + let mut dl_solver = DLSolver::new(atoms); + let mut atomic_solves: BTreeMap<_, _>; + + match dl_solver.solve_partial(analyzer)? { + SolveStatus::Unsat => { + println!("TRUE UNSAT"); + return Ok(AtomicSolveStatus::Unsat); + } + SolveStatus::Sat { + const_solves, + dl_solves, + } => { + atomic_solves = const_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + self.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect(); + atomic_solves.extend( + dl_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + self.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect::>(), + ); + } + SolveStatus::Indeterminate { const_solves } => { + atomic_solves = const_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + self.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect() + } + } + // println!("solved for: {:#?}", atomic_solves); + println!("-------------------------"); + + if atomic_solves.len() == self.atomics.len() { + println!("DONE HERE"); + + return Ok(AtomicSolveStatus::Sat(atomic_solves)); + } else { + atomic_solves.iter().for_each(|(atomic, val)| { + self.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { + atomic + .idxs + .iter() + .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()))); + }); + }); + + atomic_solves.clone().into_iter().for_each(|(atomic, val)| { + self.intermediate_atomic_ranges.insert( + atomic, + SolcRange::new(val.clone().into(), val.into(), vec![]), + ); + }); + } + + let mut solved_for = atomic_solves + .keys() + .filter_map(|k| self.atomics.iter().position(|r| r == k)) + .collect(); + while self.recurse_check(self.start_idx, &mut solved_for, analyzer)? {} + if self.successful_passes == self.atomics.len() { + let mapping = self + .intermediate_atomic_ranges + .iter() + .filter(|(_, range)| range.is_const(analyzer).unwrap()) + .map(|(name, range)| { + ( + name.clone(), + range + .evaled_range_min(analyzer) + .unwrap() + .maybe_concrete() + .unwrap() + .val, + ) + }) + .collect::>(); + if mapping.len() == self.intermediate_atomic_ranges.len() { + let all_good = self.ranges.iter().all(|(_dep, range)| { + let mut new_range = range.clone(); + self.intermediate_atomic_ranges + .iter() + .for_each(|(atomic, range)| { + atomic.idxs.iter().for_each(|idx| { + new_range.replace_dep(idx.0.into(), range.min.clone()); + }); + }); + new_range.cache_eval(analyzer).unwrap(); + // println!("{}, original range: [{}, {}], new range: [{}, {}]", dep.display_name(analyzer).unwrap(), range.min, range.max, new_range.min_cached.clone().unwrap(), new_range.max_cached.clone().unwrap()); + new_range.sat(analyzer) + }); + if all_good { + Ok(AtomicSolveStatus::Sat(mapping)) + } else { + println!("thought we solved but we didnt"); + Ok(AtomicSolveStatus::Indeterminate) + } + } else { + Ok(AtomicSolveStatus::Indeterminate) + } + } else { + Ok(AtomicSolveStatus::Indeterminate) + } + } + + fn recurse_check( + &mut self, + i: usize, + solved_atomics: &mut Vec, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result { + // println!("recurse check for: {}", self.atomics[i].idxs[0].display_name(analyzer).unwrap()); + if i >= self.lmrs.len() { + return Ok(false); + } + + if solved_atomics.contains(&i) { + self.increase_start(); + self.successful_passes += 1; + return Ok(true); + } + + let _atomic = &self.atomics[i]; + + let lmr = self.lmrs[i].clone(); + // println!("solving: {i}, {}, successful passes: {}", atomic.idxs[0].display_name(analyzer).unwrap(), self.successful_passes); + // println!("initial range: [{min_s},{max_s}], is_const: {}", atomic.idxs[0].is_const(analyzer)?); + match self.check(i, (lmr.low, lmr.mid, lmr.high), solved_atomics, analyzer)? { + (true, Some(HintOrRanges::Ranges(new_ranges))) => { + // sat, try solving next var with new intermediate ranges + solved_atomics.push(i); + self.intermediate_ranges = new_ranges; + self.successful_passes += 1; + self.increase_start(); + Ok(true) + } + (false, Some(HintOrRanges::Higher)) => { + self.successful_passes = 0; + *solved_atomics = vec![]; + // unsat, try raising + if self.raise_lmr(i, analyzer) { + self.recurse_check(i, solved_atomics, analyzer) + } else { + // we couldn't solve, try increasing global start + if self.increase_start() { + self.intermediate_ranges = self.ranges.clone(); + self.recurse_check(self.start_idx, solved_atomics, analyzer) + } else { + Ok(false) + } + } + } + (false, Some(HintOrRanges::Lower)) => { + // unsat, try lowering + self.successful_passes = 0; + *solved_atomics = vec![]; + if self.lower_lmr(i, analyzer) { + self.recurse_check(i, solved_atomics, analyzer) + } else { + // we couldn't solve, try increasing global start + if self.increase_start() { + self.intermediate_ranges = self.ranges.clone(); + self.recurse_check(self.start_idx, solved_atomics, analyzer) + } else { + Ok(false) + } + } + } + (false, None) => { + // unsat, try lowering + self.successful_passes = 0; + *solved_atomics = vec![]; + if self.lower_lmr(i, analyzer) { + self.recurse_check(i, solved_atomics, analyzer) + } else { + // we couldn't solve, try increasing global start + if self.increase_start() { + self.intermediate_ranges = self.ranges.clone(); + self.recurse_check(self.start_idx, solved_atomics, analyzer) + } else { + Ok(false) + } + } + } + _ => unreachable!(), + } + } + + fn check( + &mut self, + solved_for_idx: usize, + (low, mid, high): (Elem, Elem, Elem), + solved_atomics: &mut Vec, + analyzer: &(impl GraphBackend + AnalyzerBackend), + ) -> Result<(bool, Option), GraphError> { + let solved_dep = &self.atomics[solved_for_idx].clone(); + + fn match_check( + this: &mut BruteBinSearchSolver, + solved_for_idx: usize, + solved_dep: &Atomic, + (low, mid, high): (Elem, Elem, Elem), + low_done: bool, + mut mid_done: bool, + mut high_done: bool, + solved_atomics: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result<(bool, Option), GraphError> { + let res = if !low_done { + check_for_lmr( + this, + solved_for_idx, + solved_dep, + low.clone(), + solved_atomics, + analyzer, + ) + } else if !mid_done { + check_for_lmr( + this, + solved_for_idx, + solved_dep, + mid.clone(), + solved_atomics, + analyzer, + ) + } else { + check_for_lmr( + this, + solved_for_idx, + solved_dep, + high.clone(), + solved_atomics, + analyzer, + ) + }; + + match res { + Ok((true, ranges)) => Ok((true, ranges)), + Ok((false, _)) => { + if high_done { + res + } else { + high_done = mid_done; + mid_done = true; + match_check( + this, + solved_for_idx, + solved_dep, + (low, mid, high), + true, + mid_done, + high_done, + solved_atomics, + analyzer, + ) + } + } + Err(e) => Err(e), + } + } + + fn check_for_lmr( + this: &mut BruteBinSearchSolver, + solved_for_idx: usize, + solved_dep: &Atomic, + conc: Elem, + solved_atomics: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result<(bool, Option), GraphError> { + // println!("checking: {}, conc: {}, {}", this.atomics[solved_for_idx].idxs[0].display_name(analyzer).unwrap(), conc.maximize(analyzer)?.to_range_string(true, analyzer).s, conc.minimize(analyzer)?.to_range_string(false, analyzer).s); + solved_atomics.push(solved_for_idx); + let mut new_ranges = BTreeMap::default(); + this.intermediate_atomic_ranges.insert( + solved_dep.clone(), + SolcRange::new(conc.clone(), conc.clone(), vec![]), + ); + let atoms = this + .intermediate_ranges + .iter() + .filter_map(|(_, range)| { + if let Some(atom) = range + .min + .simplify_minimize(&mut vec![], analyzer) + .unwrap() + .atomize() + { + Some(atom) + } else { + range + .max + .simplify_maximize(&mut vec![], analyzer) + .unwrap() + .atomize() + } + }) + .collect::>(); + + let mut dl_solver = DLSolver::new(atoms); + let mut atomic_solves: BTreeMap<_, _>; + + match dl_solver.solve_partial(analyzer)? { + SolveStatus::Unsat => { + println!("TRUE UNSAT"); + return Ok((false, None)); + } + SolveStatus::Sat { + const_solves, + dl_solves, + } => { + atomic_solves = const_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + this.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect(); + atomic_solves.extend( + dl_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + this.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect::>(), + ); + } + SolveStatus::Indeterminate { const_solves } => { + atomic_solves = const_solves + .into_iter() + .filter_map(|(dep, solve)| { + Some(( + this.atomics + .iter() + .find(|atomic| atomic.idxs.contains(&dep))? + .clone(), + solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + )) + }) + .collect() + } + } + + atomic_solves.iter().for_each(|(atomic, val)| { + this.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { + atomic + .idxs + .iter() + .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()))); + }); + }); + + atomic_solves.clone().into_iter().for_each(|(atomic, val)| { + this.intermediate_atomic_ranges.insert( + atomic, + SolcRange::new(val.clone().into(), val.into(), vec![]), + ); + }); + // println!("new solves: {atomic_solves:#?}"); + + for dep in this.deps.iter() { + let range = this + .intermediate_ranges + .get(dep) + .expect("No range for dep?"); + // if dep.display_name(analyzer).unwrap() == "(p2 < (61 * p3)) == true" { + // println!("range: {:#?}\n{:#?}", range.min, range.max); + // println!("simplified range: {:#?}\n{:#?}", range.min.simplify_minimize(&mut vec![], analyzer), range.max.simplify_maximize(&mut vec![], analyzer)); + // } + // println!("atomizing dep: {}", dep.display_name(analyzer).unwrap()); + // println!("min atomized: {:#?}, max atomized: {:#?}", range.min.simplify_minimize(&mut vec![], analyzer)?.atomize(), range.max.simplify_maximize(&mut vec![], analyzer)?.atomize()); + if solved_dep.idxs.contains(dep) { + // println!("FOR SOLVED DEP"); + continue; + } + // check that the concrete value doesn't break any + let mut new_range = range.clone(); + + // check if const now + // if let Some((Some(idx), const_ineq)) = new_range.min.maybe_const_inequality() { + // println!("min const ineq: {} for {}", const_ineq.maybe_concrete().unwrap().val.as_human_string(), ContextVarNode::from(idx).display_name(analyzer).unwrap()); + + // if let Some(position) = this.atomics.iter().position(|atomic| atomic.idxs.contains(&ContextVarNode::from(idx))) { + // // check and return) + // if !solved_atomics.contains(&position) { + // println!("inner min const ineq"); + // return check_for_lmr(this, position, &this.atomics[position].clone(), const_ineq, solved_atomics, analyzer); + // } + // } + + // } + // if let Some((Some(idx), const_ineq)) = new_range.max.maybe_const_inequality() { + // println!("max const ineq: {} for {} ({}), {:#?}", const_ineq.maybe_concrete().unwrap().val.as_human_string(), ContextVarNode::from(idx).display_name(analyzer).unwrap(), idx.index(), this.atomics); + // if let Some(position) = this.atomics.iter().position(|atomic| atomic.idxs.contains(&ContextVarNode::from(idx))) { + // // check and return + // if !solved_atomics.contains(&position) { + // println!("inner max const ineq"); + // return check_for_lmr(this, position, &this.atomics[position].clone(), const_ineq, solved_atomics, analyzer); + // } + // } + // } + + // check if the new range is dependent on the solved variable + let is_dependent_on_solved = new_range + .dependent_on() + .iter() + .any(|dep| solved_dep.idxs.contains(dep)); + + // dont run sat check on non-dependent range + if !is_dependent_on_solved { + new_ranges.insert(*dep, new_range); + continue; + } + + // println!("new range for {} dependent_on: {:?}, replacing {:?}, is dependent on solved: {is_dependent_on_solved}", dep.display_name(analyzer).unwrap(), new_range.dependent_on(), solved_dep.idxs); + // println!("dep {}:\n\tinitial range: [{}, {}],\n\tcurr range: [{}, {}]", + // dep.display_name(analyzer).unwrap(), + // dep.evaled_range_min(analyzer)?.unwrap().to_range_string(false, analyzer).s, + // dep.evaled_range_max(analyzer)?.unwrap().to_range_string(true, analyzer).s, + // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, + // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, + // // new_range.range_min() + // ); + + // println!("dep {} range: {:#?} {:#?}", dep.display_name(analyzer).unwrap(), new_range.min, new_range.max); + if new_range.unsat(analyzer) { + return Ok((false, None)); + // panic!("initial range unsat???") + } + + this.atomics[solved_for_idx] + .idxs + .iter() + .for_each(|atomic_alias| { + new_range.replace_dep(atomic_alias.0.into(), conc.clone()); + }); + new_range.cache_eval(analyzer)?; + + // println!("new range: [{}, {}], [{}, {}]", + // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, + // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, + // new_range.min.to_range_string(false, analyzer).s, + // new_range.max.to_range_string(true, analyzer).s, + // ); + if new_range.unsat(analyzer) { + // figure out *where* we need to increase or decrease + // work on the unreplace range for now + let min_is_dependent = !range.min.dependent_on().is_empty(); + let max_is_dependent = !range.max.dependent_on().is_empty(); + + match (min_is_dependent, max_is_dependent) { + (true, true) => { + // both sides dependent + // println!("both"); + } + (false, true) => { + // just max is dependent + // println!("just max"); + } + (true, false) => { + // just min is dependent + // println!("just min"); + } + (false, false) => { + // panic!("this shouldnt happen"); + } + } + + // println!("new unsat range: [{}, {}]", + // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, + // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, + // ); + // compare new range to prev range to see if they moved down or up + + // panic!("here"); + let min_change = new_range + .evaled_range_min(analyzer)? + .range_ord(&range.evaled_range_min(analyzer)?); + let max_change = new_range + .evaled_range_max(analyzer)? + .range_ord(&range.evaled_range_max(analyzer)?); + match (min_change, max_change) { + (Some(std::cmp::Ordering::Less), Some(std::cmp::Ordering::Greater)) => { + // panic!("initial range must have been unsat to start"); + } + (Some(std::cmp::Ordering::Greater), Some(std::cmp::Ordering::Less)) => { + // we shrank our range, dont give a hint + // println!("None, dep isnt sat: {}, dep initial range: {}", dep.display_name(analyzer).unwrap(), dep.range_string(analyzer).unwrap().unwrap()); + return Ok((false, None)); + } + (Some(std::cmp::Ordering::Greater), _) => { + // both grew, try lowering + // println!("Lower, dep isnt sat: {}, dep initial range: {}", dep.display_name(analyzer).unwrap(), dep.range_string(analyzer).unwrap().unwrap()); + return Ok((false, Some(HintOrRanges::Lower))); + } + + (Some(std::cmp::Ordering::Less), _) => { + // both grew, try lowering + // println!("Higher, dep isnt sat: {}, dep initial range: {}", dep.display_name(analyzer).unwrap(), dep.range_string(analyzer).unwrap().unwrap()); + return Ok((false, Some(HintOrRanges::Higher))); + } + // (Some(std::cmp::Ordering::Equal), _) => { + // panic!("here"); + // } + // (_, Some(std::cmp::Ordering::Equal)) => { + // panic!("here"); + // } + _ => { + // println!("None empty, dep isnt sat: {}, dep initial range: {}", dep.display_name(analyzer).unwrap(), dep.range_string(analyzer).unwrap().unwrap()); + return Ok((false, None)); + } + } + } else { + new_ranges.insert(*dep, new_range); + } + } + Ok((true, Some(HintOrRanges::Ranges(new_ranges)))) + } + + match_check( + self, + solved_for_idx, + solved_dep, + (low, mid, high), + false, + false, + false, + solved_atomics, + analyzer, + ) + } +} \ No newline at end of file diff --git a/crates/graph/src/solvers/mod.rs b/crates/graph/src/solvers/mod.rs index 3da078a9..a233e5ad 100644 --- a/crates/graph/src/solvers/mod.rs +++ b/crates/graph/src/solvers/mod.rs @@ -1,4 +1,6 @@ pub mod dl; mod atoms; +mod brute; +pub use brute::*; pub use atoms::*; diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 2000130f..588368eb 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,9 +1,22 @@ use crate::Analyzer; -use shared::GraphLike; -use graph::{GraphBackend, Node, Edge}; +use shared::{GraphDot, NodeIdx, GraphLike, Search}; +use graph::{ + ContextEdge, AnalyzerBackend, as_dot_str, AsDotStr, GraphBackend, Node, Edge, + nodes::ContextNode, +}; -use petgraph::{Graph, Directed}; +use petgraph::{ + Direction, Graph, Directed, + graph::EdgeIndex, + dot::Dot, + visit::EdgeRef, +}; + +use std::{ + collections::BTreeSet, + sync::{Mutex, Arc}, +}; impl GraphLike for Analyzer { type Node = Node; @@ -17,4 +30,582 @@ impl GraphLike for Analyzer { } } -impl GraphBackend for Analyzer {} \ No newline at end of file +impl GraphBackend for Analyzer {} + +impl GraphDot for Analyzer { + fn cluster_str( + &self, + node: NodeIdx, + cluster_num: &mut usize, + is_killed: bool, + handled_nodes: Arc>>, + handled_edges: Arc>>>, + depth: usize, + as_mermaid: bool, + ) -> Option + where + Self: std::marker::Sized, + { + *cluster_num += 1; + let curr_cluster = *cluster_num; + + // only used for mermaid + let curr_cluster_name = format!( + "cluster_{cluster_num}_{}", + if is_killed && curr_cluster % 2 == 0 { + "bgcolor_7a0b0b" + } else if is_killed { + "bgcolor_e04646" + } else if curr_cluster % 2 == 0 { + "bgcolor_252C46" + } else { + "bgcolor_1a1b26" + } + ); + + if self + .graph() + .edges_directed(node, Direction::Outgoing) + .collect::>() + .is_empty() + { + return None; + } + let new_graph = self.graph().filter_map( + |_idx, node| match node { + Node::ContextVar(_cvar) => Some(node.clone()), + _ => Some(node.clone()), + }, + |_idx, edge| Some(*edge), + ); + + let g = &G { graph: &new_graph }; + let children = g.children_exclude(node, 0, &[Edge::Context(ContextEdge::Subcontext)]); + let mut children_edges = g.edges_for_nodes(&children); + children_edges.extend( + self.graph() + .edges_directed(node, Direction::Incoming) + .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) + .collect::)>>(), + ); + let preindent = " ".repeat(4 * depth.saturating_sub(1)); + let indent = " ".repeat(4 * depth); + let child_node_str = children + .iter() + .filter_map(|child| { + let post_str = match self.node(*child) { + Node::Context(c) => { + *cluster_num += 2; + if let Some(inner) = self.cluster_str( + *child, + cluster_num, + c.killed.is_some(), + handled_nodes.clone(), + handled_edges.clone(), + depth + 1, + as_mermaid, + ) { + inner + } else { + "".to_string() + } + } + Node::ContextFork => { + let children = g.children_exclude(*child, 0, &[]); + let mut child_iter = children.iter(); + let l_fork = child_iter.next()?; + let r_fork = child_iter.next()?; + let l_ctx = ContextNode::from(*l_fork); + let r_ctx = ContextNode::from(*r_fork); + *cluster_num += 1; + let l_fork = if let Some(inner) = self.cluster_str( + *l_fork, + cluster_num, + l_ctx.is_killed(self).ok()?, + handled_nodes.clone(), + handled_edges.clone(), + depth + 1, + as_mermaid, + ) { + inner + } else { + "".to_string() + }; + + *cluster_num += 2; + let r_fork = if let Some(inner) = self.cluster_str( + *r_fork, + cluster_num, + r_ctx.is_killed(self).ok()?, + handled_nodes.clone(), + handled_edges.clone(), + depth + 1, + as_mermaid, + ) { + inner + } else { + "".to_string() + }; + + format!("{l_fork}\n{r_fork}\n") + } + Node::FunctionCall => { + let children = g.children_exclude(*child, 0, &[]); + let mut child_iter = children.iter(); + let func = child_iter.next()?; + let func_ctx = ContextNode::from(*func); + if let Some(inner) = self.cluster_str( + *func, + cluster_num, + func_ctx.is_killed(self).ok()?, + handled_nodes.clone(), + handled_edges.clone(), + depth + 1, + as_mermaid, + ) { + inner + } else { + "".to_string() + } + } + Node::ContextVar(_) => { + let mut children = g.children(*child); + children.insert(*child); + children + .iter() + .map(|child| { + // if !handled_nodes.lock().unwrap().contains(child) { + // return None + // } else { + // handled_nodes.lock().unwrap().insert(*child); + // } + mermaid_node(g, &indent, *child, true, Some(&curr_cluster_name)) + }) + .collect::>() + .join("\n") + } + _ => "".to_string(), + }; + + if as_mermaid { + if !post_str.is_empty() { + Some(post_str) + } else { + if !handled_nodes.lock().unwrap().contains(child) { + return None; + } else { + handled_nodes.lock().unwrap().insert(*child); + } + Some(mermaid_node( + g, + &indent, + *child, + true, + Some(&curr_cluster_name), + )) + } + } else { + { + if !handled_nodes.lock().unwrap().contains(child) { + return None; + } else { + handled_nodes.lock().unwrap().insert(*child); + } + } + Some(format!( + "{indent}{} [label = \"{}\", color = \"{}\"]\n{}", + petgraph::graph::GraphIndex::index(child), + as_dot_str(*child, g).replace('\"', "\'"), + self.node(*child).dot_str_color(), + post_str + )) + } + }) + .collect::>() + .join("\n"); + + let edge_str = children_edges + .iter() + .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) + .map(|(from, to, edge, idx)| { + handled_edges.lock().unwrap().insert(*idx); + let from = petgraph::graph::GraphIndex::index(from); + let to = petgraph::graph::GraphIndex::index(to); + let edge_idx = idx.index(); + if as_mermaid { + format!("{indent}{from:} -->|\"{edge:?}\"| {to:}\n{indent}class {to} linkSource{edge_idx}\n{indent}class {from} linkTarget{edge_idx}") + } else { + format!("{indent}{from:} -> {to:} [label = \"{edge:?}\"]",) + } + }) + .collect::>() + .join("\n"); + + if as_mermaid { + let node_str = { + if handled_nodes.lock().unwrap().contains(&node) { + "".to_string() + } else { + { + handled_nodes.lock().unwrap().insert(node); + } + mermaid_node(g, &indent, node, true, Some(&curr_cluster_name)) + } + }; + + let child_node_str = if child_node_str.is_empty() { + "".into() + } else { + format!("\n{child_node_str}") + }; + let edge_str = if edge_str.is_empty() { + "".into() + } else { + format!("\n{edge_str}") + }; + if node_str.is_empty() && child_node_str.is_empty() && edge_str.is_empty() { + return None; + } + Some(format!( + "{preindent}subgraph {curr_cluster_name}\n{node_str}{child_node_str}{edge_str}\n{preindent}end", + )) + } else { + Some(format!( + "{preindent}subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", + cluster_num, + if is_killed && curr_cluster % 2 == 0 { + format!("{indent}bgcolor=\"#7a0b0b\"") + } else if is_killed { + format!("{indent}bgcolor=\"#e04646\"") + } else if curr_cluster % 2 == 0 { + format!("{indent}bgcolor=\"#545e87\"") + } else { + format!("{indent}bgcolor=\"#1a1b26\"") + }, + format!( + "{indent}{} [label = \"{}\", color = \"{}\"]", + node.index(), + as_dot_str(node, g).replace('\"', "\'"), + self.node(node).dot_str_color() + ), + child_node_str, + edge_str, + )) + } + } + + fn dot_str(&self) -> String + where + Self: std::marker::Sized, + Self: AnalyzerBackend, + { + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26"; rankdir="BT"; splines=ortho;"##; + dot_str.push(raw_start_str.to_string()); + let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); + let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); + let (nodes, edges) = ( + self.graph().node_indices().collect::>(), + self.graph().edge_indices().collect::>(), + ); + let mut cluster_num = 0; + let mut skip = BTreeSet::default(); + let nodes_str = nodes + .iter() + .filter_map(|node| { + if self + .graph() + .edges_directed(*node, Direction::Outgoing) + .collect::>() + .is_empty() + && !matches!(self.node(*node), Node::Entry) + { + skip.insert(*node); + return None; + } + if !handled_nodes.lock().unwrap().contains(node) { + match self.node(*node) { + Node::Function(_) => { + cluster_num += 2; + Some(self.cluster_str( + *node, + &mut cluster_num, + false, + handled_nodes.clone(), + handled_edges.clone(), + 2, + false, + )?) + } + n => Some(format!( + " {} [label = \"{}\", color = \"{}\"]", + petgraph::graph::GraphIndex::index(node), + as_dot_str(*node, self).replace('\"', "\'"), + n.dot_str_color() + )), + } + } else { + None + } + }) + .collect::>() + .join("\n"); + let edges_str = edges + .into_iter() + .filter_map(|edge| { + if !handled_edges.lock().unwrap().contains(&edge) { + let (from, to) = self.graph().edge_endpoints(edge).unwrap(); + if skip.contains(&from) || skip.contains(&to) { + return None; + } + let from = from.index(); + let to = to.index(); + Some(format!( + " {from:} -> {to:} [label = \"{:?}\"]", + self.graph().edge_weight(edge).unwrap() + )) + } else { + None + } + }) + .collect::>() + .join("\n"); + dot_str.push(nodes_str); + dot_str.push(edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + dot_str.join("\n") + } + + fn dot_str_no_tmps(&self) -> String + where + Self: std::marker::Sized, + Self: GraphLike + AnalyzerBackend, + { + let new_graph = self.graph().filter_map( + |_idx, node| match node { + Node::ContextVar(cvar) => { + if !cvar.is_symbolic || cvar.tmp_of.is_some() { + None + } else { + Some(node.clone()) + } + } + _ => Some(node.clone()), + }, + |_idx, edge| Some(*edge), + ); + let mut dot_str = Vec::new(); + let raw_start_str = r##"digraph G { + node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; + edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; + bgcolor="#1a1b26";"##; + dot_str.push(raw_start_str.to_string()); + let nodes_and_edges_str = format!( + "{:?}", + Dot::with_attr_getters( + &new_graph, + &[ + petgraph::dot::Config::GraphContentOnly, + petgraph::dot::Config::NodeNoLabel, + petgraph::dot::Config::EdgeNoLabel + ], + &|_graph, edge_ref| { + match edge_ref.weight() { + Edge::Context(edge) => format!("label = \"{edge:?}\""), + e => format!("label = \"{e:?}\""), + } + }, + &|_graph, (idx, node_ref)| { + let inner = match node_ref { + Node::ContextVar(cvar) => { + let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { + r.as_dot_str(self) + // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) + } else { + "".to_string() + }; + + format!( + "{} -- {} -- range: {}", + cvar.display_name, + cvar.ty.as_string(self).unwrap(), + range_str + ) + } + _ => as_dot_str(idx, &G { graph: &new_graph }), + }; + format!( + "label = \"{}\", color = \"{}\"", + inner.replace('\"', "\'"), + node_ref.dot_str_color() + ) + } + ) + ); + dot_str.push(nodes_and_edges_str); + let raw_end_str = r#"}"#; + dot_str.push(raw_end_str.to_string()); + dot_str.join("\n") + } + + fn mermaid_str(&self) -> String + where + Self: std::marker::Sized, + Self: AnalyzerBackend, + { + let mut dot_str = Vec::new(); + let raw_start_str = r#" +%%{ + init : { + 'theme': 'base', + 'themeVariables': { + 'primaryColor': '#1a1b26', + 'primaryTextColor': '#d5daf0', + 'primaryBorderColor': '#7C0000', + 'lineColor': '#414868', + 'secondaryColor': '#24283b', + 'tertiaryColor': '#24283b' + }, + "flowchart" : { + "defaultRenderer": "elk" + } + } +}%% + +flowchart BT +"#; + dot_str.push(raw_start_str.to_string()); + let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); + let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); + let (nodes, edges) = ( + self.graph().node_indices().collect::>(), + self.graph().edge_indices().collect::>(), + ); + let mut cluster_num = 0; + let mut skip = BTreeSet::default(); + let nodes_str = nodes + .iter() + .filter_map(|node| { + if self + .graph() + .edges_directed(*node, Direction::Outgoing) + .collect::>() + .is_empty() + && !matches!(self.node(*node), Node::Entry) + { + skip.insert(*node); + return None; + } + if !handled_nodes.lock().unwrap().contains(node) { + match self.node(*node) { + Node::Function(_) => { + cluster_num += 2; + Some(self.cluster_str( + *node, + &mut cluster_num, + false, + handled_nodes.clone(), + handled_edges.clone(), + 2, + true, + )?) + } + Node::ContextVar(_) => None, + n => { + handled_nodes.lock().unwrap().insert(*node); + Some(format!( + " {}(\"{}\")\n style {} stroke:{}", + petgraph::graph::GraphIndex::index(node), + as_dot_str(*node, self).replace('\"', "\'"), + petgraph::graph::GraphIndex::index(node), + n.dot_str_color() + )) + } + } + } else { + None + } + }) + .collect::>() + .join("\n"); + let edges_str = edges + .into_iter() + .filter_map(|edge| { + if !handled_edges.lock().unwrap().contains(&edge) { + let (from, to) = self.graph().edge_endpoints(edge).unwrap(); + if skip.contains(&from) || skip.contains(&to) { + return None; + } + let from = from.index(); + let to = to.index(); + let edge_idx = edge.index(); + Some(format!( + " {from:} -->|\"{:?}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", + self.graph().edge_weight(edge).unwrap() + )) + } else { + None + } + }) + .collect::>() + .join("\n"); + dot_str.push(nodes_str); + dot_str.push(edges_str); + dot_str.join("\n") + } + + +} + +struct G<'a> { + pub graph: &'a Graph, +} + +impl GraphLike for G<'_> { + type Node = Node; + type Edge = Edge; + fn graph_mut(&mut self) -> &mut Graph { + panic!("Should call this") + } + + fn graph(&self) -> &Graph { + self.graph + } +} + +impl GraphBackend for G<'_> {} + +pub fn mermaid_node( + g: &impl GraphBackend, + indent: &str, + node: NodeIdx, + style: bool, + class: Option<&str>, +) -> String { + let mut node_str = format!( + "{indent}{}(\"{}\")", + petgraph::graph::GraphIndex::index(&node), + as_dot_str(node, g).replace('\"', "\'"), + ); + + if style { + node_str.push_str(&format!( + "\n{indent}style {} stroke:{}", + petgraph::graph::GraphIndex::index(&node), + g.node(node).dot_str_color() + )); + } + + if let Some(class) = class { + node_str.push_str(&format!( + "\n{indent}class {} {class}", + petgraph::graph::GraphIndex::index(&node), + )); + } + + node_str +} \ No newline at end of file diff --git a/crates/pyrometer/src/lib.rs b/crates/pyrometer/src/lib.rs index 0b2a1f42..99454bef 100644 --- a/crates/pyrometer/src/lib.rs +++ b/crates/pyrometer/src/lib.rs @@ -3,6 +3,6 @@ mod builtin_fns; mod analyzer_backend; mod graph_backend; -pub use analyzer::Analyzer; +pub use analyzer::*; diff --git a/crates/queries/src/lib.rs b/crates/queries/src/lib.rs index 18fde10f..b1470cf7 100644 --- a/crates/queries/src/lib.rs +++ b/crates/queries/src/lib.rs @@ -1,2 +1 @@ -pub mod storage_write; -pub mod taint; +/// Currently Empty \ No newline at end of file diff --git a/crates/queries/src/storage_write/access.rs b/crates/queries/src/storage_write/access.rs deleted file mode 100644 index 86efab45..00000000 --- a/crates/queries/src/storage_write/access.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::{ - analyzer::*, - context::ContextNode, - nodes::{TypeNode, VarType}, - NodeIdx, -}; - -use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; -use std::collections::BTreeMap; - -#[derive(Debug, Clone)] -pub struct AccessStorageWriteReport { - pub msgs: Vec, -} - -impl AccessStorageWriteReport { - pub fn new(msgs: Vec) -> Self { - Self { msgs } - } -} - -impl ReportDisplay for AccessStorageWriteReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Access Analysis", Color::Green) - } - fn msg(&self, _analyzer: &impl GraphLike) -> String { - self.msgs.join(";\n") - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let report = Report::build(self.report_kind(), "".to_string(), 0) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - vec![report.finish()] - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl AccessStorageWriteQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait AccessStorageWriteQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn access_query( - &self, - _entry: NodeIdx, - _file_mapping: &'_ BTreeMap, - _report_config: ReportConfig, - _contract_name: String, - _storage_var_name: String, - ) -> AccessStorageWriteReport { - todo!() - } - - fn recurse(&self, ctx: ContextNode, storage_var_name: String) -> Vec { - if let Some(cvar) = ctx.var_by_name(self, &storage_var_name) { - match cvar.ty(self).unwrap() { - VarType::User(TypeNode::Struct(s_node), _) => { - let fields = s_node - .fields(self) - .iter() - .map(|field| format!("{}.{}", storage_var_name, field.name(self).unwrap())) - .collect(); - fields - } - _ => vec![storage_var_name], - } - } else { - vec![storage_var_name] - } - } -} diff --git a/crates/queries/src/storage_write/mod.rs b/crates/queries/src/storage_write/mod.rs deleted file mode 100644 index 17f8adc3..00000000 --- a/crates/queries/src/storage_write/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod access; -pub use access::*; - -mod target; -pub use target::*; diff --git a/crates/queries/src/storage_write/target.rs b/crates/queries/src/storage_write/target.rs deleted file mode 100644 index d244f04d..00000000 --- a/crates/queries/src/storage_write/target.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::{ - analyzer::*, - range::{range_string::ToRangeString, Range, SolcRange}, - NodeIdx, -}; - -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span}; -use std::collections::BTreeMap; - -#[derive(Debug, Clone)] -pub struct StorageRangeReport { - pub target: SolcRange, - pub write_loc: Option, - pub analysis: VarBoundAnalysis, -} - -impl ReportDisplay for StorageRangeReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Storage Write Query", Color::Green) - } - fn msg(&self, analyzer: &impl GraphLike) -> String { - let bounds_string = self - .analysis - .ctx - .ctx_deps(analyzer) - .unwrap() - .iter() - .filter_map(|(_name, cvar)| { - let min = if self.analysis.report_config.eval_bounds { - cvar.range(analyzer) - .unwrap()? - .evaled_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else if self.analysis.report_config.simplify_bounds { - cvar.range(analyzer) - .unwrap()? - .simplified_range_min(analyzer) - .unwrap() - .to_range_string(false, analyzer) - .s - } else { - cvar.range(analyzer) - .unwrap()? - .range_min() - .to_range_string(false, analyzer) - .s - }; - - let max = if self.analysis.report_config.eval_bounds { - cvar.range(analyzer) - .unwrap()? - .evaled_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else if self.analysis.report_config.simplify_bounds { - cvar.range(analyzer) - .unwrap()? - .simplified_range_max(analyzer) - .unwrap() - .to_range_string(true, analyzer) - .s - } else { - cvar.range(analyzer) - .unwrap()? - .range_max() - .to_range_string(true, analyzer) - .s - }; - - Some(format!( - "\"{}\" ∈ {{{}, {}}}", - cvar.display_name(analyzer).unwrap(), - min, - max, - )) - }) - .collect::>() - .join(" ∧ "); - format!( - "Found storage write that could lead to target value in ctx {}: \"{}\" ∈ {{{}, {}}}{}{} ", - self.analysis.ctx.path(analyzer), - self.analysis.var_name, - self.target - .evaled_range_min(analyzer).unwrap() .to_range_string(false, analyzer) - .s, - self.target - .evaled_range_max(analyzer).unwrap() .to_range_string(true, analyzer) - .s, - if bounds_string.is_empty() { - "" - } else { - ", where " - }, - bounds_string.fg(Color::Yellow) - ) - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let mut report = Report::build( - self.analysis.report_kind(), - self.analysis.var_def.0.source(), - self.analysis.var_def.0.start(), - ) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - - report.add_labels(self.analysis.labels(analyzer)); - - let reports = vec![report.finish()]; - reports - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl StorageRangeQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait StorageRangeQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn func_query( - &mut self, - _entry: NodeIdx, - _file_mapping: &'_ BTreeMap, - _report_config: ReportConfig, - _contract_name: String, - _func_name: String, - _storage_var_name: String, - _target: SolcRange, - ) -> Option { - todo!() - } -} diff --git a/crates/queries/src/taint.rs b/crates/queries/src/taint.rs deleted file mode 100644 index 83d03571..00000000 --- a/crates/queries/src/taint.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::analyzers::{VarBoundAnalyzer, *}; -use shared::context::CallFork; - -use shared::{analyzer::*, NodeIdx}; - -use ariadne::{Cache, Color, Config, Label, Report, ReportKind}; - -#[derive(Debug, Clone)] -pub struct TaintReport { - pub msgs: Vec, -} - -impl TaintReport { - pub fn new(msgs: Vec) -> Self { - Self { msgs } - } -} - -impl ReportDisplay for TaintReport { - fn report_kind(&self) -> ReportKind { - ReportKind::Custom("Taint Analysis", Color::Green) - } - fn msg(&self, _analyzer: &impl GraphLike) -> String { - self.msgs.join(";\n") - } - - fn labels(&self, _analyzer: &impl GraphLike) -> Vec> { - vec![] - } - - fn reports(&self, analyzer: &impl GraphLike) -> Vec> { - let report = Report::build(self.report_kind(), "".to_string(), 0) - .with_message(self.msg(analyzer)) - .with_config( - Config::default() - .with_cross_gap(false) - .with_underlines(true) - .with_tab_width(4), - ); - vec![report.finish()] - } - - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - for report in reports.iter() { - report.print(&mut *src).unwrap(); - } - } - - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphLike) { - let reports = &self.reports(analyzer); - reports.iter().for_each(|report| { - report.eprint(&mut src).unwrap(); - }); - } -} - -impl TaintQuery for T where T: VarBoundAnalyzer + Search + AnalyzerLike + Sized {} -pub trait TaintQuery: VarBoundAnalyzer + Search + AnalyzerLike + Sized { - #[allow(clippy::too_many_arguments)] - fn taint_query(&self, _entry: NodeIdx, _contract_name: String) { - todo!() - } - - fn recurse_children(&self, _child: CallFork) { - todo!() - } -} diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 01834f60..10015bab 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -87,283 +87,30 @@ pub trait GraphDot: GraphLike { fn cluster_str( &self, node: NodeIdx, - cluster_num: usize, + cluster_num: &mut usize, is_killed: bool, handled_nodes: Arc>>, handled_edges: Arc>>>, - ) -> String; - // { - // if self - // .graph() - // .edges_directed(node, Direction::Outgoing) - // .collect::>() - // .is_empty() - // { - // return "".to_string(); - // } - // let new_graph = self.graph().filter_map( - // |_idx, node| match node { - // Node::ContextVar(_cvar) => { - // // if !cvar.is_symbolic { - // // None - // // } else { - // Some(node.clone()) - // // } - // } - // _ => Some(node.clone()), - // }, - // |_idx, edge| Some(*edge), - // ); - - // let g = &G { graph: &new_graph }; - // let children = g.children(node); - // let children_edges = g.children_edges(node); - // let mut cn = cluster_num + 1; - // let child_node_str = children - // .iter() - // .map(|child| { - // { - // handled_nodes.lock().unwrap().insert(*child); - // } - - // if g.graph - // .edges_directed(*child, Direction::Outgoing) - // .collect::>() - // .is_empty() - // { - // return "".to_string(); - // } - // let post_str = match self.node(*child) { - // Node::Context(c) => { - // cn += 2; - // self.cluster_str( - // *child, - // cn, - // c.killed.is_some(), - // handled_nodes.clone(), - // handled_edges.clone(), - // ) - // } - // _ => "".to_string(), - // }; - - // format!( - // " {} [label = \"{}\", color = \"{}\"]\n{}\n", - // petgraph::graph::GraphIndex::index(child), - // child.as_dot_str(g).replace('\"', "\'"), - // self.node(*child).dot_str_color(), - // post_str - // ) - // }) - // .collect::>() - // .join(""); - - // let edge_str = children_edges - // .iter() - // .filter(|(_, _, _, idx)| !handled_edges.lock().unwrap().contains(idx)) - // .map(|(from, to, edge, idx)| { - // handled_edges.lock().unwrap().insert(*idx); - // let from = petgraph::graph::GraphIndex::index(from); - // let to = petgraph::graph::GraphIndex::index(to); - // format!(" {from:} -> {to:} [label = \"{edge:?}\"]\n",) - // }) - // .collect::>() - // .join(""); - // format!( - // " subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", - // cluster_num, - // if is_killed && cluster_num % 2 == 0 { - // " bgcolor=\"#7a0b0b\"" - // } else if is_killed { - // " bgcolor=\"#e04646\"" - // } else if cluster_num % 2 == 0 { - // " bgcolor=\"#545e87\"" - // } else { - // " bgcolor=\"#1a1b26\"" - // }, - // format!( - // " {} [label = \"{}\", color = \"{}\"]\n", - // node.index(), - // node.as_dot_str(g).replace('\"', "\'"), - // self.node(node).dot_str_color() - // ), - // child_node_str, - // edge_str, - // ) - // } + depth: usize, + as_mermaid: bool, + ) -> Option + where + Self: std::marker::Sized; /// Constructs a dot string fn dot_str(&self) -> String where Self: std::marker::Sized, Self: AnalyzerLike; - // { - // let mut dot_str = Vec::new(); - // let raw_start_str = r##"digraph G { - // node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - // edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - // bgcolor="#1a1b26"; rankdir="BT""##; - // dot_str.push(raw_start_str.to_string()); - // let handled_edges = Arc::new(Mutex::new(BTreeSet::new())); - // let handled_nodes = Arc::new(Mutex::new(BTreeSet::new())); - // let (nodes, edges) = ( - // self.graph().node_indices().collect::>(), - // self.graph().edge_indices().collect::>(), - // ); - // let mut cluster_num = 0; - // let mut skip = BTreeSet::default(); - // let nodes_str = nodes - // .iter() - // .filter_map(|node| { - // if self - // .graph() - // .edges_directed(*node, Direction::Outgoing) - // .collect::>() - // .is_empty() - // && !matches!(self.node(*node), Node::Entry) - // { - // skip.insert(*node); - // return None; - // } - // if !handled_nodes.lock().unwrap().contains(node) { - // match self.node(*node) { - // Node::Function(_) => { - // cluster_num += 2; - // Some(self.cluster_str( - // *node, - // cluster_num, - // false, - // handled_nodes.clone(), - // handled_edges.clone(), - // )) - // } - // n => Some(format!( - // "{} [label = \"{}\", color = \"{}\"]", - // petgraph::graph::GraphIndex::index(node), - // node.as_dot_str(self).replace('\"', "\'"), - // n.dot_str_color() - // )), - // } - // } else { - // None - // } - // }) - // .collect::>() - // .join("\n "); - // let edges_str = edges - // .into_iter() - // .filter_map(|edge| { - // if !handled_edges.lock().unwrap().contains(&edge) { - // let (from, to) = self.graph().edge_endpoints(edge).unwrap(); - // if skip.contains(&from) || skip.contains(&to) { - // return None; - // } - // let from = from.index(); - // let to = to.index(); - // Some(format!( - // "{from:} -> {to:} [label = \"{:?}\"]", - // self.graph().edge_weight(edge).unwrap() - // )) - // } else { - // None - // } - // }) - // .collect::>() - // .join("\n "); - - // dot_str.push(nodes_str); - // dot_str.push(edges_str); - // let raw_end_str = r#"}"#; - // dot_str.push(raw_end_str.to_string()); - // dot_str.join("\n") - // } /// Construct a dot string while filtering temporary variables fn dot_str_no_tmps(&self) -> String where Self: std::marker::Sized, Self: GraphLike + AnalyzerLike; - // { - // let new_graph = self.graph().filter_map( - // |_idx, node| match node { - // Node::ContextVar(cvar) => { - // if !cvar.is_symbolic || cvar.tmp_of.is_some() { - // None - // } else { - // Some(node.clone()) - // } - // } - // _ => Some(node.clone()), - // }, - // |_idx, edge| Some(*edge), - // ); - // let mut dot_str = Vec::new(); - // let raw_start_str = r##"digraph G { - // node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - // edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - // bgcolor="#1a1b26";"##; - // dot_str.push(raw_start_str.to_string()); - // let nodes_and_edges_str = format!( - // "{:?}", - // Dot::with_attr_getters( - // &new_graph, - // &[ - // petgraph::dot::Config::GraphContentOnly, - // petgraph::dot::Config::NodeNoLabel, - // petgraph::dot::Config::EdgeNoLabel - // ], - // &|_graph, edge_ref| { - // match edge_ref.weight() { - // Edge::Context(edge) => format!("label = \"{edge:?}\""), - // e => format!("label = \"{e:?}\""), - // } - // }, - // &|_graph, (idx, node_ref)| { - // let inner = match node_ref { - // Node::ContextVar(cvar) => { - // let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { - // r.as_dot_str(self) - // // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - // } else { - // "".to_string() - // }; - - // format!( - // "{} -- {} -- range: {}", - // cvar.display_name, - // cvar.ty.as_string(self).unwrap(), - // range_str - // ) - // } - // _ => idx.as_dot_str(&G { graph: &new_graph }), - // }; - // format!( - // "label = \"{}\", color = \"{}\"", - // inner.replace('\"', "\'"), - // node_ref.dot_str_color() - // ) - // } - // ) - // ); - // dot_str.push(nodes_and_edges_str); - // let raw_end_str = r#"}"#; - // dot_str.push(raw_end_str.to_string()); - // dot_str.join("\n") - // } -} -struct G<'a, Node, Edge> { - pub graph: &'a Graph, -} - -impl GraphLike for G<'_, Node, Edge> { - type Node = Node; - type Edge = Edge; - fn graph_mut(&mut self) -> &mut Graph { - panic!("Should call this") - } - - fn graph(&self) -> &Graph { - self.graph - } + fn mermaid_str(&self) -> String + where + Self: std::marker::Sized, + Self: AnalyzerLike; } \ No newline at end of file From 49a7caee5e8a451999d178e1d6d91d633e6fb1d4 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 13:19:41 -0800 Subject: [PATCH 15/71] move tests --- .../tests}/benches/flat_comptroller.sol | 0 .../pyrometer/tests}/benches/flat_ctoken.sol | 0 .../pyrometer/tests}/challenges/apron.sol | 0 .../tests}/challenges/func_stress.sol | 0 .../challenges/reverse_bound_propogation.sol | 0 {tests => crates/pyrometer/tests}/helpers.rs | 55 ++++++++++--------- .../pyrometer/tests}/no_killed_ctxs.rs | 0 .../pyrometer/tests}/test_data/abstract.sol | 0 .../pyrometer/tests}/test_data/assembly.sol | 0 .../pyrometer/tests}/test_data/bitwise.sol | 0 .../pyrometer/tests}/test_data/cast.sol | 15 ++++- .../pyrometer/tests}/test_data/const_var.sol | 0 .../tests}/test_data/constructor.sol | 4 +- .../pyrometer/tests}/test_data/dyn_types.sol | 0 .../pyrometer/tests}/test_data/env.sol | 0 .../tests}/test_data/func_override.sol | 0 .../tests}/test_data/function_calls.sol | 0 .../pyrometer/tests}/test_data/interface.sol | 0 .../pyrometer/tests}/test_data/intrinsics.sol | 0 .../pyrometer/tests}/test_data/logical.sol | 0 .../pyrometer/tests}/test_data/loops.sol | 0 .../pyrometer/tests}/test_data/math.sol | 0 .../pyrometer/tests}/test_data/modifier.sol | 13 +++-- .../tests}/test_data/named_func_call.sol | 0 .../pyrometer/tests}/test_data/precedence.sol | 0 .../relative_imports/relative_import.sol | 0 .../tests}/test_data/remapping_import.sol | 0 .../pyrometer/tests}/test_data/remappings.txt | 0 .../pyrometer/tests}/test_data/require.sol | 0 .../pyrometer/tests}/test_data/storage.sol | 0 .../pyrometer/tests}/test_data/using.sol | 0 crates/queries/src/lib.rs | 2 +- 32 files changed, 53 insertions(+), 36 deletions(-) rename {tests => crates/pyrometer/tests}/benches/flat_comptroller.sol (100%) rename {tests => crates/pyrometer/tests}/benches/flat_ctoken.sol (100%) rename {tests => crates/pyrometer/tests}/challenges/apron.sol (100%) rename {tests => crates/pyrometer/tests}/challenges/func_stress.sol (100%) rename {tests => crates/pyrometer/tests}/challenges/reverse_bound_propogation.sol (100%) rename {tests => crates/pyrometer/tests}/helpers.rs (61%) rename {tests => crates/pyrometer/tests}/no_killed_ctxs.rs (100%) rename {tests => crates/pyrometer/tests}/test_data/abstract.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/assembly.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/bitwise.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/cast.sol (96%) rename {tests => crates/pyrometer/tests}/test_data/const_var.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/constructor.sol (96%) rename {tests => crates/pyrometer/tests}/test_data/dyn_types.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/env.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/func_override.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/function_calls.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/interface.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/intrinsics.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/logical.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/loops.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/math.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/modifier.sol (89%) rename {tests => crates/pyrometer/tests}/test_data/named_func_call.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/precedence.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/relative_imports/relative_import.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/remapping_import.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/remappings.txt (100%) rename {tests => crates/pyrometer/tests}/test_data/require.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/storage.sol (100%) rename {tests => crates/pyrometer/tests}/test_data/using.sol (100%) diff --git a/tests/benches/flat_comptroller.sol b/crates/pyrometer/tests/benches/flat_comptroller.sol similarity index 100% rename from tests/benches/flat_comptroller.sol rename to crates/pyrometer/tests/benches/flat_comptroller.sol diff --git a/tests/benches/flat_ctoken.sol b/crates/pyrometer/tests/benches/flat_ctoken.sol similarity index 100% rename from tests/benches/flat_ctoken.sol rename to crates/pyrometer/tests/benches/flat_ctoken.sol diff --git a/tests/challenges/apron.sol b/crates/pyrometer/tests/challenges/apron.sol similarity index 100% rename from tests/challenges/apron.sol rename to crates/pyrometer/tests/challenges/apron.sol diff --git a/tests/challenges/func_stress.sol b/crates/pyrometer/tests/challenges/func_stress.sol similarity index 100% rename from tests/challenges/func_stress.sol rename to crates/pyrometer/tests/challenges/func_stress.sol diff --git a/tests/challenges/reverse_bound_propogation.sol b/crates/pyrometer/tests/challenges/reverse_bound_propogation.sol similarity index 100% rename from tests/challenges/reverse_bound_propogation.sol rename to crates/pyrometer/tests/challenges/reverse_bound_propogation.sol diff --git a/tests/helpers.rs b/crates/pyrometer/tests/helpers.rs similarity index 61% rename from tests/helpers.rs rename to crates/pyrometer/tests/helpers.rs index bd69d17d..1d159513 100644 --- a/tests/helpers.rs +++ b/crates/pyrometer/tests/helpers.rs @@ -1,39 +1,33 @@ +use analyzers::ReportConfig; +use analyzers::ReportDisplay; +use analyzers::FunctionVarsBoundAnalyzer; +use shared::Search; use ariadne::sources; -use pyrometer::context::analyzers::ReportConfig; -use pyrometer::context::analyzers::{FunctionVarsBoundAnalyzer, ReportDisplay}; -use pyrometer::Analyzer; -use shared::analyzer::Search; +use pyrometer::{Analyzer, SourcePath}; use shared::NodeIdx; -use shared::{nodes::FunctionNode, Edge}; +use graph::{nodes::FunctionNode, Edge}; use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; pub fn assert_no_ctx_killed(path_str: String, sol: &str) { let mut analyzer = Analyzer::default(); - let (maybe_entry, mut all_sources) = - analyzer.parse(sol, &PathBuf::from(path_str.clone()), true); - all_sources.push((maybe_entry, path_str.clone(), sol.to_string(), 0)); + let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); + let maybe_entry = analyzer.parse(sol, ¤t_path, true); let entry = maybe_entry.unwrap(); - no_ctx_killed(analyzer, entry, path_str, all_sources); + no_ctx_killed(analyzer, entry); } pub fn remapping_assert_no_ctx_killed(path_str: String, remapping_file: String, sol: &str) { let mut analyzer = Analyzer::default(); analyzer.set_remappings_and_root(remapping_file); - let (maybe_entry, mut all_sources) = - analyzer.parse(sol, &PathBuf::from(path_str.clone()), true); - all_sources.push((maybe_entry, path_str.clone(), sol.to_string(), 0)); + let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); + let maybe_entry = analyzer.parse(sol, ¤t_path, true); let entry = maybe_entry.unwrap(); - no_ctx_killed(analyzer, entry, path_str, all_sources); + no_ctx_killed(analyzer, entry); } -pub fn no_ctx_killed( - mut analyzer: Analyzer, - entry: NodeIdx, - path_str: String, - all_sources: Vec<(Option, String, String, usize)>, -) { +pub fn no_ctx_killed(mut analyzer: Analyzer, entry: NodeIdx) { assert!( analyzer.expr_errs.is_empty(), "Analyzer encountered parse errors" @@ -51,14 +45,21 @@ pub fn no_ctx_killed( show_unreachables: true, show_nonreverts: true, }; - let file_mapping: BTreeMap<_, _> = vec![(0usize, path_str)].into_iter().collect(); - - let mut source_map = sources( - all_sources - .iter() - .map(|(_entry, name, src, _num)| (name.clone(), src)) - .collect::>(), - ); + let mut file_mapping: BTreeMap = BTreeMap::new(); + let mut src_map: HashMap = HashMap::new(); + for (source_path, sol, o_file_no, _o_entry) in analyzer.sources.iter() { + if let Some(file_no) = o_file_no { + file_mapping.insert( + *file_no, + source_path.path_to_solidity_source().display().to_string(), + ); + } + src_map.insert( + source_path.path_to_solidity_source().display().to_string(), + sol.to_string(), + ); + } + let mut source_map = sources(src_map); let funcs = analyzer.search_children(entry, &Edge::Func); for func in funcs.into_iter() { diff --git a/tests/no_killed_ctxs.rs b/crates/pyrometer/tests/no_killed_ctxs.rs similarity index 100% rename from tests/no_killed_ctxs.rs rename to crates/pyrometer/tests/no_killed_ctxs.rs diff --git a/tests/test_data/abstract.sol b/crates/pyrometer/tests/test_data/abstract.sol similarity index 100% rename from tests/test_data/abstract.sol rename to crates/pyrometer/tests/test_data/abstract.sol diff --git a/tests/test_data/assembly.sol b/crates/pyrometer/tests/test_data/assembly.sol similarity index 100% rename from tests/test_data/assembly.sol rename to crates/pyrometer/tests/test_data/assembly.sol diff --git a/tests/test_data/bitwise.sol b/crates/pyrometer/tests/test_data/bitwise.sol similarity index 100% rename from tests/test_data/bitwise.sol rename to crates/pyrometer/tests/test_data/bitwise.sol diff --git a/tests/test_data/cast.sol b/crates/pyrometer/tests/test_data/cast.sol similarity index 96% rename from tests/test_data/cast.sol rename to crates/pyrometer/tests/test_data/cast.sol index 4b91ecb2..78465c4e 100644 --- a/tests/test_data/cast.sol +++ b/crates/pyrometer/tests/test_data/cast.sol @@ -231,9 +231,22 @@ contract Cast { require(b == x); } + + function downcast_uint_conc() public returns (uint64) { + uint128 y = type(uint128).max; + y -= type(uint32).max; + return uint64(y); + } + + function downcast_int_conc() public returns (int64) { + int128 x = type(int128).max; + x -= type(int32).max; + return int64(x); + } + function userInt() internal { int256 x = -100; - MyUint a = MyInt.wrap(x); + MyInt a = MyInt.wrap(x); int256 b = MyInt.unwrap(a); require(b == x); } diff --git a/tests/test_data/const_var.sol b/crates/pyrometer/tests/test_data/const_var.sol similarity index 100% rename from tests/test_data/const_var.sol rename to crates/pyrometer/tests/test_data/const_var.sol diff --git a/tests/test_data/constructor.sol b/crates/pyrometer/tests/test_data/constructor.sol similarity index 96% rename from tests/test_data/constructor.sol rename to crates/pyrometer/tests/test_data/constructor.sol index ef9c2dd5..cbf4d23e 100644 --- a/tests/test_data/constructor.sol +++ b/crates/pyrometer/tests/test_data/constructor.sol @@ -46,7 +46,7 @@ abstract contract H { abstract contract I is H { H a; - function liquidateBorrowInternal(H _a) internal returns (uint, uint) { + function liquidateBorrowInternal(H _a) internal returns (uint, uint, uint) { uint b = foo(); uint b2 = _a.foo(); uint b3 = a.foo(); @@ -54,7 +54,7 @@ abstract contract I is H { if (b2 != 1) {} if (b3 != 1) {} - return (b2, b3); + return (b, b2, b3); } function foo() public virtual override returns (uint){ diff --git a/tests/test_data/dyn_types.sol b/crates/pyrometer/tests/test_data/dyn_types.sol similarity index 100% rename from tests/test_data/dyn_types.sol rename to crates/pyrometer/tests/test_data/dyn_types.sol diff --git a/tests/test_data/env.sol b/crates/pyrometer/tests/test_data/env.sol similarity index 100% rename from tests/test_data/env.sol rename to crates/pyrometer/tests/test_data/env.sol diff --git a/tests/test_data/func_override.sol b/crates/pyrometer/tests/test_data/func_override.sol similarity index 100% rename from tests/test_data/func_override.sol rename to crates/pyrometer/tests/test_data/func_override.sol diff --git a/tests/test_data/function_calls.sol b/crates/pyrometer/tests/test_data/function_calls.sol similarity index 100% rename from tests/test_data/function_calls.sol rename to crates/pyrometer/tests/test_data/function_calls.sol diff --git a/tests/test_data/interface.sol b/crates/pyrometer/tests/test_data/interface.sol similarity index 100% rename from tests/test_data/interface.sol rename to crates/pyrometer/tests/test_data/interface.sol diff --git a/tests/test_data/intrinsics.sol b/crates/pyrometer/tests/test_data/intrinsics.sol similarity index 100% rename from tests/test_data/intrinsics.sol rename to crates/pyrometer/tests/test_data/intrinsics.sol diff --git a/tests/test_data/logical.sol b/crates/pyrometer/tests/test_data/logical.sol similarity index 100% rename from tests/test_data/logical.sol rename to crates/pyrometer/tests/test_data/logical.sol diff --git a/tests/test_data/loops.sol b/crates/pyrometer/tests/test_data/loops.sol similarity index 100% rename from tests/test_data/loops.sol rename to crates/pyrometer/tests/test_data/loops.sol diff --git a/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol similarity index 100% rename from tests/test_data/math.sol rename to crates/pyrometer/tests/test_data/math.sol diff --git a/tests/test_data/modifier.sol b/crates/pyrometer/tests/test_data/modifier.sol similarity index 89% rename from tests/test_data/modifier.sol rename to crates/pyrometer/tests/test_data/modifier.sol index c887f556..86aad8ff 100644 --- a/tests/test_data/modifier.sol +++ b/crates/pyrometer/tests/test_data/modifier.sol @@ -19,7 +19,6 @@ contract Modifier { require(l == 100); a += 1; _; - a = 1; a += 1; } @@ -35,19 +34,23 @@ contract Modifier { a += 1; } + function requireBoth() public RequireBefore RequireAfter { + a += 1; + } + function input(uint256 b) public Input(b) { uint256 a = b; - require(a == 1); + require(a == 2); } function input(uint256 b, uint256 q) public Input(b) Input(q) { uint256 k = b; - require(a == 2); + require(a == 4); } function internalMod(uint256 b) internal Input(b) { uint256 k = b; - require(a == 1); + require(a == 2); } function internalModPub(uint256 b) public { @@ -63,7 +66,7 @@ contract Modifier { } function inputFuncConst(uint256 x) internal Input(addOne(99)) returns (uint256) { - require(a == 1); + require(a == 2); return x; } diff --git a/tests/test_data/named_func_call.sol b/crates/pyrometer/tests/test_data/named_func_call.sol similarity index 100% rename from tests/test_data/named_func_call.sol rename to crates/pyrometer/tests/test_data/named_func_call.sol diff --git a/tests/test_data/precedence.sol b/crates/pyrometer/tests/test_data/precedence.sol similarity index 100% rename from tests/test_data/precedence.sol rename to crates/pyrometer/tests/test_data/precedence.sol diff --git a/tests/test_data/relative_imports/relative_import.sol b/crates/pyrometer/tests/test_data/relative_imports/relative_import.sol similarity index 100% rename from tests/test_data/relative_imports/relative_import.sol rename to crates/pyrometer/tests/test_data/relative_imports/relative_import.sol diff --git a/tests/test_data/remapping_import.sol b/crates/pyrometer/tests/test_data/remapping_import.sol similarity index 100% rename from tests/test_data/remapping_import.sol rename to crates/pyrometer/tests/test_data/remapping_import.sol diff --git a/tests/test_data/remappings.txt b/crates/pyrometer/tests/test_data/remappings.txt similarity index 100% rename from tests/test_data/remappings.txt rename to crates/pyrometer/tests/test_data/remappings.txt diff --git a/tests/test_data/require.sol b/crates/pyrometer/tests/test_data/require.sol similarity index 100% rename from tests/test_data/require.sol rename to crates/pyrometer/tests/test_data/require.sol diff --git a/tests/test_data/storage.sol b/crates/pyrometer/tests/test_data/storage.sol similarity index 100% rename from tests/test_data/storage.sol rename to crates/pyrometer/tests/test_data/storage.sol diff --git a/tests/test_data/using.sol b/crates/pyrometer/tests/test_data/using.sol similarity index 100% rename from tests/test_data/using.sol rename to crates/pyrometer/tests/test_data/using.sol diff --git a/crates/queries/src/lib.rs b/crates/queries/src/lib.rs index b1470cf7..3ac5e78c 100644 --- a/crates/queries/src/lib.rs +++ b/crates/queries/src/lib.rs @@ -1 +1 @@ -/// Currently Empty \ No newline at end of file +//! Currently Empty \ No newline at end of file From 357d1c9ab96a35c2970c832de23e2270067c1476 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 13:21:01 -0800 Subject: [PATCH 16/71] lint --- crates/analyzers/src/bounds.rs | 11 ++- crates/analyzers/src/func_analyzer/mod.rs | 11 +-- .../src/func_analyzer/report_display.rs | 13 +-- crates/analyzers/src/lib.rs | 2 +- crates/analyzers/src/var_analyzer/mod.rs | 7 +- .../src/var_analyzer/report_display.rs | 13 +-- crates/cli/src/main.rs | 97 +++++++++---------- crates/graph/src/graph_elements.rs | 30 +++--- crates/graph/src/lib.rs | 5 +- crates/graph/src/nodes/block.rs | 2 +- crates/graph/src/nodes/builtin.rs | 27 ++++-- crates/graph/src/nodes/concrete.rs | 16 +-- crates/graph/src/nodes/context/context_tys.rs | 4 +- crates/graph/src/nodes/context/expr_ret.rs | 3 +- crates/graph/src/nodes/context/mod.rs | 9 +- crates/graph/src/nodes/context/node.rs | 12 ++- crates/graph/src/nodes/context/querying.rs | 10 +- crates/graph/src/nodes/context/solving.rs | 29 ++++-- crates/graph/src/nodes/context/typing.rs | 14 +-- crates/graph/src/nodes/context/underlying.rs | 12 +-- crates/graph/src/nodes/context/var/mod.rs | 4 +- crates/graph/src/nodes/context/var/node.rs | 18 ++-- crates/graph/src/nodes/context/var/ranging.rs | 8 +- crates/graph/src/nodes/context/var/typing.rs | 24 +++-- .../graph/src/nodes/context/var/underlying.rs | 16 ++- .../graph/src/nodes/context/var/versioning.rs | 8 +- crates/graph/src/nodes/context/variables.rs | 22 +++-- crates/graph/src/nodes/context/versioning.rs | 19 ++-- crates/graph/src/nodes/contract_ty.rs | 16 ++- crates/graph/src/nodes/enum_ty.rs | 2 +- crates/graph/src/nodes/func_ty.rs | 26 +++-- crates/graph/src/nodes/mod.rs | 2 +- crates/graph/src/nodes/msg.rs | 7 +- crates/graph/src/nodes/struct_ty.rs | 13 ++- crates/graph/src/nodes/var_ty.rs | 15 ++- crates/graph/src/range/elem/concrete.rs | 7 +- crates/graph/src/range/elem/elem_enum.rs | 21 +--- crates/graph/src/range/elem/elem_trait.rs | 14 ++- crates/graph/src/range/elem/expr.rs | 15 +-- crates/graph/src/range/elem/map_or_array.rs | 10 +- crates/graph/src/range/elem/mod.rs | 5 +- crates/graph/src/range/elem/reference.rs | 11 ++- crates/graph/src/range/exec/add.rs | 2 +- crates/graph/src/range/exec/bitwise.rs | 2 +- crates/graph/src/range/exec/cast.rs | 2 +- crates/graph/src/range/exec/concat.rs | 2 +- crates/graph/src/range/exec/div.rs | 2 +- crates/graph/src/range/exec/exec_op.rs | 8 +- crates/graph/src/range/exec/exp.rs | 2 +- crates/graph/src/range/exec/logical.rs | 2 +- crates/graph/src/range/exec/max.rs | 2 +- crates/graph/src/range/exec/min.rs | 2 +- crates/graph/src/range/exec/mod.rs | 2 +- crates/graph/src/range/exec/modulo.rs | 2 +- crates/graph/src/range/exec/mul.rs | 4 +- crates/graph/src/range/exec/ord.rs | 4 +- crates/graph/src/range/exec/shift.rs | 2 +- crates/graph/src/range/exec/sub.rs | 2 +- crates/graph/src/range/exec_traits.rs | 10 +- crates/graph/src/range/mod.rs | 4 +- crates/graph/src/range/range_string.rs | 3 +- crates/graph/src/range/range_trait.rs | 18 ++-- crates/graph/src/range/solc_range.rs | 13 ++- crates/graph/src/solvers/atoms.rs | 21 ++-- crates/graph/src/solvers/brute.rs | 14 +-- crates/graph/src/solvers/dl.rs | 23 ++--- crates/graph/src/solvers/mod.rs | 4 +- crates/graph/src/var_type.rs | 26 +++-- crates/pyrometer/src/analyzer.rs | 24 +++-- crates/pyrometer/src/analyzer_backend.rs | 27 ++---- crates/pyrometer/src/builtin_fns.rs | 4 +- crates/pyrometer/src/graph_backend.rs | 23 ++--- crates/pyrometer/src/lib.rs | 4 +- crates/pyrometer/tests/helpers.rs | 6 +- crates/queries/src/lib.rs | 2 +- crates/shared/src/analyzer_like.rs | 11 +-- crates/shared/src/graph_like.rs | 21 ++-- crates/shared/src/lib.rs | 6 +- crates/shared/src/search.rs | 93 +++++++++++++++--- crates/solc-expressions/src/array.rs | 11 +-- crates/solc-expressions/src/bin_op.rs | 15 +-- crates/solc-expressions/src/cmp.rs | 11 ++- crates/solc-expressions/src/cond_op.rs | 9 +- .../src/context_builder/mod.rs | 18 ++-- crates/solc-expressions/src/env.rs | 8 +- .../src/func_call/internal_call.rs | 8 +- .../src/func_call/intrinsic_call.rs | 16 +-- crates/solc-expressions/src/func_call/mod.rs | 20 ++-- .../src/func_call/modifier.rs | 10 +- .../src/func_call/namespaced_call.rs | 8 +- crates/solc-expressions/src/lib.rs | 6 +- crates/solc-expressions/src/list.rs | 8 +- crates/solc-expressions/src/literal.rs | 10 +- crates/solc-expressions/src/loops.rs | 17 ++-- .../solc-expressions/src/member_access/mod.rs | 11 ++- crates/solc-expressions/src/require.rs | 12 ++- crates/solc-expressions/src/variable.rs | 8 +- crates/solc-expressions/src/yul/mod.rs | 6 +- .../solc-expressions/src/yul/yul_cond_op.rs | 22 +++-- crates/solc-expressions/src/yul/yul_funcs.rs | 16 +-- 100 files changed, 701 insertions(+), 558 deletions(-) diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index de485d00..1044558c 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -1,9 +1,7 @@ -use crate::{LocSpan, LocStrSpan, ReportConfig, VarBoundAnalysis, FunctionVarsBoundAnalysis}; +use crate::{FunctionVarsBoundAnalysis, LocSpan, LocStrSpan, ReportConfig, VarBoundAnalysis}; use graph::{ - GraphBackend, Range, RangeEval, SolcRange, - range_string::ToRangeString, - nodes::ContextNode, + nodes::ContextNode, range_string::ToRangeString, GraphBackend, Range, RangeEval, SolcRange, }; use ariadne::{Color, Fmt, Label, Span}; @@ -106,7 +104,10 @@ impl OrderedAnalysis { Self { analyses } } - pub fn from_func_analysis(fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphBackend) -> Self { + pub fn from_func_analysis( + fvba: FunctionVarsBoundAnalysis, + analyzer: &impl GraphBackend, + ) -> Self { let mut analyses = Self::default(); fvba.vars_by_ctx.iter().for_each(|(_ctx, bas)| { bas.iter().for_each(|ba| { diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index 560954a8..a5161b29 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -1,19 +1,18 @@ use crate::{ - bounds::range_parts, - VarBoundAnalysis, VarBoundAnalyzer, LocStrSpan, ReportConfig, - ReportKind, ReportDisplay, + bounds::range_parts, LocStrSpan, ReportConfig, ReportDisplay, ReportKind, VarBoundAnalysis, + VarBoundAnalyzer, }; use graph::{ - GraphBackend, AnalyzerBackend, nodes::{ContextNode, KilledKind}, range_string::ToRangeString, - solvers::{SolverAtom, Atomize} + solvers::{Atomize, SolverAtom}, + AnalyzerBackend, GraphBackend, }; use shared::Search; use ariadne::{Color, Config, Fmt, Label, Report, Span}; -use solang_parser::pt::{CodeLocation}; +use solang_parser::pt::CodeLocation; use std::collections::{BTreeMap, BTreeSet}; mod report_display; diff --git a/crates/analyzers/src/func_analyzer/report_display.rs b/crates/analyzers/src/func_analyzer/report_display.rs index 4df1c53e..9bead892 100644 --- a/crates/analyzers/src/func_analyzer/report_display.rs +++ b/crates/analyzers/src/func_analyzer/report_display.rs @@ -1,15 +1,8 @@ -use crate::{ - LocStrSpan, - ReportKind, - FunctionVarsBoundAnalysis, - ReportDisplay -}; +use crate::{FunctionVarsBoundAnalysis, LocStrSpan, ReportDisplay, ReportKind}; -use graph::{ - GraphBackend, -}; +use graph::GraphBackend; -use ariadne::{Color, Config, Fmt, Label, Report, Span, Cache}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, Span}; use std::collections::BTreeMap; diff --git a/crates/analyzers/src/lib.rs b/crates/analyzers/src/lib.rs index ed1d00e4..a2fbc7fe 100644 --- a/crates/analyzers/src/lib.rs +++ b/crates/analyzers/src/lib.rs @@ -1,7 +1,7 @@ pub mod bounds; -use graph::{GraphBackend, AnalyzerBackend}; use ariadne::{Cache, Label, Report, ReportKind, Span}; +use graph::{AnalyzerBackend, GraphBackend}; use shared::Search; use solang_parser::pt::Loc; use std::collections::BTreeMap; diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 5141ce5a..09e0fdd4 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -1,11 +1,11 @@ use crate::{ bounds::{range_parts, AnalysisItem, RangePart}, - LocStrSpan, ReportConfig + LocStrSpan, ReportConfig, }; use graph::{ - GraphBackend, AnalyzerBackend, Range, SolcRange, - nodes::{ContextVarNode, ContextNode, KilledKind}, + nodes::{ContextNode, ContextVarNode, KilledKind}, + AnalyzerBackend, GraphBackend, Range, SolcRange, }; use shared::Search; @@ -15,7 +15,6 @@ use solang_parser::pt::{CodeLocation, StorageLocation}; use std::collections::BTreeMap; mod report_display; -pub use report_display::*; #[derive(PartialOrd, Eq, PartialEq, Ord, Clone, Debug)] pub struct CtxSwitch { diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index cf826e57..e53b7e10 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -1,16 +1,11 @@ use crate::{ - LocStrSpan, - ReportKind, - ReportDisplay, - VarBoundAnalysis, - bounds::{range_parts, AnalysisItem} + bounds::{range_parts, AnalysisItem}, + LocStrSpan, ReportDisplay, ReportKind, VarBoundAnalysis, }; -use graph::{ - GraphBackend, -}; +use graph::GraphBackend; -use ariadne::{Color, Config, Fmt, Label, Report, Span, Cache}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, Span}; impl ReportDisplay for VarBoundAnalysis { fn report_kind(&self) -> ReportKind { diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 9d6ae5ee..12774ae9 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,27 +1,24 @@ - -use shared::GraphDot; -use analyzers::{ - ReportDisplay, FunctionVarsBoundAnalyzer, ReportConfig -}; +use analyzers::{FunctionVarsBoundAnalyzer, ReportConfig, ReportDisplay}; use graph::{ - Edge, Range, - nodes::{ContractNode, FunctionNode, Concrete}, elem::{Elem, RangeElem}, - solvers::{SolcSolver, AtomicSolveStatus, BruteBinSearchSolver}, + nodes::{Concrete, ContractNode, FunctionNode}, + solvers::{AtomicSolveStatus, BruteBinSearchSolver, SolcSolver}, + Edge, Range, }; -use pyrometer::{Root, SourcePath, Analyzer}; -use shared::{Search}; +use pyrometer::{Analyzer, Root, SourcePath}; +use shared::GraphDot; +use shared::Search; use ariadne::sources; use clap::{ArgAction, Parser, ValueHint}; -use tracing_subscriber::prelude::*; use ethers_core::types::I256; +use tracing_subscriber::prelude::*; use std::{ collections::{BTreeMap, HashMap}, - path::PathBuf, env::{self}, - fs + fs, + path::PathBuf, }; #[derive(Parser, Debug)] @@ -279,46 +276,46 @@ fn main() { // TODO: clean this up to actually run on all contracts // if args.swq { - // println!("Creating SWQ graph for {} contracts", all_contracts.len()); - // let mut cond_graph: Option = None; - // for i in 0..all_contracts.len() { - // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { - // (Some(ref mut existing), Some(new)) => { - // existing.append_graph(new); - // } - // (None, Some(new)) => { - // cond_graph = Some(new); - // } - // _ => {} - // } - // } + // println!("Creating SWQ graph for {} contracts", all_contracts.len()); + // let mut cond_graph: Option = None; + // for i in 0..all_contracts.len() { + // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { + // (Some(ref mut existing), Some(new)) => { + // existing.append_graph(new); + // } + // (None, Some(new)) => { + // cond_graph = Some(new); + // } + // _ => {} + // } + // } - // if let Some(graph) = cond_graph { - // println!("{}", graph.dot_str()); - // graph.open_dot(); - // } else { - // println!("no graph"); - // } + // if let Some(graph) = cond_graph { + // println!("{}", graph.dot_str()); + // graph.open_dot(); + // } else { + // println!("no graph"); + // } // } else if args.swq_mermaid { - // println!("Creating SWQ graph for {} contracts", all_contracts.len()); - // let mut cond_graph: Option = None; - // for i in 0..all_contracts.len() { - // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { - // (Some(ref mut existing), Some(new)) => { - // existing.append_graph(new); - // } - // (None, Some(new)) => { - // cond_graph = Some(new); - // } - // _ => {} - // } - // } + // println!("Creating SWQ graph for {} contracts", all_contracts.len()); + // let mut cond_graph: Option = None; + // for i in 0..all_contracts.len() { + // match (&mut cond_graph, analyzer.func_query(all_contracts[i])) { + // (Some(ref mut existing), Some(new)) => { + // existing.append_graph(new); + // } + // (None, Some(new)) => { + // cond_graph = Some(new); + // } + // _ => {} + // } + // } - // if let Some(graph) = cond_graph { - // println!("{}", graph.mermaid_str()); - // } else { - // println!("no graph"); - // } + // if let Some(graph) = cond_graph { + // println!("{}", graph.mermaid_str()); + // } else { + // println!("no graph"); + // } // } else { let _t1 = std::time::Instant::now(); if args.contracts.is_empty() { diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 9e0e99c4..73cd06ca 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -1,25 +1,24 @@ -use crate::{VarType, nodes::*}; +use crate::{nodes::*, VarType}; -use shared::{ NodeIdx, AnalyzerLike, GraphLike, Heirarchical}; +use shared::{AnalyzerLike, GraphLike, Heirarchical, NodeIdx}; use lazy_static::lazy_static; use solang_parser::pt::Identifier; use std::collections::HashMap; -pub trait GraphBackend: GraphLike< - Edge = Edge, - Node = Node, - -> {} -pub trait AnalyzerBackend: AnalyzerLike< - Builtin = Builtin, - MsgNode = MsgNode, - BlockNode = BlockNode, - FunctionParam = FunctionParam, - FunctionReturn = FunctionReturn, - Function = Function -> + GraphBackend {} +pub trait GraphBackend: GraphLike {} +pub trait AnalyzerBackend: + AnalyzerLike< + Builtin = Builtin, + MsgNode = MsgNode, + BlockNode = BlockNode, + FunctionParam = FunctionParam, + FunctionReturn = FunctionReturn, + Function = Function, + > + GraphBackend +{ +} pub trait AsDotStr { fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String; @@ -373,4 +372,3 @@ pub enum ContextEdge { /// Unused Range, } - diff --git a/crates/graph/src/lib.rs b/crates/graph/src/lib.rs index 08006b17..2f35381d 100644 --- a/crates/graph/src/lib.rs +++ b/crates/graph/src/lib.rs @@ -1,11 +1,10 @@ mod graph_elements; -mod var_type; mod range; +mod var_type; pub mod nodes; pub mod solvers; - -pub use var_type::*; pub use graph_elements::*; pub use range::*; +pub use var_type::*; diff --git a/crates/graph/src/nodes/block.rs b/crates/graph/src/nodes/block.rs index 0e09c2f9..be71be01 100644 --- a/crates/graph/src/nodes/block.rs +++ b/crates/graph/src/nodes/block.rs @@ -1,4 +1,4 @@ -use crate::{GraphBackend, AsDotStr, Node, GraphError}; +use crate::{AsDotStr, GraphBackend, GraphError, Node}; use shared::NodeIdx; use ethers_core::types::{Address, H256, U256}; diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 876fc282..0dde90b4 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -1,10 +1,10 @@ -use crate::{AnalyzerBackend, GraphBackend, SolcRange, VarType, Node, GraphError, nodes::Concrete}; +use crate::{nodes::Concrete, AnalyzerBackend, GraphBackend, GraphError, Node, SolcRange, VarType}; -use shared::NodeIdx; use crate::range::elem::*; +use shared::NodeIdx; -use solang_parser::pt::{Type, Expression, Loc}; -use ethers_core::types::{Address, H256, U256, I256}; +use ethers_core::types::{Address, H256, I256, U256}; +use solang_parser::pt::{Expression, Loc, Type}; /// A builtin node #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] @@ -12,7 +12,10 @@ pub struct BuiltInNode(pub usize); impl BuiltInNode { /// Gets the underlying builtin from the graph - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Builtin, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Builtin, GraphError> { match analyzer.node(*self) { Node::Builtin(b) => Ok(b), e => Err(GraphError::NodeConfusion(format!( @@ -85,7 +88,10 @@ impl BuiltInNode { } /// Returns whether the builtin is a sized array or bytes - pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn maybe_array_size( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match self.underlying(analyzer)? { Builtin::SizedArray(s, _) => Ok(Some(*s)), Builtin::Bytes(s) => Ok(Some(U256::from(*s))), @@ -104,7 +110,10 @@ impl BuiltInNode { } /// Returns the zero range for this builtin type, i.e. uint256 -> [0, 0] - pub fn zero_range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn zero_range( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { Ok(self.underlying(analyzer)?.zero_range()) } } @@ -174,7 +183,7 @@ impl Builtin { } } - /// Possible types that this type could have been had a literal been parsed differently - i.e. a `1` + /// Possible types that this type could have been had a literal been parsed differently - i.e. a `1` /// could be uint8 to uint256. pub fn possible_builtins_from_ty_inf(&self) -> Vec { let mut builtins = vec![]; @@ -459,4 +468,4 @@ impl Builtin { ), } } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index fb38973f..c8d4452d 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -1,4 +1,4 @@ -use crate::{AnalyzerBackend, GraphBackend, Node, GraphError, nodes::Builtin, VarType}; +use crate::{nodes::Builtin, AnalyzerBackend, GraphBackend, GraphError, Node, VarType}; use shared::NodeIdx; use ethers_core::types::{Address, H256, I256, U256}; @@ -9,7 +9,10 @@ pub struct ConcreteNode(pub usize); impl ConcreteNode { /// Gets the underlying node data for the [`Concrete`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Concrete, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Concrete, GraphError> { match analyzer.node(*self) { Node::Concrete(c) => Ok(c), e => Err(GraphError::NodeConfusion(format!( @@ -49,7 +52,10 @@ impl ConcreteNode { } /// Returns the size of the array size if it is an array-like concrete - pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn maybe_array_size( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { Ok(self.underlying(analyzer)?.maybe_array_size()) } @@ -327,9 +333,7 @@ impl Concrete { } } } - Builtin::Int(size) => { - Some(Concrete::Int(size, I256::from_raw(val))) - } + Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), Builtin::Bytes(size) => { let mask = if size == 32 { U256::MAX diff --git a/crates/graph/src/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs index 0d625c72..cbd2b5ce 100644 --- a/crates/graph/src/nodes/context/context_tys.rs +++ b/crates/graph/src/nodes/context/context_tys.rs @@ -1,4 +1,4 @@ -use crate::nodes::{ContextNode, ContextVarNode, FunctionNode, ContractNode}; +use crate::nodes::{ContextNode, ContextVarNode, ContractNode, FunctionNode}; use shared::NodeIdx; use solang_parser::pt::Loc; @@ -81,4 +81,4 @@ pub struct ContextCache { pub associated_source: Option, /// Associated contract of this context pub associated_contract: Option, -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index 9e1cf80a..a4fd2e64 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -1,7 +1,6 @@ -use crate::{GraphBackend, AsDotStr, GraphError, Node, VarType, nodes::context::ContextVarNode,}; +use crate::{nodes::context::ContextVarNode, AsDotStr, GraphBackend, GraphError, Node, VarType}; use shared::NodeIdx; - /// The reason a context was killed #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum KilledKind { diff --git a/crates/graph/src/nodes/context/mod.rs b/crates/graph/src/nodes/context/mod.rs index cebf990c..4e8ac1ac 100644 --- a/crates/graph/src/nodes/context/mod.rs +++ b/crates/graph/src/nodes/context/mod.rs @@ -4,16 +4,15 @@ mod node; mod underlying; mod var; +pub use context_tys::{CallFork, ContextCache, ModifierState}; +pub use expr_ret::{ExprRet, KilledKind}; pub use node::ContextNode; pub use underlying::Context; -pub use var::{ContextVarNode, TmpConstruction, ContextVar}; -pub use expr_ret::{KilledKind, ExprRet}; -pub use context_tys::{ ModifierState, ContextCache, CallFork }; - +pub use var::{ContextVar, ContextVarNode, TmpConstruction}; // ContextNode implementations are split to ease in maintainability mod querying; mod solving; mod typing; mod variables; -mod versioning; \ No newline at end of file +mod versioning; diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index a23e2fd7..e01331e2 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,7 +1,6 @@ use crate::{ - AsDotStr, AnalyzerBackend, - nodes::{ FunctionParamNode, ContextVarNode, Context, FunctionNode, KilledKind }, - GraphError, Node, GraphBackend + nodes::{Context, ContextVarNode, FunctionNode, FunctionParamNode, KilledKind}, + AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; @@ -62,7 +61,10 @@ impl ContextNode { } /// Gets an immutable reference to the underlying context in the graph - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Context, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Context, GraphError> { match analyzer.node(*self) { Node::Context(c) => Ok(c), e => Err(GraphError::NodeConfusion(format!( @@ -155,4 +157,4 @@ impl From for ContextNode { fn from(idx: NodeIdx) -> Self { ContextNode(idx.index()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 1bedb637..b2f9f018 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -1,13 +1,13 @@ use crate::{ - AnalyzerBackend, GraphBackend, GraphError, Edge, ContextEdge, - nodes::{ContextNode, StructNode, ContractNode, FunctionNode}, + nodes::{ContextNode, ContractNode, FunctionNode, StructNode}, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, }; use shared::{NodeIdx, Search}; -use std::collections::{BTreeSet, BTreeMap}; +use std::collections::{BTreeMap, BTreeSet}; impl ContextNode { - /// Gets the associated contract for the function for the context + /// Gets the associated contract for the function for the context pub fn associated_contract( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), @@ -240,4 +240,4 @@ impl ContextNode { pub fn associated_fn_name(&self, analyzer: &impl GraphBackend) -> Result { self.associated_fn(analyzer)?.name(analyzer) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 7cd18697..273d97c0 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,9 +1,12 @@ use crate::{ - solvers::{SolverAtom, Atomize, dl::{SolveStatus, DLSolver}}, + as_dot_str, + nodes::{ContextNode, ContextVarNode}, range::{elem::RangeOp, RangeEval}, - nodes::{ContextVarNode, ContextNode}, - Node, GraphError, GraphBackend, AnalyzerBackend, AsDotStr, - as_dot_str + solvers::{ + dl::{DLSolver, SolveStatus}, + Atomize, SolverAtom, + }, + AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; @@ -13,8 +16,8 @@ use petgraph::dot::Dot; use std::collections::BTreeMap; impl ContextNode { - /// Use a Difference Logic solver to see if it is unreachable - pub fn unreachable(&self, analyzer: &impl GraphBackend) -> Result { + /// Use a Difference Logic solver to see if it is unreachable + pub fn unreachable(&self, analyzer: &impl GraphBackend) -> Result { let mut solver = self.dl_solver(analyzer)?.clone(); match solver.solve_partial(analyzer)? { SolveStatus::Unsat => Ok(true), @@ -55,12 +58,18 @@ impl ContextNode { } /// Get the difference logic solver associated with this context - pub fn dl_solver<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a DLSolver, GraphError> { + pub fn dl_solver<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a DLSolver, GraphError> { Ok(&self.underlying(analyzer)?.dl_solver) } /// Returns a map of variable dependencies for this context - pub fn ctx_deps(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn ctx_deps( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { Ok(self.underlying(analyzer)?.ctx_deps.clone()) } @@ -89,7 +98,7 @@ impl ContextNode { Ok(()) } - /// Creates a DAG of the context dependencies and opens it with graphviz + /// Creates a DAG of the context dependencies and opens it with graphviz pub fn deps_dag(&self, g: &impl GraphBackend) -> Result<(), GraphError> { let deps = self.ctx_deps(g)?; // #[derive(Debug, Copy, Clone)] @@ -209,4 +218,4 @@ impl ContextNode { .expect("failed to execute process"); Ok(()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index ad3d3d2c..49e2612e 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -1,17 +1,17 @@ use crate::{ - GraphError, GraphBackend, AnalyzerBackend, - nodes::{ContextNode, FunctionNode} + nodes::{ContextNode, FunctionNode}, + AnalyzerBackend, GraphBackend, GraphError, }; impl ContextNode { - /// Returns whether this context is killed or returned + /// Returns whether this context is killed or returned pub fn killed_or_ret(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; Ok(underlying.killed.is_some() || (!underlying.ret.is_empty() && underlying.modifier_state.is_none())) } - /// Returns whether the context is killed + /// Returns whether the context is killed pub fn is_returned(&self, analyzer: &impl GraphBackend) -> Result { Ok(!self.underlying(analyzer)?.ret.is_empty()) } @@ -27,8 +27,8 @@ impl ContextNode { Ok(underlying.child.is_some() || underlying.killed.is_some() || !underlying.ret.is_empty()) } - /// Check if this context is in an external function call - pub fn is_ext_fn(&self, analyzer: &impl GraphBackend) -> Result { + /// Check if this context is in an external function call + pub fn is_ext_fn(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.ext_fn_call.is_some()) } @@ -80,4 +80,4 @@ impl ContextNode { self.underlying_mut(analyzer)?.unchecked = false; Ok(()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index aa3344d0..2901dc4f 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -1,16 +1,14 @@ use crate::{ - GraphError, AnalyzerBackend, - solvers::dl::DLSolver, nodes::{ - ExprRet, KilledKind, ContextCache, - FunctionNode, ContextVarNode, ContextNode, CallFork, + CallFork, ContextCache, ContextNode, ContextVarNode, ExprRet, FunctionNode, KilledKind, ModifierState, - } + }, + solvers::dl::DLSolver, + AnalyzerBackend, GraphError, }; use solang_parser::pt::Loc; - #[derive(Debug, Clone, Eq, PartialEq)] pub struct Context { /// The function associated with this context @@ -250,4 +248,4 @@ impl Context { pub fn as_string(&mut self) -> String { "Context".to_string() } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/mod.rs b/crates/graph/src/nodes/context/var/mod.rs index d4909ebe..1f665e95 100644 --- a/crates/graph/src/nodes/context/var/mod.rs +++ b/crates/graph/src/nodes/context/var/mod.rs @@ -1,8 +1,8 @@ mod node; mod ranging; -mod underlying; mod typing; +mod underlying; mod versioning; pub use node::*; -pub use underlying::*; \ No newline at end of file +pub use underlying::*; diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index ef691f92..023a05b3 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -1,14 +1,13 @@ use crate::{ - GraphBackend, AsDotStr, - GraphError, Node, ContextEdge, Edge, - nodes::{VarNode, ContextNode, ContextVar, TmpConstruction}, - range::{Range, range_string::ToRangeString, elem::RangeElem}, + nodes::{ContextNode, ContextVar, TmpConstruction, VarNode}, + range::{elem::RangeElem, range_string::ToRangeString, Range}, + AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, }; use shared::{NodeIdx, Search}; use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{StorageLocation, Loc}; +use solang_parser::pt::{Loc, StorageLocation}; use std::collections::BTreeMap; @@ -88,7 +87,6 @@ impl ContextVarNode { ) -> Result<&'a Option, GraphError> { Ok(&self.underlying(analyzer)?.storage) } - pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self @@ -193,7 +191,10 @@ impl ContextVarNode { return_assignments } - pub fn tmp_of(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn tmp_of( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { Ok(self.underlying(analyzer)?.tmp_of()) } @@ -248,7 +249,6 @@ impl ContextVarNode { .collect() } - pub fn dependent_on( &self, analyzer: &impl GraphBackend, @@ -301,4 +301,4 @@ impl ContextVarNode { Ok(tree) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 0569cad2..504ae6f2 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,7 +1,7 @@ use crate::{ - AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, - nodes::{ContextVarNode, ContextNode, Concrete}, + nodes::{Concrete, ContextNode, ContextVarNode}, range::{range_string::ToRangeString, Range}, + AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, }; use crate::range::elem::*; @@ -9,7 +9,7 @@ use crate::range::elem::*; use solang_parser::pt::Loc; impl ContextVarNode { - #[tracing::instrument(level = "trace", skip_all)] + #[tracing::instrument(level = "trace", skip_all)] pub fn update_deps( &mut self, ctx: ContextNode, @@ -320,4 +320,4 @@ impl ContextVarNode { } Ok(()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 8aee4e98..dd625544 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,19 +1,19 @@ use crate::{ - AnalyzerBackend, GraphBackend, GraphError, VarType, Node, Edge, ContextEdge, - nodes::{ContextVarNode, ContextNode, Concrete, Builtin}, + nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; use shared::Search; use petgraph::Direction; -use solang_parser::pt::{StorageLocation, Loc}; +use solang_parser::pt::{Loc, StorageLocation}; impl ContextVarNode { - pub fn ty<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a VarType, GraphError> { + pub fn ty<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a VarType, GraphError> { Ok(&self.underlying(analyzer)?.ty) } - pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { + pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_mapping(analyzer) } @@ -145,7 +145,11 @@ impl ContextVarNode { Ok(false) } - pub fn is_return_node_in_any(&self, ctxs: &[ContextNode], analyzer: &impl GraphBackend) -> bool { + pub fn is_return_node_in_any( + &self, + ctxs: &[ContextNode], + analyzer: &impl GraphBackend, + ) -> bool { ctxs.iter().any(|ctx| { ctx.underlying(analyzer) .unwrap() @@ -223,7 +227,11 @@ impl ContextVarNode { Ok(analyzer.add_node(Node::ContextVar(new_underlying)).into()) } - pub fn ty_eq(&self, other: &Self, analyzer: &mut impl GraphBackend) -> Result { + pub fn ty_eq( + &self, + other: &Self, + analyzer: &mut impl GraphBackend, + ) -> Result { self.ty(analyzer)?.ty_eq(other.ty(analyzer)?, analyzer) } @@ -306,4 +314,4 @@ impl ContextVarNode { pub fn is_int(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_int(analyzer) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 69bdf92a..45edabe3 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -1,13 +1,16 @@ use crate::{ - AnalyzerBackend, GraphBackend, GraphError, VarType, Node, SolcRange, TypeNode, + nodes::{ + BuiltInNode, Builtin, Concrete, ConcreteNode, ContextNode, ContextVarNode, ContractNode, + EnumNode, Field, FunctionNode, FunctionParam, FunctionReturn, StructNode, TyNode, + }, range::Range, - nodes::{ContextVarNode, ContextNode, Concrete, Builtin, ContractNode, FunctionNode, FunctionParam, FunctionReturn, BuiltInNode, EnumNode, Field, TyNode, StructNode, ConcreteNode}, + AnalyzerBackend, GraphBackend, GraphError, Node, SolcRange, TypeNode, VarType, }; use crate::range::elem::*; use shared::NodeIdx; -use solang_parser::pt::{StorageLocation, Loc}; +use solang_parser::pt::{Loc, StorageLocation}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ContextVar { @@ -576,7 +579,10 @@ impl ContextVar { } } - pub fn maybe_new_from_func_ret(analyzer: &impl GraphBackend, ret: FunctionReturn) -> Option { + pub fn maybe_new_from_func_ret( + analyzer: &impl GraphBackend, + ret: FunctionReturn, + ) -> Option { if let Some(name) = ret.name { if let Some(ty) = VarType::try_from_idx(analyzer, ret.ty) { Some(ContextVar { @@ -625,4 +631,4 @@ impl ContextVar { Ok(None) } } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index f3b4a9c0..483dac22 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -1,15 +1,14 @@ use crate::{ - GraphBackend, GraphError, Edge, ContextEdge, - nodes::{ContextVarNode, ContextNode}, + nodes::{ContextNode, ContextVarNode}, + ContextEdge, Edge, GraphBackend, GraphError, }; use shared::NodeIdx; use petgraph::{visit::EdgeRef, Direction}; - impl ContextVarNode { - pub fn latest_version(&self, analyzer: &impl GraphBackend) -> Self { + pub fn latest_version(&self, analyzer: &impl GraphBackend) -> Self { let mut latest = *self; while let Some(next) = latest.next_version(analyzer) { latest = next; @@ -194,4 +193,3 @@ impl ContextVarNode { } } } - diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 0dae0097..e4d29266 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -1,6 +1,6 @@ use crate::{ - AnalyzerBackend, GraphBackend, Node, Edge, GraphError, ContextEdge, - nodes::{ContextVarNode, ContextNode, ExprRet}, + nodes::{ContextNode, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, }; use solang_parser::pt::Loc; @@ -8,8 +8,8 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; impl ContextNode { - /// Add a variable to this context - pub fn add_var( + /// Add a variable to this context + pub fn add_var( &self, var: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), @@ -20,7 +20,7 @@ impl ContextNode { Ok(()) } - /// Gets a variable by name in the context + /// Gets a variable by name in the context pub fn var_by_name(&self, analyzer: &impl GraphBackend, name: &str) -> Option { self.underlying(analyzer) .unwrap() @@ -46,7 +46,10 @@ impl ContextNode { } /// Gets all variables associated with a context - pub fn vars<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a BTreeMap { + pub fn vars<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> &'a BTreeMap { &self.underlying(analyzer).unwrap().cache.vars } @@ -248,10 +251,13 @@ impl ContextNode { } /// Gets local vars that were assigned from an external function return - pub fn vars_assigned_from_ext_fn_ret(&self, analyzer: &impl GraphBackend) -> Vec { + pub fn vars_assigned_from_ext_fn_ret( + &self, + analyzer: &impl GraphBackend, + ) -> Vec { self.local_vars(analyzer) .iter() .flat_map(|(_name, var)| var.ext_return_assignments(analyzer)) .collect() } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index a19aab1f..e56bf422 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,13 +1,13 @@ use crate::{ - AnalyzerBackend, GraphBackend, Node, GraphError, - nodes::{ContextNode, CallFork, KilledKind, FunctionNode} + nodes::{CallFork, ContextNode, FunctionNode, KilledKind}, + AnalyzerBackend, GraphBackend, GraphError, Node, }; use solang_parser::pt::Loc; impl ContextNode { - /// Query whether this context has a parent - pub fn has_parent(&self, analyzer: &impl GraphBackend) -> Result { + /// Query whether this context has a parent + pub fn has_parent(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.parent_ctx.is_some()) } @@ -27,7 +27,7 @@ impl ContextNode { } } - /// Gets the subcontexts of this context + /// Gets the subcontexts of this context pub fn subcontexts(&self, analyzer: &impl GraphBackend) -> Vec { let underlying = self.underlying(analyzer).unwrap(); match underlying.child { @@ -75,7 +75,7 @@ impl ContextNode { .collect()) } - /// Returns tail contexts associated with the context + /// Returns tail contexts associated with the context pub fn live_edges(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(child) = self.underlying(analyzer)?.child { let mut lineage = vec![]; @@ -391,7 +391,10 @@ impl ContextNode { } /// Gets parent list - pub fn parent_list(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn parent_list( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let context = self.underlying(analyzer)?; let mut parents = vec![]; if let Some(parent_ctx) = context.parent_ctx { @@ -428,4 +431,4 @@ impl ContextNode { ) -> Result, GraphError> { todo!() } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 3afd79de..2098ea69 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -1,4 +1,7 @@ -use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, Edge, nodes::{StructNode, FunctionNode, VarNode}}; +use crate::{ + nodes::{FunctionNode, StructNode, VarNode}, + AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, +}; use shared::{NodeIdx, Search}; use petgraph::{visit::EdgeRef, Direction}; @@ -27,7 +30,10 @@ impl AsDotStr for ContractNode { impl ContractNode { /// Gets the underlying node data for the [`Contract`] - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Contract, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Contract, GraphError> { match analyzer.node(*self) { Node::Contract(contract) => Ok(contract), e => Err(GraphError::NodeConfusion(format!( @@ -45,7 +51,11 @@ impl ContractNode { .collect() } - pub fn inherit(&self, inherits: Vec, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) { + pub fn inherit( + &self, + inherits: Vec, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ) { let src = self.associated_source(analyzer); let all_contracts = analyzer.search_children_include_via( src, diff --git a/crates/graph/src/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs index 6ca7041d..869547cb 100644 --- a/crates/graph/src/nodes/enum_ty.rs +++ b/crates/graph/src/nodes/enum_ty.rs @@ -1,4 +1,4 @@ -use crate::{AsDotStr, GraphBackend, SolcRange, GraphError, Node, nodes::Concrete}; +use crate::{nodes::Concrete, AsDotStr, GraphBackend, GraphError, Node, SolcRange}; use shared::NodeIdx; diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index efbae343..a25e3f1a 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -1,4 +1,8 @@ -use crate::{AnalyzerBackend, GraphBackend, AsDotStr, SolcRange, Edge, VarType, GraphError, Node, ContextEdge, nodes::{ContextNode, ContractNode}}; +use crate::{ + nodes::{ContextNode, ContractNode}, + AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, SolcRange, + VarType, +}; use shared::{NodeIdx, Search}; @@ -6,9 +10,8 @@ use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ helpers::CodeLocation, pt::{ - ParameterList, Statement, Type, VariableDefinition, - Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, - Loc, Parameter, StorageLocation, Visibility, + Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, + Parameter, ParameterList, Statement, StorageLocation, Type, VariableDefinition, Visibility, }, }; use std::collections::BTreeMap; @@ -16,7 +19,10 @@ use std::collections::BTreeMap; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct FunctionNode(pub usize); impl FunctionNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Function, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Function, GraphError> { match analyzer.node(*self) { Node::Function(func) => Ok(func), e => Err(GraphError::NodeConfusion(format!( @@ -39,7 +45,10 @@ impl FunctionNode { } /// Gets an ordered list of modifiers for a given function - pub fn modifiers(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> Vec { + pub fn modifiers( + &self, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ) -> Vec { if let Some(mods) = &self.underlying(analyzer).unwrap().cache.modifiers { mods.values().copied().collect() } else { @@ -249,7 +258,10 @@ impl FunctionNode { } } - pub fn associated_source(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> NodeIdx { + pub fn associated_source( + &self, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ) -> NodeIdx { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { src } else { diff --git a/crates/graph/src/nodes/mod.rs b/crates/graph/src/nodes/mod.rs index 1f47295b..d4a53246 100644 --- a/crates/graph/src/nodes/mod.rs +++ b/crates/graph/src/nodes/mod.rs @@ -32,4 +32,4 @@ mod builtin; pub use builtin::*; mod context; -pub use context::*; \ No newline at end of file +pub use context::*; diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index de4e0600..4e1966a8 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -1,8 +1,11 @@ -use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, nodes::{Concrete, Builtin, ContextNode, ContextVar}}; +use crate::{ + nodes::{Builtin, Concrete, ContextNode, ContextVar}, + AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, +}; use shared::NodeIdx; -use ethers_core::types::{U256, Address}; +use ethers_core::types::{Address, U256}; use solang_parser::pt::Loc; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index f7fbdf64..2d4409bc 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -1,4 +1,4 @@ -use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, Edge, VarType}; +use crate::{AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, VarType}; use shared::NodeIdx; @@ -9,7 +9,10 @@ use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableD pub struct StructNode(pub usize); impl StructNode { - pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Struct, GraphError> { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Struct, GraphError> { match analyzer.node(*self) { Node::Struct(st) => Ok(st), e => Err(GraphError::NodeConfusion(format!( @@ -42,7 +45,11 @@ impl StructNode { fields } - pub fn find_field(&self, analyzer: &impl GraphBackend, ident: &Identifier) -> Option { + pub fn find_field( + &self, + analyzer: &impl GraphBackend, + ident: &Identifier, + ) -> Option { analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 9c985e2a..794b595d 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,4 +1,7 @@ -use crate::{AsDotStr, AnalyzerBackend, GraphBackend, Node, Edge, VarType, ContextEdge, nodes::{ContextVar, ContractNode, ContextVarNode}, GraphError}; +use crate::{ + nodes::{ContextVar, ContextVarNode, ContractNode}, + AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, +}; use shared::{NodeIdx, Search}; @@ -75,7 +78,10 @@ impl VarNode { .map(ContractNode::from) } - pub fn maybe_associated_source_unit_part(&self, analyzer: &impl GraphBackend) -> Option { + pub fn maybe_associated_source_unit_part( + &self, + analyzer: &impl GraphBackend, + ) -> Option { if let Some(con) = self.maybe_associated_contract(analyzer) { Some(con.associated_source_unit_part(analyzer)) } else { @@ -95,7 +101,10 @@ impl VarNode { } } - pub fn maybe_associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> Option { + pub fn maybe_associated_source( + &self, + analyzer: &(impl GraphBackend + Search), + ) -> Option { let sup = self.maybe_associated_source_unit_part(analyzer)?; analyzer.search_for_ancestor(sup, &Edge::Part) } diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index d86a85e4..37e3c6ff 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,6 +1,7 @@ use crate::{ - GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, - range::elem::{RangeElem, RangeOp, Elem} + nodes::{Concrete, ContextVarNode}, + range::elem::{Elem, RangeElem, RangeOp}, + GraphBackend, GraphError, }; use shared::NodeIdx; @@ -152,4 +153,4 @@ impl RangeElem for RangeConcrete { ) -> Result { Ok(false) } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 5b7015ef..03f8e358 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,9 +1,9 @@ -use solang_parser::pt::Loc; use crate::{ - GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, - range::elem::{RangeElem, RangeOp, Reference, RangeDyn, RangeConcrete, RangeExpr}, + range::elem::{RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference}, + GraphBackend, GraphError, }; +use solang_parser::pt::Loc; use shared::NodeIdx; @@ -11,18 +11,7 @@ use ethers_core::types::I256; use std::{ collections::BTreeMap, - ops::{ - Add, - Sub, - Mul, - Div, - Shl, - Shr, - Rem, - BitAnd, - BitOr, - BitXor, - } + ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}, }; /// A core range element. @@ -592,4 +581,4 @@ impl Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index e7139743..966b0a36 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -1,4 +1,8 @@ -use crate::{GraphBackend, nodes::ContextVarNode, range::elem::{RangeExpr, RangeOp, Elem}}; +use crate::{ + nodes::ContextVarNode, + range::elem::{Elem, RangeExpr, RangeOp}, + GraphBackend, +}; use shared::NodeIdx; @@ -7,7 +11,11 @@ use std::collections::BTreeMap; pub trait RangeElem { type GraphError; /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables - fn flatten(&self, maximize: bool, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value fn maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Maximizes the element and caches the result for quicker use later @@ -67,4 +75,4 @@ pub trait RangeElem { op_set: &[RangeOp], analyzer: &impl GraphBackend, ) -> Result; -} \ No newline at end of file +} diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index d71d626d..0418bb19 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -1,14 +1,17 @@ use crate::{ - GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, - range::{elem::{RangeElem, RangeOp, Elem, MinMaxed}, exec_traits::*} + nodes::{Concrete, ContextVarNode}, + range::{ + elem::{Elem, MinMaxed, RangeElem, RangeOp}, + exec_traits::*, + }, + GraphBackend, GraphError, }; -use shared::{NodeIdx}; use ethers_core::types::U256; +use shared::NodeIdx; use std::collections::BTreeMap; - pub static SINGLETON_EQ_OPS: &[RangeOp] = &[ RangeOp::Eq, RangeOp::Neq, @@ -31,7 +34,6 @@ pub static EQ_OPS: &[RangeOp] = &[ pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; - /// A range expression composed of other range [`Elem`] #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeExpr { @@ -203,7 +205,6 @@ impl RangeElem for RangeExpr { } } - enum MaybeCollapsed { Collapsed(Elem), Not(Elem, Elem), @@ -574,4 +575,4 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed }, _ => MaybeCollapsed::Not(l, r), } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index cbacbf12..66a7b028 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -1,4 +1,8 @@ -use crate::{GraphBackend, GraphError, nodes::{ContextVarNode, Concrete}, range::elem::{RangeElem, RangeOp, MinMaxed, Elem}}; +use crate::{ + nodes::{Concrete, ContextVarNode}, + range::elem::{Elem, MinMaxed, RangeElem, RangeOp}, + GraphBackend, GraphError, +}; use shared::NodeIdx; @@ -33,11 +37,9 @@ impl RangeDyn { } } - - impl RangeElem for RangeDyn { type GraphError = GraphError; - + fn range_eq(&self, _other: &Self) -> bool { false } diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index 06a596e3..1fe3a99d 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -1,17 +1,16 @@ mod concrete; mod elem_enum; +mod elem_trait; mod expr; mod map_or_array; mod reference; -mod elem_trait; pub use concrete::*; pub use elem_enum::*; +pub use elem_trait::*; pub use expr::*; pub use map_or_array::*; pub use reference::*; -pub use elem_trait::*; - #[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum MinMaxed { diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 88131d37..57065f78 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -1,4 +1,11 @@ -use crate::{GraphBackend, GraphError, nodes::{ContextVarNode, Concrete}, TypeNode, VarType, range::{Range, elem::{RangeElem, RangeConcrete, RangeOp, MinMaxed, Elem}}}; +use crate::{ + nodes::{Concrete, ContextVarNode}, + range::{ + elem::{Elem, MinMaxed, RangeConcrete, RangeElem, RangeOp}, + Range, + }, + GraphBackend, GraphError, TypeNode, VarType, +}; use shared::NodeIdx; @@ -207,4 +214,4 @@ impl RangeElem for Reference { _e => Ok(false), } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/add.rs b/crates/graph/src/range/exec/add.rs index 571d4788..0e1bc7b3 100644 --- a/crates/graph/src/range/exec/add.rs +++ b/crates/graph/src/range/exec/add.rs @@ -108,4 +108,4 @@ impl RangeAdd for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs index e437439b..97010932 100644 --- a/crates/graph/src/range/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -163,4 +163,4 @@ impl RangeBitwise for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/cast.rs b/crates/graph/src/range/exec/cast.rs index e5da78ed..dbbdd5e6 100644 --- a/crates/graph/src/range/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -255,4 +255,4 @@ impl RangeCast for Elem { _e => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/concat.rs b/crates/graph/src/range/exec/concat.rs index 75e26c5f..aa3ffb2f 100644 --- a/crates/graph/src/range/exec/concat.rs +++ b/crates/graph/src/range/exec/concat.rs @@ -146,4 +146,4 @@ impl RangeConcat for Elem { _e => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/div.rs b/crates/graph/src/range/exec/div.rs index 11c3f32c..62476206 100644 --- a/crates/graph/src/range/exec/div.rs +++ b/crates/graph/src/range/exec/div.rs @@ -143,4 +143,4 @@ impl RangeDiv for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index ea50e212..e255aeb2 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -1,8 +1,12 @@ -use crate::{GraphBackend, GraphError, nodes::Concrete, range::{elem::*, exec_traits::*}}; +use crate::{ + nodes::Concrete, + range::{elem::*, exec_traits::*}, + GraphBackend, GraphError, +}; use shared::NodeIdx; -use ethers_core::types::{ I256, U256 }; +use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; impl ExecOp for RangeExpr { diff --git a/crates/graph/src/range/exec/exp.rs b/crates/graph/src/range/exec/exp.rs index 70cb4dd9..97462da5 100644 --- a/crates/graph/src/range/exec/exp.rs +++ b/crates/graph/src/range/exec/exp.rs @@ -82,4 +82,4 @@ impl RangeExp for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/logical.rs b/crates/graph/src/range/exec/logical.rs index 93befcd9..5d3c6129 100644 --- a/crates/graph/src/range/exec/logical.rs +++ b/crates/graph/src/range/exec/logical.rs @@ -52,4 +52,4 @@ impl RangeUnary for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/max.rs b/crates/graph/src/range/exec/max.rs index 646f7b2d..c32eb45e 100644 --- a/crates/graph/src/range/exec/max.rs +++ b/crates/graph/src/range/exec/max.rs @@ -40,4 +40,4 @@ impl RangeMax for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/min.rs b/crates/graph/src/range/exec/min.rs index 761b34d5..338ed35a 100644 --- a/crates/graph/src/range/exec/min.rs +++ b/crates/graph/src/range/exec/min.rs @@ -40,4 +40,4 @@ impl RangeMin for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/mod.rs b/crates/graph/src/range/exec/mod.rs index 9efed125..4946baed 100644 --- a/crates/graph/src/range/exec/mod.rs +++ b/crates/graph/src/range/exec/mod.rs @@ -3,8 +3,8 @@ mod bitwise; mod cast; mod concat; mod div; -mod exp; mod exec_op; +mod exp; mod logical; mod max; mod min; diff --git a/crates/graph/src/range/exec/modulo.rs b/crates/graph/src/range/exec/modulo.rs index a021a8ac..66db9b60 100644 --- a/crates/graph/src/range/exec/modulo.rs +++ b/crates/graph/src/range/exec/modulo.rs @@ -1,7 +1,7 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; -use ethers_core::types::{I256}; +use ethers_core::types::I256; impl RangeMod for RangeConcrete { fn range_mod(&self, other: &Self) -> Option> { diff --git a/crates/graph/src/range/exec/mul.rs b/crates/graph/src/range/exec/mul.rs index a671ee9e..63940124 100644 --- a/crates/graph/src/range/exec/mul.rs +++ b/crates/graph/src/range/exec/mul.rs @@ -3,8 +3,6 @@ use crate::range::{elem::*, exec_traits::*}; use ethers_core::types::{I256, U256}; - - impl RangeMul for RangeConcrete { fn range_mul(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { @@ -110,4 +108,4 @@ impl RangeMul for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/ord.rs b/crates/graph/src/range/exec/ord.rs index 04364730..4e867e25 100644 --- a/crates/graph/src/range/exec/ord.rs +++ b/crates/graph/src/range/exec/ord.rs @@ -1,8 +1,6 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; - - impl RangeOrd for RangeConcrete { fn range_ord_eq(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { @@ -215,4 +213,4 @@ impl RangeOrd for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/shift.rs b/crates/graph/src/range/exec/shift.rs index f33e473e..cf68f6fc 100644 --- a/crates/graph/src/range/exec/shift.rs +++ b/crates/graph/src/range/exec/shift.rs @@ -160,4 +160,4 @@ impl RangeShift for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/sub.rs b/crates/graph/src/range/exec/sub.rs index 1a32dd4d..dfe80219 100644 --- a/crates/graph/src/range/exec/sub.rs +++ b/crates/graph/src/range/exec/sub.rs @@ -146,4 +146,4 @@ impl RangeSub for Elem { _ => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index 3fdc67ce..d970a133 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,14 +1,16 @@ -use crate::{GraphBackend, range::elem::Elem}; +use crate::{range::elem::Elem, GraphBackend}; use shared::NodeIdx; - - /// For execution of operations to be performed on range expressions pub trait ExecOp { type GraphError; /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side /// and right-hand-side - fn exec_op(&self, maximize: bool, analyzer: &impl GraphBackend) -> Result, Self::GraphError> { + fn exec_op( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError> { self.exec(self.spread(analyzer)?, maximize) } diff --git a/crates/graph/src/range/mod.rs b/crates/graph/src/range/mod.rs index 54932657..f61240b9 100644 --- a/crates/graph/src/range/mod.rs +++ b/crates/graph/src/range/mod.rs @@ -1,11 +1,9 @@ -pub mod exec_traits; pub mod elem; pub mod exec; +pub mod exec_traits; pub mod range_string; mod range_trait; mod solc_range; pub use range_trait::*; pub use solc_range::*; - - diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index d9941996..b50444f9 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -1,7 +1,7 @@ use crate::{ - GraphBackend, nodes::{Concrete, ContextVarNode}, range::elem::*, + GraphBackend, }; use solang_parser::pt::Loc; use std::collections::BTreeMap; @@ -42,7 +42,6 @@ pub trait ToRangeString { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString; } - impl ToRangeString for Elem { fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { match self { diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index f4314b9d..c24b2de2 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -1,15 +1,21 @@ -use crate::{GraphBackend, range::elem::RangeElem}; +use crate::{range::elem::RangeElem, GraphBackend}; use shared::NodeIdx; pub trait Range { - type GraphError; + type GraphError; type ElemTy: RangeElem + Clone; /// Evaluate both the minimum and the maximum - cache along the way fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Evaluate the range minimum - fn evaled_range_min(&self, analyzer: &impl GraphBackend) -> Result; + fn evaled_range_min( + &self, + analyzer: &impl GraphBackend, + ) -> Result; /// Evaluate the range maximum - fn evaled_range_max(&self, analyzer: &impl GraphBackend) -> Result; + fn evaled_range_max( + &self, + analyzer: &impl GraphBackend, + ) -> Result; /// Simplify the minimum, leaving references in place fn simplified_range_min( &self, @@ -42,7 +48,7 @@ pub trait Range { fn range_exclusions(&self) -> Vec where Self: std::marker::Sized; - /// Set the range minimum + /// Set the range minimum fn set_range_min(&mut self, new: Self::ElemTy); /// Set the range maximum fn set_range_max(&mut self, new: Self::ElemTy); @@ -68,4 +74,4 @@ pub trait RangeEval>: Range { fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; fn contains_elem(&self, other: &T, analyzer: &impl GraphBackend) -> bool; fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; -} \ No newline at end of file +} diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index ea499259..83593952 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -1,7 +1,7 @@ use crate::{ + nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, + range::{elem::*, range_string::*, Range, RangeEval}, AsDotStr, GraphBackend, GraphError, - nodes::{ContextVarNode, ContextNode, Builtin, Concrete}, - range::{RangeEval, Range, elem::*, range_string::*} }; use shared::NodeIdx; @@ -68,7 +68,12 @@ impl SolcRange { } /// Update a particular context variable with the latest version - pub fn update_deps(&mut self, node: ContextVarNode, ctx: ContextNode, analyzer: &impl GraphBackend) { + pub fn update_deps( + &mut self, + node: ContextVarNode, + ctx: ContextNode, + analyzer: &impl GraphBackend, + ) { let deps = self.dependent_on(); let mapping: BTreeMap = deps .into_iter() @@ -734,4 +739,4 @@ impl RangeEval> for SolcRange { _ => false, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index a0d70a08..c91259bf 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -1,20 +1,12 @@ use crate::{ - GraphBackend, nodes::{Concrete, ContextVarNode}, range::{ - elem::{ - RangeElem, - RangeOp, - Elem, - RangeExpr, - Reference - }, - range_string::{ToRangeString, RangeElemString}, + elem::{Elem, RangeElem, RangeExpr, RangeOp, Reference}, + range_string::{RangeElemString, ToRangeString}, }, + GraphBackend, }; - - use ethers_core::types::U256; use std::collections::BTreeMap; @@ -270,7 +262,10 @@ impl Atomize for Elem { }; AtomOrPart::Atom(atom) } - (Elem::Reference(Reference { .. }), Elem::Reference(Reference { .. })) => { + ( + Elem::Reference(Reference { .. }), + Elem::Reference(Reference { .. }), + ) => { let ty = if DL_OPS.contains(&expr.op) { OpType::DL } else if CONST_OPS.contains(&expr.op) { @@ -329,7 +324,7 @@ impl Atomize for Elem { use Elem::*; match self { - Reference(_) => None, //{ println!("was dyn"); None}, + Reference(_) => None, //{ println!("was dyn"); None}, Null => None, //{ println!("was null"); None}, Concrete(_c) => None, //{ println!("was conc: {}", c.val.as_human_string()); None }, ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 38057178..01ea3f71 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -1,9 +1,11 @@ use crate::{ - GraphBackend, AnalyzerBackend, GraphError, - SolcRange, Range, RangeEval, - elem::{RangeElem, Elem}, - nodes::{ContextVarNode, Concrete, VarNode}, - solvers::{dl::{SolveStatus, DLSolver}, Atomize, SolverAtom}, + elem::{Elem, RangeElem}, + nodes::{Concrete, ContextVarNode, VarNode}, + solvers::{ + dl::{DLSolver, SolveStatus}, + Atomize, SolverAtom, + }, + AnalyzerBackend, GraphBackend, GraphError, Range, RangeEval, SolcRange, }; use ethers_core::types::U256; @@ -861,4 +863,4 @@ impl SolcSolver for BruteBinSearchSolver { analyzer, ) } -} \ No newline at end of file +} diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 83828341..be29164f 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -1,23 +1,17 @@ use crate::{ - GraphBackend, GraphError, nodes::{Concrete, ContextVarNode}, range::elem::*, solvers::{AtomOrPart, Atomize, OpType, SolverAtom}, + GraphBackend, GraphError, }; -use ethers_core::types::{U256, I256}; +use ethers_core::types::{I256, U256}; use itertools::Itertools; use petgraph::{ - stable_graph::StableGraph, graph::NodeIndex, - visit::{ - EdgeRef, - IntoNodeIdentifiers, - NodeIndexable, - VisitMap, - Visitable, - }, - Directed + stable_graph::StableGraph, + visit::{EdgeRef, IntoNodeIdentifiers, NodeIndexable, VisitMap, Visitable}, + Directed, }; use std::collections::BTreeMap; @@ -203,7 +197,10 @@ impl DLSolver { self.normalized_constraints.values().cloned().collect() } - pub fn solve_partial(&mut self, analyzer: &impl GraphBackend) -> Result { + pub fn solve_partial( + &mut self, + analyzer: &impl GraphBackend, + ) -> Result { let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { let deps = constraint.dependent_on(); @@ -940,4 +937,4 @@ fn bellman_ford_initialize_relax( } } (distance, predecessor) -} \ No newline at end of file +} diff --git a/crates/graph/src/solvers/mod.rs b/crates/graph/src/solvers/mod.rs index a233e5ad..9711d3e3 100644 --- a/crates/graph/src/solvers/mod.rs +++ b/crates/graph/src/solvers/mod.rs @@ -1,6 +1,6 @@ -pub mod dl; mod atoms; mod brute; +pub mod dl; -pub use brute::*; pub use atoms::*; +pub use brute::*; diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index 2b59199c..dcbc1b61 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -1,16 +1,18 @@ use crate::{ - AnalyzerBackend, GraphBackend, AsDotStr, - range::{elem::{Elem, Reference, RangeElem}, Range, SolcRange}, - GraphError, Node, nodes::{ - ContextVarNode, FunctionNode, TyNode, BuiltInNode, - ConcreteNode, Builtin, Concrete, StructNode, EnumNode, ContractNode - } + BuiltInNode, Builtin, Concrete, ConcreteNode, ContextVarNode, ContractNode, EnumNode, + FunctionNode, StructNode, TyNode, + }, + range::{ + elem::{Elem, RangeElem, Reference}, + Range, SolcRange, + }, + AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; -use ethers_core::types::{Address, U256, H256}; +use ethers_core::types::{Address, H256, U256}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum VarType { @@ -496,8 +498,9 @@ impl VarType { let Concrete::Bytes(_, val) = min.val else { return Ok(None); }; - let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() else { - return Ok(None) + let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() + else { + return Ok(None); }; let Concrete::Uint(_, idx) = idx.val else { return Ok(None); @@ -642,7 +645,10 @@ impl VarType { } } - pub fn maybe_array_size(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn maybe_array_size( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match self { Self::BuiltIn(node, _) => node.maybe_array_size(analyzer), Self::Concrete(node) => node.maybe_array_size(analyzer), diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 95388ab7..b3b5b4b7 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -1,24 +1,28 @@ use crate::builtin_fns; use analyzers::LocStrSpan; -use solc_expressions::{ContextBuilder,IntoExprErr, ExprErr}; -use graph::{Edge, Node, nodes::*, VarType, ContextEdge}; -use shared::{Search, GraphLike, AnalyzerLike, NodeIdx}; +use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; +use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; +use solc_expressions::{ContextBuilder, ExprErr, IntoExprErr}; +use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; +use petgraph::{graph::*, Directed}; +use serde_json::Value; use solang_parser::{ diagnostics::Diagnostic, helpers::CodeLocation, pt::{ ContractDefinition, ContractPart, EnumDefinition, ErrorDefinition, Expression, - FunctionDefinition, FunctionTy, SourceUnit, SourceUnitPart, StructDefinition, TypeDefinition, - Using, UsingList, VariableDefinition, Identifier, Import, - } + FunctionDefinition, FunctionTy, Identifier, Import, SourceUnit, SourceUnitPart, + StructDefinition, TypeDefinition, Using, UsingList, VariableDefinition, + }, }; -use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Span, Source}; -use petgraph::{graph::*, Directed}; -use serde_json::Value; -use std::{path::{PathBuf, Path}, collections::{BTreeMap, HashMap}, fs}; +use std::{ + collections::{BTreeMap, HashMap}, + fs, + path::{Path, PathBuf}, +}; /// A path to either a single solidity file or a Solc Standard JSON file #[derive(Debug, Clone)] diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 610b44ec..3c7fcf4f 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -1,30 +1,22 @@ use crate::Analyzer; use graph::{ - AnalyzerBackend, Node, Edge, VarType, - nodes::{ - Concrete, - FunctionParamNode, - ConcreteNode, - MsgNode, - BlockNode, - FunctionParam, - FunctionReturn, - Builtin, - Function, - } + nodes::{ + BlockNode, Builtin, Concrete, ConcreteNode, Function, FunctionParam, FunctionParamNode, + FunctionReturn, MsgNode, + }, + AnalyzerBackend, Edge, Node, VarType, }; -use shared::{AnalyzerLike, NodeIdx, GraphLike}; -use solc_expressions::{IntoExprErr, ExprErr}; +use shared::{AnalyzerLike, GraphLike, NodeIdx}; +use solc_expressions::{ExprErr, IntoExprErr}; use ethers_core::types::U256; -use solang_parser::{pt::Expression, helpers::CodeLocation}; +use solang_parser::{helpers::CodeLocation, pt::Expression}; use std::collections::HashMap; impl AnalyzerBackend for Analyzer {} - impl AnalyzerLike for Analyzer { type Expr = Expression; type ExprErr = ExprErr; @@ -36,7 +28,6 @@ impl AnalyzerLike for Analyzer { type FunctionReturn = FunctionReturn; type Builtin = Builtin; - fn builtin_fn_nodes(&self) -> &HashMap { &self.builtin_fn_nodes } @@ -232,4 +223,4 @@ impl AnalyzerLike for Analyzer { None } } -} \ No newline at end of file +} diff --git a/crates/pyrometer/src/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs index 83175f73..d996a30f 100644 --- a/crates/pyrometer/src/builtin_fns.rs +++ b/crates/pyrometer/src/builtin_fns.rs @@ -1,6 +1,4 @@ -use graph::nodes::{ - Builtin, Function, FunctionParam, FunctionReturn -}; +use graph::nodes::{Builtin, Function, FunctionParam, FunctionReturn}; use shared::{AnalyzerLike, GraphLike}; use solang_parser::pt::{FunctionAttribute, Identifier, Loc, StorageLocation, Visibility}; diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 588368eb..d47b89e1 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,26 +1,21 @@ use crate::Analyzer; -use shared::{GraphDot, NodeIdx, GraphLike, Search}; use graph::{ - ContextEdge, AnalyzerBackend, as_dot_str, AsDotStr, GraphBackend, Node, Edge, - nodes::ContextNode, + as_dot_str, nodes::ContextNode, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, + Node, }; +use shared::{GraphDot, GraphLike, NodeIdx, Search}; -use petgraph::{ - Direction, Graph, Directed, - graph::EdgeIndex, - dot::Dot, - visit::EdgeRef, -}; +use petgraph::{dot::Dot, graph::EdgeIndex, visit::EdgeRef, Directed, Direction, Graph}; use std::{ collections::BTreeSet, - sync::{Mutex, Arc}, + sync::{Arc, Mutex}, }; impl GraphLike for Analyzer { - type Node = Node; - type Edge = Edge; + type Node = Node; + type Edge = Edge; fn graph_mut(&mut self) -> &mut Graph { &mut self.graph } @@ -557,8 +552,6 @@ flowchart BT dot_str.push(edges_str); dot_str.join("\n") } - - } struct G<'a> { @@ -608,4 +601,4 @@ pub fn mermaid_node( } node_str -} \ No newline at end of file +} diff --git a/crates/pyrometer/src/lib.rs b/crates/pyrometer/src/lib.rs index 99454bef..bedfe8d6 100644 --- a/crates/pyrometer/src/lib.rs +++ b/crates/pyrometer/src/lib.rs @@ -1,8 +1,6 @@ mod analyzer; -mod builtin_fns; mod analyzer_backend; +mod builtin_fns; mod graph_backend; pub use analyzer::*; - - diff --git a/crates/pyrometer/tests/helpers.rs b/crates/pyrometer/tests/helpers.rs index 1d159513..75c8a1f0 100644 --- a/crates/pyrometer/tests/helpers.rs +++ b/crates/pyrometer/tests/helpers.rs @@ -1,11 +1,11 @@ +use analyzers::FunctionVarsBoundAnalyzer; use analyzers::ReportConfig; use analyzers::ReportDisplay; -use analyzers::FunctionVarsBoundAnalyzer; -use shared::Search; use ariadne::sources; +use graph::{nodes::FunctionNode, Edge}; use pyrometer::{Analyzer, SourcePath}; use shared::NodeIdx; -use graph::{nodes::FunctionNode, Edge}; +use shared::Search; use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; diff --git a/crates/queries/src/lib.rs b/crates/queries/src/lib.rs index 3ac5e78c..325bbed8 100644 --- a/crates/queries/src/lib.rs +++ b/crates/queries/src/lib.rs @@ -1 +1 @@ -//! Currently Empty \ No newline at end of file +//! Currently Empty diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 028cd523..9d323e7e 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -22,8 +22,6 @@ pub trait AnalyzerLike: GraphLike { /// Type of a builtin type Builtin; - - /// Gets the builtin functions map fn builtin_fns(&self) -> &HashMap; /// Mutably gets the builtin functions map @@ -43,10 +41,12 @@ pub trait AnalyzerLike: GraphLike { fn add_expr_err(&mut self, err: Self::ExprErr); fn expr_errs(&self) -> Vec; - fn builtin_fn_inputs(&self) -> &HashMap, Vec)>; + fn builtin_fn_inputs( + &self, + ) -> &HashMap, Vec)>; fn builtins(&self) -> &HashMap; fn builtins_mut(&mut self) -> &mut HashMap; - + fn builtin_or_add(&mut self, builtin: Self::Builtin) -> NodeIdx; // { // if let Some(idx) = self.builtins().get(&builtin) { @@ -91,7 +91,6 @@ pub trait AnalyzerLike: GraphLike { // } // } - fn add_if_err(&mut self, err: Result) -> Option { match err { Ok(t) => Some(t), @@ -101,4 +100,4 @@ pub trait AnalyzerLike: GraphLike { } } } -} \ No newline at end of file +} diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 10015bab..5d6f2972 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,15 +1,14 @@ -use crate::Heirarchical; use crate::AnalyzerLike; +use crate::Heirarchical; -use std::{ - sync::{Arc, Mutex}, - collections::BTreeSet -}; use petgraph::{ + graph::{EdgeIndex, Graph, NodeIndex}, Directed, - graph::{Graph, EdgeIndex, NodeIndex} }; - +use std::{ + collections::BTreeSet, + sync::{Arc, Mutex}, +}; pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; @@ -53,10 +52,10 @@ pub trait GraphLike { /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphDot: GraphLike { /// Open a dot using graphviz - fn open_dot(&self) + fn open_dot(&self) where Self: std::marker::Sized, - Self: AnalyzerLike + Self: AnalyzerLike, { use std::env::temp_dir; use std::fs; @@ -83,7 +82,7 @@ pub trait GraphDot: GraphLike { .expect("failed to execute process"); } - /// Creates a subgraph for visually identifying contexts and subcontexts + /// Creates a subgraph for visually identifying contexts and subcontexts fn cluster_str( &self, node: NodeIdx, @@ -113,4 +112,4 @@ pub trait GraphDot: GraphLike { where Self: std::marker::Sized, Self: AnalyzerLike; -} \ No newline at end of file +} diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 5391d213..88f88d06 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -1,7 +1,7 @@ -mod graph_like; mod analyzer_like; +mod graph_like; mod search; -pub use search::*; +pub use analyzer_like::*; pub use graph_like::*; -pub use analyzer_like::*; \ No newline at end of file +pub use search::*; diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs index fd5757e4..c048f7a4 100644 --- a/crates/shared/src/search.rs +++ b/crates/shared/src/search.rs @@ -1,18 +1,28 @@ -use std::collections::{BTreeSet, BTreeMap}; +use std::collections::{BTreeMap, BTreeSet}; -use crate::{NodeIdx, GraphLike}; -use petgraph::{visit::EdgeRef, graph::*, Direction}; +use crate::{GraphLike, NodeIdx}; +use petgraph::{graph::*, visit::EdgeRef, Direction}; pub trait Heirarchical { fn heirarchical_num(&self) -> usize; } -impl Search for T where T: GraphLike, ::Edge: Ord + PartialEq + Heirarchical + Copy {} +impl Search for T +where + T: GraphLike, + ::Edge: Ord + PartialEq + Heirarchical + Copy, +{ +} /// A trait for searching through a graph pub trait Search: GraphLike - where ::Edge: PartialEq + Heirarchical + Copy +where + ::Edge: PartialEq + Heirarchical + Copy, { - fn search_for_ancestor(&self, start: NodeIdx, edge_ty: &::Edge) -> Option { + fn search_for_ancestor( + &self, + start: NodeIdx, + edge_ty: &::Edge, + ) -> Option { tracing::trace!("searching for ancestor"); let edges = self.graph().edges_directed(start, Direction::Outgoing); if let Some(edge) = edges.clone().find(|edge| edge.weight() == edge_ty) { @@ -26,7 +36,11 @@ pub trait Search: GraphLike } } - fn search_for_ancestor_multi(&self, start: NodeIdx, edge_tys: &[::Edge]) -> Option { + fn search_for_ancestor_multi( + &self, + start: NodeIdx, + edge_tys: &[::Edge], + ) -> Option { tracing::trace!("searching for ancestor_multi"); let edges = self.graph().edges_directed(start, Direction::Outgoing); if let Some(edge) = edges.clone().find(|edge| edge_tys.contains(edge.weight())) { @@ -40,7 +54,11 @@ pub trait Search: GraphLike } } - fn search_children_same_heirarchy(&self, start: NodeIdx, edge_ty: &::Edge) -> BTreeSet { + fn search_children_same_heirarchy( + &self, + start: NodeIdx, + edge_ty: &::Edge, + ) -> BTreeSet { tracing::trace!("search_children_same_heirarchy"); let num = edge_ty.heirarchical_num(); let edges = self @@ -71,7 +89,11 @@ pub trait Search: GraphLike /// i.e.: a -my_edge-> b -other_edge-> c -my_edge-> d /// /// This function would build a set { b, d } if we are looking for `my_edge` and start at a. - fn search_children(&self, start: NodeIdx, edge_ty: &::Edge) -> BTreeSet { + fn search_children( + &self, + start: NodeIdx, + edge_ty: &::Edge, + ) -> BTreeSet { tracing::trace!("search_children"); let mut seen = Default::default(); self.search_children_prevent_cycle(start, edge_ty, &mut seen) @@ -428,7 +450,15 @@ pub trait Search: GraphLike fn edges_for_nodes( &self, nodes: &BTreeSet, - ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + ) -> BTreeSet<( + NodeIdx, + NodeIdx, + ::Edge, + EdgeIndex, + )> + where + ::Edge: Ord, + { tracing::trace!("children_edges"); nodes @@ -437,7 +467,12 @@ pub trait Search: GraphLike self.graph() .edges_directed(*node, Direction::Incoming) .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) - .collect::::Edge, EdgeIndex)>>() + .collect::::Edge, + EdgeIndex, + )>>() }) .collect() } @@ -446,7 +481,15 @@ pub trait Search: GraphLike fn children_edges( &self, start: NodeIdx, - ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + ) -> BTreeSet<( + NodeIdx, + NodeIdx, + ::Edge, + EdgeIndex, + )> + where + ::Edge: Ord, + { tracing::trace!("children_edges"); let mut seen = Default::default(); self.children_edges_prevent_cycle(start, &mut seen) @@ -456,7 +499,15 @@ pub trait Search: GraphLike &self, start: NodeIdx, seen: &mut BTreeSet, - ) -> BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> where ::Edge: Ord { + ) -> BTreeSet<( + NodeIdx, + NodeIdx, + ::Edge, + EdgeIndex, + )> + where + ::Edge: Ord, + { if seen.contains(&start) { return Default::default(); } else { @@ -464,7 +515,12 @@ pub trait Search: GraphLike } let edges = self.graph().edges_directed(start, Direction::Incoming); - let mut this_children_edges: BTreeSet<(NodeIdx, NodeIdx, ::Edge, EdgeIndex)> = edges + let mut this_children_edges: BTreeSet<( + NodeIdx, + NodeIdx, + ::Edge, + EdgeIndex, + )> = edges .clone() .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) .collect(); @@ -472,7 +528,12 @@ pub trait Search: GraphLike this_children_edges.extend( edges .flat_map(|edge| self.children_edges_prevent_cycle(edge.source(), seen)) - .collect::::Edge, EdgeIndex)>>(), + .collect::::Edge, + EdgeIndex, + )>>(), ); this_children_edges } @@ -534,4 +595,4 @@ pub trait Search: GraphLike Some(map) } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 9d51681f..a870b1e5 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,12 +1,9 @@ -use crate::{ - ContextBuilder, IntoExprErr, - ExprErr, member_access::MemberAccess, require::Require, -}; +use crate::{member_access::MemberAccess, require::Require, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{Builtin, ContextVar, ContextVarNode, ContextNode, ExprRet}, - elem::RangeOp + elem::RangeOp, + nodes::{Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; use solang_parser::{ diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 117b7f9c..8df465ea 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -1,9 +1,12 @@ -use crate::{ContextBuilder, IntoExprErr, ExprErr, require::Require}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{BuiltInNode, Builtin, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, KilledKind, ExprRet, }, - elem::*, Range, RangeEval, SolcRange + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, + KilledKind, TmpConstruction, + }, + AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; use ethers_core::types::{I256, U256}; @@ -302,8 +305,8 @@ pub trait BinOp: AnalyzerBackend + Sized { // }), Elem::from(Concrete::from(U256::from(1))).cast( Elem::from(Reference::new(tmp_rhs.into())), // .range_min(self) - // .into_expr_err(loc)? - // .expect("No range minimum?"), + // .into_expr_err(loc)? + // .expect("No range minimum?"), ), ); diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index b3fe62ad..a773584c 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -1,9 +1,12 @@ -use crate::{ContextBuilder, IntoExprErr, ExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Node, VarType, GraphError, - nodes::{BuiltInNode, Builtin, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, ExprRet, }, - elem::*, Range, SolcRange + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, + TmpConstruction, + }, + AnalyzerBackend, GraphError, Node, Range, SolcRange, VarType, }; use solang_parser::pt::{Expression, Loc}; diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 4b271aed..00ac50e9 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -1,15 +1,16 @@ -use crate::{ContextBuilder, IntoExprErr, ExprErr, require::Require}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, ContextEdge, - nodes::{Context, ContextNode, } + nodes::{Context, ContextNode}, + AnalyzerBackend, ContextEdge, Edge, Node, }; use shared::NodeIdx; use solang_parser::pt::CodeLocation; use solang_parser::pt::{Expression, Loc, Statement}; -impl CondOp for T where T: AnalyzerBackend + Require + Sized {} +impl CondOp for T where T: AnalyzerBackend + Require + Sized +{} pub trait CondOp: AnalyzerBackend + Require + Sized { #[tracing::instrument(level = "trace", skip_all)] fn cond_op_stmt( diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index f49d60b0..25bb1696 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1,19 +1,22 @@ use crate::{ - yul::YulBuilder, func_call::FuncCaller, loops::Looper, ExprParser, IntoExprErr, ExprErr + func_call::FuncCaller, loops::Looper, yul::YulBuilder, ExprErr, ExprParser, IntoExprErr, }; use graph::{ - GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, GraphError, - nodes::{FunctionReturnNode, FunctionParamNode, Context, KilledKind, Builtin, FunctionNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, - elem::*, Range + elem::*, + nodes::{ + Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, FunctionReturnNode, KilledKind, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, Range, VarType, }; use shared::NodeIdx; use ethers_core::types::{I256, U256}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ - pt::{VariableDeclaration, YulStatement, Expression, Loc, Statement}, - helpers::CodeLocation + helpers::CodeLocation, + pt::{Expression, Loc, Statement, VariableDeclaration, YulStatement}, }; impl ContextBuilder for T where @@ -987,7 +990,8 @@ pub trait ContextBuilder: fn delete_match( ctx: ContextNode, loc: &Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + + AnalyzerBackend), ret: ExprRet, ) { match ret { diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index ea18f207..13e82ce1 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,11 +1,11 @@ -use crate::{func_call::FuncCaller, IntoExprErr, ExprErr}; +use crate::{func_call::FuncCaller, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, ContextEdge, - nodes::{Builtin, ContextNode, ContextVar, Concrete, ExprRet, } + nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, }; -use solang_parser::pt::{Loc, Expression, Identifier}; +use solang_parser::pt::{Expression, Identifier, Loc}; impl Env for T where T: AnalyzerBackend + Sized {} pub trait Env: AnalyzerBackend + Sized { diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 443d11d4..029fce88 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,10 +1,8 @@ -use crate::{ - ContextBuilder, IntoExprErr, ExprErr, FuncCaller -}; +use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; use graph::{ - GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{Builtin, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, + nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, VarType, }; use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index d62ce87d..4f585e82 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -1,15 +1,17 @@ use crate::{ - ContextBuilder, IntoExprErr, ExprErr, FuncCaller, - require::Require, array::Array, - member_access::MemberAccess, + array::Array, member_access::MemberAccess, require::Require, ContextBuilder, ExprErr, + FuncCaller, IntoExprErr, }; use graph::{ - GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{TyNode, StructNode, BuiltInNode, Builtin, Context, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, - elem::*, Range, SolcRange + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, + StructNode, TyNode, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, SolcRange, VarType, }; -use shared::{Search, NodeIdx}; +use shared::{NodeIdx, Search}; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index bac2a516..e1d0e5e7 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,22 +1,22 @@ use crate::{ - ContextBuilder, IntoExprErr, ExprErr, - namespaced_call::NameSpaceFuncCaller, - internal_call::InternalFuncCaller, - intrinsic_call::IntrinsicFuncCaller + internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, + namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, IntoExprErr, }; use graph::{ - GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{FunctionNode, ModifierState, FunctionParamNode, FunctionReturnNode, CallFork, Context, ContextNode, ContextVarNode, ContextVar, ExprRet, }, - Range, + nodes::{ + CallFork, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, FunctionReturnNode, ModifierState, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, VarType, }; use shared::NodeIdx; -use std::cell::RefCell; -use std::rc::Rc; use solang_parser::helpers::CodeLocation; -use std::collections::BTreeMap; use solang_parser::pt::{Expression, Loc, NamedArgument, StorageLocation}; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::rc::Rc; pub mod internal_call; pub mod intrinsic_call; diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index 8a6e21f5..a6d56a05 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -1,10 +1,8 @@ -use crate::{ - IntoExprErr, ExprErr, FuncCaller -}; +use crate::{ExprErr, FuncCaller, IntoExprErr}; use graph::{ - GraphBackend, AnalyzerBackend, - nodes::{FunctionNode, ContextNode, ExprRet, } + nodes::{ContextNode, ExprRet, FunctionNode}, + AnalyzerBackend, GraphBackend, }; use solang_parser::pt::{Expression, Loc}; @@ -30,4 +28,4 @@ pub trait ModifierCaller: todo!() } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 8fa6eb7b..1086c7d9 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,13 +1,11 @@ use crate::{ - FuncCaller, - ContextBuilder, IntoExprErr, ExprErr, - member_access::MemberAccess, - intrinsic_call::IntrinsicFuncCaller + intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, + FuncCaller, IntoExprErr, }; use graph::{ + nodes::{BuiltInNode, ContextNode, ContextVarNode, ExprRet, FunctionNode}, AnalyzerBackend, GraphBackend, Node, - nodes::{BuiltInNode, FunctionNode, ContextNode, ContextVarNode, ExprRet, } }; use shared::NodeIdx; diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index 5b7d450d..5c25648a 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -20,8 +20,8 @@ pub use bin_op::*; pub use cmp::*; pub use cond_op::*; pub use context_builder::*; -pub use func_call::*; pub use env::*; +pub use func_call::*; pub use list::*; pub use literal::*; pub use loops::*; @@ -144,9 +144,7 @@ impl ExprErr { GraphError(_loc, graph::GraphError::MaxStackWidthReached(msg), ..) => msg, GraphError(_loc, graph::GraphError::ChildRedefinition(msg), ..) => msg, GraphError(_loc, graph::GraphError::DetachedVariable(msg), ..) => msg, - GraphError(_loc, graph::GraphError::VariableUpdateInOldContext(msg), ..) => { - msg - } + GraphError(_loc, graph::GraphError::VariableUpdateInOldContext(msg), ..) => msg, GraphError(_loc, graph::GraphError::ExpectedSingle(msg), ..) => msg, GraphError(_loc, graph::GraphError::StackLengthMismatch(msg), ..) => msg, GraphError(_loc, graph::GraphError::UnbreakableRecursion(msg), ..) => msg, diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 5b94b01c..c4b6b5a8 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -1,11 +1,11 @@ -use crate::{ContextBuilder, IntoExprErr, ExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{ContextNode, ContextVar, ExprRet, } + nodes::{ContextNode, ContextVar, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; -use solang_parser::pt::{Parameter, ParameterList, Loc, Expression}; +use solang_parser::pt::{Expression, Loc, Parameter, ParameterList}; impl List for T where T: AnalyzerBackend + Sized {} diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index d8c1f25f..242834ae 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -1,13 +1,13 @@ -use crate::{IntoExprErr, ExprErr}; +use crate::{ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, ContextEdge, - nodes::{Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, elem::*, + nodes::{Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, }; -use ethers_core::types::{H256, I256, U256, Address}; -use solang_parser::pt::{Identifier, HexLiteral, Loc}; +use ethers_core::types::{Address, H256, I256, U256}; +use solang_parser::pt::{HexLiteral, Identifier, Loc}; use std::str::FromStr; diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index dd64713b..c7aec51a 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -1,14 +1,19 @@ -use crate::{ContextBuilder, IntoExprErr, ExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - GraphBackend, AnalyzerBackend, Node, - nodes::{Context, ContextNode, }, + nodes::{Context, ContextNode}, + AnalyzerBackend, GraphBackend, Node, }; -use solang_parser::pt::{Loc, Expression, Statement}; +use solang_parser::pt::{Expression, Loc, Statement}; -impl Looper for T where T: AnalyzerBackend + Sized + GraphBackend {} -pub trait Looper: GraphBackend + AnalyzerBackend + Sized { +impl Looper for T where + T: AnalyzerBackend + Sized + GraphBackend +{ +} +pub trait Looper: + GraphBackend + AnalyzerBackend + Sized +{ #[tracing::instrument(level = "trace", skip_all)] fn for_loop( &mut self, diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index 682768b7..798f3a72 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -1,9 +1,12 @@ -use crate::{ContextBuilder, Variable, Env, IntoExprErr, ExprErr}; +use crate::{ContextBuilder, Env, ExprErr, IntoExprErr, Variable}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, TypeNode, - nodes::{BuiltInNode, Builtin, FunctionNode, StructNode, EnumNode, TyNode, ContractNode, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, - elem::*, Range, SolcRange + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ContractNode, + EnumNode, ExprRet, FunctionNode, StructNode, TyNode, + }, + AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, TypeNode, VarType, }; use shared::NodeIdx; diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 6a6b57df..2d2469c4 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,9 +1,13 @@ -use crate::{ContextBuilder, BinOp, Variable, IntoExprErr, ExprErr}; +use crate::{BinOp, ContextBuilder, ExprErr, IntoExprErr, Variable}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{BuiltInNode, Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, TmpConstruction, Concrete, KilledKind, ExprRet, }, - elem::*, Range, RangeEval, SolcRange, range_string::ToRangeString, + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, + ExprRet, KilledKind, TmpConstruction, + }, + range_string::ToRangeString, + AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; use ethers_core::types::I256; diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 502de6b6..ba91ba49 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,11 +1,11 @@ -use crate::{ContextBuilder, env::Env, IntoExprErr, ExprErr}; +use crate::{env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, ContextEdge, - nodes::{VarNode, ContextNode, ContextVar, ExprRet, } + nodes::{ContextNode, ContextVar, ExprRet, VarNode}, + AnalyzerBackend, ContextEdge, Edge, Node, }; -use solang_parser::pt::{Identifier, Expression}; +use solang_parser::pt::{Expression, Identifier}; impl Variable for T where T: AnalyzerBackend + Sized {} diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index 2a0a98c2..ddcba561 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -1,8 +1,8 @@ -use crate::{ContextBuilder, ExprParser, IntoExprErr, ExprErr}; +use crate::{ContextBuilder, ExprErr, ExprParser, IntoExprErr}; use graph::{ - AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{Builtin, Context, ContextNode, ContextVarNode, ContextVar, ExprRet, }, + nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; use solang_parser::{ diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index 2616e18b..8faf7127 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -1,21 +1,25 @@ -use crate::{YulBuilder, ContextBuilder, IntoExprErr, ExprErr, require::Require}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, YulBuilder}; use graph::{ - AnalyzerBackend, Edge, Node, ContextEdge, - nodes::{ConcreteNode, Context, ContextNode, ContextVarNode, ContextVar, Concrete, ExprRet, }, - elem::* + elem::*, + nodes::{Concrete, ConcreteNode, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, }; use shared::NodeIdx; use ethers_core::types::U256; use solang_parser::pt::{ - Identifier, YulBlock, YulFunctionCall, YulSwitchOptions, CodeLocation, - Expression, Loc, YulExpression, YulStatement + CodeLocation, Expression, Identifier, Loc, YulBlock, YulExpression, YulFunctionCall, + YulStatement, YulSwitchOptions, }; -impl YulCondOp for T where T: AnalyzerBackend + Require + Sized -{} -pub trait YulCondOp: AnalyzerBackend + Require + Sized { +impl YulCondOp for T where + T: AnalyzerBackend + Require + Sized +{ +} +pub trait YulCondOp: + AnalyzerBackend + Require + Sized +{ #[tracing::instrument(level = "trace", skip_all)] fn yul_cond_op_stmt( &mut self, diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 473bc4f4..ad712560 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,18 +1,20 @@ -use crate::{ContextBuilder, Cmp, Env, YulBuilder, BinOp, IntoExprErr, ExprErr}; +use crate::{BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, YulBuilder}; use graph::{ - GraphBackend, AnalyzerBackend, Edge, Node, VarType, ContextEdge, - nodes::{Builtin, ConcreteNode, ContextNode, ContextVarNode, ContextVar, Concrete, KilledKind, ExprRet, }, - elem::*, SolcRange + elem::*, + nodes::{ + Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ExprRet, + KilledKind, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, SolcRange, VarType, }; use ethers_core::types::U256; -use solang_parser::pt::{YulExpression, YulFunctionCall, Expression, Loc, StorageLocation}; +use solang_parser::pt::{Expression, Loc, StorageLocation, YulExpression, YulFunctionCall}; use std::cell::RefCell; use std::rc::Rc; - impl YulFuncCaller for T where T: AnalyzerBackend + Sized + GraphBackend { @@ -745,4 +747,4 @@ pub trait YulFuncCaller: Ok(()) } } -} \ No newline at end of file +} From 3d1b17a4af284b6f9293734dc17aa553fbdf096a Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 15:45:01 -0800 Subject: [PATCH 17/71] Change storagelocation to include block and msg + fix benches --- Cargo.lock | 378 +++++++++++++++++- Cargo.toml | 3 - crates/analyzers/src/bounds.rs | 6 +- crates/analyzers/src/var_analyzer/mod.rs | 4 +- crates/graph/src/nodes/context/var/node.rs | 4 +- crates/graph/src/nodes/context/var/typing.rs | 22 +- .../graph/src/nodes/context/var/underlying.rs | 4 +- crates/graph/src/nodes/func_ty.rs | 8 +- crates/graph/src/range/elem/expr.rs | 30 +- crates/pyrometer/Cargo.toml | 12 +- .../pyrometer/benches}/README.md | 0 .../pyrometer/benches}/flamegraphs/parse.svg | 0 .../pyrometer/benches}/parse.rs | 10 +- crates/pyrometer/src/builtin_fns.rs | 4 +- crates/shared/src/lib.rs | 38 ++ .../src/context_builder/mod.rs | 4 +- crates/solc-expressions/src/env.rs | 20 + crates/solc-expressions/src/func_call/mod.rs | 4 +- crates/solc-expressions/src/list.rs | 4 +- crates/solc-expressions/src/yul/yul_funcs.rs | 3 +- 20 files changed, 516 insertions(+), 42 deletions(-) rename {benches => crates/pyrometer/benches}/README.md (100%) rename {benches => crates/pyrometer/benches}/flamegraphs/parse.svg (100%) rename {benches => crates/pyrometer/benches}/parse.rs (92%) diff --git a/Cargo.lock b/Cargo.lock index cfbd8fc9..eb2ec0c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ dependencies = [ "solang-parser", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anstream" version = "0.6.4" @@ -93,6 +99,17 @@ dependencies = [ "term", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "auto_impl" version = "1.1.0" @@ -171,6 +188,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "byte-slice-cast" version = "1.2.2" @@ -192,6 +215,12 @@ dependencies = [ "serde", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cfg-if" version = "1.0.0" @@ -207,6 +236,45 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags 1.3.2", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "textwrap", +] + [[package]] name = "clap" version = "4.4.11" @@ -225,7 +293,7 @@ checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", - "clap_lex", + "clap_lex 0.6.0", "strsim", ] @@ -241,6 +309,15 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "clap_lex" version = "0.6.0" @@ -253,7 +330,7 @@ version = "0.1.0" dependencies = [ "analyzers", "ariadne", - "clap", + "clap 4.4.11", "ethers-core", "graph", "petgraph", @@ -297,6 +374,75 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap 3.2.25", + "criterion-plot", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -612,6 +758,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.14.3" @@ -624,6 +782,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.3" @@ -683,6 +850,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -690,7 +867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.3", ] [[package]] @@ -699,7 +876,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.3", "rustix", "windows-sys 0.48.0", ] @@ -719,6 +896,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.13.2" @@ -838,6 +1024,15 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -891,6 +1086,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "open-fastrlp" version = "0.1.4" @@ -916,6 +1117,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + [[package]] name = "overload" version = "0.1.1" @@ -978,7 +1185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 2.1.0", ] [[package]] @@ -1048,6 +1255,34 @@ dependencies = [ "spki", ] +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1149,6 +1384,7 @@ version = "0.2.0" dependencies = [ "analyzers", "ariadne", + "criterion", "ethers-core", "graph", "petgraph", @@ -1228,6 +1464,26 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1355,6 +1611,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scale-info" version = "2.10.0" @@ -1639,6 +1904,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + [[package]] name = "thiserror" version = "1.0.50" @@ -1678,6 +1949,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -1690,7 +1971,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -1701,7 +1982,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -1827,12 +2108,86 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1849,6 +2204,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index a9b7eced..483bdfa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,9 +48,6 @@ petgraph = "0.6.2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -# [dev-dependencies] -# criterion = { version = "0.4"} # benching - # [workspace] # members = ["cli", "shared"] diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index 1044558c..4a1cc911 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -3,9 +3,9 @@ use crate::{FunctionVarsBoundAnalysis, LocSpan, LocStrSpan, ReportConfig, VarBou use graph::{ nodes::ContextNode, range_string::ToRangeString, GraphBackend, Range, RangeEval, SolcRange, }; +use shared::StorageLocation; use ariadne::{Color, Fmt, Label, Span}; -use solang_parser::pt::StorageLocation; use std::collections::{BTreeMap, BTreeSet}; pub static MIN_COLOR: Color = Color::Fixed(111); @@ -171,6 +171,8 @@ impl From for Label { Some(StorageLocation::Memory(..)) => Color::Blue, Some(StorageLocation::Storage(..)) => Color::Green, Some(StorageLocation::Calldata(..)) => Color::White, + Some(StorageLocation::Block(..)) => Color::Magenta, + Some(StorageLocation::Msg(..)) => Color::Cyan, None => Color::Cyan, }, val.order, @@ -185,6 +187,8 @@ impl From for Label { Some(StorageLocation::Memory(..)) => "Memory var ", Some(StorageLocation::Storage(..)) => "Storage var ", Some(StorageLocation::Calldata(..)) => "Calldata var ", + Some(StorageLocation::Block(..)) => "Block var ", + Some(StorageLocation::Msg(..)) => "Msg var ", None => "", }, val.name, diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 09e0fdd4..991f6c45 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -7,11 +7,11 @@ use graph::{ nodes::{ContextNode, ContextVarNode, KilledKind}, AnalyzerBackend, GraphBackend, Range, SolcRange, }; -use shared::Search; +use shared::{StorageLocation, Search}; use std::collections::BTreeSet; -use solang_parser::pt::{CodeLocation, StorageLocation}; +use solang_parser::pt::CodeLocation; use std::collections::BTreeMap; mod report_display; diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 023a05b3..9254c003 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -4,10 +4,10 @@ use crate::{ AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, }; -use shared::{NodeIdx, Search}; +use shared::{NodeIdx, Search, StorageLocation}; use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{Loc, StorageLocation}; +use solang_parser::pt::Loc; use std::collections::BTreeMap; diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index dd625544..0a3e91c5 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -3,10 +3,10 @@ use crate::{ AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; -use shared::Search; +use shared::{StorageLocation, Search}; use petgraph::Direction; -use solang_parser::pt::{Loc, StorageLocation}; +use solang_parser::pt::Loc; impl ContextVarNode { pub fn ty<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a VarType, GraphError> { @@ -66,6 +66,8 @@ impl ContextVarNode { Ok((global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer) + || global_first.is_msg(analyzer)? + || global_first.is_block(analyzer)? || ( // if its a function input, and we are evaluating the function // as a standalone (i.e. its internal, but we are treating it like its external) @@ -84,7 +86,7 @@ impl ContextVarNode { } pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result { - if self.is_storage_or_calldata_input(analyzer)? { + if self.is_storage_or_calldata_input(analyzer)? || self.is_msg(analyzer)? || self.is_block(analyzer)? { Ok(true) } else if let Some(tmp) = self.tmp_of(analyzer)? { let rhs_controllable = if let Some(rhs) = tmp.rhs { @@ -107,6 +109,20 @@ impl ContextVarNode { .any(|edge| Edge::Context(ContextEdge::CalldataVariable) == *edge.weight()) } + pub fn is_msg(&self, analyzer: &impl GraphBackend) -> Result { + Ok(matches!( + self.underlying(analyzer)?.storage, + Some(StorageLocation::Msg(..)) + )) + } + + pub fn is_block(&self, analyzer: &impl GraphBackend) -> Result { + Ok(matches!( + self.underlying(analyzer)?.storage, + Some(StorageLocation::Block(..)) + )) + } + pub fn is_func_input(&self, analyzer: &impl GraphBackend) -> bool { let first = self.first_version(analyzer); analyzer diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 45edabe3..4d9bd14f 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -8,9 +8,9 @@ use crate::{ }; use crate::range::elem::*; -use shared::NodeIdx; +use shared::{StorageLocation, NodeIdx}; -use solang_parser::pt::{Loc, StorageLocation}; +use solang_parser::pt::Loc; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ContextVar { diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index a25e3f1a..51fc5821 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -4,14 +4,14 @@ use crate::{ VarType, }; -use shared::{NodeIdx, Search}; +use shared::{NodeIdx, Search, StorageLocation}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ helpers::CodeLocation, pt::{ Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, - Parameter, ParameterList, Statement, StorageLocation, Type, VariableDefinition, Visibility, + Parameter, ParameterList, Statement, Type, VariableDefinition, Visibility, }, }; use std::collections::BTreeMap; @@ -785,7 +785,7 @@ impl FunctionParam { loc: param.loc, ty: analyzer.parse_expr(¶m.ty, None), order, - storage: param.storage, + storage: if let Some(s) = param.storage { Some(s.into()) } else { None }, name: param.name, } } @@ -875,7 +875,7 @@ impl FunctionReturn { FunctionReturn { loc: param.loc, ty: analyzer.parse_expr(¶m.ty, None), - storage: param.storage, + storage: if let Some(s) = param.storage { Some(s.into()) } else { None }, name: param.name, } } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 0418bb19..d7e65947 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -50,13 +50,13 @@ impl RangeExpr { if SINGLETON_EQ_OPS.contains(&self.op) { let mut new_self = self.clone(); new_self.uncache(); - new_self.op = new_self.op.logical_inverse().unwrap(); + new_self.op = new_self.op.logical_inverse()?; Some(new_self) } else { // non-singleton, i.e. AND or OR let mut new_self = self.clone(); new_self.uncache(); - new_self.op = new_self.op.inverse().unwrap(); + new_self.op = new_self.op.inverse()?; if let Some(new_lhs) = new_self.inverse_if_boolean() { *new_self.lhs = Elem::Expr(new_lhs); } @@ -220,6 +220,32 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed let y = expr.rhs; let z = c; match (expr.op, op) { + (RangeOp::Sub(false), RangeOp::Min) => { + // min{x - y, z} + // if x <= z, then x - y will be the minimum if y >= 0 + if matches!(x.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less)) + && matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) { + MaybeCollapsed::Collapsed(l) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(false), RangeOp::Max) => { + // max{x + y, z} + // if x >= z, then x + y will be the maximum if y >= 0 + // or if y >= z, then x + y will be the maximum if x >= 0 + if ( + matches!(x.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) + && matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) + ) || ( + matches!(y.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) + && matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) + ) { + MaybeCollapsed::Collapsed(l) + } else { + MaybeCollapsed::Not(l, r) + } + } (RangeOp::Eq, RangeOp::Eq) => { // ((x == y) == z) // can skip if x and z eq diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml index 37f0d37f..79831938 100644 --- a/crates/pyrometer/Cargo.toml +++ b/crates/pyrometer/Cargo.toml @@ -22,4 +22,14 @@ ethers-core.workspace = true ariadne.workspace = true tracing.workspace = true tracing-subscriber.workspace = true -serde_json = "1" \ No newline at end of file +serde_json = "1" + + + + +[dev-dependencies] +criterion = { version = "0.4"} # benching + +[[bench]] +name = "parse" +harness = false \ No newline at end of file diff --git a/benches/README.md b/crates/pyrometer/benches/README.md similarity index 100% rename from benches/README.md rename to crates/pyrometer/benches/README.md diff --git a/benches/flamegraphs/parse.svg b/crates/pyrometer/benches/flamegraphs/parse.svg similarity index 100% rename from benches/flamegraphs/parse.svg rename to crates/pyrometer/benches/flamegraphs/parse.svg diff --git a/benches/parse.rs b/crates/pyrometer/benches/parse.rs similarity index 92% rename from benches/parse.rs rename to crates/pyrometer/benches/parse.rs index baf7e115..1f2f0e58 100644 --- a/benches/parse.rs +++ b/crates/pyrometer/benches/parse.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use pyrometer::Analyzer; +use pyrometer::{Analyzer, SourcePath}; use std::path::PathBuf; use std::env::{self}; @@ -73,9 +73,7 @@ fn bench(c: &mut Criterion) { /// * `path` - A `PathBuf` representing the path to the source code file. /// * `sol` - A string containing the Solidity source code. fn parse(path: &PathBuf, sol: String) { - let mut analyzer = Analyzer { - root: path.clone(), - ..Default::default() - }; - let (_maybe_entry, mut _all_sources) = analyzer.parse(&sol, &path, true); + let mut analyzer = Analyzer::default(); + let current_path = SourcePath::SolidityFile(path.clone()); + let _maybe_entry = analyzer.parse(&sol, ¤t_path, true); } diff --git a/crates/pyrometer/src/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs index d996a30f..67df88e1 100644 --- a/crates/pyrometer/src/builtin_fns.rs +++ b/crates/pyrometer/src/builtin_fns.rs @@ -1,7 +1,7 @@ use graph::nodes::{Builtin, Function, FunctionParam, FunctionReturn}; -use shared::{AnalyzerLike, GraphLike}; +use shared::{AnalyzerLike, GraphLike, StorageLocation}; -use solang_parser::pt::{FunctionAttribute, Identifier, Loc, StorageLocation, Visibility}; +use solang_parser::pt::{FunctionAttribute, Identifier, Loc, Visibility}; use std::collections::HashMap; diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 88f88d06..9e1538b0 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -5,3 +5,41 @@ mod search; pub use analyzer_like::*; pub use graph_like::*; pub use search::*; + + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub enum StorageLocation { + Memory(solang_parser::pt::Loc), + Storage(solang_parser::pt::Loc), + Calldata(solang_parser::pt::Loc), + Block(solang_parser::pt::Loc), + Msg(solang_parser::pt::Loc), +} + +impl std::fmt::Display for StorageLocation { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Memory(_) => write!(f, "memory"), + Self::Storage(_) => write!(f, "storage"), + Self::Calldata(_) => write!(f, "calldata"), + Self::Block(_) => write!(f, "block"), + Self::Msg(_) => write!(f, "msg"), + } + } +} + +impl From for StorageLocation { + fn from(sl: solang_parser::pt::StorageLocation) -> Self { + match sl { + solang_parser::pt::StorageLocation::Memory(m) =>{ + StorageLocation::Memory(m) + } + solang_parser::pt::StorageLocation::Storage(m) =>{ + StorageLocation::Storage(m) + } + solang_parser::pt::StorageLocation::Calldata(m) =>{ + StorageLocation::Calldata(m) + } + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 25bb1696..7d96f5b6 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -615,7 +615,7 @@ pub trait ContextBuilder: loc: Some(loc), name: name.to_string(), display_name: name.to_string(), - storage: var_decl.storage.clone(), + storage: if let Some(s) = &var_decl.storage { Some(s.clone().into()) } else { None }, is_tmp: false, is_symbolic: true, tmp_of: None, @@ -642,7 +642,7 @@ pub trait ContextBuilder: loc: Some(loc), name: name.to_string(), display_name: name.to_string(), - storage: var_decl.storage.clone(), + storage: if let Some(s) = &var_decl.storage { Some(s.clone().into()) } else { None }, is_tmp: false, is_symbolic: true, tmp_of: None, diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 13e82ce1..7dca8db2 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,9 +1,11 @@ + use crate::{func_call::FuncCaller, ExprErr, IntoExprErr}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; +use shared::StorageLocation; use solang_parser::pt::{Expression, Identifier, Loc}; @@ -72,6 +74,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.blockhash".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -93,6 +96,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.basefee".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -114,6 +118,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.chainid".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -135,6 +140,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.coinbase".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -156,6 +162,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.difficulty".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -177,6 +184,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.gaslimit".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -198,6 +206,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.number".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -219,6 +228,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.prevrandao".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -240,6 +250,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "block.timestamp".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -258,6 +269,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = name; var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Block(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -294,6 +306,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "msg.data".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -315,6 +328,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "msg.sender".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -336,6 +350,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "msg.sig".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -357,6 +372,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "msg.value".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -378,6 +394,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "tx.origin".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -399,6 +416,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = "tx.gasprice".to_string(); var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -415,6 +433,7 @@ pub trait Env: AnalyzerBackend + Sized { .into_expr_err(loc)?; var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -434,6 +453,7 @@ pub trait Env: AnalyzerBackend + Sized { var.display_name = name; var.is_tmp = false; var.is_symbolic = true; + var.storage = Some(StorageLocation::Msg(loc)); let cvar = self.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index e1d0e5e7..a1dce7d3 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -10,10 +10,10 @@ use graph::{ }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, VarType, }; -use shared::NodeIdx; +use shared::{StorageLocation, NodeIdx}; use solang_parser::helpers::CodeLocation; -use solang_parser::pt::{Expression, Loc, NamedArgument, StorageLocation}; +use solang_parser::pt::{Expression, Loc, NamedArgument}; use std::cell::RefCell; use std::collections::BTreeMap; use std::rc::Rc; diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index c4b6b5a8..a3af89d9 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -64,7 +64,7 @@ pub trait List: AnalyzerBackend + Sized { loc: Some(*loc), name: input_name.to_string(), display_name: input_name.to_string(), - storage: input.storage.clone(), + storage: input.storage.as_ref().map(|s| s.clone().into()), is_tmp: false, is_symbolic: false, tmp_of: None, @@ -89,7 +89,7 @@ pub trait List: AnalyzerBackend + Sized { loc: Some(*loc), name: format!("tmp{tmp_num}"), display_name: format!("tmp{tmp_num}"), - storage: input.storage.clone(), + storage: input.storage.as_ref().map(|s| s.clone().into()), is_tmp: true, is_symbolic: false, tmp_of: None, diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index ad712560..0d28f98e 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -8,9 +8,10 @@ use graph::{ }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, SolcRange, VarType, }; +use shared::StorageLocation; use ethers_core::types::U256; -use solang_parser::pt::{Expression, Loc, StorageLocation, YulExpression, YulFunctionCall}; +use solang_parser::pt::{Expression, Loc, YulExpression, YulFunctionCall}; use std::cell::RefCell; use std::rc::Rc; From 5252d8cf46be1bbb4301db18383b78c305ea1635 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 15:45:31 -0800 Subject: [PATCH 18/71] lint --- crates/analyzers/src/var_analyzer/mod.rs | 6 +-- .../src/var_analyzer/report_display.rs | 2 +- crates/graph/src/nodes/context/var/typing.rs | 7 ++- .../graph/src/nodes/context/var/underlying.rs | 4 +- crates/graph/src/nodes/func_ty.rs | 4 +- crates/graph/src/range/elem/expr.rs | 29 +++++++---- crates/shared/src/lib.rs | 51 ++++++++----------- crates/solc-expressions/src/array.rs | 2 +- .../src/context_builder/mod.rs | 4 +- crates/solc-expressions/src/env.rs | 1 - crates/solc-expressions/src/func_call/mod.rs | 2 +- .../solc-expressions/src/member_access/mod.rs | 2 +- 12 files changed, 60 insertions(+), 54 deletions(-) diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 991f6c45..29d3609d 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -7,7 +7,7 @@ use graph::{ nodes::{ContextNode, ContextVarNode, KilledKind}, AnalyzerBackend, GraphBackend, Range, SolcRange, }; -use shared::{StorageLocation, Search}; +use shared::{Search, StorageLocation}; use std::collections::BTreeSet; @@ -98,7 +98,7 @@ impl VarBoundAnalysis { order: -1, name: self.var_display_name.clone(), loc: self.var_def.0.clone(), - storage: self.storage.clone(), + storage: self.storage, ctx: self.ctx, ctx_conditionals: self.conditionals(analyzer), parts, @@ -215,7 +215,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { ), bound_changes: vec![], report_config, - storage: curr.underlying(self).unwrap().storage.clone(), + storage: curr.underlying(self).unwrap().storage, ctx_killed: ctx .killed_loc(self) .unwrap() diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index e53b7e10..006a594d 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -41,7 +41,7 @@ impl ReportDisplay for VarBoundAnalysis { name: self.var_display_name.clone(), loc: bound_change.0.clone(), order: i as i32, - storage: self.storage.clone(), + storage: self.storage, ctx: self.ctx, ctx_conditionals: self.conditionals(analyzer), parts, diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 0a3e91c5..44fc49b6 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -3,7 +3,7 @@ use crate::{ AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; -use shared::{StorageLocation, Search}; +use shared::{Search, StorageLocation}; use petgraph::Direction; use solang_parser::pt::Loc; @@ -86,7 +86,10 @@ impl ContextVarNode { } pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result { - if self.is_storage_or_calldata_input(analyzer)? || self.is_msg(analyzer)? || self.is_block(analyzer)? { + if self.is_storage_or_calldata_input(analyzer)? + || self.is_msg(analyzer)? + || self.is_block(analyzer)? + { Ok(true) } else if let Some(tmp) = self.tmp_of(analyzer)? { let rhs_controllable = if let Some(rhs) = tmp.rhs { diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 4d9bd14f..d8cfda8e 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -8,7 +8,7 @@ use crate::{ }; use crate::range::elem::*; -use shared::{StorageLocation, NodeIdx}; +use shared::{NodeIdx, StorageLocation}; use solang_parser::pt::Loc; @@ -479,7 +479,7 @@ impl ContextVar { display_name: parent_var.name.clone() + "." + &field.name.expect("Field had no name").name, - storage: parent_var.storage.clone(), + storage: parent_var.storage, is_tmp: false, tmp_of: None, is_symbolic: true, diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 51fc5821..eee61d52 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -785,7 +785,7 @@ impl FunctionParam { loc: param.loc, ty: analyzer.parse_expr(¶m.ty, None), order, - storage: if let Some(s) = param.storage { Some(s.into()) } else { None }, + storage: param.storage.map(|s| s.into()), name: param.name, } } @@ -875,7 +875,7 @@ impl FunctionReturn { FunctionReturn { loc: param.loc, ty: analyzer.parse_expr(¶m.ty, None), - storage: if let Some(s) = param.storage { Some(s.into()) } else { None }, + storage: param.storage.map(|s| s.into()), name: param.name, } } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index d7e65947..e8c6aa1c 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -223,8 +223,13 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed (RangeOp::Sub(false), RangeOp::Min) => { // min{x - y, z} // if x <= z, then x - y will be the minimum if y >= 0 - if matches!(x.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less)) - && matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) { + if matches!( + x.range_ord(&z), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less) + ) && matches!( + y.range_ord(&zero), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ) { MaybeCollapsed::Collapsed(l) } else { MaybeCollapsed::Not(l, r) @@ -234,13 +239,19 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed // max{x + y, z} // if x >= z, then x + y will be the maximum if y >= 0 // or if y >= z, then x + y will be the maximum if x >= 0 - if ( - matches!(x.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) - && matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) - ) || ( - matches!(y.range_ord(&z), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) - && matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater)) - ) { + if (matches!( + x.range_ord(&z), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ) && matches!( + y.range_ord(&zero), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + )) || (matches!( + y.range_ord(&z), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ) && matches!( + x.range_ord(&zero), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + )) { MaybeCollapsed::Collapsed(l) } else { MaybeCollapsed::Not(l, r) diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 9e1538b0..bc09b01e 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -6,40 +6,33 @@ pub use analyzer_like::*; pub use graph_like::*; pub use search::*; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] pub enum StorageLocation { - Memory(solang_parser::pt::Loc), - Storage(solang_parser::pt::Loc), - Calldata(solang_parser::pt::Loc), - Block(solang_parser::pt::Loc), - Msg(solang_parser::pt::Loc), + Memory(solang_parser::pt::Loc), + Storage(solang_parser::pt::Loc), + Calldata(solang_parser::pt::Loc), + Block(solang_parser::pt::Loc), + Msg(solang_parser::pt::Loc), } impl std::fmt::Display for StorageLocation { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Memory(_) => write!(f, "memory"), - Self::Storage(_) => write!(f, "storage"), - Self::Calldata(_) => write!(f, "calldata"), - Self::Block(_) => write!(f, "block"), - Self::Msg(_) => write!(f, "msg"), - } - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Memory(_) => write!(f, "memory"), + Self::Storage(_) => write!(f, "storage"), + Self::Calldata(_) => write!(f, "calldata"), + Self::Block(_) => write!(f, "block"), + Self::Msg(_) => write!(f, "msg"), + } + } } impl From for StorageLocation { - fn from(sl: solang_parser::pt::StorageLocation) -> Self { - match sl { - solang_parser::pt::StorageLocation::Memory(m) =>{ - StorageLocation::Memory(m) - } - solang_parser::pt::StorageLocation::Storage(m) =>{ - StorageLocation::Storage(m) - } - solang_parser::pt::StorageLocation::Calldata(m) =>{ - StorageLocation::Calldata(m) - } - } - } -} \ No newline at end of file + fn from(sl: solang_parser::pt::StorageLocation) -> Self { + match sl { + solang_parser::pt::StorageLocation::Memory(m) => StorageLocation::Memory(m), + solang_parser::pt::StorageLocation::Storage(m) => StorageLocation::Storage(m), + solang_parser::pt::StorageLocation::Calldata(m) => StorageLocation::Calldata(m), + } + } +} diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index a870b1e5..3cead0f6 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -165,7 +165,7 @@ pub trait Array: AnalyzerBackend + Sized { parent.display_name(self).into_expr_err(loc)?, index.display_name(self).into_expr_err(loc)? ), - storage: parent.storage(self).into_expr_err(loc)?.clone(), + storage: *parent.storage(self).into_expr_err(loc)?, is_tmp: false, tmp_of: None, is_symbolic: true, diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 7d96f5b6..9ce07c73 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -615,7 +615,7 @@ pub trait ContextBuilder: loc: Some(loc), name: name.to_string(), display_name: name.to_string(), - storage: if let Some(s) = &var_decl.storage { Some(s.clone().into()) } else { None }, + storage: var_decl.storage.as_ref().map(|s| s.clone().into()), is_tmp: false, is_symbolic: true, tmp_of: None, @@ -642,7 +642,7 @@ pub trait ContextBuilder: loc: Some(loc), name: name.to_string(), display_name: name.to_string(), - storage: if let Some(s) = &var_decl.storage { Some(s.clone().into()) } else { None }, + storage: var_decl.storage.as_ref().map(|s| s.clone().into()), is_tmp: false, is_symbolic: true, tmp_of: None, diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 7dca8db2..e203455e 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,4 +1,3 @@ - use crate::{func_call::FuncCaller, ExprErr, IntoExprErr}; use graph::{ diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index a1dce7d3..33c82738 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -10,7 +10,7 @@ use graph::{ }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, VarType, }; -use shared::{StorageLocation, NodeIdx}; +use shared::{NodeIdx, StorageLocation}; use solang_parser::helpers::CodeLocation; use solang_parser::pt::{Expression, Loc, NamedArgument}; diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index 798f3a72..80abecc6 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -851,7 +851,7 @@ pub trait MemberAccess: AnalyzerBackend + loc, parent_name, parent_display_name, - parent_stor.clone(), + *parent_stor, &parent_ty, ContextVarNode::from(*idx), ) From 0b347610ddd4264ddc6ee639aff9f1c64159c6fc Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 20:00:44 -0800 Subject: [PATCH 19/71] fix mermaid graph --- crates/cli/src/main.rs | 7 +++ crates/graph/src/nodes/func_ty.rs | 6 +-- crates/pyrometer/src/graph_backend.rs | 41 +++++++++-------- crates/pyrometer/tests/test_data/viz.sol | 2 + .../pyrometer/tests/test_data/viz/basic.sol | 12 +++++ .../tests/test_data/viz/func_call.sol | 13 ++++++ crates/shared/src/graph_like.rs | 44 +++++++++++++++++++ crates/shared/src/mermaidConfig.json | 3 ++ crates/shared/src/search.rs | 20 +++++---- .../src/context_builder/mod.rs | 1 + 10 files changed, 118 insertions(+), 31 deletions(-) create mode 100644 crates/pyrometer/tests/test_data/viz.sol create mode 100644 crates/pyrometer/tests/test_data/viz/basic.sol create mode 100644 crates/pyrometer/tests/test_data/viz/func_call.sol create mode 100644 crates/shared/src/mermaidConfig.json diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 12774ae9..a92b8408 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -64,6 +64,9 @@ struct Args { /// Whether to generate and open a dot visualization of the analyzed contracts #[clap(long, short, default_value = "false")] pub open_dot: bool, + /// Whether to generate and open a mermaid visualization of the analyzed contracts + #[clap(long, default_value = "false")] + pub open_mermaid: bool, /// Whether to evaluate variables down to their intervals or to keep them symbolic/relational to other variables #[clap(long, short)] pub eval: Option, @@ -263,6 +266,10 @@ fn main() { println!("{}", analyzer.mermaid_str()); } + if args.open_mermaid { + analyzer.open_mermaid(); + } + if args.debug { return; } diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index eee61d52..06b110b2 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -451,7 +451,7 @@ impl AsDotStr for FunctionNode { format!( "{} {}({}) {}", self.underlying(analyzer).unwrap().ty, - self.name(analyzer).unwrap(), + self.name(analyzer).unwrap().split('(').collect::>()[0], inputs, attrs ) @@ -682,7 +682,7 @@ impl AsDotStr for FunctionParamNode { if let Some(stor) = &self.underlying(analyzer).unwrap().storage { format!(" {stor} ") } else { - "".to_string() + " ".to_string() }, if let Some(name) = self.maybe_name(analyzer).unwrap() { name @@ -804,7 +804,7 @@ impl AsDotStr for FunctionReturnNode { if let Some(stor) = &self.underlying(analyzer).unwrap().storage { format!(" {stor} ") } else { - "".to_string() + " ".to_string() }, if let Some(name) = self.maybe_name(analyzer).unwrap() { name diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index d47b89e1..9a4f7865 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -76,10 +76,13 @@ impl GraphDot for Analyzer { let g = &G { graph: &new_graph }; let children = g.children_exclude(node, 0, &[Edge::Context(ContextEdge::Subcontext)]); - let mut children_edges = g.edges_for_nodes(&children); + let mut children_edges = g.edges_for_nodes(&children).into_iter().filter(|(_, _, e, _)| { + *e != Edge::Context(ContextEdge::InputVariable) + }).collect::>(); children_edges.extend( self.graph() .edges_directed(node, Direction::Incoming) + .filter(|edge| *edge.weight() != Edge::Context(ContextEdge::InputVariable)) .map(|edge| (edge.source(), edge.target(), *edge.weight(), edge.id())) .collect::)>>(), ); @@ -164,7 +167,7 @@ impl GraphDot for Analyzer { } } Node::ContextVar(_) => { - let mut children = g.children(*child); + let mut children = g.children_exclude(*child, usize::MAX, &[Edge::Context(ContextEdge::InputVariable)]); children.insert(*child); children .iter() @@ -513,11 +516,11 @@ flowchart BT n => { handled_nodes.lock().unwrap().insert(*node); Some(format!( - " {}(\"{}\")\n style {} stroke:{}", + " {}(\"{}\")",//\n style {} stroke:{}", petgraph::graph::GraphIndex::index(node), as_dot_str(*node, self).replace('\"', "\'"), - petgraph::graph::GraphIndex::index(node), - n.dot_str_color() + // petgraph::graph::GraphIndex::index(node), + // n.dot_str_color() )) } } @@ -539,7 +542,7 @@ flowchart BT let to = to.index(); let edge_idx = edge.index(); Some(format!( - " {from:} -->|\"{:?}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", + " {from:} -->|\"{:?}\"| {to:}", // class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", self.graph().edge_weight(edge).unwrap() )) } else { @@ -585,20 +588,20 @@ pub fn mermaid_node( as_dot_str(node, g).replace('\"', "\'"), ); - if style { - node_str.push_str(&format!( - "\n{indent}style {} stroke:{}", - petgraph::graph::GraphIndex::index(&node), - g.node(node).dot_str_color() - )); - } + // if style { + // node_str.push_str(&format!( + // "\n{indent}style {} stroke:{}", + // petgraph::graph::GraphIndex::index(&node), + // g.node(node).dot_str_color() + // )); + // } - if let Some(class) = class { - node_str.push_str(&format!( - "\n{indent}class {} {class}", - petgraph::graph::GraphIndex::index(&node), - )); - } + // if let Some(class) = class { + // node_str.push_str(&format!( + // "\n{indent}class {} {class}", + // petgraph::graph::GraphIndex::index(&node), + // )); + // } node_str } diff --git a/crates/pyrometer/tests/test_data/viz.sol b/crates/pyrometer/tests/test_data/viz.sol new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/crates/pyrometer/tests/test_data/viz.sol @@ -0,0 +1,2 @@ + + diff --git a/crates/pyrometer/tests/test_data/viz/basic.sol b/crates/pyrometer/tests/test_data/viz/basic.sol new file mode 100644 index 00000000..2033878b --- /dev/null +++ b/crates/pyrometer/tests/test_data/viz/basic.sol @@ -0,0 +1,12 @@ +contract A { + uint256 storageVariable; + uint256 public publicStorageVariable; + uint256 constant const; + + + function func(uint256 input0, bytes32 input1, uint256[] memory input2) public returns (uint256 ret) { + uint256 innerVar = 100; + storageVariable = innerVar; + ret = innerVar; + } +} \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/viz/func_call.sol b/crates/pyrometer/tests/test_data/viz/func_call.sol new file mode 100644 index 00000000..2e114b10 --- /dev/null +++ b/crates/pyrometer/tests/test_data/viz/func_call.sol @@ -0,0 +1,13 @@ +contract A { + uint256 storageVariable; + // uint256 public publicStorageVariable; + // uint256 constant const; + + function funcA() public returns (uint256 ret) { + ret = funcB(storageVariable); + } + + function funcB(uint256 innerInput0) internal returns (uint256 ret) { + ret = innerInput0 + 10; + } +} \ No newline at end of file diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 5d6f2972..8afcc3ed 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -82,6 +82,50 @@ pub trait GraphDot: GraphLike { .expect("failed to execute process"); } + fn open_mermaid(&self) + where + Self: std::marker::Sized, + Self: AnalyzerLike, + { + println!("Generating mermaid... This may take a moment"); + use std::env::temp_dir; + use std::fs; + use std::io::Write; + use std::process::Command; + let temp_dir = temp_dir(); + let file_name = "mermaid.mmd"; + let config_name = "mermaidConfig.json"; + let mut temp_path = temp_dir.clone(); + let mut temp_config_path = temp_dir.clone(); + temp_path.push(file_name); + temp_config_path.push(config_name); + + let mut file = fs::File::create(temp_config_path.clone()).unwrap(); + file.write_all(include_bytes!("./mermaidConfig.json")).unwrap(); + + let temp_svg_filename: String = format!("{}/mermaid.svg", &temp_dir.to_string_lossy()); + + + let mut file = fs::File::create(temp_path.clone()).unwrap(); + file.write_all(self.mermaid_str().as_bytes()).unwrap(); + Command::new("mmdc") + .arg("-i") + .arg(temp_path) + .arg("-o") + .arg(&temp_svg_filename) + .arg("-c") + .arg(temp_config_path) + .arg("-b") + .arg("#1a1b26") + .output() + .expect("You may need to install mermaid-cli (https://github.com/mermaid-js/mermaid-cli), check if command 'mmdc' is in your $PATH"); + println!("Done generating mermaid svg, opening..."); + Command::new("open") + .arg(&temp_svg_filename) + .spawn() + .expect("failed to execute process"); + } + /// Creates a subgraph for visually identifying contexts and subcontexts fn cluster_str( &self, diff --git a/crates/shared/src/mermaidConfig.json b/crates/shared/src/mermaidConfig.json new file mode 100644 index 00000000..6e029963 --- /dev/null +++ b/crates/shared/src/mermaidConfig.json @@ -0,0 +1,3 @@ +{ + "maxTextSize": 99999999 +} \ No newline at end of file diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs index c048f7a4..b3efed41 100644 --- a/crates/shared/src/search.rs +++ b/crates/shared/src/search.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::collections::{BTreeMap, BTreeSet}; use crate::{GraphLike, NodeIdx}; @@ -10,13 +11,15 @@ pub trait Heirarchical { impl Search for T where T: GraphLike, - ::Edge: Ord + PartialEq + Heirarchical + Copy, + ::Edge: Ord + PartialEq + Heirarchical + Copy + Debug, + ::Node: Debug, { } /// A trait for searching through a graph pub trait Search: GraphLike where - ::Edge: PartialEq + Heirarchical + Copy, + ::Edge: PartialEq + Heirarchical + Copy + Debug, + ::Node: Debug, { fn search_for_ancestor( &self, @@ -387,15 +390,14 @@ where seen.insert(start); } - let edges = self.graph().edges_directed(start, Direction::Incoming); + let edges = self.graph().edges_directed(start, Direction::Incoming).filter(|edge| { + !exclude_edges.contains(edge.weight()) + }); + let mut this_children: BTreeSet = edges .clone() - .filter_map(|edge| { - if !exclude_edges.contains(edge.weight()) { - Some(edge.source()) - } else { - None - } + .map(|edge| { + edge.source() }) .collect(); diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 9ce07c73..9cb83558 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -538,6 +538,7 @@ pub trait ContextBuilder: true } Err(e) => { + println!("e: {e:#?}"); let res = ctx .kill(self, e.loc(), KilledKind::ParseError) .into_expr_err(e.loc()); From 18ebcda6f20e9316bce404c285a3d52f13fabf44 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Fri, 8 Dec 2023 20:01:26 -0800 Subject: [PATCH 20/71] lint --- crates/pyrometer/src/graph_backend.rs | 26 ++++++++++++++++---------- crates/shared/src/graph_like.rs | 4 ++-- crates/shared/src/search.rs | 21 +++++++++------------ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 9a4f7865..8ac14cd5 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -76,9 +76,11 @@ impl GraphDot for Analyzer { let g = &G { graph: &new_graph }; let children = g.children_exclude(node, 0, &[Edge::Context(ContextEdge::Subcontext)]); - let mut children_edges = g.edges_for_nodes(&children).into_iter().filter(|(_, _, e, _)| { - *e != Edge::Context(ContextEdge::InputVariable) - }).collect::>(); + let mut children_edges = g + .edges_for_nodes(&children) + .into_iter() + .filter(|(_, _, e, _)| *e != Edge::Context(ContextEdge::InputVariable)) + .collect::>(); children_edges.extend( self.graph() .edges_directed(node, Direction::Incoming) @@ -167,7 +169,11 @@ impl GraphDot for Analyzer { } } Node::ContextVar(_) => { - let mut children = g.children_exclude(*child, usize::MAX, &[Edge::Context(ContextEdge::InputVariable)]); + let mut children = g.children_exclude( + *child, + usize::MAX, + &[Edge::Context(ContextEdge::InputVariable)], + ); children.insert(*child); children .iter() @@ -513,10 +519,10 @@ flowchart BT )?) } Node::ContextVar(_) => None, - n => { + _n => { handled_nodes.lock().unwrap().insert(*node); Some(format!( - " {}(\"{}\")",//\n style {} stroke:{}", + " {}(\"{}\")", //\n style {} stroke:{}", petgraph::graph::GraphIndex::index(node), as_dot_str(*node, self).replace('\"', "\'"), // petgraph::graph::GraphIndex::index(node), @@ -540,7 +546,7 @@ flowchart BT } let from = from.index(); let to = to.index(); - let edge_idx = edge.index(); + let _edge_idx = edge.index(); Some(format!( " {from:} -->|\"{:?}\"| {to:}", // class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", self.graph().edge_weight(edge).unwrap() @@ -579,10 +585,10 @@ pub fn mermaid_node( g: &impl GraphBackend, indent: &str, node: NodeIdx, - style: bool, - class: Option<&str>, + _style: bool, + _class: Option<&str>, ) -> String { - let mut node_str = format!( + let node_str = format!( "{indent}{}(\"{}\")", petgraph::graph::GraphIndex::index(&node), as_dot_str(node, g).replace('\"', "\'"), diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 8afcc3ed..792bfe80 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -101,11 +101,11 @@ pub trait GraphDot: GraphLike { temp_config_path.push(config_name); let mut file = fs::File::create(temp_config_path.clone()).unwrap(); - file.write_all(include_bytes!("./mermaidConfig.json")).unwrap(); + file.write_all(include_bytes!("./mermaidConfig.json")) + .unwrap(); let temp_svg_filename: String = format!("{}/mermaid.svg", &temp_dir.to_string_lossy()); - let mut file = fs::File::create(temp_path.clone()).unwrap(); file.write_all(self.mermaid_str().as_bytes()).unwrap(); Command::new("mmdc") diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs index b3efed41..a0b86381 100644 --- a/crates/shared/src/search.rs +++ b/crates/shared/src/search.rs @@ -1,5 +1,5 @@ -use std::fmt::Debug; use std::collections::{BTreeMap, BTreeSet}; +use std::fmt::Debug; use crate::{GraphLike, NodeIdx}; use petgraph::{graph::*, visit::EdgeRef, Direction}; @@ -19,7 +19,7 @@ where pub trait Search: GraphLike where ::Edge: PartialEq + Heirarchical + Copy + Debug, - ::Node: Debug, + ::Node: Debug, { fn search_for_ancestor( &self, @@ -390,16 +390,13 @@ where seen.insert(start); } - let edges = self.graph().edges_directed(start, Direction::Incoming).filter(|edge| { - !exclude_edges.contains(edge.weight()) - }); - - let mut this_children: BTreeSet = edges - .clone() - .map(|edge| { - edge.source() - }) - .collect(); + let edges = self + .graph() + .edges_directed(start, Direction::Incoming) + .filter(|edge| !exclude_edges.contains(edge.weight())); + + let mut this_children: BTreeSet = + edges.clone().map(|edge| edge.source()).collect(); this_children.extend( edges From 486b3dc9c213cbf2ae375bc9a0d71f4315ad7f34 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 11:26:28 -0800 Subject: [PATCH 21/71] fix issue 69 Cleans up wrapping subtraction and when an assign occurs, the assignee inherits tmp_of from assignor --- crates/graph/src/nodes/context/solving.rs | 2 +- crates/graph/src/nodes/context/var/typing.rs | 21 +- crates/graph/src/range/elem/reference.rs | 6 +- crates/graph/src/range/exec/exec_op.rs | 100 +- crates/pyrometer/src/graph_backend.rs | 44 +- crates/pyrometer/tests/test_data/math.sol | 1232 +++++++++-------- .../tests/test_data/repros/issue69.sol | 15 + .../src/context_builder/mod.rs | 2 +- 8 files changed, 765 insertions(+), 657 deletions(-) create mode 100644 crates/pyrometer/tests/test_data/repros/issue69.sol diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 273d97c0..390a2efb 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -79,7 +79,7 @@ impl ContextNode { dep: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { - tracing::trace!("Adding ctx dependency: {}", dep.display_name(analyzer)?); + tracing::trace!("Adding ctx dependency: {}, is_controllable: {}", dep.display_name(analyzer)?, dep.is_controllable(analyzer)?); if dep.is_controllable(analyzer)? { let range = dep.ref_range(analyzer)?.unwrap(); let r = range.into_flattened_range(analyzer)?; diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 44fc49b6..ce9d4340 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -57,7 +57,7 @@ impl ContextVarNode { Ok(global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer)) } - pub fn is_independent_and_storage_or_calldata( + pub fn is_fundamental( &self, analyzer: &impl GraphBackend, ) -> Result { @@ -86,22 +86,13 @@ impl ContextVarNode { } pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result { - if self.is_storage_or_calldata_input(analyzer)? - || self.is_msg(analyzer)? - || self.is_block(analyzer)? - { - Ok(true) - } else if let Some(tmp) = self.tmp_of(analyzer)? { - let rhs_controllable = if let Some(rhs) = tmp.rhs { - rhs.is_controllable(analyzer)? + Ok(self.dependent_on(analyzer, true)?.iter().any(|dependent_on| { + if let Ok(t) = dependent_on.is_fundamental(analyzer) { + t } else { false - }; - let lhs_controllable = tmp.lhs.is_controllable(analyzer)?; - Ok(lhs_controllable || rhs_controllable) - } else { - Ok(false) - } + } + })) } pub fn is_calldata_input(&self, analyzer: &impl GraphBackend) -> bool { diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 57065f78..5b65d34f 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -65,7 +65,7 @@ impl RangeElem for Reference { analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); - if cvar.is_independent_and_storage_or_calldata(analyzer)? { + if cvar.is_fundamental(analyzer)? { return Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), ))); @@ -142,7 +142,7 @@ impl RangeElem for Reference { ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); - let independent = cvar.is_independent_and_storage_or_calldata(analyzer)?; + let independent = cvar.is_fundamental(analyzer)?; if independent { Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), @@ -159,7 +159,7 @@ impl RangeElem for Reference { analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); - if cvar.is_independent_and_storage_or_calldata(analyzer)? { + if cvar.is_fundamental(analyzer)? { Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), ))) diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index e255aeb2..e68d9b47 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -204,12 +204,108 @@ impl ExecOp for RangeExpr { } RangeOp::Sub(unchecked) => { if unchecked { - let candidates = vec![ + let mut candidates = vec![]; + // check if rhs contains zero, if so add lhs_min and max as candidates + let zero = Elem::from(Concrete::from(U256::from(0))); + let one = Elem::from(Concrete::from(U256::from(1))); + let rhs_min_contains_zero = matches!( + rhs_min.range_ord(&zero), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let rhs_max_contains_zero = matches!( + rhs_max.range_ord(&zero), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if rhs_min_contains_zero && rhs_max_contains_zero { + candidates.push(Some(lhs_min.clone())); + candidates.push(Some(lhs_max.clone())); + } + + // If we have the below case, where the lhs + // contains the rhs, we can add zero. Futher more, if + // the lhs contains rhs - 1, we can add max as it + // would overflow to uint256.max + // zero min max uint256.max + // lhs: | - - |----------------------------| - - | + // rhs: | - - |--| - - - - - - - - - - - - - - - | + match lhs_max.range_ord(&rhs_min) { + Some(std::cmp::Ordering::Less) => { + // We are going to overflow, zero not possible + } + Some(std::cmp::Ordering::Equal) => { + // We are going to at least be zero, + // we may overflow. check if rhs is const, otherwise + // add uint256.max as a candidate + candidates.push(Some(zero.clone())); + if !consts.1 { + candidates.push(zero.range_wrapping_sub(&one)); + } + } + Some(std::cmp::Ordering::Greater) => { + // No guarantees on overflow, check lhs_min + match lhs_min.range_ord(&rhs_min) { + Some(std::cmp::Ordering::Less) => { + // fully contained, add zero and max + candidates.push(Some(zero.clone())); + candidates.push(zero.range_wrapping_sub(&one)); + } + Some(std::cmp::Ordering::Equal) => { + // We are going to at least be zero, + // we may overflow. check if rhs is const, otherwise + // add uint256.max as a candidate + candidates.push(Some(zero.clone())); + if !consts.1 { + candidates.push(zero.range_wrapping_sub(&one)); + } + } + Some(std::cmp::Ordering::Greater) => { + // current info: + // zero min max uint256.max + // lhs: | - - |----------------------------| - - | + // rhs: | - |----? - - - - - - - - - - - - - - - | + // figure out where rhs max is + match lhs_min.range_ord(&rhs_max) { + Some(std::cmp::Ordering::Less) => { + // zero min + // lhs: | - - |---? + // rhs: | - |----| + // min max + // Add both + candidates.push(Some(zero.clone())); + candidates.push(zero.range_wrapping_sub(&one)); + } + Some(std::cmp::Ordering::Equal) => { + // zero min + // lhs: | - - |---? + // rhs: | |---| + // min max + // Add zero + candidates.push(Some(zero.clone())); + } + Some(std::cmp::Ordering::Greater) => { + // zero min + // lhs: | - - |---? + // rhs: |-----| + // min max + // Add nothing + } + _ => {} + } + } + _ => {} + } + } + _ => {} + } + + candidates.extend(vec![ lhs_min.range_wrapping_sub(&rhs_min), lhs_min.range_wrapping_sub(&rhs_max), lhs_max.range_wrapping_sub(&rhs_min), lhs_max.range_wrapping_sub(&rhs_max), - ]; + ]); let mut candidates = candidates.into_iter().flatten().collect::>(); candidates.sort_by(|a, b| match a.range_ord(b) { Some(r) => r, diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 8ac14cd5..e842d82b 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -519,14 +519,14 @@ flowchart BT )?) } Node::ContextVar(_) => None, - _n => { + n => { handled_nodes.lock().unwrap().insert(*node); Some(format!( - " {}(\"{}\")", //\n style {} stroke:{}", + " {}(\"{}\")\n style {} stroke:{}", petgraph::graph::GraphIndex::index(node), as_dot_str(*node, self).replace('\"', "\'"), - // petgraph::graph::GraphIndex::index(node), - // n.dot_str_color() + petgraph::graph::GraphIndex::index(node), + n.dot_str_color() )) } } @@ -546,9 +546,9 @@ flowchart BT } let from = from.index(); let to = to.index(); - let _edge_idx = edge.index(); + let edge_idx = edge.index(); Some(format!( - " {from:} -->|\"{:?}\"| {to:}", // class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", + " {from:} -->|\"{:?}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", self.graph().edge_weight(edge).unwrap() )) } else { @@ -585,29 +585,29 @@ pub fn mermaid_node( g: &impl GraphBackend, indent: &str, node: NodeIdx, - _style: bool, - _class: Option<&str>, + style: bool, + class: Option<&str>, ) -> String { - let node_str = format!( + let mut node_str = format!( "{indent}{}(\"{}\")", petgraph::graph::GraphIndex::index(&node), as_dot_str(node, g).replace('\"', "\'"), ); - // if style { - // node_str.push_str(&format!( - // "\n{indent}style {} stroke:{}", - // petgraph::graph::GraphIndex::index(&node), - // g.node(node).dot_str_color() - // )); - // } + if style { + node_str.push_str(&format!( + "\n{indent}style {} stroke:{}", + petgraph::graph::GraphIndex::index(&node), + g.node(node).dot_str_color() + )); + } - // if let Some(class) = class { - // node_str.push_str(&format!( - // "\n{indent}class {} {class}", - // petgraph::graph::GraphIndex::index(&node), - // )); - // } + if let Some(class) = class { + node_str.push_str(&format!( + "\n{indent}class {} {class}", + petgraph::graph::GraphIndex::index(&node), + )); + } node_str } diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index d4d4786f..2acbf8d6 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -1,620 +1,626 @@ -contract Div { - function div(uint256 x, uint256 y) public returns (uint256) { - return x / y; - } - - function int_div(int256 x, int256 y) public returns (int256) { - return x / y; - } - - function div_conc() public returns (uint256) { - uint256 a1 = div(100, 1); - require(a1 == 100); - uint256 a2 = div(100, 2); - require(a2 == 50); - uint256 a3 = div(100, 4); - require(a3 == 25); - uint256 a4 = div(100, 8); - require(a4 == 12); - uint256 a5 = div(1000000000, 8); - require(a5 == 125000000); - uint256 a6 = div(1000000000, 16); - require(a6 == 62500000); - uint256 a7 = div(10000000000, 32); - require(a7 == 312500000); - uint256 a8 = div(100000000000000000000, 64); - require(a8 == 1562500000000000000); - uint256 a9 = div(100000000000000000000000000000000000, 128); - require(a9 == 781250000000000000000000000000000); - uint256 a10 = div(1, 255); - require(a10 == 0); - } - - function int_div_conc() public { - int256 a1 = int_div(100, 1); - require(a1 == 100); - int256 a2 = int_div(100, 2); - require(a2 == 50); - int256 a3 = int_div(100, 4); - require(a3 == 25); - int256 a4 = int_div(100, 8); - require(a4 == 12); - int256 a5 = int_div(1000000000, 8); - require(a5 == 125000000); - int256 a6 = int_div(1000000000, 16); - require(a6 == 62500000); - int256 a7 = int_div(10000000000, 32); - require(a7 == 312500000); - int256 a8 = int_div(100000000000000000000, 64); - require(a8 == 1562500000000000000); - int256 a9 = int_div(100000000000000000000000000000000000, 128); - require(a9 == 781250000000000000000000000000000); - int256 a10 = int_div(1, 255); - require(a10 == 0); - - int256 a11 = int_div(-100, 1); - require(a11 == -100); - int256 a12 = int_div(-100, 2); - require(a12 == -50); - int256 a13 = int_div(-100, 4); - require(a13 == -25); - int256 a14 = int_div(-100, 8); - require(a14 == -12); - int256 a15 = int_div(-1000000000, 8); - require(a15 == -125000000); - int256 a16 = int_div(-1000000000, 16); - require(a16 == -62500000); - int256 a17 = int_div(-10000000000, 32); - require(a17 == -312500000); - int256 a18 = int_div(-100000000000000000000, 64); - require(a18 == -1562500000000000000); - int256 a19 = int_div(-100000000000000000000000000000000000, 128); - require(a19 == -781250000000000000000000000000000); - int256 a20 = int_div(-1, 255); - require(a20 == 0); - - int256 a21 = int_div(-100, -1); - require(a21 == 100); - int256 a22 = int_div(-100, -2); - require(a22 == 50); - int256 a23 = int_div(-100, -4); - require(a23 == 25); - int256 a24 = int_div(-100, -8); - require(a24 == 12); - int256 a25 = int_div(-1000000000, -8); - require(a25 == 125000000); - int256 a26 = int_div(-1000000000, -16); - require(a26 == 62500000); - int256 a27 = int_div(-10000000000, -32); - require(a27 == 312500000); - int256 a28 = int_div(-100000000000000000000, -64); - require(a28 == 1562500000000000000); - int256 a29 = int_div(-100000000000000000000000000000000000, -128); - require(a29 == 781250000000000000000000000000000); - int256 a30 = int_div(-1, -255); - require(a30 == 0); - - int256 a31 = int_div(100, -1); - require(a31 == -100); - int256 a32 = int_div(100, -2); - require(a32 == -50); - int256 a33 = int_div(100, -4); - require(a33 == -25); - int256 a34 = int_div(100, -8); - require(a34 == -12); - int256 a35 = int_div(1000000000, -8); - require(a35 == -125000000); - int256 a36 = int_div(1000000000, -16); - require(a36 == -62500000); - int256 a37 = int_div(10000000000, -32); - require(a37 == -312500000); - int256 a38 = int_div(100000000000000000000, -64); - require(a38 == -1562500000000000000); - int256 a39 = int_div(100000000000000000000000000000000000, -128); - require(a39 == -781250000000000000000000000000000); - int256 a40 = int_div(1, -255); - require(a40 == 0); - } -} - -contract Mul { - function mul(uint256 x, uint256 y) public returns (uint256) { - return x * y; - } - - function int_mul(int256 x, int256 y) public returns (int256) { - return x * y; - } - - function mul_conc() public returns (uint256) { - uint256 a1 = mul(100, 1); - require(a1 == 100); - uint256 a2 = mul(100, 2); - require(a2 == 200); - uint256 a3 = mul(100, 4); - require(a3 == 400); - uint256 a4 = mul(100, 8); - require(a4 == 800); - uint256 a5 = mul(1000000000, 8); - require(a5 == 8000000000); - uint256 a6 = mul(1000000000, 16); - require(a6 == 16000000000); - uint256 a7 = mul(10000000000, 32); - require(a7 == 320000000000); - uint256 a8 = mul(100000000000000000000, 64); - require(a8 == 6400000000000000000000); - uint256 a9 = mul(100000000000000000000000000000000000, 128); - require(a9 == 12800000000000000000000000000000000000); - uint256 a10 = mul(1, 255); - require(a10 == 255); - } - - function int_mul_conc() public { - int256 a1 = int_mul(100, 1); - require(a1 == 100); - int256 a2 = int_mul(100, 2); - require(a2 == 200); - int256 a3 = int_mul(100, 4); - require(a3 == 400); - int256 a4 = int_mul(100, 8); - require(a4 == 800); - int256 a5 = int_mul(1000000000, 8); - require(a5 == 8000000000); - int256 a6 = int_mul(1000000000, 16); - require(a6 == 16000000000); - int256 a7 = int_mul(10000000000, 32); - require(a7 == 320000000000); - int256 a8 = int_mul(100000000000000000000, 64); - require(a8 == 6400000000000000000000); - int256 a9 = int_mul(100000000000000000000000000000000000, 128); - require(a9 == 12800000000000000000000000000000000000); - int256 a10 = int_mul(1, 255); - require(a10 == 255); - - int256 a11 = int_mul(-100, 1); - require(a11 == -100); - int256 a12 = int_mul(-100, 2); - require(a12 == -200); - int256 a13 = int_mul(-100, 4); - require(a13 == -400); - int256 a14 = int_mul(-100, 8); - require(a14 == -800); - int256 a15 = int_mul(-1000000000, 8); - require(a15 == -8000000000); - int256 a16 = int_mul(-1000000000, 16); - require(a16 == -16000000000); - int256 a17 = int_mul(-10000000000, 32); - require(a17 == -320000000000); - int256 a18 = int_mul(-100000000000000000000, 64); - require(a18 == -6400000000000000000000); - int256 a19 = int_mul(-100000000000000000000000000000000000, 128); - require(a19 == -12800000000000000000000000000000000000); - int256 a20 = int_mul(-1, 255); - require(a20 == -255); - - int256 a21 = int_mul(-100, -1); - require(a21 == 100); - int256 a22 = int_mul(-100, -2); - require(a22 == 200); - int256 a23 = int_mul(-100, -4); - require(a23 == 400); - int256 a24 = int_mul(-100, -8); - require(a24 == 800); - int256 a25 = int_mul(-1000000000, -8); - require(a25 == 8000000000); - int256 a26 = int_mul(-1000000000, -16); - require(a26 == 16000000000); - int256 a27 = int_mul(-10000000000, -32); - require(a27 == 320000000000); - int256 a28 = int_mul(-100000000000000000000, -64); - require(a28 == 6400000000000000000000); - int256 a29 = int_mul(-100000000000000000000000000000000000, -128); - require(a29 == 12800000000000000000000000000000000000); - int256 a30 = int_mul(-1, -255); - require(a30 == 255); - - int256 a31 = int_mul(100, -1); - require(a31 == -100); - int256 a32 = int_mul(100, -2); - require(a32 == -200); - int256 a33 = int_mul(100, -4); - require(a33 == -400); - int256 a34 = int_mul(100, -8); - require(a34 == -800); - int256 a35 = int_mul(1000000000, -8); - require(a35 == -8000000000); - int256 a36 = int_mul(1000000000, -16); - require(a36 == -16000000000); - int256 a37 = int_mul(10000000000, -32); - require(a37 == -320000000000); - int256 a38 = int_mul(100000000000000000000, -64); - require(a38 == -6400000000000000000000); - int256 a39 = int_mul(100000000000000000000000000000000000, -128); - require(a39 == -12800000000000000000000000000000000000); - int256 a40 = int_mul(1, -255); - require(a40 == -255); - } -} - -contract Add { - function add(uint256 x, uint256 y) public returns (uint256) { - return x + y; - } - - function int_add(int256 x, int256 y) public returns (int256) { - return x + y; - } - - function add_conc() public returns (uint256) { - uint256 a1 = add(100, 1); - require(a1 == 101); - uint256 a2 = add(100, 2); - require(a2 == 102); - uint256 a3 = add(100, 4); - require(a3 == 104); - uint256 a4 = add(100, 8); - require(a4 == 108); - uint256 a5 = add(1000000000, 8); - require(a5 == 1000000008); - uint256 a6 = add(1000000000, 16); - require(a6 == 1000000016); - uint256 a7 = add(10000000000, 32); - require(a7 == 10000000032); - uint256 a8 = add(100000000000000000000, 64); - require(a8 == 100000000000000000064); - uint256 a9 = add(100000000000000000000000000000000000, 128); - require(a9 == 100000000000000000000000000000000128); - uint256 a10 = add(1, 255); - require(a10 == 256); - } - - function int_add_conc() public { - int256 a1 = int_add(100, 1); - require(a1 == 101); - int256 a2 = int_add(100, 2); - require(a2 == 102); - int256 a3 = int_add(100, 4); - require(a3 == 104); - int256 a4 = int_add(100, 8); - require(a4 == 108); - int256 a5 = int_add(1000000000, 8); - require(a5 == 1000000008); - int256 a6 = int_add(1000000000, 16); - require(a6 == 1000000016); - int256 a7 = int_add(10000000000, 32); - require(a7 == 10000000032); - int256 a8 = int_add(100000000000000000000, 64); - require(a8 == 100000000000000000064); - int256 a9 = int_add(100000000000000000000000000000000000, 128); - require(a9 == 100000000000000000000000000000000128); - int256 a10 = int_add(1, 255); - require(a10 == 256); - - int256 a11 = int_add(-100, 1); - require(a11 == -99); - int256 a12 = int_add(-100, 2); - require(a12 == -98); - int256 a13 = int_add(-100, 4); - require(a13 == -96); - int256 a14 = int_add(-100, 8); - require(a14 == -92); - int256 a15 = int_add(-1000000000, 8); - require(a15 == -999999992); - int256 a16 = int_add(-1000000000, 16); - require(a16 == -999999984); - int256 a17 = int_add(-10000000000, 32); - require(a17 == -9999999968); - int256 a18 = int_add(-100000000000000000000, 64); - require(a18 == -99999999999999999936); - int256 a19 = int_add(-100000000000000000000000000000000000, 128); - require(a19 == -99999999999999999999999999999999872); - int256 a20 = int_add(-1, 255); - require(a20 == 254); - - int256 a21 = int_add(-100, -1); - require(a21 == -101); - int256 a22 = int_add(-100, -2); - require(a22 == -102); - int256 a23 = int_add(-100, -4); - require(a23 == -104); - int256 a24 = int_add(-100, -8); - require(a24 == -108); - int256 a25 = int_add(-1000000000, -8); - require(a25 == -1000000008); - int256 a26 = int_add(-1000000000, -16); - require(a26 == -1000000016); - int256 a27 = int_add(-10000000000, -32); - require(a27 == -10000000032); - int256 a28 = int_add(-100000000000000000000, -64); - require(a28 == -100000000000000000064); - int256 a29 = int_add(-100000000000000000000000000000000000, -128); - require(a29 == -100000000000000000000000000000000128); - int256 a30 = int_add(-1, -255); - require(a30 == -256); - - int256 a31 = int_add(100, -1); - require(a31 == 99); - int256 a32 = int_add(100, -2); - require(a32 == 98); - int256 a33 = int_add(100, -4); - require(a33 == 96); - int256 a34 = int_add(100, -8); - require(a34 == 92); - int256 a35 = int_add(1000000000, -8); - require(a35 == 999999992); - int256 a36 = int_add(1000000000, -16); - require(a36 == 999999984); - int256 a37 = int_add(10000000000, -32); - require(a37 == 9999999968); - int256 a38 = int_add(100000000000000000000, -64); - require(a38 == 99999999999999999936); - int256 a39 = int_add(100000000000000000000000000000000000, -128); - require(a39 == 99999999999999999999999999999999872); - int256 a40 = int_add(1, -255); - require(a40 == -254); - } -} - -contract Sub { - function sub(uint256 x, uint256 y) public returns (uint256) { - return x - y; - } - - function int_sub(int256 x, int256 y) public returns (int256) { - return x - y; - } - - function sub_conc() public returns (uint256) { - uint256 a1 = sub(100, 1); - require(a1 == 99); - uint256 a2 = sub(100, 2); - require(a2 == 98); - uint256 a3 = sub(100, 4); - require(a3 == 96); - uint256 a4 = sub(100, 8); - require(a4 == 92); - uint256 a5 = sub(1000000000, 8); - require(a5 == 999999992); - uint256 a6 = sub(1000000000, 16); - require(a6 == 999999984); - uint256 a7 = sub(10000000000, 32); - require(a7 == 9999999968); - uint256 a8 = sub(100000000000000000000, 64); - require(a8 == 99999999999999999936); - uint256 a9 = sub(100000000000000000000000000000000000, 128); - require(a9 == 99999999999999999999999999999999872); - } - - function int_sub_conc() public { - int256 a1 = int_sub(100, 1); - require(a1 == 99); - int256 a2 = int_sub(100, 2); - require(a2 == 98); - int256 a3 = int_sub(100, 4); - require(a3 == 96); - int256 a4 = int_sub(100, 8); - require(a4 == 92); - int256 a5 = int_sub(1000000000, 8); - require(a5 == 999999992); - int256 a6 = int_sub(1000000000, 16); - require(a6 == 999999984); - int256 a7 = int_sub(10000000000, 32); - require(a7 == 9999999968); - int256 a8 = int_sub(100000000000000000000, 64); - require(a8 == 99999999999999999936); - int256 a9 = int_sub(100000000000000000000000000000000000, 128); - require(a9 == 99999999999999999999999999999999872); - int256 a10 = int_sub(1, 255); - require(a10 == -254); - - int256 a11 = int_sub(-100, 1); - require(a11 == -101); - int256 a12 = int_sub(-100, 2); - require(a12 == -102); - int256 a13 = int_sub(-100, 4); - require(a13 == -104); - int256 a14 = int_sub(-100, 8); - require(a14 == -108); - int256 a15 = int_sub(-1000000000, 8); - require(a15 == -1000000008); - int256 a16 = int_sub(-1000000000, 16); - require(a16 == -1000000016); - int256 a17 = int_sub(-10000000000, 32); - require(a17 == -10000000032); - int256 a18 = int_sub(-100000000000000000000, 64); - require(a18 == -100000000000000000064); - int256 a19 = int_sub(-100000000000000000000000000000000000, 128); - require(a19 == -100000000000000000000000000000000128); - int256 a20 = int_sub(-1, 255); - require(a20 == -256); - - int256 a21 = int_sub(-100, -1); - require(a21 == -99); - int256 a22 = int_sub(-100, -2); - require(a22 == -98); - int256 a23 = int_sub(-100, -4); - require(a23 == -96); - int256 a24 = int_sub(-100, -8); - require(a24 == -92); - int256 a25 = int_sub(-1000000000, -8); - require(a25 == -999999992); - int256 a26 = int_sub(-1000000000, -16); - require(a26 == -999999984); - int256 a27 = int_sub(-10000000000, -32); - require(a27 == -9999999968); - int256 a28 = int_sub(-100000000000000000000, -64); - require(a28 == -99999999999999999936); - int256 a29 = int_sub(-100000000000000000000000000000000000, -128); - require(a29 == -99999999999999999999999999999999872); - int256 a30 = int_sub(-1, -255); - require(a30 == 254); - - int256 a31 = int_sub(100, -1); - require(a31 == 101); - int256 a32 = int_sub(100, -2); - require(a32 == 102); - int256 a33 = int_sub(100, -4); - require(a33 == 104); - int256 a34 = int_sub(100, -8); - require(a34 == 108); - int256 a35 = int_sub(1000000000, -8); - require(a35 == 1000000008); - int256 a36 = int_sub(1000000000, -16); - require(a36 == 1000000016); - int256 a37 = int_sub(10000000000, -32); - require(a37 == 10000000032); - int256 a38 = int_sub(100000000000000000000, -64); - require(a38 == 100000000000000000064); - int256 a39 = int_sub(100000000000000000000000000000000000, -128); - require(a39 == 100000000000000000000000000000000128); - int256 a40 = int_sub(1, -255); - require(a40 == 256); - } -} - -contract AssignMath { - function assignAdd(uint256 x) public { - x += 10; - } - - function assignSub(uint256 x) public { - x -= 10; - } - - function assignDiv(uint256 x) public { - x /= 10; - } - - function assignMul(uint256 x) public { - x *= 10; - } - - function preincrement(uint256 x) public returns (uint256, uint256) { - uint256 y = ++x; - return (y, x); - } - - function postincrement(uint256 x) public returns (uint256, uint256) { - uint256 y = x++; - return (y, x); - } - - function predecrement(uint256 x) public returns (uint256, uint256) { - uint256 y = --x; - return (y, x); - } - - function postdecrement(uint256 x) public returns (uint256, uint256) { - uint256 y = x--; - return (y, x); - } - - function pre_conc() public { - (uint256 y, uint256 x) = preincrement(100); - require(y == 101); - require(x == 101); - } - - function post_conc() public { - (uint256 y, uint256 x) = postincrement(100); - require(y == 100); - require(x == 101); - } - - function pre_deconc() public { - (uint256 y, uint256 x) = predecrement(100); - require(y == 99); - require(x == 99); - } - - function post_deconc() public { - (uint256 y, uint256 x) = postdecrement(100); - require(y == 100); - require(x == 99); - } -} - -contract Math { - function rmod(uint256 x, uint256 y) public returns (uint256) { - return x % y; - } - - function rexp(uint256 x, uint256 y) public returns (uint256) { - return x ** y; - } - - function int_rmod(int256 x, int256 y) public returns (int256) { - return x % y; - } - - function int_rexp(int256 x, uint256 y) public returns (int256) { - return x ** y; - } -} +// contract Div { +// function div(uint256 x, uint256 y) public returns (uint256) { +// return x / y; +// } + +// function int_div(int256 x, int256 y) public returns (int256) { +// return x / y; +// } + +// function div_conc() public returns (uint256) { +// uint256 a1 = div(100, 1); +// require(a1 == 100); +// uint256 a2 = div(100, 2); +// require(a2 == 50); +// uint256 a3 = div(100, 4); +// require(a3 == 25); +// uint256 a4 = div(100, 8); +// require(a4 == 12); +// uint256 a5 = div(1000000000, 8); +// require(a5 == 125000000); +// uint256 a6 = div(1000000000, 16); +// require(a6 == 62500000); +// uint256 a7 = div(10000000000, 32); +// require(a7 == 312500000); +// uint256 a8 = div(100000000000000000000, 64); +// require(a8 == 1562500000000000000); +// uint256 a9 = div(100000000000000000000000000000000000, 128); +// require(a9 == 781250000000000000000000000000000); +// uint256 a10 = div(1, 255); +// require(a10 == 0); +// } + +// function int_div_conc() public { +// int256 a1 = int_div(100, 1); +// require(a1 == 100); +// int256 a2 = int_div(100, 2); +// require(a2 == 50); +// int256 a3 = int_div(100, 4); +// require(a3 == 25); +// int256 a4 = int_div(100, 8); +// require(a4 == 12); +// int256 a5 = int_div(1000000000, 8); +// require(a5 == 125000000); +// int256 a6 = int_div(1000000000, 16); +// require(a6 == 62500000); +// int256 a7 = int_div(10000000000, 32); +// require(a7 == 312500000); +// int256 a8 = int_div(100000000000000000000, 64); +// require(a8 == 1562500000000000000); +// int256 a9 = int_div(100000000000000000000000000000000000, 128); +// require(a9 == 781250000000000000000000000000000); +// int256 a10 = int_div(1, 255); +// require(a10 == 0); + +// int256 a11 = int_div(-100, 1); +// require(a11 == -100); +// int256 a12 = int_div(-100, 2); +// require(a12 == -50); +// int256 a13 = int_div(-100, 4); +// require(a13 == -25); +// int256 a14 = int_div(-100, 8); +// require(a14 == -12); +// int256 a15 = int_div(-1000000000, 8); +// require(a15 == -125000000); +// int256 a16 = int_div(-1000000000, 16); +// require(a16 == -62500000); +// int256 a17 = int_div(-10000000000, 32); +// require(a17 == -312500000); +// int256 a18 = int_div(-100000000000000000000, 64); +// require(a18 == -1562500000000000000); +// int256 a19 = int_div(-100000000000000000000000000000000000, 128); +// require(a19 == -781250000000000000000000000000000); +// int256 a20 = int_div(-1, 255); +// require(a20 == 0); + +// int256 a21 = int_div(-100, -1); +// require(a21 == 100); +// int256 a22 = int_div(-100, -2); +// require(a22 == 50); +// int256 a23 = int_div(-100, -4); +// require(a23 == 25); +// int256 a24 = int_div(-100, -8); +// require(a24 == 12); +// int256 a25 = int_div(-1000000000, -8); +// require(a25 == 125000000); +// int256 a26 = int_div(-1000000000, -16); +// require(a26 == 62500000); +// int256 a27 = int_div(-10000000000, -32); +// require(a27 == 312500000); +// int256 a28 = int_div(-100000000000000000000, -64); +// require(a28 == 1562500000000000000); +// int256 a29 = int_div(-100000000000000000000000000000000000, -128); +// require(a29 == 781250000000000000000000000000000); +// int256 a30 = int_div(-1, -255); +// require(a30 == 0); + +// int256 a31 = int_div(100, -1); +// require(a31 == -100); +// int256 a32 = int_div(100, -2); +// require(a32 == -50); +// int256 a33 = int_div(100, -4); +// require(a33 == -25); +// int256 a34 = int_div(100, -8); +// require(a34 == -12); +// int256 a35 = int_div(1000000000, -8); +// require(a35 == -125000000); +// int256 a36 = int_div(1000000000, -16); +// require(a36 == -62500000); +// int256 a37 = int_div(10000000000, -32); +// require(a37 == -312500000); +// int256 a38 = int_div(100000000000000000000, -64); +// require(a38 == -1562500000000000000); +// int256 a39 = int_div(100000000000000000000000000000000000, -128); +// require(a39 == -781250000000000000000000000000000); +// int256 a40 = int_div(1, -255); +// require(a40 == 0); +// } +// } + +// contract Mul { +// function mul(uint256 x, uint256 y) public returns (uint256) { +// return x * y; +// } + +// function int_mul(int256 x, int256 y) public returns (int256) { +// return x * y; +// } + +// function mul_conc() public returns (uint256) { +// uint256 a1 = mul(100, 1); +// require(a1 == 100); +// uint256 a2 = mul(100, 2); +// require(a2 == 200); +// uint256 a3 = mul(100, 4); +// require(a3 == 400); +// uint256 a4 = mul(100, 8); +// require(a4 == 800); +// uint256 a5 = mul(1000000000, 8); +// require(a5 == 8000000000); +// uint256 a6 = mul(1000000000, 16); +// require(a6 == 16000000000); +// uint256 a7 = mul(10000000000, 32); +// require(a7 == 320000000000); +// uint256 a8 = mul(100000000000000000000, 64); +// require(a8 == 6400000000000000000000); +// uint256 a9 = mul(100000000000000000000000000000000000, 128); +// require(a9 == 12800000000000000000000000000000000000); +// uint256 a10 = mul(1, 255); +// require(a10 == 255); +// } + +// function int_mul_conc() public { +// int256 a1 = int_mul(100, 1); +// require(a1 == 100); +// int256 a2 = int_mul(100, 2); +// require(a2 == 200); +// int256 a3 = int_mul(100, 4); +// require(a3 == 400); +// int256 a4 = int_mul(100, 8); +// require(a4 == 800); +// int256 a5 = int_mul(1000000000, 8); +// require(a5 == 8000000000); +// int256 a6 = int_mul(1000000000, 16); +// require(a6 == 16000000000); +// int256 a7 = int_mul(10000000000, 32); +// require(a7 == 320000000000); +// int256 a8 = int_mul(100000000000000000000, 64); +// require(a8 == 6400000000000000000000); +// int256 a9 = int_mul(100000000000000000000000000000000000, 128); +// require(a9 == 12800000000000000000000000000000000000); +// int256 a10 = int_mul(1, 255); +// require(a10 == 255); + +// int256 a11 = int_mul(-100, 1); +// require(a11 == -100); +// int256 a12 = int_mul(-100, 2); +// require(a12 == -200); +// int256 a13 = int_mul(-100, 4); +// require(a13 == -400); +// int256 a14 = int_mul(-100, 8); +// require(a14 == -800); +// int256 a15 = int_mul(-1000000000, 8); +// require(a15 == -8000000000); +// int256 a16 = int_mul(-1000000000, 16); +// require(a16 == -16000000000); +// int256 a17 = int_mul(-10000000000, 32); +// require(a17 == -320000000000); +// int256 a18 = int_mul(-100000000000000000000, 64); +// require(a18 == -6400000000000000000000); +// int256 a19 = int_mul(-100000000000000000000000000000000000, 128); +// require(a19 == -12800000000000000000000000000000000000); +// int256 a20 = int_mul(-1, 255); +// require(a20 == -255); + +// int256 a21 = int_mul(-100, -1); +// require(a21 == 100); +// int256 a22 = int_mul(-100, -2); +// require(a22 == 200); +// int256 a23 = int_mul(-100, -4); +// require(a23 == 400); +// int256 a24 = int_mul(-100, -8); +// require(a24 == 800); +// int256 a25 = int_mul(-1000000000, -8); +// require(a25 == 8000000000); +// int256 a26 = int_mul(-1000000000, -16); +// require(a26 == 16000000000); +// int256 a27 = int_mul(-10000000000, -32); +// require(a27 == 320000000000); +// int256 a28 = int_mul(-100000000000000000000, -64); +// require(a28 == 6400000000000000000000); +// int256 a29 = int_mul(-100000000000000000000000000000000000, -128); +// require(a29 == 12800000000000000000000000000000000000); +// int256 a30 = int_mul(-1, -255); +// require(a30 == 255); + +// int256 a31 = int_mul(100, -1); +// require(a31 == -100); +// int256 a32 = int_mul(100, -2); +// require(a32 == -200); +// int256 a33 = int_mul(100, -4); +// require(a33 == -400); +// int256 a34 = int_mul(100, -8); +// require(a34 == -800); +// int256 a35 = int_mul(1000000000, -8); +// require(a35 == -8000000000); +// int256 a36 = int_mul(1000000000, -16); +// require(a36 == -16000000000); +// int256 a37 = int_mul(10000000000, -32); +// require(a37 == -320000000000); +// int256 a38 = int_mul(100000000000000000000, -64); +// require(a38 == -6400000000000000000000); +// int256 a39 = int_mul(100000000000000000000000000000000000, -128); +// require(a39 == -12800000000000000000000000000000000000); +// int256 a40 = int_mul(1, -255); +// require(a40 == -255); +// } +// } + +// contract Add { +// function add(uint256 x, uint256 y) public returns (uint256) { +// return x + y; +// } + +// function int_add(int256 x, int256 y) public returns (int256) { +// return x + y; +// } + +// function add_conc() public returns (uint256) { +// uint256 a1 = add(100, 1); +// require(a1 == 101); +// uint256 a2 = add(100, 2); +// require(a2 == 102); +// uint256 a3 = add(100, 4); +// require(a3 == 104); +// uint256 a4 = add(100, 8); +// require(a4 == 108); +// uint256 a5 = add(1000000000, 8); +// require(a5 == 1000000008); +// uint256 a6 = add(1000000000, 16); +// require(a6 == 1000000016); +// uint256 a7 = add(10000000000, 32); +// require(a7 == 10000000032); +// uint256 a8 = add(100000000000000000000, 64); +// require(a8 == 100000000000000000064); +// uint256 a9 = add(100000000000000000000000000000000000, 128); +// require(a9 == 100000000000000000000000000000000128); +// uint256 a10 = add(1, 255); +// require(a10 == 256); +// } + +// function int_add_conc() public { +// int256 a1 = int_add(100, 1); +// require(a1 == 101); +// int256 a2 = int_add(100, 2); +// require(a2 == 102); +// int256 a3 = int_add(100, 4); +// require(a3 == 104); +// int256 a4 = int_add(100, 8); +// require(a4 == 108); +// int256 a5 = int_add(1000000000, 8); +// require(a5 == 1000000008); +// int256 a6 = int_add(1000000000, 16); +// require(a6 == 1000000016); +// int256 a7 = int_add(10000000000, 32); +// require(a7 == 10000000032); +// int256 a8 = int_add(100000000000000000000, 64); +// require(a8 == 100000000000000000064); +// int256 a9 = int_add(100000000000000000000000000000000000, 128); +// require(a9 == 100000000000000000000000000000000128); +// int256 a10 = int_add(1, 255); +// require(a10 == 256); + +// int256 a11 = int_add(-100, 1); +// require(a11 == -99); +// int256 a12 = int_add(-100, 2); +// require(a12 == -98); +// int256 a13 = int_add(-100, 4); +// require(a13 == -96); +// int256 a14 = int_add(-100, 8); +// require(a14 == -92); +// int256 a15 = int_add(-1000000000, 8); +// require(a15 == -999999992); +// int256 a16 = int_add(-1000000000, 16); +// require(a16 == -999999984); +// int256 a17 = int_add(-10000000000, 32); +// require(a17 == -9999999968); +// int256 a18 = int_add(-100000000000000000000, 64); +// require(a18 == -99999999999999999936); +// int256 a19 = int_add(-100000000000000000000000000000000000, 128); +// require(a19 == -99999999999999999999999999999999872); +// int256 a20 = int_add(-1, 255); +// require(a20 == 254); + +// int256 a21 = int_add(-100, -1); +// require(a21 == -101); +// int256 a22 = int_add(-100, -2); +// require(a22 == -102); +// int256 a23 = int_add(-100, -4); +// require(a23 == -104); +// int256 a24 = int_add(-100, -8); +// require(a24 == -108); +// int256 a25 = int_add(-1000000000, -8); +// require(a25 == -1000000008); +// int256 a26 = int_add(-1000000000, -16); +// require(a26 == -1000000016); +// int256 a27 = int_add(-10000000000, -32); +// require(a27 == -10000000032); +// int256 a28 = int_add(-100000000000000000000, -64); +// require(a28 == -100000000000000000064); +// int256 a29 = int_add(-100000000000000000000000000000000000, -128); +// require(a29 == -100000000000000000000000000000000128); +// int256 a30 = int_add(-1, -255); +// require(a30 == -256); + +// int256 a31 = int_add(100, -1); +// require(a31 == 99); +// int256 a32 = int_add(100, -2); +// require(a32 == 98); +// int256 a33 = int_add(100, -4); +// require(a33 == 96); +// int256 a34 = int_add(100, -8); +// require(a34 == 92); +// int256 a35 = int_add(1000000000, -8); +// require(a35 == 999999992); +// int256 a36 = int_add(1000000000, -16); +// require(a36 == 999999984); +// int256 a37 = int_add(10000000000, -32); +// require(a37 == 9999999968); +// int256 a38 = int_add(100000000000000000000, -64); +// require(a38 == 99999999999999999936); +// int256 a39 = int_add(100000000000000000000000000000000000, -128); +// require(a39 == 99999999999999999999999999999999872); +// int256 a40 = int_add(1, -255); +// require(a40 == -254); +// } +// } + +// contract Sub { +// function sub(uint256 x, uint256 y) public returns (uint256) { +// return x - y; +// } + +// function int_sub(int256 x, int256 y) public returns (int256) { +// return x - y; +// } + +// function sub_conc() public returns (uint256) { +// uint256 a1 = sub(100, 1); +// require(a1 == 99); +// uint256 a2 = sub(100, 2); +// require(a2 == 98); +// uint256 a3 = sub(100, 4); +// require(a3 == 96); +// uint256 a4 = sub(100, 8); +// require(a4 == 92); +// uint256 a5 = sub(1000000000, 8); +// require(a5 == 999999992); +// uint256 a6 = sub(1000000000, 16); +// require(a6 == 999999984); +// uint256 a7 = sub(10000000000, 32); +// require(a7 == 9999999968); +// uint256 a8 = sub(100000000000000000000, 64); +// require(a8 == 99999999999999999936); +// uint256 a9 = sub(100000000000000000000000000000000000, 128); +// require(a9 == 99999999999999999999999999999999872); +// } + +// function int_sub_conc() public { +// int256 a1 = int_sub(100, 1); +// require(a1 == 99); +// int256 a2 = int_sub(100, 2); +// require(a2 == 98); +// int256 a3 = int_sub(100, 4); +// require(a3 == 96); +// int256 a4 = int_sub(100, 8); +// require(a4 == 92); +// int256 a5 = int_sub(1000000000, 8); +// require(a5 == 999999992); +// int256 a6 = int_sub(1000000000, 16); +// require(a6 == 999999984); +// int256 a7 = int_sub(10000000000, 32); +// require(a7 == 9999999968); +// int256 a8 = int_sub(100000000000000000000, 64); +// require(a8 == 99999999999999999936); +// int256 a9 = int_sub(100000000000000000000000000000000000, 128); +// require(a9 == 99999999999999999999999999999999872); +// int256 a10 = int_sub(1, 255); +// require(a10 == -254); + +// int256 a11 = int_sub(-100, 1); +// require(a11 == -101); +// int256 a12 = int_sub(-100, 2); +// require(a12 == -102); +// int256 a13 = int_sub(-100, 4); +// require(a13 == -104); +// int256 a14 = int_sub(-100, 8); +// require(a14 == -108); +// int256 a15 = int_sub(-1000000000, 8); +// require(a15 == -1000000008); +// int256 a16 = int_sub(-1000000000, 16); +// require(a16 == -1000000016); +// int256 a17 = int_sub(-10000000000, 32); +// require(a17 == -10000000032); +// int256 a18 = int_sub(-100000000000000000000, 64); +// require(a18 == -100000000000000000064); +// int256 a19 = int_sub(-100000000000000000000000000000000000, 128); +// require(a19 == -100000000000000000000000000000000128); +// int256 a20 = int_sub(-1, 255); +// require(a20 == -256); + +// int256 a21 = int_sub(-100, -1); +// require(a21 == -99); +// int256 a22 = int_sub(-100, -2); +// require(a22 == -98); +// int256 a23 = int_sub(-100, -4); +// require(a23 == -96); +// int256 a24 = int_sub(-100, -8); +// require(a24 == -92); +// int256 a25 = int_sub(-1000000000, -8); +// require(a25 == -999999992); +// int256 a26 = int_sub(-1000000000, -16); +// require(a26 == -999999984); +// int256 a27 = int_sub(-10000000000, -32); +// require(a27 == -9999999968); +// int256 a28 = int_sub(-100000000000000000000, -64); +// require(a28 == -99999999999999999936); +// int256 a29 = int_sub(-100000000000000000000000000000000000, -128); +// require(a29 == -99999999999999999999999999999999872); +// int256 a30 = int_sub(-1, -255); +// require(a30 == 254); + +// int256 a31 = int_sub(100, -1); +// require(a31 == 101); +// int256 a32 = int_sub(100, -2); +// require(a32 == 102); +// int256 a33 = int_sub(100, -4); +// require(a33 == 104); +// int256 a34 = int_sub(100, -8); +// require(a34 == 108); +// int256 a35 = int_sub(1000000000, -8); +// require(a35 == 1000000008); +// int256 a36 = int_sub(1000000000, -16); +// require(a36 == 1000000016); +// int256 a37 = int_sub(10000000000, -32); +// require(a37 == 10000000032); +// int256 a38 = int_sub(100000000000000000000, -64); +// require(a38 == 100000000000000000064); +// int256 a39 = int_sub(100000000000000000000000000000000000, -128); +// require(a39 == 100000000000000000000000000000000128); +// int256 a40 = int_sub(1, -255); +// require(a40 == 256); +// } +// } + +// contract AssignMath { +// function assignAdd(uint256 x) public { +// x += 10; +// } + +// function assignSub(uint256 x) public { +// x -= 10; +// } + +// function assignDiv(uint256 x) public { +// x /= 10; +// } + +// function assignMul(uint256 x) public { +// x *= 10; +// } + +// function preincrement(uint256 x) public returns (uint256, uint256) { +// uint256 y = ++x; +// return (y, x); +// } + +// function postincrement(uint256 x) public returns (uint256, uint256) { +// uint256 y = x++; +// return (y, x); +// } + +// function predecrement(uint256 x) public returns (uint256, uint256) { +// uint256 y = --x; +// return (y, x); +// } + +// function postdecrement(uint256 x) public returns (uint256, uint256) { +// uint256 y = x--; +// return (y, x); +// } + +// function pre_conc() public { +// (uint256 y, uint256 x) = preincrement(100); +// require(y == 101); +// require(x == 101); +// } + +// function post_conc() public { +// (uint256 y, uint256 x) = postincrement(100); +// require(y == 100); +// require(x == 101); +// } + +// function pre_deconc() public { +// (uint256 y, uint256 x) = predecrement(100); +// require(y == 99); +// require(x == 99); +// } + +// function post_deconc() public { +// (uint256 y, uint256 x) = postdecrement(100); +// require(y == 100); +// require(x == 99); +// } +// } + +// contract Math { +// function rmod(uint256 x, uint256 y) public returns (uint256) { +// return x % y; +// } + +// function rexp(uint256 x, uint256 y) public returns (uint256) { +// return x ** y; +// } + +// function int_rmod(int256 x, int256 y) public returns (int256) { +// return x % y; +// } + +// function int_rexp(int256 x, uint256 y) public returns (int256) { +// return x ** y; +// } +// } contract Unchecked { - function assemblyWrappingSub(uint256 a) public { - assembly { - a := sub(0, 100) - } - require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - int256 y = type(int256).min; - assembly { - a := sub(y, 100) - } - require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - } - - function uncheckedSub(uint256 a) public { + // function assemblyWrappingSub(uint256 a) public { + // assembly { + // a := sub(0, 100) + // } + // require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + // int256 y = type(int256).min; + // assembly { + // a := sub(y, 100) + // } + // require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + // } + + // function uncheckedSub(uint256 a) public { + // unchecked { + // a = 0 - 100; + // } + // require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + // int256 y = type(int256).min; + // unchecked { + // a = y - 100; + // } + // require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + // } + + function uncheckedSymbolicSub(uint256 a, uint256 b) public { unchecked { - a = 0 - 100; - } - require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - int256 y = type(int256).min; - unchecked { - a = y - 100; - } - require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - } - - function assemblyWrappingAdd(uint256 a) public { - uint256 m = type(uint256).max; - assembly { - a := add(m, 100) + a -= 100; } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); } - function uncheckedAdd(uint256 a) public { - unchecked { - a = type(uint256).max + 100; - } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); - } - - function assemblyWrappingMul(uint256 a) public { - uint256 m = type(uint128).max; - assembly { - a := mul(m, m) - } - require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - a /= 3; - a *= 3; - // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - } - - function uncheckedMul(uint256 a) public { - unchecked { - a = type(uint256).max + 100; - } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); - } + // function assemblyWrappingAdd(uint256 a) public { + // uint256 m = type(uint256).max; + // assembly { + // a := add(m, 100) + // } + // require(a == 99); + // a += (type(uint256).max - 99); + // require(a == type(uint256).max); + // } + + // function uncheckedAdd(uint256 a) public { + // unchecked { + // a = type(uint256).max + 100; + // } + // require(a == 99); + // a += (type(uint256).max - 99); + // require(a == type(uint256).max); + // } + + // function assemblyWrappingMul(uint256 a) public { + // uint256 m = type(uint128).max; + // assembly { + // a := mul(m, m) + // } + // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + // a /= 3; + // a *= 3; + // // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + // } + + // function uncheckedMul(uint256 a) public { + // unchecked { + // a = type(uint256).max + 100; + // } + // require(a == 99); + // a += (type(uint256).max - 99); + // require(a == type(uint256).max); + // } } \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/repros/issue69.sol b/crates/pyrometer/tests/test_data/repros/issue69.sol new file mode 100644 index 00000000..232cf4a4 --- /dev/null +++ b/crates/pyrometer/tests/test_data/repros/issue69.sol @@ -0,0 +1,15 @@ +contract SymbolicTest { + // https://github.com/foundry-rs/foundry/issues/2851 + function backdoor(uint256 x) external pure { + uint256 number = 99; + unchecked { + uint256 z = x - 1; + if (z == 6912213124124531) { + number = 0; + } else { + number = 1; + } + } + assert(number != 0); + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 9cb83558..5a0579b4 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1332,7 +1332,7 @@ pub trait ContextBuilder: ); let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; - + new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = rhs_cvar.tmp_of(self).into_expr_err(loc)?; if lhs_cvar.is_storage(self).into_expr_err(loc)? { self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); } From 450dc5b8e689f5784d61550cc2c18ba3cf5a646b Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 11:27:28 -0800 Subject: [PATCH 22/71] lint --- crates/graph/src/nodes/context/solving.rs | 6 ++++- crates/graph/src/nodes/context/var/typing.rs | 22 +++++++++---------- crates/graph/src/range/exec/exec_op.rs | 22 +++++++++---------- .../src/context_builder/mod.rs | 3 ++- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 390a2efb..130d3609 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -79,7 +79,11 @@ impl ContextNode { dep: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { - tracing::trace!("Adding ctx dependency: {}, is_controllable: {}", dep.display_name(analyzer)?, dep.is_controllable(analyzer)?); + tracing::trace!( + "Adding ctx dependency: {}, is_controllable: {}", + dep.display_name(analyzer)?, + dep.is_controllable(analyzer)? + ); if dep.is_controllable(analyzer)? { let range = dep.ref_range(analyzer)?.unwrap(); let r = range.into_flattened_range(analyzer)?; diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index ce9d4340..c6938f4f 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -57,10 +57,7 @@ impl ContextVarNode { Ok(global_first.is_storage(analyzer)? || global_first.is_calldata_input(analyzer)) } - pub fn is_fundamental( - &self, - analyzer: &impl GraphBackend, - ) -> Result { + pub fn is_fundamental(&self, analyzer: &impl GraphBackend) -> Result { let global_first = self.global_first_version(analyzer); let is_independent = self.is_independent(analyzer)?; @@ -86,13 +83,16 @@ impl ContextVarNode { } pub fn is_controllable(&self, analyzer: &impl GraphBackend) -> Result { - Ok(self.dependent_on(analyzer, true)?.iter().any(|dependent_on| { - if let Ok(t) = dependent_on.is_fundamental(analyzer) { - t - } else { - false - } - })) + Ok(self + .dependent_on(analyzer, true)? + .iter() + .any(|dependent_on| { + if let Ok(t) = dependent_on.is_fundamental(analyzer) { + t + } else { + false + } + })) } pub fn is_calldata_input(&self, analyzer: &impl GraphBackend) -> bool { diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index e68d9b47..ef720173 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -227,9 +227,9 @@ impl ExecOp for RangeExpr { // contains the rhs, we can add zero. Futher more, if // the lhs contains rhs - 1, we can add max as it // would overflow to uint256.max - // zero min max uint256.max + // zero min max uint256.max // lhs: | - - |----------------------------| - - | - // rhs: | - - |--| - - - - - - - - - - - - - - - | + // rhs: | - - |--| - - - - - - - - - - - - - - - | match lhs_max.range_ord(&rhs_min) { Some(std::cmp::Ordering::Less) => { // We are going to overflow, zero not possible @@ -237,7 +237,7 @@ impl ExecOp for RangeExpr { Some(std::cmp::Ordering::Equal) => { // We are going to at least be zero, // we may overflow. check if rhs is const, otherwise - // add uint256.max as a candidate + // add uint256.max as a candidate candidates.push(Some(zero.clone())); if !consts.1 { candidates.push(zero.range_wrapping_sub(&one)); @@ -254,7 +254,7 @@ impl ExecOp for RangeExpr { Some(std::cmp::Ordering::Equal) => { // We are going to at least be zero, // we may overflow. check if rhs is const, otherwise - // add uint256.max as a candidate + // add uint256.max as a candidate candidates.push(Some(zero.clone())); if !consts.1 { candidates.push(zero.range_wrapping_sub(&one)); @@ -262,13 +262,13 @@ impl ExecOp for RangeExpr { } Some(std::cmp::Ordering::Greater) => { // current info: - // zero min max uint256.max + // zero min max uint256.max // lhs: | - - |----------------------------| - - | // rhs: | - |----? - - - - - - - - - - - - - - - | // figure out where rhs max is match lhs_min.range_ord(&rhs_max) { Some(std::cmp::Ordering::Less) => { - // zero min + // zero min // lhs: | - - |---? // rhs: | - |----| // min max @@ -277,21 +277,21 @@ impl ExecOp for RangeExpr { candidates.push(zero.range_wrapping_sub(&one)); } Some(std::cmp::Ordering::Equal) => { - // zero min + // zero min // lhs: | - - |---? // rhs: | |---| // min max // Add zero - candidates.push(Some(zero.clone())); + candidates.push(Some(zero.clone())); } Some(std::cmp::Ordering::Greater) => { - // zero min + // zero min // lhs: | - - |---? // rhs: |-----| // min max // Add nothing - } - _ => {} + } + _ => {} } } _ => {} diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 5a0579b4..a2aadafd 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1332,7 +1332,8 @@ pub trait ContextBuilder: ); let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; - new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = rhs_cvar.tmp_of(self).into_expr_err(loc)?; + new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = + rhs_cvar.tmp_of(self).into_expr_err(loc)?; if lhs_cvar.is_storage(self).into_expr_err(loc)? { self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); } From 125bdfe0d71926471dd49f50389e2fb54d333235 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 11:48:15 -0800 Subject: [PATCH 23/71] fix issue 66 When referencing a variable in yul, if the variable is memory based, convert it into the memory offset --- crates/graph/src/nodes/context/var/typing.rs | 7 +++++++ .../tests/test_data/repros/issue66.sol | 14 +++++++++++++ crates/solc-expressions/src/yul/mod.rs | 20 ++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 crates/pyrometer/tests/test_data/repros/issue66.sol diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index c6938f4f..beeb82a7 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -32,6 +32,13 @@ impl ContextVarNode { )) } + pub fn is_memory(&self, analyzer: &impl GraphBackend) -> Result { + Ok(matches!( + self.underlying(analyzer)?.storage, + Some(StorageLocation::Memory(..)) + )) + } + pub fn is_return_assignment(&self, analyzer: &impl GraphBackend) -> bool { analyzer .graph() diff --git a/crates/pyrometer/tests/test_data/repros/issue66.sol b/crates/pyrometer/tests/test_data/repros/issue66.sol new file mode 100644 index 00000000..27c784c9 --- /dev/null +++ b/crates/pyrometer/tests/test_data/repros/issue66.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.8.19; + +contract Foo { + struct Struct { + uint32 a; + } + + function foo() public { + Struct memory data; + assembly { + let x := eq(data, 0xFF) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index ddcba561..cacb53f2 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -277,7 +277,25 @@ pub trait YulBuilder: HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), - Variable(ident) => self.variable(ident, ctx, None), + Variable(ident) => { + self.variable(ident, ctx, None)?; + self.apply_to_edges(ctx, ident.loc, &|analyzer, edge_ctx, loc| { + if let Some(ret) = edge_ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { + if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?).is_memory(analyzer).into_expr_err(loc)? { + // its a memory based variable, push a uint instead + let b = Builtin::Uint(256); + let var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) + .into_expr_err(loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + edge_ctx.push_expr(ExprRet::Single(node), analyzer).into_expr_err(loc) + } else { + edge_ctx.push_expr(ret, analyzer).into_expr_err(loc) + } + } else { + panic!("No variable?") + } + }) + }, FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( expr.loc(), From 7add13e48360386bd575832034fd4b6d01dabc33 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 12:22:33 -0800 Subject: [PATCH 24/71] improve mistyped variable name error --- crates/cli/src/main.rs | 2 +- crates/graph/src/graph_elements.rs | 2 ++ crates/graph/src/nodes/block.rs | 1 + crates/graph/src/nodes/builtin.rs | 1 + crates/graph/src/nodes/concrete.rs | 1 + crates/graph/src/nodes/context/node.rs | 2 ++ crates/graph/src/nodes/context/var/node.rs | 2 ++ crates/graph/src/nodes/contract_ty.rs | 1 + crates/graph/src/nodes/enum_ty.rs | 1 + crates/graph/src/nodes/err_ty.rs | 1 + crates/graph/src/nodes/func_ty.rs | 4 ++++ crates/graph/src/nodes/msg.rs | 1 + crates/graph/src/nodes/struct_ty.rs | 2 ++ crates/graph/src/nodes/ty_ty.rs | 1 + crates/graph/src/nodes/var_ty.rs | 2 ++ crates/solc-expressions/src/lib.rs | 2 ++ crates/solc-expressions/src/yul/mod.rs | 8 +++++++- 17 files changed, 32 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index a92b8408..4a88654b 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -252,7 +252,7 @@ fn main() { // analyzer.print_errors(&file_mapping, &mut source_map); // let t = petgraph::algo::toposort(&analyzer.graph, None); - // analyzer.print_errors(&file_mapping, &mut source_map); + analyzer.print_errors(&file_mapping, &mut source_map); if args.open_dot { analyzer.open_dot() diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 73cd06ca..a007ab3a 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -44,6 +44,8 @@ pub enum GraphError { StackLengthMismatch(String), /// A variable had a cyclic reference to another variable and we were unable to break the cycle UnbreakableRecursion(String), + /// The analyzer thought the node was suppose to be one type, but it was a different one + UnknownVariable(String), } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/graph/src/nodes/block.rs b/crates/graph/src/nodes/block.rs index be71be01..92c0211f 100644 --- a/crates/graph/src/nodes/block.rs +++ b/crates/graph/src/nodes/block.rs @@ -12,6 +12,7 @@ impl BlockNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Block, GraphError> { match analyzer.node(*self) { Node::Block(st) => Ok(st), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Msg but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 0dde90b4..709637c4 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -18,6 +18,7 @@ impl BuiltInNode { ) -> Result<&'a Builtin, GraphError> { match analyzer.node(*self) { Node::Builtin(b) => Ok(b), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Builtin but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index c8d4452d..7cbcc5de 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -15,6 +15,7 @@ impl ConcreteNode { ) -> Result<&'a Concrete, GraphError> { match analyzer.node(*self) { Node::Concrete(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Concrete but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index e01331e2..97c7cbf6 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -54,6 +54,7 @@ impl ContextNode { ) -> Result<&'a mut Context, GraphError> { match analyzer.node_mut(*self) { Node::Context(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Context but it was: {e:?}" ))), @@ -67,6 +68,7 @@ impl ContextNode { ) -> Result<&'a Context, GraphError> { match analyzer.node(*self) { Node::Context(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Context but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 9254c003..fe22680e 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -63,6 +63,7 @@ impl ContextVarNode { ) -> Result<&'a ContextVar, GraphError> { match analyzer.node(*self) { Node::ContextVar(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be ContextVar but it was: {e:?}" ))), @@ -75,6 +76,7 @@ impl ContextVarNode { ) -> Result<&'a mut ContextVar, GraphError> { match analyzer.node_mut(*self) { Node::ContextVar(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be ContextVar but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 2098ea69..4210b53e 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -36,6 +36,7 @@ impl ContractNode { ) -> Result<&'a Contract, GraphError> { match analyzer.node(*self) { Node::Contract(contract) => Ok(contract), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Contract but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs index 869547cb..297e0c34 100644 --- a/crates/graph/src/nodes/enum_ty.rs +++ b/crates/graph/src/nodes/enum_ty.rs @@ -29,6 +29,7 @@ impl EnumNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Enum, GraphError> { match analyzer.node(*self) { Node::Enum(e) => Ok(e), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Contract but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs index af98f7d3..c5ae8de0 100644 --- a/crates/graph/src/nodes/err_ty.rs +++ b/crates/graph/src/nodes/err_ty.rs @@ -9,6 +9,7 @@ impl ErrorNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Error, GraphError> { match analyzer.node(*self) { Node::Error(err) => Ok(err), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 06b110b2..6bb637b8 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -25,6 +25,7 @@ impl FunctionNode { ) -> Result<&'a Function, GraphError> { match analyzer.node(*self) { Node::Function(func) => Ok(func), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Function but it was: {e:?}" ))), @@ -95,6 +96,7 @@ impl FunctionNode { ) -> Result<&'a mut Function, GraphError> { match analyzer.node_mut(*self) { Node::Function(func) => Ok(func), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Function but it was: {e:?}" ))), @@ -700,6 +702,7 @@ impl FunctionParamNode { ) -> Result<&'a FunctionParam, GraphError> { match analyzer.node(*self) { Node::FunctionParam(param) => Ok(param), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be FunctionParam but it was: {e:?}" ))), @@ -822,6 +825,7 @@ impl FunctionReturnNode { ) -> Result<&'a FunctionReturn, GraphError> { match analyzer.node(*self) { Node::FunctionReturn(ret) => Ok(ret), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be FunctionReturn but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index 4e1966a8..2e8aac4a 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -15,6 +15,7 @@ impl MsgNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Msg, GraphError> { match analyzer.node(*self) { Node::Msg(st) => Ok(st), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Msg but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index 2d4409bc..ecddfe55 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -15,6 +15,7 @@ impl StructNode { ) -> Result<&'a Struct, GraphError> { match analyzer.node(*self) { Node::Struct(st) => Ok(st), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Struct but it was: {e:?}" ))), @@ -127,6 +128,7 @@ impl FieldNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Field, GraphError> { match analyzer.node(*self) { Node::Field(field) => Ok(field), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Field but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs index ceb30563..a86a499d 100644 --- a/crates/graph/src/nodes/ty_ty.rs +++ b/crates/graph/src/nodes/ty_ty.rs @@ -10,6 +10,7 @@ impl TyNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Ty, GraphError> { match analyzer.node(*self) { Node::Ty(ty) => Ok(ty), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be TypeNode but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 794b595d..aa2337b6 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -17,6 +17,7 @@ impl VarNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Var, GraphError> { match analyzer.node(*self) { Node::Var(func) => Ok(func), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), @@ -29,6 +30,7 @@ impl VarNode { ) -> Result<&'a mut Var, GraphError> { match analyzer.node_mut(*self) { Node::Var(func) => Ok(func), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index 5c25648a..b3e4ace9 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -148,6 +148,7 @@ impl ExprErr { GraphError(_loc, graph::GraphError::ExpectedSingle(msg), ..) => msg, GraphError(_loc, graph::GraphError::StackLengthMismatch(msg), ..) => msg, GraphError(_loc, graph::GraphError::UnbreakableRecursion(msg), ..) => msg, + GraphError(_loc, graph::GraphError::UnknownVariable(msg), ..) => msg, } } @@ -184,6 +185,7 @@ impl ExprErr { GraphError(_loc, graph::GraphError::ExpectedSingle(_), ..) => "Graph IR Error: Expecting single expression return, got multiple. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", GraphError(_loc, graph::GraphError::StackLengthMismatch(_), ..) => "Graph IR Error: Expected a particular number of elements on the context stack but found a different amount. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", GraphError(_loc, graph::GraphError::UnbreakableRecursion(_), ..) => "Graph IR Error: Unbreakable recursion in variable range. This is potentially a bug. Please report it at https://github.com/nascentxyz/pyrometer", + GraphError(_loc, graph::GraphError::UnknownVariable(_), ..) => "Graph IR Error: Unknown variable. This is potentially a bug, but more likely a variable name is mistyped.", } } } diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index cacb53f2..95a963a3 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -292,7 +292,13 @@ pub trait YulBuilder: edge_ctx.push_expr(ret, analyzer).into_expr_err(loc) } } else { - panic!("No variable?") + Err(ExprErr::Unresolved( + ident.loc, + format!( + "Could not find variable with name: {}", + ident.name + ), + )) } }) }, From 1fa67305d3753e8c6436036f73765638cb61ae88 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 12:22:56 -0800 Subject: [PATCH 25/71] lint --- crates/graph/src/nodes/block.rs | 5 ++++- crates/graph/src/nodes/builtin.rs | 5 ++++- crates/graph/src/nodes/concrete.rs | 5 ++++- crates/graph/src/nodes/context/node.rs | 10 +++++++-- crates/graph/src/nodes/context/var/node.rs | 10 +++++++-- crates/graph/src/nodes/contract_ty.rs | 5 ++++- crates/graph/src/nodes/enum_ty.rs | 5 ++++- crates/graph/src/nodes/err_ty.rs | 5 ++++- crates/graph/src/nodes/func_ty.rs | 20 ++++++++++++++---- crates/graph/src/nodes/msg.rs | 5 ++++- crates/graph/src/nodes/struct_ty.rs | 10 +++++++-- crates/graph/src/nodes/ty_ty.rs | 5 ++++- crates/graph/src/nodes/var_ty.rs | 10 +++++++-- crates/solc-expressions/src/yul/mod.rs | 24 ++++++++++++++-------- 14 files changed, 95 insertions(+), 29 deletions(-) diff --git a/crates/graph/src/nodes/block.rs b/crates/graph/src/nodes/block.rs index 92c0211f..ded6ebc3 100644 --- a/crates/graph/src/nodes/block.rs +++ b/crates/graph/src/nodes/block.rs @@ -12,7 +12,10 @@ impl BlockNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Block, GraphError> { match analyzer.node(*self) { Node::Block(st) => Ok(st), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Msg but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 709637c4..9f90d80c 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -18,7 +18,10 @@ impl BuiltInNode { ) -> Result<&'a Builtin, GraphError> { match analyzer.node(*self) { Node::Builtin(b) => Ok(b), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Builtin but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 7cbcc5de..828c1218 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -15,7 +15,10 @@ impl ConcreteNode { ) -> Result<&'a Concrete, GraphError> { match analyzer.node(*self) { Node::Concrete(c) => Ok(c), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Concrete but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 97c7cbf6..26fc48bc 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -54,7 +54,10 @@ impl ContextNode { ) -> Result<&'a mut Context, GraphError> { match analyzer.node_mut(*self) { Node::Context(c) => Ok(c), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Context but it was: {e:?}" ))), @@ -68,7 +71,10 @@ impl ContextNode { ) -> Result<&'a Context, GraphError> { match analyzer.node(*self) { Node::Context(c) => Ok(c), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Context but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index fe22680e..a9b340b0 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -63,7 +63,10 @@ impl ContextVarNode { ) -> Result<&'a ContextVar, GraphError> { match analyzer.node(*self) { Node::ContextVar(c) => Ok(c), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be ContextVar but it was: {e:?}" ))), @@ -76,7 +79,10 @@ impl ContextVarNode { ) -> Result<&'a mut ContextVar, GraphError> { match analyzer.node_mut(*self) { Node::ContextVar(c) => Ok(c), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be ContextVar but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 4210b53e..0504365c 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -36,7 +36,10 @@ impl ContractNode { ) -> Result<&'a Contract, GraphError> { match analyzer.node(*self) { Node::Contract(contract) => Ok(contract), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Contract but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs index 297e0c34..dbd835ff 100644 --- a/crates/graph/src/nodes/enum_ty.rs +++ b/crates/graph/src/nodes/enum_ty.rs @@ -29,7 +29,10 @@ impl EnumNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Enum, GraphError> { match analyzer.node(*self) { Node::Enum(e) => Ok(e), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Contract but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs index c5ae8de0..2630b4f3 100644 --- a/crates/graph/src/nodes/err_ty.rs +++ b/crates/graph/src/nodes/err_ty.rs @@ -9,7 +9,10 @@ impl ErrorNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Error, GraphError> { match analyzer.node(*self) { Node::Error(err) => Ok(err), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 6bb637b8..47ce9c9f 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -25,7 +25,10 @@ impl FunctionNode { ) -> Result<&'a Function, GraphError> { match analyzer.node(*self) { Node::Function(func) => Ok(func), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Function but it was: {e:?}" ))), @@ -96,7 +99,10 @@ impl FunctionNode { ) -> Result<&'a mut Function, GraphError> { match analyzer.node_mut(*self) { Node::Function(func) => Ok(func), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Function but it was: {e:?}" ))), @@ -702,7 +708,10 @@ impl FunctionParamNode { ) -> Result<&'a FunctionParam, GraphError> { match analyzer.node(*self) { Node::FunctionParam(param) => Ok(param), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be FunctionParam but it was: {e:?}" ))), @@ -825,7 +834,10 @@ impl FunctionReturnNode { ) -> Result<&'a FunctionReturn, GraphError> { match analyzer.node(*self) { Node::FunctionReturn(ret) => Ok(ret), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be FunctionReturn but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index 2e8aac4a..2b1cb310 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -15,7 +15,10 @@ impl MsgNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Msg, GraphError> { match analyzer.node(*self) { Node::Msg(st) => Ok(st), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Msg but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index ecddfe55..c10596be 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -15,7 +15,10 @@ impl StructNode { ) -> Result<&'a Struct, GraphError> { match analyzer.node(*self) { Node::Struct(st) => Ok(st), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Struct but it was: {e:?}" ))), @@ -128,7 +131,10 @@ impl FieldNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Field, GraphError> { match analyzer.node(*self) { Node::Field(field) => Ok(field), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Field but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs index a86a499d..95ff78c4 100644 --- a/crates/graph/src/nodes/ty_ty.rs +++ b/crates/graph/src/nodes/ty_ty.rs @@ -10,7 +10,10 @@ impl TyNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Ty, GraphError> { match analyzer.node(*self) { Node::Ty(ty) => Ok(ty), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be TypeNode but it was: {e:?}" ))), diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index aa2337b6..19bd5c6c 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -17,7 +17,10 @@ impl VarNode { pub fn underlying<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Var, GraphError> { match analyzer.node(*self) { Node::Var(func) => Ok(func), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), @@ -30,7 +33,10 @@ impl VarNode { ) -> Result<&'a mut Var, GraphError> { match analyzer.node_mut(*self) { Node::Var(func) => Ok(func), - Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!("Could not find variable: {}", ident.name))), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), e => Err(GraphError::NodeConfusion(format!( "Node type confusion: expected node to be Var but it was: {e:?}" ))), diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index 95a963a3..a6eb5228 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -281,27 +281,33 @@ pub trait YulBuilder: self.variable(ident, ctx, None)?; self.apply_to_edges(ctx, ident.loc, &|analyzer, edge_ctx, loc| { if let Some(ret) = edge_ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { - if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?).is_memory(analyzer).into_expr_err(loc)? { + if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?) + .is_memory(analyzer) + .into_expr_err(loc)? + { // its a memory based variable, push a uint instead let b = Builtin::Uint(256); - let var = ContextVar::new_from_builtin(loc, analyzer.builtin_or_add(b).into(), analyzer) - .into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; let node = analyzer.add_node(Node::ContextVar(var)); - edge_ctx.push_expr(ExprRet::Single(node), analyzer).into_expr_err(loc) + edge_ctx + .push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) } else { edge_ctx.push_expr(ret, analyzer).into_expr_err(loc) } } else { Err(ExprErr::Unresolved( ident.loc, - format!( - "Could not find variable with name: {}", - ident.name - ), + format!("Could not find variable with name: {}", ident.name), )) } }) - }, + } FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( expr.loc(), From fda559be3d8b14d8de56efa21c9a18647bc0ec7d Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 21:28:54 -0800 Subject: [PATCH 26/71] fixes #51 We were creating a recursive range, this fixes that by removing calls to `update_deps` which was pointless anyways --- crates/graph/src/nodes/context/var/ranging.rs | 22 +- crates/graph/src/nodes/context/variables.rs | 1 + crates/graph/src/range/elem/concrete.rs | 6 + crates/graph/src/range/elem/elem_enum.rs | 20 + crates/graph/src/range/elem/elem_trait.rs | 4 + crates/graph/src/range/elem/expr.rs | 13 + crates/graph/src/range/elem/map_or_array.rs | 36 + crates/graph/src/range/elem/reference.rs | 24 + crates/graph/src/range/solc_range.rs | 14 + crates/pyrometer/tests/test_data/loops.sol | 28 + crates/pyrometer/tests/test_data/math.sol | 1232 ++++++++--------- crates/pyrometer/tests/test_data/require.sol | 4 - crates/solc-expressions/src/bin_op.rs | 19 +- .../src/context_builder/mod.rs | 39 +- .../src/func_call/intrinsic_call.rs | 9 +- crates/solc-expressions/src/require.rs | 54 +- 16 files changed, 851 insertions(+), 674 deletions(-) diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 504ae6f2..16ba76d5 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeSet; use crate::{ nodes::{Concrete, ContextNode, ContextVarNode}, range::{range_string::ToRangeString, Range}, @@ -145,7 +146,8 @@ impl ContextVarNode { analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_min: Elem, ) -> Result<(), GraphError> { - if new_min.contains_node((*self).into()) { + assert!(self.latest_version(analyzer) == *self); + if new_min.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_or_inherited_version(analyzer) { new_min.filter_recursion((*self).into(), prev.into()); } else { @@ -154,11 +156,12 @@ impl ContextVarNode { } tracing::trace!( - "setting range minimum: {} (node idx: {}), current:\n{:#?}, new_min:\n{:#?}", + "setting range minimum: {} (node idx: {}), current:{}, new_min:{}, deps: {:#?}", self.display_name(analyzer)?, self.0, - self.range_min(analyzer)?, - new_min + self.range_min(analyzer)?.unwrap(), + new_min, + new_min.recursive_dependent_on(analyzer)? ); if self.is_concrete(analyzer)? { @@ -185,14 +188,15 @@ impl ContextVarNode { analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_max: Elem, ) -> Result<(), GraphError> { - if new_max.contains_node((*self).into()) { + assert!(self.latest_version(analyzer) == *self); + if new_max.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_or_inherited_version(analyzer) { new_max.filter_recursion((*self).into(), prev.into()); } } tracing::trace!( - "setting range maximum: {:?}, {}, current:\n{:#?}, new:\n{:#?}", + "setting range maximum: {:?}, {}, current: {}, new: {:#?}", self, self.display_name(analyzer)?, self.ref_range(analyzer)?.unwrap().range_max(), // .unwrap() @@ -239,7 +243,8 @@ impl ContextVarNode { analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_min: Elem, ) -> Result { - if new_min.contains_node((*self).into()) { + assert!(self.latest_version(analyzer) == *self); + if new_min.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_version(analyzer) { new_min.filter_recursion((*self).into(), prev.into()); } @@ -267,7 +272,8 @@ impl ContextVarNode { analyzer: &mut (impl GraphBackend + AnalyzerBackend), mut new_max: Elem, ) -> Result { - if new_max.contains_node((*self).into()) { + assert!(self.latest_version(analyzer) == *self); + if new_max.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_version(analyzer) { new_max.filter_recursion((*self).into(), prev.into()); } diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index e4d29266..e5e26462 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -201,6 +201,7 @@ impl ContextNode { loc: Loc, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { + let var = var.latest_version(analyzer); if let Some(ctx) = var.maybe_ctx(analyzer) { if ctx != *self { let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 37e3c6ff..d264ee6a 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -32,6 +32,10 @@ impl RangeElem for RangeConcrete { // Elem::Concrete(self.clone()) // } + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + Ok(false) + } + fn flatten( &self, _maximize: bool, @@ -153,4 +157,6 @@ impl RangeElem for RangeConcrete { ) -> Result { Ok(false) } + + fn recursive_dependent_on(&self, _: &impl GraphBackend) -> Result, GraphError> { Ok(vec![]) } } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 03f8e358..9bf8cdf2 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -411,6 +411,26 @@ impl RangeElem for Elem { } } + fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + match self { + Self::Reference(d) => d.recursive_dependent_on(analyzer), + Self::Concrete(_) => Ok(vec![]), + Self::Expr(expr) => expr.recursive_dependent_on(analyzer), + Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer), + Self::Null => Ok(vec![]), + } + } + + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + match self { + Self::Reference(d) => d.has_cycle(seen, analyzer), + Self::Concrete(_) => Ok(false), + Self::Expr(expr) => expr.has_cycle(seen, analyzer), + Self::ConcreteDyn(d) => d.has_cycle(seen, analyzer), + Self::Null => Ok(false), + } + } + fn update_deps(&mut self, mapping: &BTreeMap) { match self { Self::Reference(d) => d.update_deps(mapping), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 966b0a36..c01eaffc 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -52,6 +52,10 @@ pub trait RangeElem { /// Traverses the range expression and finds all nodes that are dynamically pointed to /// and returns it in a vector. fn dependent_on(&self) -> Vec; + + fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result; /// Traverses the range expression and updates stale pointers from older versions /// of a variable to a newer version. /// diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index e8c6aa1c..40e3030d 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -99,6 +99,7 @@ impl RangeElem for RangeExpr { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + // println!("flattening expr: {}", Elem::Expr(self.clone())); Ok(Elem::Expr(RangeExpr::new( self.lhs.flatten(maximize, analyzer)?, self.op, @@ -116,6 +117,18 @@ impl RangeElem for RangeExpr { deps } + fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut deps = self.lhs.recursive_dependent_on(analyzer)?; + deps.extend(self.rhs.recursive_dependent_on(analyzer)?); + Ok(deps) + } + + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + let lhs_has_cycle = self.lhs.has_cycle(seen, analyzer)?; + let rhs_has_cycle = self.rhs.has_cycle(seen, analyzer)?; + Ok(lhs_has_cycle || rhs_has_cycle) + } + fn update_deps(&mut self, mapping: &BTreeMap) { self.lhs.update_deps(mapping); self.rhs.update_deps(mapping); diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 66a7b028..96996ad3 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -59,11 +59,47 @@ impl RangeElem for RangeDyn { deps } + fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut deps: Vec = self.len.recursive_dependent_on(analyzer)?; + deps.extend( + self.val + .values() + .map(|val| val.recursive_dependent_on(analyzer)) + .collect::>, _>>()? + .iter() + .flatten() + .collect::>() + ); + deps.extend( + self.val + .keys() + .map(|key| key.recursive_dependent_on(analyzer)) + .collect::>, _>>()? + .iter() + .flatten() + .collect::>() + ); + Ok(deps) + } + + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + let mut has_cycle = false; + has_cycle = has_cycle || self.len.has_cycle(seen, analyzer)?; + self.val + .iter() + .try_for_each(|(_, val)| { + has_cycle = has_cycle || val.has_cycle(seen, analyzer)?; + Ok(()) + })?; + Ok(has_cycle) + } + fn flatten( &self, maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + // println!("flattening range dyn"); Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, maximized: None, diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 5b65d34f..beb15b7c 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -52,6 +52,29 @@ impl RangeElem for Reference { fn dependent_on(&self) -> Vec { vec![self.idx.into()] } + + fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut deps = ContextVarNode(self.idx.index()).dependent_on(analyzer, true)?; + deps.push(ContextVarNode(self.idx.index())); + Ok(deps) + } + + fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + let cvar = ContextVarNode::from(self.idx); + let mut has_cycle = false; + if seen.contains(&cvar) { + Ok(true) + } else { + seen.push(cvar); + if let Some(range) = cvar.ref_range(analyzer)? { + has_cycle = has_cycle || range.min.has_cycle(seen, analyzer)?; + has_cycle = has_cycle || range.max.has_cycle(seen, analyzer)?; + Ok(has_cycle) + } else { + Ok(false) + } + } + } fn update_deps(&mut self, mapping: &BTreeMap) { if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { @@ -65,6 +88,7 @@ impl RangeElem for Reference { analyzer: &impl GraphBackend, ) -> Result, GraphError> { let cvar = ContextVarNode::from(self.idx); + // println!("flattening reference: {} (idx_{})", cvar.display_name(analyzer)?, self.idx.index()); if cvar.is_fundamental(analyzer)? { return Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 83593952..a981154f 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -67,6 +67,14 @@ impl SolcRange { deps.into_iter().map(ContextVarNode::from).collect() } + pub fn recursive_dependent_on(&self, analyzer: &impl GraphBackend,) -> Result, GraphError> { + let mut deps = self.range_min().recursive_dependent_on(analyzer)?; + deps.extend(self.range_max().recursive_dependent_on(analyzer)?); + deps.dedup(); + + Ok(deps) + } + /// Update a particular context variable with the latest version pub fn update_deps( &mut self, @@ -74,19 +82,25 @@ impl SolcRange { ctx: ContextNode, analyzer: &impl GraphBackend, ) { + assert!(node.latest_version(analyzer) == node); let deps = self.dependent_on(); let mapping: BTreeMap = deps .into_iter() .filter(|dep| !dep.is_const(analyzer).unwrap()) .map(|dep| { let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); + // let dep_depends_on_node = dep.range(analyzer).unwrap().unwrap().recursive_dependent_on(analyzer).unwrap(); + // let dep_depends_on_node = dep_depends_on_node.contains(&node) || dep_depends_on_node.contains(&); if latest == node { if let Some(prev) = latest.previous_version(analyzer) { + println!("replacing: {} with {}", dep.0, prev.0); (dep, prev) } else { + println!("replacing: {} with {}", dep.0, dep.0); (dep, dep) } } else { + println!("replacing: {} with {}", dep.0, latest.0); (dep, latest) } }) diff --git a/crates/pyrometer/tests/test_data/loops.sol b/crates/pyrometer/tests/test_data/loops.sol index f644e12c..a2e5715d 100644 --- a/crates/pyrometer/tests/test_data/loops.sol +++ b/crates/pyrometer/tests/test_data/loops.sol @@ -28,4 +28,32 @@ contract For { require(x == 10); return x; } + + function complicated_while_loop(uint256 amount) public returns (uint256) { + uint256 x = amount; + amount -= x; + return amount; + // uint256 balance = 1; + // uint256 amountToRedeem; + // if (amount > balance) { + // amountToRedeem = balance; + // } else { + // amountToRedeem = amount; + // } + // amount -= amountToRedeem; + + // return amount; + } + + function loop_op_assign(uint256 value) internal pure { + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + } } + + + diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index 2acbf8d6..efaa8712 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -1,583 +1,583 @@ -// contract Div { -// function div(uint256 x, uint256 y) public returns (uint256) { -// return x / y; -// } - -// function int_div(int256 x, int256 y) public returns (int256) { -// return x / y; -// } - -// function div_conc() public returns (uint256) { -// uint256 a1 = div(100, 1); -// require(a1 == 100); -// uint256 a2 = div(100, 2); -// require(a2 == 50); -// uint256 a3 = div(100, 4); -// require(a3 == 25); -// uint256 a4 = div(100, 8); -// require(a4 == 12); -// uint256 a5 = div(1000000000, 8); -// require(a5 == 125000000); -// uint256 a6 = div(1000000000, 16); -// require(a6 == 62500000); -// uint256 a7 = div(10000000000, 32); -// require(a7 == 312500000); -// uint256 a8 = div(100000000000000000000, 64); -// require(a8 == 1562500000000000000); -// uint256 a9 = div(100000000000000000000000000000000000, 128); -// require(a9 == 781250000000000000000000000000000); -// uint256 a10 = div(1, 255); -// require(a10 == 0); -// } - -// function int_div_conc() public { -// int256 a1 = int_div(100, 1); -// require(a1 == 100); -// int256 a2 = int_div(100, 2); -// require(a2 == 50); -// int256 a3 = int_div(100, 4); -// require(a3 == 25); -// int256 a4 = int_div(100, 8); -// require(a4 == 12); -// int256 a5 = int_div(1000000000, 8); -// require(a5 == 125000000); -// int256 a6 = int_div(1000000000, 16); -// require(a6 == 62500000); -// int256 a7 = int_div(10000000000, 32); -// require(a7 == 312500000); -// int256 a8 = int_div(100000000000000000000, 64); -// require(a8 == 1562500000000000000); -// int256 a9 = int_div(100000000000000000000000000000000000, 128); -// require(a9 == 781250000000000000000000000000000); -// int256 a10 = int_div(1, 255); -// require(a10 == 0); - -// int256 a11 = int_div(-100, 1); -// require(a11 == -100); -// int256 a12 = int_div(-100, 2); -// require(a12 == -50); -// int256 a13 = int_div(-100, 4); -// require(a13 == -25); -// int256 a14 = int_div(-100, 8); -// require(a14 == -12); -// int256 a15 = int_div(-1000000000, 8); -// require(a15 == -125000000); -// int256 a16 = int_div(-1000000000, 16); -// require(a16 == -62500000); -// int256 a17 = int_div(-10000000000, 32); -// require(a17 == -312500000); -// int256 a18 = int_div(-100000000000000000000, 64); -// require(a18 == -1562500000000000000); -// int256 a19 = int_div(-100000000000000000000000000000000000, 128); -// require(a19 == -781250000000000000000000000000000); -// int256 a20 = int_div(-1, 255); -// require(a20 == 0); - -// int256 a21 = int_div(-100, -1); -// require(a21 == 100); -// int256 a22 = int_div(-100, -2); -// require(a22 == 50); -// int256 a23 = int_div(-100, -4); -// require(a23 == 25); -// int256 a24 = int_div(-100, -8); -// require(a24 == 12); -// int256 a25 = int_div(-1000000000, -8); -// require(a25 == 125000000); -// int256 a26 = int_div(-1000000000, -16); -// require(a26 == 62500000); -// int256 a27 = int_div(-10000000000, -32); -// require(a27 == 312500000); -// int256 a28 = int_div(-100000000000000000000, -64); -// require(a28 == 1562500000000000000); -// int256 a29 = int_div(-100000000000000000000000000000000000, -128); -// require(a29 == 781250000000000000000000000000000); -// int256 a30 = int_div(-1, -255); -// require(a30 == 0); - -// int256 a31 = int_div(100, -1); -// require(a31 == -100); -// int256 a32 = int_div(100, -2); -// require(a32 == -50); -// int256 a33 = int_div(100, -4); -// require(a33 == -25); -// int256 a34 = int_div(100, -8); -// require(a34 == -12); -// int256 a35 = int_div(1000000000, -8); -// require(a35 == -125000000); -// int256 a36 = int_div(1000000000, -16); -// require(a36 == -62500000); -// int256 a37 = int_div(10000000000, -32); -// require(a37 == -312500000); -// int256 a38 = int_div(100000000000000000000, -64); -// require(a38 == -1562500000000000000); -// int256 a39 = int_div(100000000000000000000000000000000000, -128); -// require(a39 == -781250000000000000000000000000000); -// int256 a40 = int_div(1, -255); -// require(a40 == 0); -// } -// } - -// contract Mul { -// function mul(uint256 x, uint256 y) public returns (uint256) { -// return x * y; -// } - -// function int_mul(int256 x, int256 y) public returns (int256) { -// return x * y; -// } - -// function mul_conc() public returns (uint256) { -// uint256 a1 = mul(100, 1); -// require(a1 == 100); -// uint256 a2 = mul(100, 2); -// require(a2 == 200); -// uint256 a3 = mul(100, 4); -// require(a3 == 400); -// uint256 a4 = mul(100, 8); -// require(a4 == 800); -// uint256 a5 = mul(1000000000, 8); -// require(a5 == 8000000000); -// uint256 a6 = mul(1000000000, 16); -// require(a6 == 16000000000); -// uint256 a7 = mul(10000000000, 32); -// require(a7 == 320000000000); -// uint256 a8 = mul(100000000000000000000, 64); -// require(a8 == 6400000000000000000000); -// uint256 a9 = mul(100000000000000000000000000000000000, 128); -// require(a9 == 12800000000000000000000000000000000000); -// uint256 a10 = mul(1, 255); -// require(a10 == 255); -// } - -// function int_mul_conc() public { -// int256 a1 = int_mul(100, 1); -// require(a1 == 100); -// int256 a2 = int_mul(100, 2); -// require(a2 == 200); -// int256 a3 = int_mul(100, 4); -// require(a3 == 400); -// int256 a4 = int_mul(100, 8); -// require(a4 == 800); -// int256 a5 = int_mul(1000000000, 8); -// require(a5 == 8000000000); -// int256 a6 = int_mul(1000000000, 16); -// require(a6 == 16000000000); -// int256 a7 = int_mul(10000000000, 32); -// require(a7 == 320000000000); -// int256 a8 = int_mul(100000000000000000000, 64); -// require(a8 == 6400000000000000000000); -// int256 a9 = int_mul(100000000000000000000000000000000000, 128); -// require(a9 == 12800000000000000000000000000000000000); -// int256 a10 = int_mul(1, 255); -// require(a10 == 255); - -// int256 a11 = int_mul(-100, 1); -// require(a11 == -100); -// int256 a12 = int_mul(-100, 2); -// require(a12 == -200); -// int256 a13 = int_mul(-100, 4); -// require(a13 == -400); -// int256 a14 = int_mul(-100, 8); -// require(a14 == -800); -// int256 a15 = int_mul(-1000000000, 8); -// require(a15 == -8000000000); -// int256 a16 = int_mul(-1000000000, 16); -// require(a16 == -16000000000); -// int256 a17 = int_mul(-10000000000, 32); -// require(a17 == -320000000000); -// int256 a18 = int_mul(-100000000000000000000, 64); -// require(a18 == -6400000000000000000000); -// int256 a19 = int_mul(-100000000000000000000000000000000000, 128); -// require(a19 == -12800000000000000000000000000000000000); -// int256 a20 = int_mul(-1, 255); -// require(a20 == -255); - -// int256 a21 = int_mul(-100, -1); -// require(a21 == 100); -// int256 a22 = int_mul(-100, -2); -// require(a22 == 200); -// int256 a23 = int_mul(-100, -4); -// require(a23 == 400); -// int256 a24 = int_mul(-100, -8); -// require(a24 == 800); -// int256 a25 = int_mul(-1000000000, -8); -// require(a25 == 8000000000); -// int256 a26 = int_mul(-1000000000, -16); -// require(a26 == 16000000000); -// int256 a27 = int_mul(-10000000000, -32); -// require(a27 == 320000000000); -// int256 a28 = int_mul(-100000000000000000000, -64); -// require(a28 == 6400000000000000000000); -// int256 a29 = int_mul(-100000000000000000000000000000000000, -128); -// require(a29 == 12800000000000000000000000000000000000); -// int256 a30 = int_mul(-1, -255); -// require(a30 == 255); - -// int256 a31 = int_mul(100, -1); -// require(a31 == -100); -// int256 a32 = int_mul(100, -2); -// require(a32 == -200); -// int256 a33 = int_mul(100, -4); -// require(a33 == -400); -// int256 a34 = int_mul(100, -8); -// require(a34 == -800); -// int256 a35 = int_mul(1000000000, -8); -// require(a35 == -8000000000); -// int256 a36 = int_mul(1000000000, -16); -// require(a36 == -16000000000); -// int256 a37 = int_mul(10000000000, -32); -// require(a37 == -320000000000); -// int256 a38 = int_mul(100000000000000000000, -64); -// require(a38 == -6400000000000000000000); -// int256 a39 = int_mul(100000000000000000000000000000000000, -128); -// require(a39 == -12800000000000000000000000000000000000); -// int256 a40 = int_mul(1, -255); -// require(a40 == -255); -// } -// } - -// contract Add { -// function add(uint256 x, uint256 y) public returns (uint256) { -// return x + y; -// } - -// function int_add(int256 x, int256 y) public returns (int256) { -// return x + y; -// } - -// function add_conc() public returns (uint256) { -// uint256 a1 = add(100, 1); -// require(a1 == 101); -// uint256 a2 = add(100, 2); -// require(a2 == 102); -// uint256 a3 = add(100, 4); -// require(a3 == 104); -// uint256 a4 = add(100, 8); -// require(a4 == 108); -// uint256 a5 = add(1000000000, 8); -// require(a5 == 1000000008); -// uint256 a6 = add(1000000000, 16); -// require(a6 == 1000000016); -// uint256 a7 = add(10000000000, 32); -// require(a7 == 10000000032); -// uint256 a8 = add(100000000000000000000, 64); -// require(a8 == 100000000000000000064); -// uint256 a9 = add(100000000000000000000000000000000000, 128); -// require(a9 == 100000000000000000000000000000000128); -// uint256 a10 = add(1, 255); -// require(a10 == 256); -// } - -// function int_add_conc() public { -// int256 a1 = int_add(100, 1); -// require(a1 == 101); -// int256 a2 = int_add(100, 2); -// require(a2 == 102); -// int256 a3 = int_add(100, 4); -// require(a3 == 104); -// int256 a4 = int_add(100, 8); -// require(a4 == 108); -// int256 a5 = int_add(1000000000, 8); -// require(a5 == 1000000008); -// int256 a6 = int_add(1000000000, 16); -// require(a6 == 1000000016); -// int256 a7 = int_add(10000000000, 32); -// require(a7 == 10000000032); -// int256 a8 = int_add(100000000000000000000, 64); -// require(a8 == 100000000000000000064); -// int256 a9 = int_add(100000000000000000000000000000000000, 128); -// require(a9 == 100000000000000000000000000000000128); -// int256 a10 = int_add(1, 255); -// require(a10 == 256); - -// int256 a11 = int_add(-100, 1); -// require(a11 == -99); -// int256 a12 = int_add(-100, 2); -// require(a12 == -98); -// int256 a13 = int_add(-100, 4); -// require(a13 == -96); -// int256 a14 = int_add(-100, 8); -// require(a14 == -92); -// int256 a15 = int_add(-1000000000, 8); -// require(a15 == -999999992); -// int256 a16 = int_add(-1000000000, 16); -// require(a16 == -999999984); -// int256 a17 = int_add(-10000000000, 32); -// require(a17 == -9999999968); -// int256 a18 = int_add(-100000000000000000000, 64); -// require(a18 == -99999999999999999936); -// int256 a19 = int_add(-100000000000000000000000000000000000, 128); -// require(a19 == -99999999999999999999999999999999872); -// int256 a20 = int_add(-1, 255); -// require(a20 == 254); - -// int256 a21 = int_add(-100, -1); -// require(a21 == -101); -// int256 a22 = int_add(-100, -2); -// require(a22 == -102); -// int256 a23 = int_add(-100, -4); -// require(a23 == -104); -// int256 a24 = int_add(-100, -8); -// require(a24 == -108); -// int256 a25 = int_add(-1000000000, -8); -// require(a25 == -1000000008); -// int256 a26 = int_add(-1000000000, -16); -// require(a26 == -1000000016); -// int256 a27 = int_add(-10000000000, -32); -// require(a27 == -10000000032); -// int256 a28 = int_add(-100000000000000000000, -64); -// require(a28 == -100000000000000000064); -// int256 a29 = int_add(-100000000000000000000000000000000000, -128); -// require(a29 == -100000000000000000000000000000000128); -// int256 a30 = int_add(-1, -255); -// require(a30 == -256); - -// int256 a31 = int_add(100, -1); -// require(a31 == 99); -// int256 a32 = int_add(100, -2); -// require(a32 == 98); -// int256 a33 = int_add(100, -4); -// require(a33 == 96); -// int256 a34 = int_add(100, -8); -// require(a34 == 92); -// int256 a35 = int_add(1000000000, -8); -// require(a35 == 999999992); -// int256 a36 = int_add(1000000000, -16); -// require(a36 == 999999984); -// int256 a37 = int_add(10000000000, -32); -// require(a37 == 9999999968); -// int256 a38 = int_add(100000000000000000000, -64); -// require(a38 == 99999999999999999936); -// int256 a39 = int_add(100000000000000000000000000000000000, -128); -// require(a39 == 99999999999999999999999999999999872); -// int256 a40 = int_add(1, -255); -// require(a40 == -254); -// } -// } - -// contract Sub { -// function sub(uint256 x, uint256 y) public returns (uint256) { -// return x - y; -// } - -// function int_sub(int256 x, int256 y) public returns (int256) { -// return x - y; -// } - -// function sub_conc() public returns (uint256) { -// uint256 a1 = sub(100, 1); -// require(a1 == 99); -// uint256 a2 = sub(100, 2); -// require(a2 == 98); -// uint256 a3 = sub(100, 4); -// require(a3 == 96); -// uint256 a4 = sub(100, 8); -// require(a4 == 92); -// uint256 a5 = sub(1000000000, 8); -// require(a5 == 999999992); -// uint256 a6 = sub(1000000000, 16); -// require(a6 == 999999984); -// uint256 a7 = sub(10000000000, 32); -// require(a7 == 9999999968); -// uint256 a8 = sub(100000000000000000000, 64); -// require(a8 == 99999999999999999936); -// uint256 a9 = sub(100000000000000000000000000000000000, 128); -// require(a9 == 99999999999999999999999999999999872); -// } - -// function int_sub_conc() public { -// int256 a1 = int_sub(100, 1); -// require(a1 == 99); -// int256 a2 = int_sub(100, 2); -// require(a2 == 98); -// int256 a3 = int_sub(100, 4); -// require(a3 == 96); -// int256 a4 = int_sub(100, 8); -// require(a4 == 92); -// int256 a5 = int_sub(1000000000, 8); -// require(a5 == 999999992); -// int256 a6 = int_sub(1000000000, 16); -// require(a6 == 999999984); -// int256 a7 = int_sub(10000000000, 32); -// require(a7 == 9999999968); -// int256 a8 = int_sub(100000000000000000000, 64); -// require(a8 == 99999999999999999936); -// int256 a9 = int_sub(100000000000000000000000000000000000, 128); -// require(a9 == 99999999999999999999999999999999872); -// int256 a10 = int_sub(1, 255); -// require(a10 == -254); - -// int256 a11 = int_sub(-100, 1); -// require(a11 == -101); -// int256 a12 = int_sub(-100, 2); -// require(a12 == -102); -// int256 a13 = int_sub(-100, 4); -// require(a13 == -104); -// int256 a14 = int_sub(-100, 8); -// require(a14 == -108); -// int256 a15 = int_sub(-1000000000, 8); -// require(a15 == -1000000008); -// int256 a16 = int_sub(-1000000000, 16); -// require(a16 == -1000000016); -// int256 a17 = int_sub(-10000000000, 32); -// require(a17 == -10000000032); -// int256 a18 = int_sub(-100000000000000000000, 64); -// require(a18 == -100000000000000000064); -// int256 a19 = int_sub(-100000000000000000000000000000000000, 128); -// require(a19 == -100000000000000000000000000000000128); -// int256 a20 = int_sub(-1, 255); -// require(a20 == -256); - -// int256 a21 = int_sub(-100, -1); -// require(a21 == -99); -// int256 a22 = int_sub(-100, -2); -// require(a22 == -98); -// int256 a23 = int_sub(-100, -4); -// require(a23 == -96); -// int256 a24 = int_sub(-100, -8); -// require(a24 == -92); -// int256 a25 = int_sub(-1000000000, -8); -// require(a25 == -999999992); -// int256 a26 = int_sub(-1000000000, -16); -// require(a26 == -999999984); -// int256 a27 = int_sub(-10000000000, -32); -// require(a27 == -9999999968); -// int256 a28 = int_sub(-100000000000000000000, -64); -// require(a28 == -99999999999999999936); -// int256 a29 = int_sub(-100000000000000000000000000000000000, -128); -// require(a29 == -99999999999999999999999999999999872); -// int256 a30 = int_sub(-1, -255); -// require(a30 == 254); - -// int256 a31 = int_sub(100, -1); -// require(a31 == 101); -// int256 a32 = int_sub(100, -2); -// require(a32 == 102); -// int256 a33 = int_sub(100, -4); -// require(a33 == 104); -// int256 a34 = int_sub(100, -8); -// require(a34 == 108); -// int256 a35 = int_sub(1000000000, -8); -// require(a35 == 1000000008); -// int256 a36 = int_sub(1000000000, -16); -// require(a36 == 1000000016); -// int256 a37 = int_sub(10000000000, -32); -// require(a37 == 10000000032); -// int256 a38 = int_sub(100000000000000000000, -64); -// require(a38 == 100000000000000000064); -// int256 a39 = int_sub(100000000000000000000000000000000000, -128); -// require(a39 == 100000000000000000000000000000000128); -// int256 a40 = int_sub(1, -255); -// require(a40 == 256); -// } -// } - -// contract AssignMath { -// function assignAdd(uint256 x) public { -// x += 10; -// } - -// function assignSub(uint256 x) public { -// x -= 10; -// } - -// function assignDiv(uint256 x) public { -// x /= 10; -// } - -// function assignMul(uint256 x) public { -// x *= 10; -// } - -// function preincrement(uint256 x) public returns (uint256, uint256) { -// uint256 y = ++x; -// return (y, x); -// } - -// function postincrement(uint256 x) public returns (uint256, uint256) { -// uint256 y = x++; -// return (y, x); -// } - -// function predecrement(uint256 x) public returns (uint256, uint256) { -// uint256 y = --x; -// return (y, x); -// } - -// function postdecrement(uint256 x) public returns (uint256, uint256) { -// uint256 y = x--; -// return (y, x); -// } - -// function pre_conc() public { -// (uint256 y, uint256 x) = preincrement(100); -// require(y == 101); -// require(x == 101); -// } - -// function post_conc() public { -// (uint256 y, uint256 x) = postincrement(100); -// require(y == 100); -// require(x == 101); -// } - -// function pre_deconc() public { -// (uint256 y, uint256 x) = predecrement(100); -// require(y == 99); -// require(x == 99); -// } - -// function post_deconc() public { -// (uint256 y, uint256 x) = postdecrement(100); -// require(y == 100); -// require(x == 99); -// } -// } - -// contract Math { -// function rmod(uint256 x, uint256 y) public returns (uint256) { -// return x % y; -// } - -// function rexp(uint256 x, uint256 y) public returns (uint256) { -// return x ** y; -// } - -// function int_rmod(int256 x, int256 y) public returns (int256) { -// return x % y; -// } - -// function int_rexp(int256 x, uint256 y) public returns (int256) { -// return x ** y; -// } -// } +contract Div { + function div(uint256 x, uint256 y) public returns (uint256) { + return x / y; + } + + function int_div(int256 x, int256 y) public returns (int256) { + return x / y; + } + + function div_conc() public returns (uint256) { + uint256 a1 = div(100, 1); + require(a1 == 100); + uint256 a2 = div(100, 2); + require(a2 == 50); + uint256 a3 = div(100, 4); + require(a3 == 25); + uint256 a4 = div(100, 8); + require(a4 == 12); + uint256 a5 = div(1000000000, 8); + require(a5 == 125000000); + uint256 a6 = div(1000000000, 16); + require(a6 == 62500000); + uint256 a7 = div(10000000000, 32); + require(a7 == 312500000); + uint256 a8 = div(100000000000000000000, 64); + require(a8 == 1562500000000000000); + uint256 a9 = div(100000000000000000000000000000000000, 128); + require(a9 == 781250000000000000000000000000000); + uint256 a10 = div(1, 255); + require(a10 == 0); + } + + function int_div_conc() public { + int256 a1 = int_div(100, 1); + require(a1 == 100); + int256 a2 = int_div(100, 2); + require(a2 == 50); + int256 a3 = int_div(100, 4); + require(a3 == 25); + int256 a4 = int_div(100, 8); + require(a4 == 12); + int256 a5 = int_div(1000000000, 8); + require(a5 == 125000000); + int256 a6 = int_div(1000000000, 16); + require(a6 == 62500000); + int256 a7 = int_div(10000000000, 32); + require(a7 == 312500000); + int256 a8 = int_div(100000000000000000000, 64); + require(a8 == 1562500000000000000); + int256 a9 = int_div(100000000000000000000000000000000000, 128); + require(a9 == 781250000000000000000000000000000); + int256 a10 = int_div(1, 255); + require(a10 == 0); + + int256 a11 = int_div(-100, 1); + require(a11 == -100); + int256 a12 = int_div(-100, 2); + require(a12 == -50); + int256 a13 = int_div(-100, 4); + require(a13 == -25); + int256 a14 = int_div(-100, 8); + require(a14 == -12); + int256 a15 = int_div(-1000000000, 8); + require(a15 == -125000000); + int256 a16 = int_div(-1000000000, 16); + require(a16 == -62500000); + int256 a17 = int_div(-10000000000, 32); + require(a17 == -312500000); + int256 a18 = int_div(-100000000000000000000, 64); + require(a18 == -1562500000000000000); + int256 a19 = int_div(-100000000000000000000000000000000000, 128); + require(a19 == -781250000000000000000000000000000); + int256 a20 = int_div(-1, 255); + require(a20 == 0); + + int256 a21 = int_div(-100, -1); + require(a21 == 100); + int256 a22 = int_div(-100, -2); + require(a22 == 50); + int256 a23 = int_div(-100, -4); + require(a23 == 25); + int256 a24 = int_div(-100, -8); + require(a24 == 12); + int256 a25 = int_div(-1000000000, -8); + require(a25 == 125000000); + int256 a26 = int_div(-1000000000, -16); + require(a26 == 62500000); + int256 a27 = int_div(-10000000000, -32); + require(a27 == 312500000); + int256 a28 = int_div(-100000000000000000000, -64); + require(a28 == 1562500000000000000); + int256 a29 = int_div(-100000000000000000000000000000000000, -128); + require(a29 == 781250000000000000000000000000000); + int256 a30 = int_div(-1, -255); + require(a30 == 0); + + int256 a31 = int_div(100, -1); + require(a31 == -100); + int256 a32 = int_div(100, -2); + require(a32 == -50); + int256 a33 = int_div(100, -4); + require(a33 == -25); + int256 a34 = int_div(100, -8); + require(a34 == -12); + int256 a35 = int_div(1000000000, -8); + require(a35 == -125000000); + int256 a36 = int_div(1000000000, -16); + require(a36 == -62500000); + int256 a37 = int_div(10000000000, -32); + require(a37 == -312500000); + int256 a38 = int_div(100000000000000000000, -64); + require(a38 == -1562500000000000000); + int256 a39 = int_div(100000000000000000000000000000000000, -128); + require(a39 == -781250000000000000000000000000000); + int256 a40 = int_div(1, -255); + require(a40 == 0); + } +} + +contract Mul { + function mul(uint256 x, uint256 y) public returns (uint256) { + return x * y; + } + + function int_mul(int256 x, int256 y) public returns (int256) { + return x * y; + } + + function mul_conc() public returns (uint256) { + uint256 a1 = mul(100, 1); + require(a1 == 100); + uint256 a2 = mul(100, 2); + require(a2 == 200); + uint256 a3 = mul(100, 4); + require(a3 == 400); + uint256 a4 = mul(100, 8); + require(a4 == 800); + uint256 a5 = mul(1000000000, 8); + require(a5 == 8000000000); + uint256 a6 = mul(1000000000, 16); + require(a6 == 16000000000); + uint256 a7 = mul(10000000000, 32); + require(a7 == 320000000000); + uint256 a8 = mul(100000000000000000000, 64); + require(a8 == 6400000000000000000000); + uint256 a9 = mul(100000000000000000000000000000000000, 128); + require(a9 == 12800000000000000000000000000000000000); + uint256 a10 = mul(1, 255); + require(a10 == 255); + } + + function int_mul_conc() public { + int256 a1 = int_mul(100, 1); + require(a1 == 100); + int256 a2 = int_mul(100, 2); + require(a2 == 200); + int256 a3 = int_mul(100, 4); + require(a3 == 400); + int256 a4 = int_mul(100, 8); + require(a4 == 800); + int256 a5 = int_mul(1000000000, 8); + require(a5 == 8000000000); + int256 a6 = int_mul(1000000000, 16); + require(a6 == 16000000000); + int256 a7 = int_mul(10000000000, 32); + require(a7 == 320000000000); + int256 a8 = int_mul(100000000000000000000, 64); + require(a8 == 6400000000000000000000); + int256 a9 = int_mul(100000000000000000000000000000000000, 128); + require(a9 == 12800000000000000000000000000000000000); + int256 a10 = int_mul(1, 255); + require(a10 == 255); + + int256 a11 = int_mul(-100, 1); + require(a11 == -100); + int256 a12 = int_mul(-100, 2); + require(a12 == -200); + int256 a13 = int_mul(-100, 4); + require(a13 == -400); + int256 a14 = int_mul(-100, 8); + require(a14 == -800); + int256 a15 = int_mul(-1000000000, 8); + require(a15 == -8000000000); + int256 a16 = int_mul(-1000000000, 16); + require(a16 == -16000000000); + int256 a17 = int_mul(-10000000000, 32); + require(a17 == -320000000000); + int256 a18 = int_mul(-100000000000000000000, 64); + require(a18 == -6400000000000000000000); + int256 a19 = int_mul(-100000000000000000000000000000000000, 128); + require(a19 == -12800000000000000000000000000000000000); + int256 a20 = int_mul(-1, 255); + require(a20 == -255); + + int256 a21 = int_mul(-100, -1); + require(a21 == 100); + int256 a22 = int_mul(-100, -2); + require(a22 == 200); + int256 a23 = int_mul(-100, -4); + require(a23 == 400); + int256 a24 = int_mul(-100, -8); + require(a24 == 800); + int256 a25 = int_mul(-1000000000, -8); + require(a25 == 8000000000); + int256 a26 = int_mul(-1000000000, -16); + require(a26 == 16000000000); + int256 a27 = int_mul(-10000000000, -32); + require(a27 == 320000000000); + int256 a28 = int_mul(-100000000000000000000, -64); + require(a28 == 6400000000000000000000); + int256 a29 = int_mul(-100000000000000000000000000000000000, -128); + require(a29 == 12800000000000000000000000000000000000); + int256 a30 = int_mul(-1, -255); + require(a30 == 255); + + int256 a31 = int_mul(100, -1); + require(a31 == -100); + int256 a32 = int_mul(100, -2); + require(a32 == -200); + int256 a33 = int_mul(100, -4); + require(a33 == -400); + int256 a34 = int_mul(100, -8); + require(a34 == -800); + int256 a35 = int_mul(1000000000, -8); + require(a35 == -8000000000); + int256 a36 = int_mul(1000000000, -16); + require(a36 == -16000000000); + int256 a37 = int_mul(10000000000, -32); + require(a37 == -320000000000); + int256 a38 = int_mul(100000000000000000000, -64); + require(a38 == -6400000000000000000000); + int256 a39 = int_mul(100000000000000000000000000000000000, -128); + require(a39 == -12800000000000000000000000000000000000); + int256 a40 = int_mul(1, -255); + require(a40 == -255); + } +} + +contract Add { + function add(uint256 x, uint256 y) public returns (uint256) { + return x + y; + } + + function int_add(int256 x, int256 y) public returns (int256) { + return x + y; + } + + function add_conc() public returns (uint256) { + uint256 a1 = add(100, 1); + require(a1 == 101); + uint256 a2 = add(100, 2); + require(a2 == 102); + uint256 a3 = add(100, 4); + require(a3 == 104); + uint256 a4 = add(100, 8); + require(a4 == 108); + uint256 a5 = add(1000000000, 8); + require(a5 == 1000000008); + uint256 a6 = add(1000000000, 16); + require(a6 == 1000000016); + uint256 a7 = add(10000000000, 32); + require(a7 == 10000000032); + uint256 a8 = add(100000000000000000000, 64); + require(a8 == 100000000000000000064); + uint256 a9 = add(100000000000000000000000000000000000, 128); + require(a9 == 100000000000000000000000000000000128); + uint256 a10 = add(1, 255); + require(a10 == 256); + } + + function int_add_conc() public { + int256 a1 = int_add(100, 1); + require(a1 == 101); + int256 a2 = int_add(100, 2); + require(a2 == 102); + int256 a3 = int_add(100, 4); + require(a3 == 104); + int256 a4 = int_add(100, 8); + require(a4 == 108); + int256 a5 = int_add(1000000000, 8); + require(a5 == 1000000008); + int256 a6 = int_add(1000000000, 16); + require(a6 == 1000000016); + int256 a7 = int_add(10000000000, 32); + require(a7 == 10000000032); + int256 a8 = int_add(100000000000000000000, 64); + require(a8 == 100000000000000000064); + int256 a9 = int_add(100000000000000000000000000000000000, 128); + require(a9 == 100000000000000000000000000000000128); + int256 a10 = int_add(1, 255); + require(a10 == 256); + + int256 a11 = int_add(-100, 1); + require(a11 == -99); + int256 a12 = int_add(-100, 2); + require(a12 == -98); + int256 a13 = int_add(-100, 4); + require(a13 == -96); + int256 a14 = int_add(-100, 8); + require(a14 == -92); + int256 a15 = int_add(-1000000000, 8); + require(a15 == -999999992); + int256 a16 = int_add(-1000000000, 16); + require(a16 == -999999984); + int256 a17 = int_add(-10000000000, 32); + require(a17 == -9999999968); + int256 a18 = int_add(-100000000000000000000, 64); + require(a18 == -99999999999999999936); + int256 a19 = int_add(-100000000000000000000000000000000000, 128); + require(a19 == -99999999999999999999999999999999872); + int256 a20 = int_add(-1, 255); + require(a20 == 254); + + int256 a21 = int_add(-100, -1); + require(a21 == -101); + int256 a22 = int_add(-100, -2); + require(a22 == -102); + int256 a23 = int_add(-100, -4); + require(a23 == -104); + int256 a24 = int_add(-100, -8); + require(a24 == -108); + int256 a25 = int_add(-1000000000, -8); + require(a25 == -1000000008); + int256 a26 = int_add(-1000000000, -16); + require(a26 == -1000000016); + int256 a27 = int_add(-10000000000, -32); + require(a27 == -10000000032); + int256 a28 = int_add(-100000000000000000000, -64); + require(a28 == -100000000000000000064); + int256 a29 = int_add(-100000000000000000000000000000000000, -128); + require(a29 == -100000000000000000000000000000000128); + int256 a30 = int_add(-1, -255); + require(a30 == -256); + + int256 a31 = int_add(100, -1); + require(a31 == 99); + int256 a32 = int_add(100, -2); + require(a32 == 98); + int256 a33 = int_add(100, -4); + require(a33 == 96); + int256 a34 = int_add(100, -8); + require(a34 == 92); + int256 a35 = int_add(1000000000, -8); + require(a35 == 999999992); + int256 a36 = int_add(1000000000, -16); + require(a36 == 999999984); + int256 a37 = int_add(10000000000, -32); + require(a37 == 9999999968); + int256 a38 = int_add(100000000000000000000, -64); + require(a38 == 99999999999999999936); + int256 a39 = int_add(100000000000000000000000000000000000, -128); + require(a39 == 99999999999999999999999999999999872); + int256 a40 = int_add(1, -255); + require(a40 == -254); + } +} + +contract Sub { + function sub(uint256 x, uint256 y) public returns (uint256) { + return x - y; + } + + function int_sub(int256 x, int256 y) public returns (int256) { + return x - y; + } + + function sub_conc() public returns (uint256) { + uint256 a1 = sub(100, 1); + require(a1 == 99); + uint256 a2 = sub(100, 2); + require(a2 == 98); + uint256 a3 = sub(100, 4); + require(a3 == 96); + uint256 a4 = sub(100, 8); + require(a4 == 92); + uint256 a5 = sub(1000000000, 8); + require(a5 == 999999992); + uint256 a6 = sub(1000000000, 16); + require(a6 == 999999984); + uint256 a7 = sub(10000000000, 32); + require(a7 == 9999999968); + uint256 a8 = sub(100000000000000000000, 64); + require(a8 == 99999999999999999936); + uint256 a9 = sub(100000000000000000000000000000000000, 128); + require(a9 == 99999999999999999999999999999999872); + } + + function int_sub_conc() public { + int256 a1 = int_sub(100, 1); + require(a1 == 99); + int256 a2 = int_sub(100, 2); + require(a2 == 98); + int256 a3 = int_sub(100, 4); + require(a3 == 96); + int256 a4 = int_sub(100, 8); + require(a4 == 92); + int256 a5 = int_sub(1000000000, 8); + require(a5 == 999999992); + int256 a6 = int_sub(1000000000, 16); + require(a6 == 999999984); + int256 a7 = int_sub(10000000000, 32); + require(a7 == 9999999968); + int256 a8 = int_sub(100000000000000000000, 64); + require(a8 == 99999999999999999936); + int256 a9 = int_sub(100000000000000000000000000000000000, 128); + require(a9 == 99999999999999999999999999999999872); + int256 a10 = int_sub(1, 255); + require(a10 == -254); + + int256 a11 = int_sub(-100, 1); + require(a11 == -101); + int256 a12 = int_sub(-100, 2); + require(a12 == -102); + int256 a13 = int_sub(-100, 4); + require(a13 == -104); + int256 a14 = int_sub(-100, 8); + require(a14 == -108); + int256 a15 = int_sub(-1000000000, 8); + require(a15 == -1000000008); + int256 a16 = int_sub(-1000000000, 16); + require(a16 == -1000000016); + int256 a17 = int_sub(-10000000000, 32); + require(a17 == -10000000032); + int256 a18 = int_sub(-100000000000000000000, 64); + require(a18 == -100000000000000000064); + int256 a19 = int_sub(-100000000000000000000000000000000000, 128); + require(a19 == -100000000000000000000000000000000128); + int256 a20 = int_sub(-1, 255); + require(a20 == -256); + + int256 a21 = int_sub(-100, -1); + require(a21 == -99); + int256 a22 = int_sub(-100, -2); + require(a22 == -98); + int256 a23 = int_sub(-100, -4); + require(a23 == -96); + int256 a24 = int_sub(-100, -8); + require(a24 == -92); + int256 a25 = int_sub(-1000000000, -8); + require(a25 == -999999992); + int256 a26 = int_sub(-1000000000, -16); + require(a26 == -999999984); + int256 a27 = int_sub(-10000000000, -32); + require(a27 == -9999999968); + int256 a28 = int_sub(-100000000000000000000, -64); + require(a28 == -99999999999999999936); + int256 a29 = int_sub(-100000000000000000000000000000000000, -128); + require(a29 == -99999999999999999999999999999999872); + int256 a30 = int_sub(-1, -255); + require(a30 == 254); + + int256 a31 = int_sub(100, -1); + require(a31 == 101); + int256 a32 = int_sub(100, -2); + require(a32 == 102); + int256 a33 = int_sub(100, -4); + require(a33 == 104); + int256 a34 = int_sub(100, -8); + require(a34 == 108); + int256 a35 = int_sub(1000000000, -8); + require(a35 == 1000000008); + int256 a36 = int_sub(1000000000, -16); + require(a36 == 1000000016); + int256 a37 = int_sub(10000000000, -32); + require(a37 == 10000000032); + int256 a38 = int_sub(100000000000000000000, -64); + require(a38 == 100000000000000000064); + int256 a39 = int_sub(100000000000000000000000000000000000, -128); + require(a39 == 100000000000000000000000000000000128); + int256 a40 = int_sub(1, -255); + require(a40 == 256); + } +} + +contract AssignMath { + function assignAdd(uint256 x) public { + x += 10; + } + + function assignSub(uint256 x) public { + x -= 10; + } + + function assignDiv(uint256 x) public { + x /= 10; + } + + function assignMul(uint256 x) public { + x *= 10; + } + + function preincrement(uint256 x) public returns (uint256, uint256) { + uint256 y = ++x; + return (y, x); + } + + function postincrement(uint256 x) public returns (uint256, uint256) { + uint256 y = x++; + return (y, x); + } + + function predecrement(uint256 x) public returns (uint256, uint256) { + uint256 y = --x; + return (y, x); + } + + function postdecrement(uint256 x) public returns (uint256, uint256) { + uint256 y = x--; + return (y, x); + } + + function pre_conc() public { + (uint256 y, uint256 x) = preincrement(100); + require(y == 101); + require(x == 101); + } + + function post_conc() public { + (uint256 y, uint256 x) = postincrement(100); + require(y == 100); + require(x == 101); + } + + function pre_deconc() public { + (uint256 y, uint256 x) = predecrement(100); + require(y == 99); + require(x == 99); + } + + function post_deconc() public { + (uint256 y, uint256 x) = postdecrement(100); + require(y == 100); + require(x == 99); + } +} + +contract Math { + function rmod(uint256 x, uint256 y) public returns (uint256) { + return x % y; + } + + function rexp(uint256 x, uint256 y) public returns (uint256) { + return x ** y; + } + + function int_rmod(int256 x, int256 y) public returns (int256) { + return x % y; + } + + function int_rexp(int256 x, uint256 y) public returns (int256) { + return x ** y; + } +} contract Unchecked { - // function assemblyWrappingSub(uint256 a) public { - // assembly { - // a := sub(0, 100) - // } - // require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - // int256 y = type(int256).min; - // assembly { - // a := sub(y, 100) - // } - // require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - // } - - // function uncheckedSub(uint256 a) public { - // unchecked { - // a = 0 - 100; - // } - // require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - // int256 y = type(int256).min; - // unchecked { - // a = y - 100; - // } - // require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - // } + function assemblyWrappingSub(uint256 a) public { + assembly { + a := sub(0, 100) + } + require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + int256 y = type(int256).min; + assembly { + a := sub(y, 100) + } + require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + } + + function uncheckedSub(uint256 a) public { + unchecked { + a = 0 - 100; + } + require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + int256 y = type(int256).min; + unchecked { + a = y - 100; + } + require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + } function uncheckedSymbolicSub(uint256 a, uint256 b) public { unchecked { @@ -585,42 +585,42 @@ contract Unchecked { } } - // function assemblyWrappingAdd(uint256 a) public { - // uint256 m = type(uint256).max; - // assembly { - // a := add(m, 100) - // } - // require(a == 99); - // a += (type(uint256).max - 99); - // require(a == type(uint256).max); - // } - - // function uncheckedAdd(uint256 a) public { - // unchecked { - // a = type(uint256).max + 100; - // } - // require(a == 99); - // a += (type(uint256).max - 99); - // require(a == type(uint256).max); - // } - - // function assemblyWrappingMul(uint256 a) public { - // uint256 m = type(uint128).max; - // assembly { - // a := mul(m, m) - // } - // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - // a /= 3; - // a *= 3; - // // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - // } - - // function uncheckedMul(uint256 a) public { - // unchecked { - // a = type(uint256).max + 100; - // } - // require(a == 99); - // a += (type(uint256).max - 99); - // require(a == type(uint256).max); - // } + function assemblyWrappingAdd(uint256 a) public { + uint256 m = type(uint256).max; + assembly { + a := add(m, 100) + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } + + function uncheckedAdd(uint256 a) public { + unchecked { + a = type(uint256).max + 100; + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } + + function assemblyWrappingMul(uint256 a) public { + uint256 m = type(uint128).max; + assembly { + a := mul(m, m) + } + require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + a /= 3; + a *= 3; + // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + } + + function uncheckedMul(uint256 a) public { + unchecked { + a = type(uint256).max + 100; + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } } \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/require.sol b/crates/pyrometer/tests/test_data/require.sol index 419ec6be..e010536b 100644 --- a/crates/pyrometer/tests/test_data/require.sol +++ b/crates/pyrometer/tests/test_data/require.sol @@ -64,7 +64,3 @@ contract Require { require(x == bytes1(hex"13")); } } - - - - diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 8df465ea..c3bba13a 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -157,7 +157,9 @@ pub trait BinOp: AnalyzerBackend + Sized { }; let new_lhs = if assign { - self.advance_var_in_ctx(lhs_cvar, loc, ctx)? + let new = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; + new.underlying_mut(self).into_expr_err(loc)?.tmp_of = Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); + new } else { let mut new_lhs_underlying = ContextVar { loc: Some(loc), @@ -335,7 +337,8 @@ pub trait BinOp: AnalyzerBackend + Sized { } } } else if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; + let tmp_lhs = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; + // let tmp_rhs = self.advance_var_in_ctx_forcible(new_rhs, loc, ctx, true)?; if self .require( tmp_lhs, @@ -353,16 +356,9 @@ pub trait BinOp: AnalyzerBackend + Sized { // the new min is max(lhs.min, rhs.min) let min = Elem::max( Elem::from(Reference::new(lhs_cvar.into())), - // .range_min(self) - // .into_expr_err(loc)? - // .unwrap_or_else(|| { - // panic!( - // "No range minimum: {:?}", - // tmp_lhs.ty(self).unwrap().as_dot_str(self) - // ) - // }), Elem::from(rhs_cvar), ); + let tmp_lhs = tmp_lhs.latest_version(self); tmp_lhs.set_range_min(self, min).into_expr_err(loc)?; let tmp_var = ContextVar { @@ -667,9 +663,10 @@ pub trait BinOp: AnalyzerBackend + Sized { // let func = SolcRange::dyn_fn_from_op(op); // let new_range = func(lhs_range, new_rhs); new_lhs + .latest_version(self) .set_range_min(self, expr.clone()) .into_expr_err(loc)?; - new_lhs.set_range_max(self, expr).into_expr_err(loc)?; + new_lhs.latest_version(self).set_range_max(self, expr).into_expr_err(loc)?; // last ditch effort to prevent exponentiation from having a minimum of 1 instead of 0. // if the lhs is 0 check if the rhs is also 0, otherwise set minimum to 0. diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index a2aadafd..0f97cd16 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -538,7 +538,6 @@ pub trait ContextBuilder: true } Err(e) => { - println!("e: {e:#?}"); let res = ctx .kill(self, e.loc(), KilledKind::ParseError) .into_expr_err(e.loc()); @@ -719,7 +718,7 @@ pub trait ContextBuilder: } } - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self).replace('.', "\n\t.")))] fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { use Expression::*; // println!( @@ -959,7 +958,7 @@ pub trait ContextBuilder: let updated_func_expr = match **func_expr { FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { // we dont currently handle the `{value: .. gas: ..}` msg updating - self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take affect".to_string())); + self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); inner_func_expr.clone() } _ => func_expr.clone(), @@ -1322,8 +1321,8 @@ pub trait ContextBuilder: ) -> Result { tracing::trace!( "assigning: {} to {}", + rhs_cvar.display_name(self).unwrap(), lhs_cvar.display_name(self).unwrap(), - rhs_cvar.display_name(self).unwrap() ); let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( @@ -1360,6 +1359,7 @@ pub trait ContextBuilder: )); } } + if !lhs_cvar.ty_eq(&rhs_cvar, self).into_expr_err(loc)? { let cast_to_min = match lhs_cvar.range_min(self).into_expr_err(loc)? { Some(v) => v, @@ -1436,6 +1436,8 @@ pub trait ContextBuilder: } } + // advance the rhs variable to avoid recursion issues + self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; Ok(ExprRet::Single(new_lhs.into())) } @@ -1445,6 +1447,17 @@ pub trait ContextBuilder: cvar_node: ContextVarNode, loc: Loc, ctx: ContextNode, + ) -> Result { + self.advance_var_in_ctx_forcible(cvar_node, loc, ctx, false) + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + fn advance_var_in_ctx_forcible( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ctx: ContextNode, + force: bool, ) -> Result { tracing::trace!( "advancing variable: {}", @@ -1477,14 +1490,16 @@ pub trait ContextBuilder: 'a: { if let Some(old_ctx) = cvar_node.maybe_ctx(self) { - // get the previous version to remove and prevent spurious nodes - if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { - let prev_version = prev.underlying(self).into_expr_err(loc)?; - // check if there was no change between the previous version and the latest version - if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { - // there was no change in the current context, just give them the current variable - new_cvarnode = cvar_node.into(); - break 'a; + if !force { + // get the previous version to remove and prevent spurious nodes + if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { + let prev_version = prev.underlying(self).into_expr_err(loc)?; + // check if there was no change between the previous version and the latest version + if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { + // there was no change in the current context, just give them the current variable + new_cvarnode = cvar_node.into(); + break 'a; + } } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index 4f585e82..ae1d26e2 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -679,6 +679,10 @@ pub trait IntrinsicFuncCaller: let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; + cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; let expr = Elem::Expr(RangeExpr::new( Elem::from(to_be_unwrapped), @@ -688,11 +692,6 @@ pub trait IntrinsicFuncCaller: next.set_range_min(analyzer, expr.clone()) .into_expr_err(loc)?; next.set_range_max(analyzer, expr).into_expr_err(loc)?; - - cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) - .into_expr_err(loc)?; - cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) - .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) .into_expr_err(loc) }) diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 2d2469c4..0f3ff47b 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -703,6 +703,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let mut tmp_cvar = None; if let Some(lhs_range) = new_lhs + .latest_version(self) .underlying(self) .into_expr_err(loc)? .ty @@ -710,14 +711,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .into_expr_err(loc)? { let lhs_range_fn = SolcRange::dyn_fn_from_op(op); - // lhs_range.update_deps(new_lhs, ctx, self); let mut new_var_range = lhs_range_fn(lhs_range.clone(), new_rhs); if let Some(rhs_range) = new_rhs.range(self).into_expr_err(loc)? { let lhs_is_const = new_lhs.is_const(self).into_expr_err(loc)?; - // println!("is const: {lhs_is_const},[{}, {}]", new_lhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_lhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); let rhs_is_const = new_rhs.is_const(self).into_expr_err(loc)?; - // println!("is const: {rhs_is_const}, [{}, {}]", new_rhs.evaled_range_min(self).unwrap().expect("REASON").to_range_string(false, self).s, new_rhs.evaled_range_max(self).unwrap().expect("REASON").to_range_string(true, self).s); match (lhs_is_const, rhs_is_const) { (true, true) => { if self.const_killable(op, lhs_range, rhs_range) { @@ -764,6 +762,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ) )); } + new_rhs = new_rhs.latest_version(self); + new_lhs = new_lhs.latest_version(self); if let Some(backing_arr) = new_lhs.len_var_to_array(self).into_expr_err(loc)? { if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { @@ -942,8 +942,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; } - new_lhs.update_deps(ctx, self).into_expr_err(loc)?; - new_rhs.update_deps(ctx, self).into_expr_err(loc)?; + tracing::trace!( "{} is tmp: {}", new_lhs.display_name(self).unwrap(), @@ -1288,12 +1287,14 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add/sub one to the element because its strict > new_lhs + .latest_version(self) .set_range_min( self, (rhs_elem + one.clone().into()).max(lhs_range.range_min().into_owned()), ) .into_expr_err(loc)?; new_rhs + .latest_version(self) .set_range_max( self, (lhs_elem - one.into()).min(rhs_range.range_max().into_owned()), @@ -1302,26 +1303,36 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { Ok(false) } RangeOp::Gte => { + // lhs >= rhs + // lhs min is the max of current lhs_min and rhs_min + let rhs_elem = Elem::from(new_rhs.latest_version(self)); let lhs_elem = Elem::from(new_lhs.latest_version(self)); + + // if lhs.max is < rhs.min, we can't make this true - if matches!( - lhs_range - .evaled_range_max(self) - .into_expr_err(loc)? - .range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), - Some(Ordering::Less) - ) { + let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; + let min = rhs_elem.minimize(self).into_expr_err(loc)?; + if let Some(Ordering::Less) = max.range_ord(&min) { return Ok(true); } - new_lhs - .set_range_min(self, rhs_elem.max(lhs_range.range_min().into_owned())) + let new_min = Elem::Expr(RangeExpr::new(new_lhs.latest_version(self).into(), RangeOp::Max, rhs_elem)); + let new_max = Elem::Expr(RangeExpr::new(new_rhs.latest_version(self).into(), RangeOp::Min, lhs_elem)); + + let new_new_lhs = self.advance_var_in_curr_ctx(new_lhs, loc)?; + let new_new_rhs = self.advance_var_in_curr_ctx(new_rhs, loc)?; + + new_new_lhs + .set_range_min(self, new_min) .into_expr_err(loc)?; - new_rhs - .set_range_max(self, lhs_elem.min(rhs_range.range_max().into_owned())) + new_new_rhs + .set_range_max(self, new_max) .into_expr_err(loc)?; + // new_rhs + // .set_range_max(self, Elem::Expr(RangeExpr::new(new_rhs.previous_version(self).unwrap().into(), RangeOp::Min, lhs_elem))) + // .into_expr_err(loc)?; Ok(false) } RangeOp::Lt => { @@ -1344,13 +1355,18 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); - new_lhs + let new_new_lhs = self.advance_var_in_curr_ctx(new_lhs, loc)?; + let new_new_rhs = self.advance_var_in_curr_ctx(new_rhs, loc)?; + + new_new_lhs + .latest_version(self) .set_range_max( self, (rhs_elem - one.clone().into()).min(lhs_range.range_max().into_owned()), ) .into_expr_err(loc)?; - new_rhs + new_new_rhs + .latest_version(self) .set_range_min( self, (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), @@ -1372,9 +1388,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } new_lhs + .latest_version(self) .set_range_max(self, rhs_elem.min(lhs_range.range_max().into_owned())) .into_expr_err(loc)?; new_rhs + .latest_version(self) .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) .into_expr_err(loc)?; Ok(false) From 7a47c4f71a9f2ab5ce9317f8730ebd62e30180a7 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 21:29:47 -0800 Subject: [PATCH 27/71] lint --- crates/graph/src/nodes/context/var/ranging.rs | 1 - crates/graph/src/range/elem/concrete.rs | 15 ++++++++--- crates/graph/src/range/elem/elem_enum.rs | 11 ++++++-- crates/graph/src/range/elem/elem_trait.rs | 11 ++++++-- crates/graph/src/range/elem/expr.rs | 11 ++++++-- crates/graph/src/range/elem/map_or_array.rs | 25 +++++++++++-------- crates/graph/src/range/elem/reference.rs | 13 +++++++--- crates/graph/src/range/solc_range.rs | 5 +++- crates/solc-expressions/src/bin_op.rs | 8 ++++-- crates/solc-expressions/src/require.rs | 15 +++++++---- 10 files changed, 84 insertions(+), 31 deletions(-) diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 16ba76d5..7012111f 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeSet; use crate::{ nodes::{Concrete, ContextNode, ContextVarNode}, range::{range_string::ToRangeString, Range}, diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index d264ee6a..da84e397 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -32,10 +32,14 @@ impl RangeElem for RangeConcrete { // Elem::Concrete(self.clone()) // } - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + fn has_cycle( + &self, + _seen: &mut Vec, + _analyzer: &impl GraphBackend, + ) -> Result { Ok(false) } - + fn flatten( &self, _maximize: bool, @@ -158,5 +162,10 @@ impl RangeElem for RangeConcrete { Ok(false) } - fn recursive_dependent_on(&self, _: &impl GraphBackend) -> Result, GraphError> { Ok(vec![]) } + fn recursive_dependent_on( + &self, + _: &impl GraphBackend, + ) -> Result, GraphError> { + Ok(vec![]) + } } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 9bf8cdf2..39315503 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -411,7 +411,10 @@ impl RangeElem for Elem { } } - fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match self { Self::Reference(d) => d.recursive_dependent_on(analyzer), Self::Concrete(_) => Ok(vec![]), @@ -421,7 +424,11 @@ impl RangeElem for Elem { } } - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { match self { Self::Reference(d) => d.has_cycle(seen, analyzer), Self::Concrete(_) => Ok(false), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index c01eaffc..8231d603 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -53,9 +53,16 @@ pub trait RangeElem { /// and returns it in a vector. fn dependent_on(&self) -> Vec; - fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError>; - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result; + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result; /// Traverses the range expression and updates stale pointers from older versions /// of a variable to a newer version. /// diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 40e3030d..2193ceb5 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -117,13 +117,20 @@ impl RangeElem for RangeExpr { deps } - fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let mut deps = self.lhs.recursive_dependent_on(analyzer)?; deps.extend(self.rhs.recursive_dependent_on(analyzer)?); Ok(deps) } - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { let lhs_has_cycle = self.lhs.has_cycle(seen, analyzer)?; let rhs_has_cycle = self.rhs.has_cycle(seen, analyzer)?; Ok(lhs_has_cycle || rhs_has_cycle) diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 96996ad3..4dcc397d 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -59,7 +59,10 @@ impl RangeElem for RangeDyn { deps } - fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let mut deps: Vec = self.len.recursive_dependent_on(analyzer)?; deps.extend( self.val @@ -68,7 +71,7 @@ impl RangeElem for RangeDyn { .collect::>, _>>()? .iter() .flatten() - .collect::>() + .collect::>(), ); deps.extend( self.val @@ -77,20 +80,22 @@ impl RangeElem for RangeDyn { .collect::>, _>>()? .iter() .flatten() - .collect::>() + .collect::>(), ); Ok(deps) } - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { let mut has_cycle = false; has_cycle = has_cycle || self.len.has_cycle(seen, analyzer)?; - self.val - .iter() - .try_for_each(|(_, val)| { - has_cycle = has_cycle || val.has_cycle(seen, analyzer)?; - Ok(()) - })?; + self.val.iter().try_for_each(|(_, val)| { + has_cycle = has_cycle || val.has_cycle(seen, analyzer)?; + Ok(()) + })?; Ok(has_cycle) } diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index beb15b7c..0b9fd386 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -52,14 +52,21 @@ impl RangeElem for Reference { fn dependent_on(&self) -> Vec { vec![self.idx.into()] } - - fn recursive_dependent_on(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let mut deps = ContextVarNode(self.idx.index()).dependent_on(analyzer, true)?; deps.push(ContextVarNode(self.idx.index())); Ok(deps) } - fn has_cycle(&self, seen: &mut Vec, analyzer: &impl GraphBackend) -> Result { + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { let cvar = ContextVarNode::from(self.idx); let mut has_cycle = false; if seen.contains(&cvar) { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index a981154f..52bd46b5 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -67,7 +67,10 @@ impl SolcRange { deps.into_iter().map(ContextVarNode::from).collect() } - pub fn recursive_dependent_on(&self, analyzer: &impl GraphBackend,) -> Result, GraphError> { + pub fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let mut deps = self.range_min().recursive_dependent_on(analyzer)?; deps.extend(self.range_max().recursive_dependent_on(analyzer)?); deps.dedup(); diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index c3bba13a..712cfe7b 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -158,7 +158,8 @@ pub trait BinOp: AnalyzerBackend + Sized { let new_lhs = if assign { let new = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; - new.underlying_mut(self).into_expr_err(loc)?.tmp_of = Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); + new.underlying_mut(self).into_expr_err(loc)?.tmp_of = + Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); new } else { let mut new_lhs_underlying = ContextVar { @@ -666,7 +667,10 @@ pub trait BinOp: AnalyzerBackend + Sized { .latest_version(self) .set_range_min(self, expr.clone()) .into_expr_err(loc)?; - new_lhs.latest_version(self).set_range_max(self, expr).into_expr_err(loc)?; + new_lhs + .latest_version(self) + .set_range_max(self, expr) + .into_expr_err(loc)?; // last ditch effort to prevent exponentiation from having a minimum of 1 instead of 0. // if the lhs is 0 check if the rhs is also 0, otherwise set minimum to 0. diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 0f3ff47b..d27908ef 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -942,7 +942,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; } - tracing::trace!( "{} is tmp: {}", new_lhs.display_name(self).unwrap(), @@ -1309,8 +1308,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_elem = Elem::from(new_rhs.latest_version(self)); let lhs_elem = Elem::from(new_lhs.latest_version(self)); - - // if lhs.max is < rhs.min, we can't make this true let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; let min = rhs_elem.minimize(self).into_expr_err(loc)?; @@ -1318,8 +1315,16 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(true); } - let new_min = Elem::Expr(RangeExpr::new(new_lhs.latest_version(self).into(), RangeOp::Max, rhs_elem)); - let new_max = Elem::Expr(RangeExpr::new(new_rhs.latest_version(self).into(), RangeOp::Min, lhs_elem)); + let new_min = Elem::Expr(RangeExpr::new( + new_lhs.latest_version(self).into(), + RangeOp::Max, + rhs_elem, + )); + let new_max = Elem::Expr(RangeExpr::new( + new_rhs.latest_version(self).into(), + RangeOp::Min, + lhs_elem, + )); let new_new_lhs = self.advance_var_in_curr_ctx(new_lhs, loc)?; let new_new_rhs = self.advance_var_in_curr_ctx(new_rhs, loc)?; From 81dcbf85ab8f893952ff6181b06de8afc997632e Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 21:45:10 -0800 Subject: [PATCH 28/71] fix #50 --- .../tests/test_data/repros/issue50.sol | 12 ++ .../tests/test_data/repros/issue66.sol | 4 +- .../src/func_call/intrinsic_call.rs | 115 ++++++++++++------ 3 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 crates/pyrometer/tests/test_data/repros/issue50.sol diff --git a/crates/pyrometer/tests/test_data/repros/issue50.sol b/crates/pyrometer/tests/test_data/repros/issue50.sol new file mode 100644 index 00000000..fb7d4540 --- /dev/null +++ b/crates/pyrometer/tests/test_data/repros/issue50.sol @@ -0,0 +1,12 @@ +abstract contract struct_push { + struct NFTData { + string[] comments; + } + + mapping(uint256 => NFTData) nftList; + + function foo(uint index) public { + string memory comment = "hello"; + nftList[index].comments.push() = comment; + } +} \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/repros/issue66.sol b/crates/pyrometer/tests/test_data/repros/issue66.sol index 27c784c9..a743f2de 100644 --- a/crates/pyrometer/tests/test_data/repros/issue66.sol +++ b/crates/pyrometer/tests/test_data/repros/issue66.sol @@ -8,7 +8,7 @@ contract Foo { function foo() public { Struct memory data; assembly { - let x := eq(data, 0xFF) + let x = eq(data, 0xFF) } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index ae1d26e2..c5226c18 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -196,38 +196,20 @@ pub trait IntrinsicFuncCaller: } "type" => self.parse_ctx_expr(&input_exprs[0], ctx), "push" => { - assert!(input_exprs.len() == 2); - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "array[].push(..) was not an array to push to".to_string(), - )); - }; - if matches!(array, ExprRet::CtxKilled(_)) { - ctx.push_expr(array, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = + if input_exprs.len() == 1 { + // array.push() is valid syntax. It pushes a new + // empty element onto the expr ret stack + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( + return Err(ExprErr::NoLhs( loc, - "array[].push(..) was not given an element to push" - .to_string(), + "array[].push(..) was not an array to push to".to_string(), )); }; - if matches!(new_elem, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let arr = array.expect_single().into_expr_err(loc)?; let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length @@ -242,21 +224,82 @@ pub trait IntrinsicFuncCaller: ExprRet::Single(arr.latest_version(analyzer).into()), ExprRet::Single(len_as_idx.latest_version(analyzer).into()), )?; - let index = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap(); - if matches!(index, ExprRet::CtxKilled(_)) { - ctx.push_expr(index, analyzer).into_expr_err(loc)?; + Ok(()) + }) + } else if input_exprs.len() == 2 { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].push(..) was not an array to push to".to_string(), + )); + }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; return Ok(()); } - // assign index to new_elem - analyzer.match_assign_sides(ctx, loc, &index, &new_elem) + analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(new_elem) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "array[].push(..) was not given an element to push" + .to_string(), + )); + }; + + if matches!(new_elem, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let arr = array.expect_single().into_expr_err(loc)?; + let arr = ContextVarNode::from(arr).latest_version(analyzer); + // get length + let len = analyzer.tmp_length(arr, ctx, loc); + + let len_as_idx = + len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + )?; + let index = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap(); + if matches!(index, ExprRet::CtxKilled(_)) { + ctx.push_expr(index, analyzer).into_expr_err(loc)?; + return Ok(()); + } + // assign index to new_elem + analyzer.match_assign_sides(ctx, loc, &index, &new_elem) + }) }) - }) + } else { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!("array[].push(..) expected 0 or 1 inputs, got: {}", input_exprs.len()), + )) + } + + } "pop" => { - assert!(input_exprs.len() == 1); + if input_exprs.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!("array[].pop() expected 0 inputs, got: {}", input_exprs.len()), + )) + } self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(array) = From 631deaeca7aa8c7ddc376c414cab493ebc4afc5b Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sat, 9 Dec 2023 21:45:32 -0800 Subject: [PATCH 29/71] lint --- .../src/func_call/intrinsic_call.rs | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index c5226c18..1d0f3834 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -206,7 +206,8 @@ pub trait IntrinsicFuncCaller: else { return Err(ExprErr::NoLhs( loc, - "array[].push(..) was not an array to push to".to_string(), + "array[].push(..) was not an array to push to" + .to_string(), )); }; @@ -234,7 +235,8 @@ pub trait IntrinsicFuncCaller: else { return Err(ExprErr::NoLhs( loc, - "array[].push(..) was not an array to push to".to_string(), + "array[].push(..) was not an array to push to" + .to_string(), )); }; if matches!(array, ExprRet::CtxKilled(_)) { @@ -243,8 +245,9 @@ pub trait IntrinsicFuncCaller: } analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(new_elem) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -259,7 +262,8 @@ pub trait IntrinsicFuncCaller: } let arr = array.expect_single().into_expr_err(loc)?; - let arr = ContextVarNode::from(arr).latest_version(analyzer); + let arr = + ContextVarNode::from(arr).latest_version(analyzer); // get length let len = analyzer.tmp_length(arr, ctx, loc); @@ -270,7 +274,9 @@ pub trait IntrinsicFuncCaller: ctx, loc, ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + ExprRet::Single( + len_as_idx.latest_version(analyzer).into(), + ), )?; let index = ctx .pop_expr_latest(loc, analyzer) @@ -287,18 +293,22 @@ pub trait IntrinsicFuncCaller: } else { return Err(ExprErr::InvalidFunctionInput( *loc, - format!("array[].push(..) expected 0 or 1 inputs, got: {}", input_exprs.len()), - )) + format!( + "array[].push(..) expected 0 or 1 inputs, got: {}", + input_exprs.len() + ), + )); } - - } "pop" => { if input_exprs.len() != 1 { return Err(ExprErr::InvalidFunctionInput( *loc, - format!("array[].pop() expected 0 inputs, got: {}", input_exprs.len()), - )) + format!( + "array[].pop() expected 0 inputs, got: {}", + input_exprs.len() + ), + )); } self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { From a5516fa5e696315af19bf07f04e02045c1d9b9cd Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 13:08:08 -0800 Subject: [PATCH 30/71] performance improvements --- crates/cli/profile.json | 1 + crates/cli/src/main.rs | 5 + crates/graph/src/graph_elements.rs | 4 +- crates/graph/src/nodes/builtin.rs | 24 ++- crates/graph/src/nodes/context/context_tys.rs | 4 +- crates/graph/src/nodes/context/querying.rs | 42 ++++-- crates/graph/src/nodes/context/solving.rs | 21 ++- crates/graph/src/nodes/context/underlying.rs | 7 + crates/graph/src/nodes/context/var/ranging.rs | 10 ++ crates/graph/src/nodes/context/variables.rs | 1 + crates/graph/src/nodes/contract_ty.rs | 23 ++- crates/graph/src/nodes/func_ty.rs | 28 ++-- crates/graph/src/nodes/mod.rs | 6 + crates/graph/src/nodes/source_unit.rs | 139 ++++++++++++++++++ crates/graph/src/nodes/source_unit_part.rs | 127 ++++++++++++++++ crates/graph/src/nodes/var_ty.rs | 10 +- crates/graph/src/range/elem/concrete.rs | 6 + crates/graph/src/range/elem/elem_enum.rs | 23 +++ crates/graph/src/range/elem/elem_trait.rs | 4 + crates/graph/src/range/elem/expr.rs | 60 +++++++- crates/graph/src/range/elem/map_or_array.rs | 98 ++++++++---- crates/graph/src/range/elem/reference.rs | 48 +++++- crates/graph/src/range/exec/cast.rs | 36 ++--- crates/graph/src/range/exec/concat.rs | 36 ++--- crates/graph/src/range/exec/exec_op.rs | 32 ++-- crates/graph/src/range/exec_traits.rs | 2 +- crates/graph/src/range/range_trait.rs | 5 + crates/graph/src/range/solc_range.rs | 113 +++++++------- crates/graph/src/solvers/brute.rs | 4 +- crates/pyrometer/src/analyzer.rs | 42 ++++-- crates/pyrometer/tests/challenges/apron.sol | 10 +- crates/shared/src/search.rs | 22 ++- crates/solc-expressions/src/cmp.rs | 22 ++- .../src/func_call/internal_call.rs | 2 +- .../solc-expressions/src/member_access/mod.rs | 2 +- crates/solc-expressions/src/require.rs | 2 +- 36 files changed, 767 insertions(+), 254 deletions(-) create mode 100644 crates/cli/profile.json create mode 100644 crates/graph/src/nodes/source_unit.rs create mode 100644 crates/graph/src/nodes/source_unit_part.rs diff --git a/crates/cli/profile.json b/crates/cli/profile.json new file mode 100644 index 00000000..ee62d6b4 --- /dev/null +++ b/crates/cli/profile.json @@ -0,0 +1 @@ +{"meta":{"categories":[{"name":"Other","color":"grey","subcategories":["Other"]},{"name":"Regular","color":"blue","subcategories":["Other"]}],"debug":false,"extensions":{"baseURL":[],"id":[],"length":0,"name":[]},"interval":1.0,"preprocessedProfileVersion":44,"processType":0,"product":"cli","sampleUnits":{"eventDelay":"ms","threadCPUDelta":"µs","time":"ms"},"startTime":1702240022036.5378,"symbolicated":false,"pausedRanges":[],"version":24,"usesOnlyOneStackType":true,"doesNotUseFrameImplementation":true,"sourceCodeIsNotOnSearchfox":true,"markerSchema":[]},"libs":[{"name":"dyld","path":"/usr/lib/dyld","debugName":"dyld","debugPath":"/usr/lib/dyld","breakpadId":"EC7A3BA0F9BF3AB8A0F48622E5606B200","codeId":null,"arch":"arm64e"},{"name":"cli","path":"/Users/brockelmore/git_pkgs/pyrometer/target/release/cli","debugName":"cli","debugPath":"/Users/brockelmore/git_pkgs/pyrometer/target/release/cli","breakpadId":"7721603B0FB13E2CAA802837F3BC6C910","codeId":null,"arch":"arm64"},{"name":"libsystem_kernel.dylib","path":"/usr/lib/system/libsystem_kernel.dylib","debugName":"libsystem_kernel.dylib","debugPath":"/usr/lib/system/libsystem_kernel.dylib","breakpadId":"B7751381144230B591B9AD7BE461BEBE0","codeId":null,"arch":"arm64e"},{"name":"libsystem_platform.dylib","path":"/usr/lib/system/libsystem_platform.dylib","debugName":"libsystem_platform.dylib","debugPath":"/usr/lib/system/libsystem_platform.dylib","breakpadId":"FC8CD17B8769348C8DCD1BFED022F9E40","codeId":null,"arch":"arm64e"},{"name":"libsystem_malloc.dylib","path":"/usr/lib/system/libsystem_malloc.dylib","debugName":"libsystem_malloc.dylib","debugPath":"/usr/lib/system/libsystem_malloc.dylib","breakpadId":"901200AA10163DAA88165032588ED4600","codeId":null,"arch":"arm64e"}],"threads":[{"frameTable":{"length":5083,"address":[24799,463471,4728535,483391,395759,437291,4732935,4744855,9332,437815,1967263,4604803,4574255,4114235,4251667,4086836,4109755,4226751,13940,4107695,4140180,4105231,4176223,14084,4574115,4569707,4567119,4564555,4609267,4764,4117623,4095840,4574192,4114103,4232528,4561996,4107103,4232527,4113027,4232668,4109479,4212539,4965359,4552179,160227,158431,22123,14072,4105152,1967571,1968703,1971135,1983123,2056263,8939,9403,11647,28036,1985443,1998355,1905031,2060783,2079443,2082307,2045327,2082155,2085859,2084783,4850571,4992,2059247,2080295,2078083,2078495,2083671,2084835,2043604,1969623,2027975,2032895,24243,25592,1967683,1941371,2348775,2046743,2330475,2358163,1952691,2391463,2348011,2366779,2077199,2082179,2045731,1941635,2549787,1951059,1935875,1320983,1349711,1309059,1713167,2862955,2792547,1918207,2628444,1942491,1339367,1740271,1743311,1363955,1370951,1349839,1725211,1772739,1757732,1320903,1724491,1772783,1736095,1770463,1310723,1589631,1591607,1592455,1593335,1572211,2663767,3216163,4060288,4060191,4065124,1309819,1590287,1917987,1920863,2816935,2190143,2004807,1920795,2818939,2200088,1591535,1891639,1567691,2750491,2747463,2710479,2712103,3079155,3117436,1309335,1749015,2862987,2004664,1715055,1730235,1310407,1572895,3216120,1349575,1723003,1772079,1786735,1306255,1633739,1641923,1662571,1665387,1690379,1675807,2753267,2747211,2470048,1633607,1645763,1663619,1699175,2877127,2747127,2461091,2766175,2523035,2704955,2469551,2714739,2764535,2466839,2714187,2764911,3098971,3017079,8903,13627,16891,17176,1575791,1574091,2754791,2721048,1363455,1604991,1606775,1609747,1625211,1308875,1221747,1222787,1217371,1235679,4060343,4065140,1741263,1756383,1757371,1307243,1706335,1422771,1760599,1761479,1308515,1390807,1303895,1391491,1725163,1773915,1310511,1574907,1692155,1681135,2747435,2460659,2766299,3091735,3171788,1607467,1702979,2716343,2764255,2764351,2764443,2714688,1606495,1285059,3099007,2927660,1625411,4064956,1751639,1895767,1713863,2653899,2355555,4850611,14364,1607531,1300271,1349887,1277999,1368159,1376943,1255359,1274507,1256823,1386923,1380007,1930803,1925855,1928251,1928327,1928407,1929183,1309251,1534143,1306647,1570631,2522051,2711343,3080027,3076935,3076075,128440,1722115,1830619,1833203,1229863,2004631,2628392,1769439,4065012,2792611,2614359,2158539,2628483,128175,13324,2614387,2300439,4981848,2747823,2763051,2712855,2771719,2774187,2774267,2774296,2818995,2621879,2231136,1572723,2766235,2766540,1633695,1652507,1654095,1664187,2746515,2737863,2683003,2695483,16868,1743347,1854848,2158587,5348,1607735,1302595,1309171,1246867,1714907,157836,2653991,4848891,4876127,4850963,4979347,4847591,17828,1276915,2843695,2844043,2836359,2319103,2317808,2738331,2746971,2695315,2699611,2699899,5128,1577635,1691307,1670875,2695368,2710075,2713095,2525167,2524607,2574223,2574283,1633651,1638859,1745487,1878371,1746835,2098564,1737955,2610935,2147167,2827771,2756747,3064691,7492,1577471,1703343,2859859,2740943,2740256,1665227,1697059,2877664,2747155,2712979,2525279,2530011,128508,1644603,1217543,1228063,2748063,2762219,3060820,1248263,1250039,1250811,1315215,1385347,13904,2147371,2828227,2710367,2525235,127568,1339179,1734619,2165999,2259355,2866971,1920740,4876051,4979395,4847627,4759784,1308295,1596995,1598567,1700467,4850919,14340,1835467,1836015,2875427,2874515,2483619,2135291,157824,1607671,1267639,2711931,3080535,7456,1384647,2756363,2661695,157752,2299703,2313856,1385603,1314327,1381139,1863839,7380,2713215,2765904,2711835,3117399,3121543,3121476,1710711,1382051,3073095,3071744,2826843,2695383,2699531,2699455,2700960,1633911,1648975,1702859,2522363,2712235,2765847,1714912,2654079,13360,2792775,2300283,3092955,3171087,3209200,1716979,1307387,1877055,1617171,2683307,3269207,3031483,2948747,20063,28184,3104579,3331747,3347931,3043255,3043568,1601407,1219095,1309223,1542995,1593631,1567215,2711932,3060903,3056623,3057671,3057879,3046195,3041508,1572039,2712100,2524907,2761552,1640763,3057611,193368,127908,1593467,2753239,2710167,3079683,3121431,2459711,2472543,2644691,2645243,2637732,2521959,2524731,2739971,2730187,4935091,2317847,17799,128152,2473027,2623340,2700543,2638036,2464780,1388307,2460019,2472955,2524875,2761243,2513771,2513847,2513927,2513248,2683323,14108,1706731,2876867,2869472,2623359,2240104,1575123,2774247,127503,6627,7216,2711912,1383163,1925787,1929736,2525339,2531419,2544875,2531395,2529991,127672,3080131,127924,1588219,1308827,1615767,2663619,3214615,4063812,2644875,2645188,1248879,2711435,2768083,3095299,3017492,1625311,1309519,1594887,2741967,2699375,2698912,4064996,1624931,1308467,1390755,2752107,2699616,2459803,2464311,3079719,3122275,3121532,1633783,1638099,1655679,2522251,2774216,2466712,1670467,2710723,2722607,2719627,2722548,7420,2461187,2475943,2623388,1661991,6204,2513691,2513928,2827951,2760439,3065371,3056651,3041359,19312,1640019,1660087,1671607,128204,3084440,1722059,1729391,1789927,1805331,2519043,2767695,3112640,2772715,2644727,11492,2761575,2514724,3122155,4981824,1662427,1697635,128352,2827567,2758191,2699235,1307835,1392663,1393455,1402479,2741427,2743235,2721075,2722583,2514744,2463727,2544851,7408,2758799,2758575,3062503,3046183,3036936,2241788,1662507,2513907,5120,1544575,1546379,1547403,1549491,1381659,2464387,2240752,3086447,127936,3076056,1308731,1287607,1326111,1320003,128196,2200520,3122096,3122060,4060328,2531352,2760015,2699591,2753019,3061627,3057643,3057699,3057687,128444,3079192,1599987,2698688,2711075,2462583,2623348,1387839,2472887,2513564,1594987,2738395,2748736,1363351,1259639,1556171,6028,1741831,2078528,128496,2711171,4984,2240100,2638000,1285035,1910387,1912731,1910267,1908939,1908823,1912711,2949015,4981860,1548643,1928387,2749383,2699435,6088,1550227,1904783,1929091,1929368,2699612,1545219,1711663,2460375,2483047,2650779,2629364,3122216,2240120,2716395,2704775,3105103,7448,2464091,2482944,1920700,3098892,3086463,128124,1568419,2730960,4064960,1689287,1927591,157792,3079167,5884,1277871,1254279,1386455,2757519,2712423,2465100,1672927,2700215,2623623,2546563,2226080,2462584,1699311,2579019,2757556,1668603,2750243,3063183,3266859,3266919,3266947,4981740,2461923,2645324,2948411,3053591,3072344,2774419,6212,3122924,1668487,2751319,4981736,1363543,1561451,1780171,1549899,1672735,2513435,5804,1837511,3017603,95628,1706163,2869412,3216575,4063612,1743331,1766095,1765303,1767215,2484211,2047531,2257739,2260031,2744503,2669195,160236,4060215,4065152,2740648,17783,13916,2755691,2712424,1349787,1297939,1883463,1373859,1251947,2856587,2855823,2855804,2523143,4944,1254695,2097959,1381515,127972,1765267,2744915,25120,1366432,2825931,2672763,3063251,24768,3172039,4063500,3095335,2927944,1607267,1607955,2712195,3016688,2767416,1690979,1623619,1863819,1871399,1871132,4875680,1308371,1393943,1929071,1560283,1366991,1311976,1701859,95512,2654032,2767539,2490804,2466188,1694667,2695288,1838695,1263179,1841987,1780683,1272243,1804639,1925975,1927464,1549767,1204199,1803535,1209607,3073111,3072583,3072975,3045311,3051964,1551119,1916208,3216175,4064968,3076900,2047279,2744479,2775819,2771119,2774107,2771512,4060276,2004828,1710763,2878468,1682579,3096155,17168,1338083,2001407,2747924,1623627,1863847,1871343,128276,4065076,1576031,2766203,2460572,1770464,2260503,3057472,2714627,2773092,1780899,1711095,2664923,2672419,3009867,4850528,2877439,2625284,1227651,2665987,2672575,3271791,4065048,3093051,3166572,1688707,2699119,2699831,2700340,1723987,2469623,2475383,2513219,2486051,2645231,2472856,1749667,2187391,2653147,2476079,3090716,2200080,13928,1749699,2865755,2791715,1920596,17276,2855824,2460755,2474388,2525032,2699139,2698932,2758559,14048,3036964,1920656,3057659,128156,2313784,2463272,3061559,3266843,13344,1758115,14356,14348,3088819,3156095,2793379,2223136,2739943,2728756,3093639,3171400,3086431,2793239,2238059,4065044,2711475,2765899,2190571,160212,4060308,1833263,2119515,2816391,17755,1766771,2841659,2061419,14116,1736867,2876943,2845555,2845556,1682939,2711116,23936,1733111,1483691,2870231,2135195,2258555,2874643,2871112,2728816,1689359,2698795,5876,1320860,2751352,2839451,14324,3156112,2828203,26492,3076928,1736735,7440,2845379,2862352,1930627,1709751,1380604,3156187,4063524,1757935,2810411,2811559,2785663,2789027,2788576,2238104,3079695,3117788,1574995,2765972,2654020,4848596,2864247,2649671,2628223,25212,1218888,3266891,2741295,2771239,2771188,3106079,3077279,3027584,4850556,15740,2654059,1742351,2098600,1698895,1320783,2843611,2843767,4935135,2317887,1551087,3057252,1665267,1380000,1696839,4064852,3097791,3336827,3346883,3345051,3345247,6064,2695519,2200811,1570632,1690803,2685676,1703475,1871487,1871459,3095824,2513751,3016919,25336,1681015,2793107,4820,2698756,2700968,3057180,1689335,3261107,2826643,1696879,1248135,1537199,1540075,1542175,2877155,2733519,4850632,1633563,1643843,1653303,15452,1636939,2740535,2739896,2826423,95668,2699271,1671387,1928715,1927728,3101043,3077184,2513199,2466708,1920864,1772663,2139383,2249671,2267135,2270519,2270068,2249499,2673139,2699215,1595099,2767499,2792627,2794300,2317792,2223287,14572,1897031,1775359,2825391,2884527,2880851,15420,2766263,2773152,2469519,2704920,1226439,2845372,1665331,17000,2200100,2475780,3057236,2466807,2525919,2488528,1584255,127692,2516531,2735203,2659803,2703303,3089971,3169071,4062431,4060928,2749072,2241091,4063584,3112596,2826004,2740227,2728668,1576511,3098655,3162883,3201667,3206044,4063536,3073043,3071976,15931,188236,3122880,2767619,2719064,1758511,2197131,2822767,3212255,3076032,1680907,1378095,1928303,2700387,5360,2748576,4060395,4065052,2712203,2719672,127712,3266748,2719596,2354672,2669063,5188,2525615,4848748,2740503,2745564,4876035,160015,17884,1920648,3057515,7484,11388,2699507,5296,4759772,2513671,3086415,1928067,7452,3108819,2927891,3209404,2839339,13364,2699768,5856,2704840,2863043,2614667,2178079,2779224,3212319,3028251,3026807,13992,4065128,2119419,2816303,2771051,3096255,2976852,1690275,2685699,2704800,3266627,3266592,1358219,2843412,127988,1925923,2069056,1738191,2357175,2115296,128148,1298011,2855516,2699256,3017308,2710339,2190487,2751143,2712467,2524407,2319059,2317928,3057247,1928171,1731631,1733759,2874560,2811159,159864,4064888,5020,2711652,2200467,1920711,2624227,2205187,2682824,2793060,2699648,3079244,2713076,2206155,5812,1699347,3214699,2699356,2747519,2700980,1765904,2793076,2299888,1929776,2098588,2653243,2863495,2140507,2608436,2811347,4850884,3057220,2730119,2730055,2729844,4788,2355536,2785691,2788999,5848,2827231,1573511,1917944,3057395,2461596,2699544,1758003,17495,8140,2544867,3266803,7360,2531412,1255211,127976,2869443,4832,2863183,2622243,3119100,2810887,4060144,2649707,2719584,2728532,4850940,2761564,1930615,2704908,5220,2816991,2231224,127700,1592411,3258440,1308107,1404719,2763211,3240268,1767279,2878487,2320327,25691,27536,2832659,2835183,2835211,2835239,1925955,4060320,1654012,1920608,3027647,21435,23548,2513048,2513531,2712835,3212055,22051,11240,1572355,2730211,14332,3057208,2764632,3017256,2522223,2525148,2728576,2927671,4065028,3076856,2855747,3060324,2788967,3017279,4981872,2793172,1689591,2077323,2082059,2085839,2513228,2300332,4060176,4063875,4058735,4906124,1854871,2032103,2021383,2032759,2021371,1927472,4064900,2826063,2880683,2881975,2882051,2882907,2730156,3117159,3124908,21364,3117884,2728452,2826676,3211999,2855603,2200036,2826827,1915684,3057380,2774372,1566987,5112,1715175,2700956,1767023,2070791,3156140,3057300,2861055,3245895,3243887,3244263,3067539,3074283,3074243,2771708,2238116,3122104,2513587,2625483,2546883,2216631,14368,2624212,2789055,2788564,1703443,2683324,2531388,2880871,2880984,2774308,2710299,4060248,1927484,1766807,2578951,2662063,2513260,1920943,2624032,3108923,25204,2004796,3172075,3201059,3203456,2699291,2698944,3086460,2774188,3064791,2793627,2653311,2622288,10416,3076008,24500,3088644,3075992,1549371,2845536,4065024,2843144,2827051,2774027,2528579,2729099,3079819,3122860,2140691,2608252,23883,2774212,2695347,2700592,1605307,22139,95780,3122896,2728528,1736983,2098580,1568223,2313879,2354824,2525147,2544632,1685919,1871304,2663691,17500,2843467,2843444,2843168,3091883,3117792,2794323,1648527,1602063,3091951,3207803,1752723,3090804,2788608,2730239,2522783,2704987,2748535,2712587,1551387,1871511,1843643,24788,4632,1320708,2461540,6036,8052,1570367,1302531,2746383,2774087,16711,27076,1349631,2843388,2739700,2827459,1251619,2855620,1675395,2747971,27352,1267383,1633827,1636179,1654887,25256,2529972,1316187,1384567,2524355,2729868,3112611,3076712,2792007,2109239,2002987,2628783,2775643,1664711,2761647,2719068,1633167,1880607,1651347,2514748,2546636,4065104,2845459,1914728,13088,3112575,3076688,3057396,1392383,2854616,2354671,2835071,2834792,1928627,1927552,2740859,2730020,2525136,4848868,2523096,1700607,2877428,2461468,2531400,2761055,2691523,2518907,2711415,1589304,2460636,3075592,3088927,1702999,2861827,2879864,2672543,1384355,2683443,2800536,4981856,2767500,2712652,3093103,4063532,2871260,1920780,2645179,10476,1669479,2759675,3063907,2460131,2462332,1697595,4876036,4064932,2469504,4934988,2771684,1929152,1928231,2653331,5828,2614471,2235439,2466808,2712896,2845307,1929492,1741468,1929508,3243899,3244151,3068283,3074411,2004663,2628552,1685847,1871431,4860,1713915,2876995,2862488,2793640,1254439,2672548,3117176,2513880,2222984,2654031,4624,3057216,2523991,2728472,2462507,2711076,1306452,2486180,14352,3016736,2700708,1735559,2665340,4847680,4065108,2832644,128260,2628804,4878072,2793215,1549543,2878072,3056748,16872,3086516,2465072,3121416,2469700,2710683,3121704,3072084,2466328,1696947,2728284,4065132,2524856,1927892,4850960,2235055,2777896,2201088,3122128,3057847,3041659,19771,29252,2672868,4064688,3266699,3266935,128452,4065064,1230019,2627923,23828,4848824,3057660,2514331,2463344,1685947,1871415,2845255,2862456,3266907,2861315,2832687,2835227,2463364,26900,2200556,3122828,2004620,3076068,1896899,1385543,2731216,4064988,2699919,24752,2699640,2205119,14580,2544815,3087852,4935092,3122140,2845232,2793028,2810923,2681663,2881276,2740055,2734896,3091856,5152,3057563,2773704,2524480,3166827,4059284,3057531,3057672,2728799,2765908,1928695,1928607,2734664,2839504,2793372,3117136,3119256,23832,1929011,1929339,2637516,3057595,1391151,2874612,2627984,2695503,2698843,4847576,2748043,3079888,4876052,3122280,3103383,24832,1571775,3071903,3071967,3072100,2068864,2522607,7424,4672,1385395,2698676,2699991,2771875,2855728,3260707,3286175,3289003,4063560,3079928,2739840,1315651,1897871,2844972,3091595,17132,4065056,2712535,2317872,3216196,1540123,2872852,4848612,3017544,1697155,3098503,3201676,1349788,1693915,2485863,2486124,3117428,2654092,2767031,128180,2001099,8220,1838352,1544899,2871156,1633871,1647667,1659023,3113859,1930672,2771983,2771652,2624172,2625360,1693243,1871447,2762756,2474551,4850948,2231723,1699547,2140680,1928208,2826563,17328,2698772,1607319,1265939,2884351,5024,2741819,2686087,2490483,1568839,4876012,3062403,2729895,4064972,13112,2779167,1616256,1309067,1867411,2839471,4848920,2047647,2628632,1925819,1927639,6192,3203508,2828119,2834840,2083664,1871383,1675975,1770311,128140,3090795,3171279,3088812,2699636,2531376,2313748,2627956,2528743,608368,3156128,25275,26992,2300424,4935152,2260311,13920,4864,2514008,1767883,2098816,1381787,1914868,2855948,1719355,19808,2845300,2223251,16780,3108787,3057455,2513492,1549291,2300468,2927500,2098568,2522891,3105291,2862360,2747636,2767128,2685811,2525708,2098592,2158255,2354660,2524763,1929772,1615991,2628167,26504,2469492,3121572,1550971,2069048,2516843,4060304,2466200,3071819,3072932,1605583,4847560,2205151,4847832,1871144,2474552,1863951,2713975,16804,1306704,1871344,2827492,2721103,2722599,2719620,2761455,3266875,1927708,2313860,159884,2811495,2788516,23888,4696,1220879,1217195,2666231,1920620,3076063,3075580,2764484,2810243,2669303,2531472,2711443,2764720,2816268,8908,1692627,2299984,3206036,2628408,2712104,17480,4064772,1556211,2843696,2473028,1386559,6044,11615,29604,2546616,1769007,2060991,3076916,2513151,1380588,9256,1609767,1858747,1858455,1858388,2240592,2158371,27012,2470068,2513455,2514408,2699532,1914756,2757859,2677311,3118124,3031395,2919403,2930411,2004780,2771508,1625511,1557203,1875711,1558371,3056755,3056644,4065156,2880715,2881196,2225812,1692327,2732072,2004700,2714607,5324,11332,1781415,3053536,3117243,3124043,3043559,29628,2765832,1741796,2728432,3122908,17364,3057815,2645308,4063580,5924,3079164,1616031,14588,4058679,1558059,2546728,3104755,3043580,1672899,3079608,2226072,1606503,1858771,1858704,2461036,1914971,2318447,22103,18875,81199,6324,3122211,3124432,2462956,24775,74972,2700079,3041284,1871475,9096,1666715,3092612,2828151,2835419,2650831,2629112,2523455,2730312,1597331,10571,45884,2225120,3075568,2061383,13391,108644,2699355,6076,2623284,2623608,2475659,2480396,2740136,2645272,2869424,2524587,5164,2474279,2629288,2474027,2466956,2225488,3104403,2700515,4876072,2546500,1699147,3102699,3241292,2826887,2361063,2339684,3057767,1927496,1405455,3099071,2977511,19859,29300,2481091,2483187,2481084,2766236,1273468,25604,2513171,2485631,2486023,2514692,3071879,3072547,3045128,1314224,2522832,1925820,3269411,3289159,3043652,2761387,2690984,3046184,2531407,2540172,27088,3122288,2481072,2779255,4752,2759211,2754136,3101967,3240636,2874780,2475944,2475671,2629004,2645200,1928468,2771576,3053516,27040,2474380,1307423,1619767,2475875,2469444,3113839,3156392,2474159,2644843,2635712,2623308,3124972,1576835,2853331,2855776,3031367,3008988,1544172,2544876,1928787,1929311,3216059,4065148,2472679,2629104,160172,3057988,3079140,4063504,1572171,1928151,4065080,3037455,3037427,3037443,2465212,2635732,2463284,2826804,2540184,128044,2623652,2764836,2779300,2544835,2712068,4979348,3046171,1227759,3171315,2629248,3017524,2713995,2459995,2650807,2620579,2620607,3240288,3122100,3037416,2712804,1625711,1217859,1413455,2845000,1928875,2740660,2880887,2513892,2772107,2826615,2318867,2772687,2744803,2774328,3043235,3048940,1380076,2464172,1862704,2546436,2645136,3082327,3238919,3077507,3121584,3216536,2525064,2201096,2763556,2699556,2845212,2699576,2240736,2465675,2097699,4935299,23852,3117352,2825587,24876,1702776,2747091,2225528,3099047,3043120,3122832,2466911,2473831,9352,2636667,2636587,2635812,2514300,9180,2700295,2355300,1680947,2629343,19791,30140,3122224,3043071,193400,2762607,3087884,1551175,2473183,2513112,3117416,2320283,3244715,2747112,2475363,2514215,3048884,2700320,2682796,4065136,3076795,1863935,2635708,3157131,1625611,4848839,1928316,2225968,3080116,3266971,3037744,1204023,8152,2637724,3043107,29460,2763520,1708584,15432,1702831,2083687,2081943,2713044,2227676,2462287,2481060,2462948,2465347,2183135,2258164,2728616,2767968,1557975,1925991,2614732,7472,2227323,29688,4065112,3037008,1833399,1310795,2664051,2795204,4064908,2827315,2638032,3122088,2227184,127480,15588,2517775,3098759,1285079,1858395,3117860,2751176,4876128,3046143,3041268,3117164,2241784,2475796,3266764,2766599,2698815,2635968,2629136,1672947,3289131,3287300,1668191,2183199,24908,3090743,17396,2462968,3072080,3043223,1379907,2729328,4759880,2078019,2080319,16120,2713144,2695415,2700972,15908,3117356,2729856,2869488,3076876,2629043,28288,2861843,2494251,2614939,2175796,3076724,2638016,2827528,2240144,3079808,159996,2469792,3080039,20332,2844975,3121488,2737463,2719603,2718684,2826931,2628968,2623424,2544816,3203428,2475551,11156,2472263,13368,1312212,1925887,1928767,3076756,2069072,3089955,3170124,158364,2625331,4792,15712,1927915,2472768,2645348,27560,2677271,1954479,2813052,1721420,13300,2747991,2645336,4848632,3043623,3048900,2729740,2540192,2699692,1928011,2636647,2466792,3061519,2470000,2472784,4065072,1843735,2623452,4064844,2711340,3037152,1693171,29812,2355308,4065068,2774176,2719643,2466780,2644855,2637708,4848620,2461291,3056671,3090003,4060848,2704807,2771540,1579839,2741047,13372,3080323,2645292,2227336,1928252,2235048,2764332,2764848,2771568,1638440,2637443,1928087,1927652,2699184,2469764,3072959,15476,2729732,3086403,3057627,96156,2774192,6180,3056643,3046076,2628952,2513551,2825611,3091683,13612,2635988,2354808,8856,2466240,2517883,2513823,3121556,2623368,2740476,2225371,2774352,2466292,2690980,2494123,2649815,3017820,11376,1694751,1871327,95852,1694759,1871367,1843659,11624,2948548,2695508,1606911,2879927,2641587,26980,1568163,3266643,2737099,2688307,1916451,2546540,3102015,3079720,3117412,1568899,2644924,3076128,14420,3264951,2183116,1929720,2881955,5624,2690972,2825600,2205951,2755708,3043611,2464228,3017540,11452,1648936,2637980,3072540,1379336,2513728,2862212,3117740,11239,2703331,3075576,2637972,2225476,1929756,2650820,3043284,2666259,2462408,2762740,2881895,3102799,3077195,2461644,3057871,2464204,3048628,3057799,1668451,2715599,3016996,3087904,2719608,2225175,2225944,2260219,3057439,3041680,3057723,2765912,2722567,127844,2747472,4877308,2624044,2482964,24472,2077975,2083495,2083235,3209360,2463204,2747031,2461156,2546631,1582423,1954399,2657971,2693924,3203484,2882111,3217803,4064055,4876160,128064,2763519,4850620,2472804,3041603,28444,3079224,2574303,2574807,3046636,9244,2629360,2241080,2764788,2512980,1927616,3090163,3046896,2771580,2713188,3162596,2462972,3057596,3121487,3122168,2623260,2623604,2513872,2514060,2355304,2645392,1205471,3056608,2461400,16816,1379187,2854648,2464800,2740332,1609271,1858627,3057483,3041564,3088492,3096231,2513032,3043224,1617532,2514684,14360,2637763,4066056,2473288,2764708,2645132,2645244,2226132,3117332,6052,1558839,2860775,3046892,2645232,3071764,2623304,2178108,3009551,4947355,20040,2258152,2698864,2238028,2879867,2071640,2464388,3112599,95636,2710428,1702655,3268500,3094051,4060132,5196,1707020,2927568,3043612,1843687,128256,2238032,3121720,3117784,3009007,3259688,2463376,1639164,2700059,2650819,2620128,28260,14440,2845392,16848,2623352,4759776,1376619,2874404,2019195,2018975,2021855,2845460,2623644,2700920,2762771,3240232,3053712,2241076,2459536,2665476,1737167,2524904,2728564,17288,2841519,26940,2513607,2843143,127984,2514360,2528679,2575316,2740040,2862059,2831932,2880819,2069003,2091776,19879,29692,3046196,3091463,14468,4982328,6200,3095399,2976828,6032,3043676,1929768,2238088,2513128,2774200,9259,1669847,2816963,2472684,3260227,3285219,3078279,2861155,3137303,2970071,2976864,3112591,2761123,2739804,2855515,157804,1356659,2153580,1954551,1860000,2530056,1928991,1277011,2857716,6100,2462940,30532,1308419,2824963,2358899,3266604,4979304,13104,2764808,2731204,3122200,1929212,2624060,2525204,3057336,2735771,2747800,3209240,2474483,2467052,2712108,3265936,3156111,3209375,4063435,3079112,1252371,29872,2076984,9388,2240756,2877040,3122324,1706383,2518091,2258027,2465068,2711616,2638020,2839087,4850916,2766835,157800,3017064,2875196,3080143,1920588,1843612,2472664,7736,2760736,2459516,1685819,30032,1929344,1928812,3088900,2528659,193420,1615719,1582647,4065212,2728516,2843819,3266787,3266564,1573975,3240128,3104384,3017016,2753195,1920716,19364,1914727,2513876,1255163,2544844,1696607,2730971,3122856,2700432,2948539,30116,1902840,20344,30552,5264,1306519,2843120,2472976,19240,2463400,14124,2474528,127944,3090752,3084468,2513952,2473000,2622395,2545963,2223504,1570603,1548931,3048944,2619540,3204191,3195172,5888,5052,3087896,2838676,4065096,1579283,2258188,1696443,2731092,2855764,1251908,2764872,1305319,2857872,3203476,3122092,1548731,2799688,2225108,3122844,2225184,1713539,1311095,2765816,2772808,1557703,1858723,1696747,3132152,3017088,3057516,2519299,2540527,1568184,1691887,2513008,1920664,15884,4060544,2764820,128284,3076676,2464792,3091808,1308792,2728468,2206179,14612,26952,3169404,2712412,3103419,3209543,4064672,2712004,3041676,2740035,2462424,2728800,2226064,3117388,2860967,2231208,2729855,3060788,4065040,2623360,2525531,2771783,2711876,2033667,2710564,1366372,1928184,3264995,4065216,3048920,1696991,2466035,2722572,2869464,1871288,2699956,2225592,2467356,3122460,2641600,3060840,3209228,2517039,2540555,2472788,2514728,1320984,2698820,2774136,1311055,1931459,2658208,2828267,1915912,1843751,2699971,27620,2225440,3243868,1668991,2774388,1928356,2624036,1871424,2206084,2711836,1600480,3089004,3056656,2472748,2474404,3046172,1790319,1797611,2665395,3056640,2762556,3076044,2843591,5960,4063920,2712452,4064824,3048632,2700924,2645312,1706244,1672671,2700976,95784,2004808,3206024,2654008,2524023,3037056,3103436,2645320,2777695,2699811,5936,10456,19804,2710056,1306531,4491616,2712800,4063544,2360807,3270368,2514740,17640,3112604,2514736,28004,26828,95944,46199,5711,5964,3088756,2240724,2224367,3043756,2645220,2529332,3207944,2827167,2614779,2777612,2472880,2225300,1607031,2844611,2855836,3122256,2241064,3122116,3266668,2524472,1798039,2473055,4060876,2463764,2235131,17400,2635728,3121444,1858711,3285383,3122300,3046156,1550783,4877268,2183152,2529304,2746204,2621811,2764236,2845224,3117223,1226363,4847612,3053512,2200012,2513836,1348460,2461124,1843767,1309023,3136731,3235599,16388,4064976,2628984,2623396,16644,3053472,2573616,3113647,4952,3053552,2614736,3122268,3122872,2637744,3171320,2225448,2474344,2715612,2711448,13392,2523992,2739904,1320795,4491772,2097647,2453287,2607928,2629287,6072,2465411,2178784,2512976,2158540,2718720,4065000,3046212,1765719,2840623,2641596,1765159,2854600,1765788,2843136,2843676,1765160,14092,1297043,2843288,1765236,1339443,1269035,4935136,2200096,2486148,2862024,3313900,4876120,4903251,2355324,1769839,3258644,1928052,2313803,14372,24244,2470024,3209532,2216595,2774208,2635744,3079983,2713284,2767032,27960,3043692,2205292,2751200,2300068,14388,1773575,2135208,2731268,2730192,157840,2354696,1672311,1277595,2513136,1573639,4876740,1735707,2313820,1927935,1927732,2299612,2614419,13628,2238120,2205331,2793152,17531,15512,2712572,1697615,2473075,2650919,2757540,26364,1230011,2608288,2739920,2047407,3240360,2687807,96199,49711,56495,13175,5928,1227043,2256195,2365304,2839319,19288,1666923,2773136,17668,2816459,2526352,188244,2628696,2879996,1642683,2881811,2881144,2644648,1715488,2695600,2624076,1596308,128200,2824884,2734639,15376,3122152,2728680,1622899,2704828,2740167,2733844,1582091,2741316,2462340,2728704,3017128,2475660,4981828,2222951,16536,2225356,2462299,3060427,4896,2699492,2522772,1769803,1901691,2216295,2623324,5368,1925840,2525551,2575008,1592396,2819056,2519203,2759251,44251,130031,44447,17720,28408,95908,157832,3081672,2884623,157756,2699672,2879804,2766156,2466716,3096191,19840,2320228,3057547,1694795,2731867,1380580,2839647,15424,2930412,2948947,14528,2747700,2719659,128176,4850856,24864,3136887,3033535,1871460,1929416,1549059,2464772,2771016,3102575,3188904,3099056,1786183,1889756,127912,3087908,2880808,29580,16276,2083199,2082627,1871104,3092671,3180416,2729092,2530027,2544840,3136515,3152508,2711496,25067,27532,2462988,3122308,2843424,3057831,2644700,3043516,2466000,2645296,1927488,3017008,2699292,3043696,2513852,3043716,3079120,1379008,3045251,3028808,1843791,2825671,2224399,4981876,2464796,2712559,2765864,20148,30044,2241092,1871183,3041652,2839576,2714040,1700075,2728604,2747092,3048932,3102295,3079760,1930831,29768,2880751,1927740,3057524,3041420,2766996,2691536,2749599,14128,2740068,3117432,1773955,2030172,1928855,1929784,2771744,3072368,2666079,1384324,2764764,2793136,2472936,1918204,2528440,2855488,2223176,2695440,2773144,1229883,1245867,2760704,2629192,1549639,3079900,3031427,2578952,2765860,2525735,2729100,1928031,1402595,1403832,1670763,1688692,2624068,2700356,1381460,30064,2469468,23860,1637936,2531468,2638028,1307507,1610639,3046112,2747923,2927604,2638004,3098820,3046612,1706036,2081967,3087864,2466164,2767651,2719040,1699312,3080380,2463752,2514464,3209408,3102675,3077060,1606647,2494263,2071616,2525488,2764888,24652,2882131,2882308,30356,2884747,2177887,2779240,1700507,27400,24260,4063939,4058707,2735159,2773947,2771672,23824,2628992,1606451,1910283,2636600,2699560,2839663,4903160,2740296,127340,2464288,26352,3009176,2629204,2231443,1692291,2728184,1597615,2205271,1574855,95956,3056712,3041672,2241776,2462416,2835064,2467328,2644740,3076051,3075220,30492,11324,1550247,2680279,2681683,1927448,8804,3043280,3113804,2097628,2948436,3075284,3088528,3057739,2573652,2825959,3075184,1682735,3017024,2672752,2927480,2793712,25300,2462288,2874644,2862244,19248,25188,3052208,2546468,1625111,2546980,2158608,7336,1549111,2739432,2235183,2614695,3122120,4065036,1903728,2700332,3057832,3094183,3207964,2699460,2838819,2354620,2227492,2653880,1616100,24468,2862220,1618679,2606855,2320671,3156160,7108,3041320,2544712,1672979,2040464,2739960,2544856,1568183,2472908,2826492,2644664,2485719,2948387,2523012,2948372,29732,2637472,3260547,3273987,3078212,3043256,2474267,2482940,2522100,2620140,1405295,2658180,2747316,1403147,2712256,3162964,2700240,3137015,3315524,2083344,127884,7880,2969156,2518179,2466988,25664,2523487,15735,188200,1571847,3200316,3156152,2205356,25168,1797071,2283472,3043772,2513692,127428,2513276,2475896,1871256,2628224,2460315,2183096,2699248,29472,2240088,2764412,1928464,2767559,4847540,2464568,1251543,14764,3057992,2226012,2711152,16667,3189367,2225636,1380584,2828187,2834732,1714788,3086464,2818924,1927416,2695584,1731727,1734380,3093811,1702967,1915868,1929396,2832139,2626564,6448,2463224,2465080,2644880,2216520,3053380,1308880,8828,25596,1927576,23884,2624008,2645288,2773927,21507,28983,1381632,2621900,2758360,3043700,2461976,3008835,4491816,2068927,2764672,2462996,1699088,2845196,3080440,1927568,1207043,3036968,1871384,2728552,2083339,2747436,2205372,2474348,1347460,27492,4877280,2695451,1306812,3017508,3076720,2729228,2826319,2688248,2739948,2257995,2608088,2225355,2699048,3124964,2762207,1551303,2878504,30100,2738140,3266616,1306816,2744812,1404759,3201548,1393419,3258552,2461628,1709803,2711536,2645164,3117400,2513956,3201040,2513456,3072384,2522876,3266596,2623344,3098716,4979256,2544796,2919219,9364,2712264,1697300,28116,3071708,3122444,3079908,2465144,3218899,3193143,4906216,2516887,2731780,1931048,4065008,3122916,1593416,1380643,2764716,3258660,2835199,2661688,1251544,13436,2466168,3009524,3102620,2732224,1555931,1770375,2126256,2638024,2636588,2158560,3122316,1765244,19344,2719660,4065092,2525308,1710571,2665555,1736156,2700516,2764900,3046168,158452,2761315,2721060,2517055,3041428,3086532,2225056,3124660,3096984,3112580,2773848,2464732,2227308,2216244,3053544,2711636,3265912,2004632,3072700,3045236,2464360,2523564,2465688,5384,2728692,3168915,4064892,1691755,1773851,3258719,3304308,2644904,14460,3079272,4876040,2575352,1226159,2364563,4491368,2699520,3072332,3079276,3086392,3060395,4935248,3137343,2343780,3036940,2666283,4935479,2524672,2719676,2733676,17388,1668576,2492672,2728724,2728744,1555823,3135639,3066963,2714188,2608132,1616903,4876224,1798147,1661343,1575479,2466664,1205755,2772351,2078552,1706996,2686435,1928436,1709323,1931844,2625264,2882952,3216135,3288207,2625376,1930899,2719615,1729039,2874619,3243712,2742855,2675347,9304,1603816,2469592,8892,2620348,3009512,3057332,2453292,3056696,2711980,2860556,3204196,1920572,1926032,3122084,6112,2225792,3209428,3043728,2730823,2629356,16764,1675831,3210275,3216863,1929320,2224540,1380132,2843508,2718727,2466228,3266731,3195184,2638008,2663711,2839503,2217475,11548,2747128,2461560,2473168,2745011,2765884,1591828,3075200,1610323,2818967,2315536,2919392,2200028,2513932,3117892,2747448,3041300,2513908,24464,17824,3097003,3207815,3199140,3016780,3080004,2461512,2524100,3271699,3057900,2771219,2733372,1246903,2699456,1911472,2480259,2480408,27752,2653884,2620595,2753003,24884,1614499,4058112,2948496,1697351,2765936,24700,1699487,4876812,3079256,2084752,1309383,1404255,1405488,2636000,1766867,2847655,3133472,2460859,11540,2466680,3017548,1871223,1928044,1712884,3046124,1929520,2355612,4063556,2862464,19244,3088608,6324,2653976,2733976,12260,1616855,3072408,1387635,9100,5260,3080536,2514127,2731947,4960,2747476,6196,2463808,1871416,19716,2623576,2641608,2844103,2858696,4935120,1765136,4058520,2464523,2698680,2774268,4060284,2767484,1254107,2674196,2464584,2835528,2695416,1920652,1920804,2459664,5332,4728,2158440,3087892,3201436,2845360,2758359,4064904,4058432,2811259,2585876,2816408,3156092,2235144,2774232,10716,3017388,3244191,3232659,3232687,2466756,1914708,2834995,2224488,2628424,4060300,1381592,3089840,128240,3082339,2459948,2200108,1548447,1844388,3087840,1926088,4906160,1384275,2880067,2069572,2514240,2300268,2793671,2239459,23784,2733732,2206076,2877052,1220375,4884,2793144,1380451,2470012,4979328,1911483,1904012,3080144,2827008,44252,4906232,2737776,2948316,3017104,74880,5968,2464103,3009184,3157003,4850500,2948468,2466272,2530028,1871255,2513044,3189175,4063632,2715699,3209416,2483604,1550407,2469668,2227752,29588,3216147,11592,2764392,2680143,15620,2672592,1648475,29832,2513468,14100,2319024,2098596,2863127,95644,2683227,2844976,2453280,2365495,2343843,4935527,4880,2700275,2834935,2299315,2739996,2339535,2342827,2650760,2638040,7392,3048612,4850596,11292,1931023,3265043,2685476,2638012,3043704,2718728,2765940,2004692,1386587,3048904,3098740,25732,2178135,4936495,2772864,2239420,2729708,2070755,1731939,2464284,2485943,2045612,2472840,2578996,2472764,2761707,2712636,2546736,2718691,2745552,16880,2712208,1773916,2729696,2919416,3076740,1703463,1741847,2464144,3041308,1380108,3121576,1667239,2773084,3152343,2625312,2752343,2513036,3137275,3045471,3039419,25420,2881639,3122304,3244859,3269488,7916,2930396,2635696,3156132,2747808,3214660,2644764,15688,2525215,2544716,1386884,3156116,3071939,2766204,2737064,2695364,1594972,2929440,2699620,4060252,1706988,2740076,2200020,2513808,3122264,3122900,3016672,2773128,3172080,3079624,2695592,5456,3091795,3180315,2883232,3171107,2761428,3087824,4875676,2472243,3057456,2826299,1843719,127520,2513988,2097672,2546472,1640803,3285395,3288147,3287411,2767224,1928172,1356739,2000780,2755916,1858496,4800,2763008,2714672,2523971,7184,1931723,2658599,2694216,1929228,1920915,2524552,17412,3057712,3207827,95720,29720,3288051,2355580,2227448,2574268,1558020,127928,14112,2760680,3117780,2019163,1697136,4878076,2530004,3045515,2970087,2225996,3091343,3181028,3203520,4491684,2728768,2859912,1929524,2828107,2834872,2771720,2699552,2547016,3266715,2464744,2745848,2019224,1610599,2976824,3079932,1920900,1711795,1915216,28296,1715456,2700928,1605995,2462980,157844,3122236,127544,2733856,3099024,3204264,1694275,3076784,2466656,2620192,3046160,3117364,2845208,11440,2299128,2712504,1681783,2513500,2544628,2826543,1931008,2223343,14552,1569903,2685595,4981864,127256,3122292,2859888,3053484,2625468,2530024,2761056,2773140,2461064,4059860,1403819,1349588,2731684,3053567,2699624,3121544,1928372,2225956,2761531,1902820,2190104,2019151,2021627,2021500,6980,1391128,1697335,1349840,1862728,2762020,2773088,1707839,2854624,2729912,2528604,2464112,1731112,2465360,2771932,2948487,30548,2753823,127960,2464740,26892,2881452,1378844,2735731,2472928,2734632,2855592,1908847,1911668,4759788,2240124,2862472,2216608,3072380,3124448,4063608,1912764,2710144,1692307,2728148,2459935,3209176,3259667,3275115,3078331,3089987,4060860,2474160,2747188,2763195,3286712,2526268,2522567,2728636,26944,2462388,2949135,2462460,1926064,2097648,1734111,2872719,2764408,19476,1605791,2523180,2738239,2688167,3043368,2774340,13292,2475760,1660943,3132296,2462300,2773763,2695488,3216420,3266960,2699756,2474320,6164,2772207,2728544,1927980,2573628,1916519,2466304,2832035,2650491,2627120,2182923,2524428,1804904,4776,5700,2526152,19832,1668923,1862684,1929220,3043432,8188,2315504,2700940,2700500,2927616,2305216,1380152,20100,2461420,1579811,2513000,5988,2718724,3079312,6108,5824,1559127,2819024,2135399,2665976,2629020,2525952,3048648,2777492,1380064,3017292,1665307,2728124,2472416,17432,1709804,2663591,2488535,1689307,2855788,4060280,2528596,1929764,3122260,3057428,2762208,1703344,2466880,2719680,3200968,1685911,2464092,3098984,19640,1765988,1381487,3053592,2771136,2750636,2871188,1216935,2844011,2858840,2881208,1706960,2473903,2460624,6104,1543376,2546947,2530016,1926092,2470040,2722412,2764636,3117160,2573668,2513924,2719560,2751435,2676663,1860040,2474687,2762336,2098692,7072,1780719,2662295,2700016,1385275,4876044,2740152,4804,3017280,17784,4063760,16044,2698624,2843448,1581056,2729880,2466300,3240248,13352,1711635,2700568,3009488,127276,2719052,9236,2712520,2772308,2748028,1567768,2683000,160228,2637728,4060792,2653960,3201588,3119276,1381608,2620100,2695564,2679436,3075584,1766811,3259012,24488,2474368,1363083,1886772,3209544,4063460,2300379,1381439,1930932,3043672,1689724,160292,1679699,2522183,1384576,2700964,2660199,3266716,2628976,1737672,1380280,2525196,2733855,3060780,2855736,1381759,1915172,1929748,2761199,1928456,7308,2793795,2747780,4060296,2763555,2623572,128324,3124952,2861307,2836435,1920868,2682780,3017148,8940,2731328,2882936,3041432,1926080,1206175,1381640,1920600,17172,2698660,3243776,2097483,1589632,2767296,2513132,2712760,3080099,127556,7732,2513720,3266816,3087856,1709724,1366571,127479,7008,1732835,2854844,1689255,2764352,4065144,3017204,2544868,1929760,24664,2718711,2459672,2077143,2084571,2069287,1347627,2858492,1926096,3288176,3113627,4063576,3124924,2313736,3124600,108632,1675227,2685911,3154503,3046644,2862891,2862484,27692,1404195,4935256,2524336,3057628,2699144,2225660,2728812,1640443,2875388,2226028,1699283,1915920,1589931,2871200,2712008,1575792,2158568,4491604,2469768,1702571,1954396,2077296,2761456,2200632,2832043,2650359,2625983,2675291,2800532,2078627,2084607,2052592,2698640,1297660,2238040,2355572,4060316,2745608,2645376,2752071,2754180,1771759,2871012,2256175,3319592,1672296,2540196,157760,2698780,2474504,2225432,2513516,2461444,2225456,4850900,3122188,2483736,2836360,2771963,3017340,2628400,1380663,2473063,2480412,2675407,1916452,2610892,2843276,2738535,2719308,1734551,1922599,2042248,2735655,4948,3152175,1221991,1246523,1787807,1821120,2712175,1308832,2494307,2050799,2413984,2001824,4850612,2187396,1625911,438647,560019,550199,124379,149064,440219,424427,420983,97639,71160,86503,99487,68111,70119,229207,205268,97416,86587,67640,86531,99619,25448,98399,202631,27540,27604,98387,97052,70103,99627,70079,67623,98435,68171,85152,229259,205080,99567,99603,205236,68147,70036,205431,30228,99587,205131,86523,229247,195404,98215,128120,70016,97435,86639,70084,68092,27764,68131,67639,98508,97455,27576,98347,202436,67603,98167,27496,98187,27148,70060,98251,202468,205072,44120,19888,86623,99568,70072,97364,30484,70135,78719,227627,203751,30288,129959,3872,68163,67604,74936,127664,97436,70091,85164,70096,99448,99548,229120,205452,97424,26516,86551,202636,128516,196959,196931,196544,68112,128164,7404,229235,196452,205056,195424,25192,196480,85196,25476,98223,69332,205280,25931,53531,85172,25551,181779,24100,86508,202480,195448,227564,99404,26007,53896,205192,86684,70156,86524,20160,86580,99380,205375,25484,7372,99588,67584,98283,20955,58079,27592,25492,196947,53816,53328,205132,26343,19628,26255,54675,20180,229236,98544,25652,54268,205448,88820,69360,53484,128144,196524,98196,97164,128040,29412,67636,23848,28232,196536,26976,99620,229224,29316,20372,99416,127732,97472,196792,20360,227591,203360,202331,196932,24776,27744,96144,13212,193360,202240,229268,99600,29476,99608,30528,202575,181944,205040,54340,229220,67668,20184,229276,67616,30524,205092,95508,127680,99392,20315,107555,26916,30284,25548,54464,27064,29492,421019,49396],"inlineDepth":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"category":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"subcategory":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"func":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082],"nativeSymbol":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"innerWindowID":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"implementation":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"line":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"column":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"optimizations":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"funcTable":{"length":5083,"name":[1,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,2125,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086],"isJS":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"relevantForJS":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"resource":[0,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,3,1,1,1,1,3,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,4,3,1,1,1,1,1,1,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,3,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,4,4,1,1,4,4,1,4,1,1,1,1,4,1,1,1,1,3,1,4,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,1,4,4,1,1,4,1,1,4,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,4,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,3,3,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,4,4,4,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,1,1,1,4,4,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,4,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,4,1,3,4,1,1,1,4,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,4,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,4,1,4,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,4,4,4,1,1,1,4,1,3,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,3,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,4,1,1,4,4,4,4,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1,1,1,1,1,1,1,1,4,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,4,4,4,2,2,1,1,1,1,4,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,4,4,2,4,4,4,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,3,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,4,1,4,4,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,4,1,4,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,1,4,4,1,1,1,4,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,4,1,3,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1,4,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,3,1,4,1,4,1,1,1,1,1,1,3,1,1,1,4,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,1,4,1,1,1,1,4,4,1,1,1,1,4,1,1,1,1,4,4,3,1,1,4,4,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,4,4,1,1,1,1,4,1,1,4,1,1,1,4,4,1,4,4,4,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,4,4,1,1,1,4,4,4,4,1,4,4,1,4,4,4,4,4,1,1,4,4,1,1,1,4,4,1,1,1,4,4,1,4,4,1,4,1,1,4,4,1,4,1,1,4,1,1,1,1,4,4,4,3,4,1,1,1,4,1,4,1,4,1,4,1,1,4,1,1,4,1,4,4,1,4,4,4,4,4,4,4,4,1,4],"fileName":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"lineNumber":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"columnNumber":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"markers":{"length":0,"category":[],"data":[],"endTime":[],"name":[],"phase":[],"startTime":[]},"name":"GeckoMain","nativeSymbols":{"length":0,"address":[],"functionSize":[],"libIndex":[],"name":[]},"pausedRanges":[],"pid":70383,"processName":"cli","processShutdownTime":13416.374542,"processStartupTime":380.192208,"processType":"default","registerTime":380.192208,"resourceTable":{"length":5,"lib":[0,1,2,3,4],"name":[0,2,10,21,48],"host":[null,null,null,null,null],"type":[1,1,1,1,1]},"samples":{"length":12956,"stack":[8,15,18,20,23,29,31,32,34,35,38,40,48,49,58,70,79,84,93,102,114,127,150,161,176,187,199,222,237,266,276,290,343,365,385,395,421,484,526,537,573,590,616,644,674,714,743,763,797,824,836,843,856,883,931,949,963,974,979,986,1000,1025,1032,1048,1059,1068,1088,1098,1157,1168,1177,1182,1224,1269,1277,1311,1323,1328,1332,1339,1354,1377,1409,1459,1491,1518,1552,1594,1623,1650,1665,1683,1697,1710,1720,1737,1746,1757,1774,1811,1819,1832,1844,1852,1858,1862,1889,1915,1920,1947,1959,1983,1993,2007,2022,2032,2049,2065,2074,2088,2102,2116,2126,2144,2152,2174,2204,2241,2275,2301,2331,2346,2359,2380,2412,2427,2458,2484,2493,2544,2577,2601,2632,2684,2693,2709,2735,2763,2781,2798,2811,2832,2859,2894,2931,2975,3002,3024,3060,3089,3105,3117,3135,3160,3176,3189,3213,3224,3268,3307,3342,3368,3390,3394,3420,3444,3468,3487,3498,3519,3540,3566,3604,3626,3653,3680,3712,3721,3726,3743,3749,3756,3780,3801,3807,3838,3855,3900,3905,3978,3999,4043,4094,4117,4145,4230,4245,4258,4272,4299,4306,4309,4319,4336,4345,4359,4376,4388,4395,4401,4413,4437,4443,4453,4455,4468,4481,4493,4505,4519,4523,4532,4543,4580,4625,4636,4668,4685,4689,4700,4708,4744,4748,4824,4844,4893,4909,4944,4981,5006,5022,5034,5045,5087,5099,5109,5117,5131,5151,5164,5173,5183,5192,5211,5216,5225,5251,5323,5333,5355,5375,5381,5389,5396,5404,5408,5417,5425,5438,5443,5451,5461,5464,5472,5493,5504,5507,5509,5520,5534,5538,5553,5557,5558,5570,5586,5588,5645,5653,5664,5674,5683,5688,5695,5696,5702,5705,5711,5720,5730,5742,5748,5758,5771,5778,5786,5796,5805,5814,5820,5825,5831,5842,5854,5856,5858,5860,5862,5868,5870,5874,5890,5898,5899,5913,5915,5917,5919,5922,5928,5937,5946,6005,6025,6072,6111,6150,6221,6234,6242,6256,6276,6284,6297,6306,6316,6372,6383,6407,6415,6420,6435,6443,6447,6459,6474,6483,6496,6508,6522,6532,6564,6609,6619,6632,6652,6694,6711,6719,6741,6746,6752,6764,6789,6800,6812,6817,6821,6832,6838,6868,6877,6896,6962,6974,6993,7004,7014,7031,7037,7054,7059,7064,7083,7097,7125,7126,7132,7142,7146,7154,7171,7177,7184,7219,7230,7240,7255,7267,7272,7301,7307,7311,7332,7358,7365,7379,7393,7399,7401,7411,7420,7431,7442,7465,7474,7476,7494,7515,7518,7530,7542,7551,7559,7566,7576,7605,7611,7620,7628,7638,7665,7675,7681,7693,7700,7706,7715,7731,7735,7742,7753,7755,7764,7775,7781,7801,7802,7810,7823,7828,7838,7844,7846,7853,7857,7867,7875,7878,7894,7903,8003,8010,8014,8021,8033,8042,8054,8061,8068,8081,8086,8090,8099,8101,8104,8105,8112,8122,8129,8131,8139,8140,8152,8159,8167,8169,8190,8191,8193,8201,8208,8227,8231,8243,8246,8258,8259,8276,8277,8280,7240,8290,8291,8298,8301,8305,8320,8325,8336,8337,8339,8340,8344,8364,8372,8375,8385,8387,8403,8414,8421,8427,8438,8448,8449,8462,8473,8477,8485,8496,8522,8526,8536,8538,8541,8548,8564,8568,8578,8582,8584,8591,8594,8599,8617,8621,8632,8636,8640,8649,8652,8662,8685,8702,8705,8719,8730,8732,8748,8758,8762,8765,8766,8771,8782,8787,8797,8808,8816,8831,8839,8844,8852,8862,8874,8892,8902,8909,8918,8930,8936,8946,8954,8958,8967,8972,8993,8999,9006,9015,9016,9021,9022,9063,9068,9076,9077,9083,9089,9095,9100,9103,9112,9113,9114,9116,9125,9132,9146,9147,9149,9150,9151,9170,9175,9182,9185,9188,9190,9192,9193,9197,9206,9212,9224,9243,9255,9188,9265,9273,9274,9291,9302,9304,9306,9323,9334,9355,9365,9367,9374,9396,9399,9413,9414,9424,9434,9438,9448,9460,9469,9474,9478,9490,9495,9496,9498,9503,9516,9533,9546,9188,9551,9556,9565,9577,9582,9594,9602,9604,9606,9634,9638,9639,9648,9113,9670,9682,9686,9691,9692,9710,9711,9734,9744,9751,9760,9766,9767,9769,9771,9774,9077,9781,9193,9782,9788,9793,9796,9810,9836,9844,9846,7311,9862,9863,9865,9867,9876,9887,9892,9900,9905,9906,9911,9914,9926,9956,9958,9961,9962,9971,9767,9972,9976,9987,9992,10009,10023,10026,10029,10033,10036,10038,10046,10057,10064,10069,10075,10095,10103,10105,10110,10112,8766,8101,10114,10118,10122,10128,7240,10134,10144,10169,10251,10263,10273,10277,10286,10289,10295,10308,10310,10317,10318,10323,10339,10355,10356,10368,10371,10376,10381,10383,10384,10390,10404,10417,10425,10438,7742,10458,10473,9193,10498,10530,10601,10616,10657,10690,10702,10749,10756,10820,10840,10854,10906,10930,10944,10953,10969,10979,10993,11016,11020,11091,11102,11111,11127,11138,11156,11175,11184,11191,11192,11194,11198,11205,11212,11222,8766,11228,11230,11239,11241,11251,11265,7240,11272,11276,11288,11291,11296,11309,11315,11316,11323,11324,11333,11344,11349,11356,11370,11382,11397,11436,11444,11454,11463,11468,11471,11473,11477,11483,11486,11500,11503,11511,11516,5211,11523,11528,11486,11540,11547,11554,11567,11570,11590,11608,11623,11633,11644,11654,11662,11670,11673,11674,11678,11682,11689,11695,11702,11707,11717,11726,11728,11730,11733,11735,11737,11743,11749,9962,11755,7240,11756,11818,11826,7240,5586,7240,11830,11892,11898,11908,11919,11937,11945,11948,11966,11967,11970,11980,11991,11993,12003,12008,12015,12041,12048,12049,12051,12057,12059,12068,12072,12074,12076,12083,12091,12094,12095,12102,12108,12114,12120,12125,7240,12127,12134,12140,12149,12160,12162,12163,12165,12170,12172,12173,12176,12180,12184,12188,12207,12216,12220,12227,12231,12240,12246,12254,12255,12260,12262,12264,12265,12275,12276,12277,12285,12294,12295,12297,12299,12302,8473,12321,12323,12324,12331,12336,12337,12347,5538,12348,12362,12369,12378,12382,12383,12392,12394,12403,12404,12405,12415,12419,12431,12433,12438,12445,12455,12460,12465,12467,12474,12475,12478,12485,12492,12508,12517,12522,12528,8473,12530,12540,12543,12545,12551,12561,12567,12568,12574,12575,12262,12577,12583,4689,12588,12589,12605,12609,12613,12618,12622,12627,12634,12639,12651,12658,12659,12670,12672,12678,12679,12684,12694,12698,12706,12711,12715,12716,12719,12730,12745,12265,12763,12766,12768,12787,12788,12794,12798,12804,12810,12818,12827,12831,12836,12847,12855,12860,12861,12871,12874,12886,12887,12888,12889,12896,12903,12149,12914,12921,12923,12927,12935,12942,12949,7240,12956,12957,12964,12969,12972,12976,12979,12984,12993,12994,13006,13012,7240,13021,13023,13025,13035,13039,13044,13060,13065,13072,13078,13087,13093,7240,13104,13106,13111,13114,13115,13118,13122,13128,13131,13136,13139,13148,12265,13157,13158,13162,13172,13182,13194,13290,13323,10263,13385,13419,13444,13467,13517,13525,13571,13573,13585,13634,13664,13678,13713,13761,13767,13814,13865,13879,13890,13910,13915,13947,13975,13979,13999,14000,14011,14068,14083,14110,14112,14123,14174,14178,14195,14236,14274,14286,14289,14294,14295,14309,14325,14348,14358,14385,14402,14421,14440,14485,14518,14534,14564,14615,14639,14651,14661,14676,14681,14696,14701,14726,14749,14752,14753,14769,14812,14856,14869,14882,14907,14909,14922,14924,14964,14975,15003,15016,15041,15050,15100,15143,15164,15190,15229,15271,15277,15308,15335,15344,15362,15383,15407,15418,15453,15475,15497,15499,15509,15418,15527,15543,15545,15558,15577,15592,15603,15603,15619,15650,15685,15717,15750,15789,15805,15808,15811,15818,15825,15834,15846,15856,15874,15901,15917,15931,15950,15968,15973,15978,16000,16015,16025,16027,16030,16044,16062,16080,16094,16113,16117,16118,16120,16126,16134,16137,16149,16165,16186,16195,16197,16207,16219,16229,16245,16248,16252,16263,16274,16279,16292,16304,16308,16312,16320,16322,16323,16339,16348,16362,16363,16383,16398,16418,16423,16426,16428,16442,16363,16449,16452,16459,16472,16485,16494,16515,16524,16539,16274,16551,16553,16569,16577,16579,16588,16589,16605,16607,16621,16630,16701,16702,16719,16721,16731,16732,16735,16363,16740,16761,16768,16779,16783,16791,16801,16803,16814,16819,16824,16842,16852,16858,16871,16881,16903,16906,16927,16363,16931,16938,16945,16952,16956,16960,16969,16972,16974,16979,16993,17003,17004,17012,17013,17025,16363,17034,17035,17043,16779,17045,17046,17052,17057,17064,17066,17077,17084,17123,17127,17137,17148,17159,17161,17173,17175,17181,17183,17189,17202,17204,17215,17217,17224,17225,16363,17237,17251,17260,17266,17273,17284,17293,17302,17312,17328,17347,17351,17359,17368,17371,17379,17389,17398,17404,16363,17413,17426,17430,17434,17435,17446,17456,17458,17469,17204,17473,17483,17485,17541,17578,17629,17676,17706,17840,17861,17896,17978,17984,17992,18010,18036,18042,18052,18061,18068,18091,18101,18117,18132,18140,18202,18227,18237,18263,18266,18278,18292,18305,18309,18325,18343,18359,18368,18384,18402,18415,18431,18440,18457,18470,18475,18498,18503,18532,18568,18576,18582,18598,18604,18606,18620,18626,18645,18655,18668,18674,18686,18693,18704,18711,18718,18719,18721,18735,18751,18792,18795,18809,18829,18858,18889,18903,18922,18932,18943,18949,18964,18976,18989,18994,19001,19012,19024,19031,19036,19043,19060,19071,19079,19087,19099,19107,19119,19124,19134,19152,19158,19162,19177,19186,19199,19221,19238,19247,19260,19275,19279,19290,19292,19304,19317,19333,19340,19353,19364,19380,19384,19388,19405,19416,19423,19438,19455,19464,19477,19488,19498,19505,19509,19513,19522,19527,19537,19561,19565,19581,19584,19592,19598,19611,19620,19622,19626,19632,19636,19645,19653,19667,19672,19686,19692,19702,19710,19714,19717,19725,19728,19731,19738,19745,19753,19758,19763,19769,19782,19792,19809,19812,19828,19829,19840,19853,19858,19863,19875,19882,19887,19896,19900,19905,19906,19916,19922,19926,19930,19938,19954,19959,19970,19981,19994,20005,20011,20023,20027,20041,20047,20057,20066,20076,20087,20098,20106,20111,20115,20126,20135,20157,20162,20165,20180,20182,20183,20188,20209,20222,20229,20244,20245,20255,20275,20281,20287,20293,20319,20325,20330,20349,20352,20356,20369,20382,20463,20468,20471,20477,20488,20497,20507,20528,20533,20543,20571,20580,20592,20605,20611,20620,20623,20626,20628,20639,20655,20659,19199,20662,20672,20681,20690,20704,20706,20714,20725,20734,20737,20741,20745,20753,20758,20761,20786,20794,20800,20808,20813,20819,20835,20839,20844,20858,20863,20870,20880,20892,20901,20905,20915,20919,20927,20941,20943,20952,20963,20978,20984,20991,21004,21014,21020,21021,21023,21036,21040,21051,21067,21078,21088,21092,21099,21103,21104,21110,21119,21124,21125,21133,21134,21140,21152,21157,21158,21165,21166,21170,21172,21178,21185,21192,21206,21215,21216,21225,21227,21231,21236,21244,21250,21253,21256,21258,21261,21272,21275,21320,21323,21345,21353,21357,21377,21388,21393,21407,21421,21429,21432,21441,21444,21445,21451,21467,21471,21477,21485,21502,21511,21522,21537,21543,21553,21566,21567,21573,21583,21588,21592,21596,21599,21617,21623,21634,21643,21652,21663,21675,21688,21696,21698,21706,21719,21721,21729,21739,21760,21763,17578,21764,21776,19981,21789,21800,21806,21819,21822,21827,21830,21837,21844,21854,21856,21868,21874,21875,21879,21885,21894,21902,21911,21920,21929,21944,21949,21956,21961,21974,21980,21986,21989,22000,22005,22010,22020,22029,22040,22117,22137,22146,22150,22159,22168,22170,22180,22188,22190,22194,22201,22209,22212,22216,22227,22235,22242,22254,22263,22264,22266,22276,22277,22285,22300,22321,22327,22328,22336,22340,22348,22353,22356,22359,22384,22399,22406,22411,22418,22422,22424,22429,22431,22434,22438,22443,22447,22453,22462,22465,22480,22486,22498,22501,22506,22516,22527,22534,22539,22547,22557,22559,22570,22580,22581,22584,22594,22600,22604,22615,22631,22635,22646,22651,22653,22665,22672,22681,22684,22688,22693,22702,22712,17578,22716,22719,22725,22737,22742,22745,22749,22760,22765,22776,22787,22791,22796,22808,22818,22822,22827,22832,22840,22846,22852,22867,22873,22880,22894,22902,22912,22918,22924,18994,22932,22934,22937,22941,22954,22961,22969,22973,22982,22995,22999,23005,23009,23016,23020,23036,23043,23050,23055,23062,23109,23113,23121,23122,23128,23146,23160,23171,23181,23186,23191,23199,23207,23212,23218,23237,23243,23250,23254,23256,23257,23261,23264,23268,23271,23272,23278,23281,23285,23294,23303,23307,23309,23318,23319,23324,23332,23337,23346,23353,23367,23378,23382,23392,23393,23399,23408,23411,23415,23416,23419,23420,23427,23432,23439,23452,23455,23464,18440,23470,23481,19906,23489,23496,23503,23508,23513,23516,23522,23532,23570,23571,23574,23585,23591,23595,23604,23605,23619,23622,23626,23628,23638,23641,23642,23651,23673,23710,23713,23716,23724,23734,23744,23751,23763,23775,23783,23790,23791,23801,23791,23802,23809,23814,23824,23827,23836,23852,23875,23878,23890,23895,23896,23902,23906,23907,23910,23919,23933,23937,23943,23949,23960,23962,23978,23987,23992,24005,24112,24118,24123,24130,24133,24138,24143,24147,24151,24161,24172,24182,24189,24198,24202,24206,24216,24230,24235,24236,24243,24245,24249,24255,24267,23050,24270,24274,24280,24286,24296,24300,24310,24316,24328,24335,24343,24355,19906,24356,24362,24368,24380,24387,24391,24398,24406,24410,24415,24418,24425,24429,24439,24453,24470,24472,24477,24489,24499,24502,24509,24519,24522,24526,24532,24538,24544,19199,24554,24556,24561,24573,24586,24591,24601,24613,21567,24623,24630,24640,24644,24648,24656,24662,24666,24675,24685,24690,24697,24707,24720,24722,24733,24740,24749,24755,24771,24772,24776,24783,24791,24795,24801,24813,24817,24820,24825,24826,24827,24832,24841,24845,24849,24853,24869,24871,24875,24884,24899,24904,24906,24915,24923,24925,24942,24948,24953,24963,24967,24972,24977,24990,24997,24998,25000,25002,25008,25015,25025,25032,25036,25045,25057,25058,25060,25063,25064,25065,25073,25091,25100,25102,25104,25109,25116,25121,25125,17578,25130,25134,20963,25146,25152,25153,25166,25175,25183,25188,25191,25193,25195,25204,25211,25214,25217,25222,25226,25237,25247,25253,25263,25267,25275,24236,25282,25291,25300,25307,25318,25322,25323,25326,19199,25340,25346,25348,25359,25365,25367,25368,25376,25382,25383,25390,25404,25412,25418,25419,25423,25426,25431,25437,25501,25509,25528,25536,25541,25548,25555,25562,25568,25585,25590,25593,25597,25614,25621,25626,25631,25646,25647,25651,25663,25666,25670,25677,22539,25678,25686,25700,25701,25703,25709,25716,25728,25738,25746,25755,25759,25765,25772,25774,25778,25781,25782,25785,25790,25801,25804,25805,25816,25819,25823,25832,24300,25841,25850,25857,25864,25867,25881,25892,25894,25898,25905,25907,25914,25921,25928,25932,25945,25952,24915,25959,25961,25973,25986,25993,25996,26003,26009,26011,26015,26026,26028,26030,26042,26046,26050,26061,26068,26079,26083,26088,26090,26098,26106,26110,26120,26125,26129,26137,26144,26150,26156,26158,26163,26164,26174,26177,26183,26194,26205,26206,26209,26222,26225,26228,26241,26245,26254,26259,26265,26289,26291,26296,26302,24439,26310,26314,26321,26322,26343,26345,26352,26354,26360,26364,26371,26383,26390,26392,26393,26401,26410,26413,26419,26426,26432,26438,26450,26452,26460,26462,26480,26486,26487,26492,26498,26501,26393,26512,26515,26524,26532,26539,26545,26548,26555,26556,26557,26564,26573,26584,26589,26599,26601,26606,26615,26619,26626,26630,26633,26641,26642,26646,26651,26652,26659,26662,26664,26668,26675,26679,26689,26695,26708,26712,26720,26731,26739,26745,26750,26763,26776,26779,26780,26790,26794,26795,26807,26814,26844,26851,26861,26868,26870,26877,26889,26893,26895,26910,26917,26921,26931,26940,26943,26948,26953,26961,26966,26977,26978,26982,26988,26993,27000,27008,27012,27021,27022,27025,27032,27044,27045,27054,27061,27063,27066,27068,27074,27078,27079,27087,27095,27100,27101,27103,27108,27114,27120,27121,27123,27128,27138,27143,27148,27150,27165,27176,25647,27182,27186,27192,27203,27208,27213,27216,27242,27246,27250,27252,27258,27259,27263,17578,27267,27275,27278,27285,27293,27300,27305,27307,27322,27333,27342,27368,27369,27371,27379,27387,27395,27397,27404,27408,25237,27416,27430,27433,27445,27455,27461,27462,27469,27473,27475,27476,27499,27500,27502,27507,27512,27517,27519,27525,27539,27540,27544,27547,27550,27551,27553,27564,27566,27568,27578,27580,27584,27585,27592,27600,27609,27617,27623,27624,27630,27639,25104,25782,27643,21567,27644,27647,27649,27658,27660,27671,27676,27689,27697,27703,27708,27715,27716,27724,27731,27733,27739,27744,27750,27752,27766,27767,27768,27776,26174,27784,27789,27804,27822,27824,27832,27841,27852,23791,27857,25065,27866,27871,27933,18266,27936,27937,27941,27949,27957,27963,27975,27983,27989,27997,28003,26487,28012,28019,28023,28028,28040,28042,28048,28054,28088,28092,25647,28098,28110,28115,28126,28132,28137,28138,28139,28149,28158,28159,28163,28169,28187,28191,28193,28200,28208,28209,28214,28220,28222,28227,28239,28242,28253,28263,28270,28275,28282,28291,28300,28341,28344,28353,28368,28375,28377,28384,28391,28394,27462,28409,28430,28438,28440,28446,28454,28455,28458,28466,28475,28480,28482,28488,26393,28503,28507,28514,28515,28523,28529,27462,18266,28534,23791,28535,28538,28546,28555,28559,23416,28567,28570,28576,28579,28582,28587,28599,28601,28608,28621,28629,28636,28638,28646,28650,28656,28660,28667,28668,28670,28671,28690,23791,28700,28707,17578,28711,28721,28725,28726,28732,28743,28752,28761,28766,28780,21567,27462,28781,28788,23791,28793,28795,28804,28811,28814,28818,28819,28829,28833,28835,25359,28839,28843,28845,28846,28854,28858,28860,28866,28877,28885,28889,28898,28904,28905,28911,28919,28926,28935,28944,28953,28957,27462,21567,28968,28971,28976,28977,28981,28992,28997,29004,29011,29021,29024,29028,29029,24915,29033,29041,29043,29055,29062,29066,29070,29081,29086,29088,29089,29093,29101,29106,29107,23791,29109,29117,29118,29121,17578,29130,29132,25647,29138,29149,29150,29152,29156,29157,29160,21567,29166,29172,29173,29181,29185,29189,29193,29194,29196,29198,29203,29219,29223,29234,29242,29247,29254,29256,29259,27462,29263,29277,29280,29281,29286,29288,29290,29296,29297,29299,29304,29308,29311,29330,29344,29352,29356,29366,29373,29380,29388,29389,23791,29391,21134,29402,29417,29418,29420,29427,29499,29504,29513,29519,29524,29535,29550,29554,29561,29572,29573,29575,29587,29596,29602,29606,29610,29619,29620,29624,26393,29628,29631,29637,25237,29640,29651,29652,29657,29662,29664,29670,29673,29674,29677,29686,29695,29702,29712,29715,29721,29730,19906,29731,29733,29738,17578,29740,29743,29748,29754,29759,29760,29767,29777,21567,29779,29783,29789,29790,29793,29796,27462,29803,29807,29811,29814,29817,29823,27176,29831,29841,29854,29861,21567,29869,29870,29874,29883,29895,29899,29902,29903,29907,23791,29909,19199,29917,29926,29929,25359,29938,29940,29941,29951,29955,29957,29964,29977,29981,29983,29987,30004,30010,30011,30012,30014,30020,30024,30036,30041,30048,30052,30061,21567,30062,30065,30072,30144,30148,30154,23791,30160,30171,30179,30181,30182,30185,30187,30188,21567,30199,30202,30204,30210,30220,30244,30249,30252,30266,30267,30269,30281,30285,30297,30300,30310,30312,30317,30319,23420,30322,30324,30330,30338,30347,30351,30360,30367,30369,30372,30380,30386,25237,30391,30392,30393,21567,30396,30397,30401,30410,30421,30427,30429,30433,30443,30450,30452,30458,30460,30467,30477,30484,30494,27462,30498,30507,30508,30515,30518,30520,30521,30523,30586,30588,30593,30602,30612,30618,30621,30625,30632,30640,30644,30647,30653,30665,30674,30682,30683,30689,30698,30706,30714,30719,30726,30734,28926,30743,19981,30745,30750,25065,30756,23791,30757,21567,30760,20919,30768,30774,30784,30787,30791,30794,30797,30813,25237,30815,30818,30819,30827,30838,30849,27462,30859,30867,30873,30879,30888,30896,21567,30897,17578,30898,30901,30908,30916,30921,30924,30930,30941,30945,30954,30959,30963,23050,30967,30972,30979,30983,30985,30995,31003,31009,31013,31014,31015,31019,31028,31035,27462,31045,31047,31055,21567,31059,31064,31066,31072,31077,31086,31096,31105,19981,31109,31110,31114,31121,31125,31129,31131,31137,31138,31145,31149,31150,31151,31157,31159,31166,31171,31175,31192,31202,31205,31211,31215,31218,31219,31224,31230,31235,31244,31250,31259,31260,26393,24915,31264,31267,31271,31279,31283,31287,31291,31292,31296,31305,31310,31317,31323,31324,31331,31346,31347,31350,31356,31357,31370,31377,31389,31400,31407,21567,31415,31416,26652,31425,31429,31433,31435,31439,31449,31455,31457,31463,31469,31471,31482,31484,31489,31494,31496,31499,31506,31515,31524,31525,31539,31548,31551,31555,31559,31568,31577,31580,31584,31590,26174,31593,31608,31610,31618,31629,27462,31632,31640,31645,31649,31652,31661,31668,31669,31673,31683,31684,31702,31703,31706,30995,31707,31708,31715,31721,31729,31733,31744,31745,31752,31759,31764,31772,31773,31776,31781,31795,31801,31803,31806,31809,31811,31813,25237,31827,31845,31850,31851,31859,31864,31871,31879,31883,23791,31886,31887,31895,31896,31899,31901,31356,31904,31910,31911,31921,31929,25993,31934,31942,23791,31944,31945,31954,31960,31965,31968,31973,31988,25805,31993,19199,32001,31096,32011,19981,32019,32020,32021,32030,32036,32040,32041,32049,32054,27462,21567,32058,21567,32061,32065,32071,32079,25647,32088,32093,27462,32097,32103,21567,32109,32112,32122,32127,32128,32136,32142,32145,32152,32159,32167,32170,25647,32181,32191,27462,32197,32202,32204,32208,32212,32213,32221,32223,32235,32240,32243,32245,32252,32255,32258,32264,32270,32277,32286,32291,32302,21567,32306,32310,32320,32329,32332,32341,32350,32354,26393,27404,32361,32373,32376,32381,32383,32384,32391,32397,32399,32402,32409,32412,32415,32418,32431,32432,32433,32436,32440,32443,32445,32450,32458,32463,22559,32466,32469,32474,32476,32488,23791,32493,32494,32497,32501,32508,32510,32514,32522,25647,32528,32532,27462,32535,32539,32540,32541,32552,32555,32657,32659,32667,32673,32674,32680,32684,32693,32696,32704,25647,32716,32727,32730,23791,32734,32745,32746,32747,32749,32750,21134,32751,32757,32759,32764,32771,30995,32781,25237,32789,32794,32796,32797,32803,32809,32810,32812,32823,23791,32825,32826,32830,32837,32859,32862,32867,32871,32879,32881,32892,32898,32904,32911,32919,32921,32922,32928,23791,32931,32935,32937,32943,32948,32952,32955,32960,32971,32983,32991,32994,32995,33005,33006,33011,33013,33027,33034,33044,23050,33047,33048,33054,33057,33061,33062,33070,33075,25237,33080,33082,33086,33088,33095,33102,33172,33173,33187,33189,33192,33196,33197,33206,33209,33212,33213,33222,33226,33230,33231,33241,33244,33245,33247,33258,23791,33262,33265,33275,33290,33296,33301,33306,33314,33318,33321,33322,33326,27176,33336,33343,33359,33361,23791,33365,33370,33373,33377,33391,33392,33394,33395,33403,33404,33409,19199,33411,33417,25647,33418,33427,33432,33437,26487,33447,33453,33456,33457,33463,23791,33464,33465,33471,33472,33474,19199,33477,33483,25647,33484,33486,33489,27462,33498,33501,33512,33516,33521,33532,33542,27462,33545,33555,33557,33558,33567,33574,33578,33580,33592,33601,33603,33610,33617,33621,33631,33633,33650,33655,33663,33664,33670,33679,29152,33682,33687,33800,33863,33936,34024,34131,34188,34215,34283,34348,34433,34537,34611,34710,34804,34924,35009,35083,35194,35286,35402,35494,35578,35720,35784,35901,36026,36035,36052,36092,36129,36159,36195,36215,36256,36277,36308,36336,36345,36362,36369,36371,36395,36404,36420,36436,36447,36459,36465,36476,36486,36504,36513,36519,36523,36538,36549,36568,36581,36586,36621,36643,36670,36693,36714,36741,36749,36751,36761,36795,36804,36811,36825,36834,36842,36856,36867,36873,36880,36900,36915,36925,36948,37002,37017,37023,37037,37064,37082,37101,37112,37125,37131,37143,37150,37161,37170,36751,37177,37186,36751,37189,37198,37205,37219,37223,37225,37243,37254,37256,37265,37272,37292,37295,37298,37308,37322,37331,37339,37341,37345,37358,37369,37379,37381,37390,37397,37404,37415,37423,37430,36670,37432,37443,37450,37454,37465,37470,37479,37481,37482,37494,37507,37518,37522,37531,37535,37537,37544,37545,37548,37549,37561,37567,37574,37583,37584,37612,37613,37617,37465,37623,37549,37627,37634,37637,37652,37658,37661,37678,37703,37725,37731,37735,37479,37744,37748,37763,37777,37778,37782,37784,37256,37790,37792,37812,37814,37818,37833,37834,37835,37843,37848,37866,37875,37879,37888,37902,37915,37933,37944,37955,37965,37966,37972,37977,37978,37990,37479,37991,38002,38015,38030,36670,37358,38035,38041,38044,37345,38048,38056,38061,38067,38080,38094,38096,36670,38110,38119,37549,38129,38145,38153,38154,38157,38165,38170,38174,38178,38190,38195,38200,38212,38213,38220,38223,38224,38234,38238,38239,37358,38249,38258,38262,38267,38282,38284,38292,38293,38296,38299,38304,38305,38310,38314,37465,38322,38323,38324,38329,38330,38336,37358,38344,38353,37479,38362,38363,38370,38468,38501,38517,38542,38559,38611,38650,38671,38703,38732,38766,38797,38831,38842,38843,38854,38873,38886,38897,38910,38934,38947,38960,38972,38986,39011,39029,39043,39068,39083,39094,39114,39137,39149,38766,39159,39170,39195,39208,39221,39226,39229,39235,39245,39254,39265,39276,39302,39323,39324,39333,39351,39360,39362,39386,38854,39404,39333,38766,39406,39411,39414,39429,39444,39464,39484,39495,39511,39523,39534,39541,39551,39568,39578,39587,39603,39616,38897,39619,39636,39649,39655,39667,39679,39688,39704,39710,39719,39724,38766,38854,39733,39733,39739,39746,39754,39764,39771,39772,39784,39797,39810,39811,39824,39828,39834,39854,39869,39875,39888,39903,39913,39936,39952,39957,39959,39966,39972,39982,39992,40004,40014,40021,40024,40035,40044,40055,40074,40092,40107,40113,40120,40122,40138,40146,40154,40165,40171,40173,40252,40258,40262,40280,40288,40295,40309,40321,40334,40340,40350,40363,40374,40380,38766,40390,40394,40400,38766,40404,40418,40429,40434,40439,40449,40455,40485,40504,40516,40518,40523,40535,40544,40550,40557,40569,40575,40587,40603,40612,40634,40643,40650,40656,40664,40671,40684,40692,40697,40702,40712,40722,40736,40739,40743,40753,40757,40760,40768,40792,40799,38766,40807,40820,40822,40825,40831,40842,40849,38897,40857,40870,40874,40976,40985,40989,40998,41012,41019,41041,41046,40122,41048,41066,41071,41078,41083,41093,41098,41099,41110,41129,41140,41146,41147,41158,40055,41170,41183,41185,41202,41208,41218,41227,41238,41244,41252,41266,41276,41284,41293,41303,41318,41324,41328,41330,41336,41341,41351,41358,41362,41367,41377,38766,41379,41383,41394,41395,41397,41410,41414,41425,41426,41434,41441,41473,41478,41492,41505,41512,41518,41526,41543,41551,38766,41560,41575,41583,41589,41592,41605,41140,41610,41685,41699,41707,41711,41147,38986,41719,41725,41736,41742,41755,41760,41769,41784,41795,41796,41803,41812,41817,41822,41830,41840,38854,41848,41855,40753,41857,41863,41870,41890,41904,41910,41918,41927,41936,41940,41946,41954,41959,41973,38766,41981,41992,41998,42008,42017,42025,42037,42041,42053,42062,42072,42079,42085,42087,42091,42097,42099,42104,42110,42115,42126,42134,42147,42153,42166,42175,42181,42186,42198,42211,42226,42234,42236,38854,42239,41140,42243,42246,42255,42264,42272,42279,42290,42303,42305,42312,40544,42325,42331,42348,42357,42369,42371,42385,42398,42414,42418,42500,42501,42510,42516,42522,42528,42543,41140,42547,42556,41147,42560,40055,42568,42575,42587,42597,42605,42616,42623,39811,42628,42641,42645,38854,42648,42649,42653,42658,42666,42677,42684,42695,42701,42708,42718,42727,42730,42733,42742,42748,42755,42768,42779,38854,42783,42789,42827,42831,42833,42838,42839,42851,42864,42865,42867,42874,42879,41140,42891,42895,42898,42903,42917,41140,42923,42929,42937,42944,42954,42962,42963,42974,42977,42992,40092,42994,43001,43010,43011,43013,43020,43035,43038,43041,43042,43047,43055,43063,43068,38766,43073,43086,43096,43145,43148,43150,43153,43168,43174,40092,43180,43193,43206,43207,43217,43230,43239,43240,43246,43257,43259,43266,43274,43277,43284,43288,43296,43302,43305,43317,43325,43334,39043,43342,43357,43363,43366,43380,43390,43402,43413,43420,43425,43428,43447,43451,43453,43462,43473,43481,43489,43490,43499,43501,43506,43513,38766,43517,43526,43538,38854,43539,43543,43548,43554,43562,43571,43577,43586,43602,43609,43613,43617,43621,43631,43637,43642,43651,43663,43668,43672,41140,43673,43679,43688,43691,43692,43695,43705,43715,43722,43727,38986,43736,43747,43751,43764,43778,43784,43786,43795,43798,43803,43804,43814,43821,43825,43837,43844,43848,43851,43854,43859,43868,43872,43880,43901,43907,43923,43937,43947,43953,43959,43965,43967,43968,38766,43977,43982,41140,43992,43999,44001,44009,44013,44019,44027,44029,40753,44034,44039,39043,44050,44052,44061,44068,44080,44087,44092,44096,44103,44109,44111,44116,44128,44130,44139,44141,42839,44152,44164,44166,44172,44186,44196,38766,44211,44221,44227,44231,44232,44235,44243,38766,44249,44269,44324,44326,44332,44339,44348,44355,44376,44382,44391,44405,44409,44418,44428,44434,44444,44448,44456,44460,44467,44474,44489,44513,44518,42839,44527,41351,40092,44538,44546,44547,44553,44562,44567,44578,44581,44595,44598,44601,44602,44612,44620,39811,44622,44628,44632,44637,44643,44644,44665,44679,44688,44693,44700,44705,44712,44721,44727,44738,44750,38854,44757,38854,44767,42658,44772,44781,38986,44787,44790,44796,44804,44815,44817,44824,44832,44835,44840,44846,44854,44860,44861,44867,44871,39811,44873,44877,44882,44891,44896,44901,44912,44923,44925,44934,44944,44948,44961,44967,44970,44973,44985,38897,44989,44994,44999,45016,45022,45029,45033,45044,45049,45059,45068,45069,45071,45075,41140,45078,45085,45103,45108,43011,45110,45120,41140,45123,45128,38986,45138,45140,45157,45167,45173,45184,45188,41140,45200,45215,45221,45222,45229,45233,45235,45242,45250,45261,45273,45278,45283,45292,45302,45306,45314,45325,45333,45338,45341,41140,45344,45345,45357,45361,38897,45365,45378,45389,45393,45404,42839,45412,45413,45430,40092,44538,45443,45446,41140,45453,45457,45458,45463,45470,45473,45480,45483,45493,45501,45514,45519,42166,38986,45522,45535,40092,45537,45548,45559,45567,39333,45580,41140,45587,45591,45598,45612,45616,45618,45625,45632,45639,45662,45665,45673,45674,45679,45689,45690,45697,45714,45721,45725,45738,45742,45748,45751,45752,45757,45761,45763,45776,45782,45785,45789,45796,45803,45814,45817,45824,45829,45832,45833,45839,45842,45848,45851,45866,45873,38897,45880,45881,45999,46000,46003,46004,46008,46020,46100,40092,46110,46120,46121,46127,46132,46135,46141,41140,46152,46159,46164,38843,46165,46175,46193,46210,46217,46226,40753,46230,46235,46243,46250,46254,46256,46264,46279,46284,46290,46299,46307,46316,46317,46321,41140,46331,46334,46340,46342,46345,46346,46353,46358,46359,46364,46370,46375,46389,46391,42649,46395,46401,46411,41140,38897,46414,46420,46433,38854,46435,46439,46444,46445,46448,46450,46459,46475,46480,46484,46492,46511,46521,46528,46534,46535,46540,46546,46547,38766,46552,46560,46568,46577,46583,46584,46600,46608,43631,46612,46623,46637,46639,46640,46645,46651,41140,46656,46662,46668,46675,41140,46679,46686,38854,46698,39739,46701,46709,46722,42839,46728,46730,46739,40092,46757,46760,46769,46771,46774,46775,46806,41426,46814,41140,46815,46825,46838,46839,38854,46842,46845,46848,46852,46872,38986,46878,46892,46897,46907,46923,46924,46926,46942,41140,46943,41140,46947,46954,46961,46962,46967,46983,46986,46990,41147,47002,47010,47027,47038,47044,47047,47057,47061,47062,47067,47068,47070,41140,47074,47075,47078,47083,47087,47092,47094,47097,47107,47113,47121,47129,47136,47150,47160,47171,38854,47198,47201,47208,47211,47223,47225,47228,47229,47234,47241,47255,47261,47266,47269,47274,47285,47295,47301,47305,47311,47321,47326,47330,47336,47340,47347,47354,47358,47366,47371,38766,47373,47375,41140,47377,47378,47383,47384,47395,47398,47412,47425,47433,47436,47438,41140,47444,41140,47455,47459,47470,47475,47476,47488,47489,47497,47499,47500,47504,47511,47517,47519,47533,47543,47551,47559,47569,47572,47576,47585,47590,47596,47602,47610,47612,47616,47622,47625,47629,47637,47644,40092,47654,47664,38766,47665,47670,47672,47676,47679,47688,47693,47698,47704,39811,47707,47708,47710,47713,47718,47723,47727,47728,47740,47745,47751,47752,47757,47760,47761,47772,47779,47792,47803,47810,47811,47816,47818,47829,47831,47835,44781,47844,47847,41351,40092,47851,47854,47860,47861,47870,47880,47885,41140,47888,47892,47899,47906,47909,47910,47920,47923,47927,47931,47932,40753,47934,47941,39043,47946,47962,47970,47981,47983,38854,47990,38854,47994,47995,47999,41140,48005,48016,48022,48030,42839,48040,48046,48051,48052,48058,48066,38766,48073,48077,48081,38766,48082,48087,48088,48097,48128,48134,48144,48176,48180,48186,48192,48204,48248,48253,48269,48274,48277,48287,48293,48300,38766,48310,48314,48319,48324,48332,48336,48337,48338,44781,38986,48341,48352,43631,39043,48362,48378,48387,48393,48395,48400,48401,48409,48417,39739,48422,48431,48433,48436,48443,48448,48450,44781,48453,48458,48464,48468,48475,48489,48490,48491,48504,48505,48508,48514,48526,48535,48541,48543,48549,48563,48568,48591,48596,42839,48608,41351,40092,42867,48620,48632,48634,48645,48684,48685,38766,48694,48705,48712,48713,48717,48723,39333,48725,48736,48744,48748,43631,48750,48756,48770,48773,48777,48792,42658,38766,47665,48799,48800,48803,48806,48807,48812,48823,48826,48831,48835,48842,48848,48860,48863,48864,48877,48880,40122,48882,48893,41140,48895,48897,48907,48916,48927,40122,48935,48943,48948,48952,48953,48959,48968,48981,40092,48983,48998,38766,49000,49012,49013,49015,49020,49026,49033,49039,49046,49058,49059,49070,49076,39811,49080,44781,49089,38986,49091,49093,43631,49103,49108,49116,49119,49121,49127,49129,49133,38854,49137,49142,49144,49145,49155,49164,45016,49171,42839,48040,41351,49182,49183,49192,49203,38766,49208,49216,41140,43692,49217,49221,49222,38897,38766,49229,49232,49235,49242,49249,49251,49255,43631,49256,49265,49271,49272,49281,41140,49283,49286,49292,49296,44861,38766,49345,49356,49358,49362,49366,48040,49372,49376,49383,49393,49400,49412,49421,38766,49422,49429,49432,49433,49434,49440,49458,49463,49467,49474,49483,49489,49490,49496,49501,49503,49505,49506,49513,49523,49524,49532,49540,42658,38766,46547,49556,49558,49568,41426,49575,49576,49585,49588,49592,49598,49605,49614,49619,49624,49634,39324,49640,49647,49648,49651,49652,49656,41140,49657,49662,49667,49672,49673,49676,49753,49796,49846,49856,44538,49866,49871,49874,49887,49890,49897,49901,49909,49927,49935,49942,49948,49957,49965,49970,49972,49977,49997,49999,50003,50006,50015,50022,50026,50033,50043,50047,50048,50050,50054,41426,50057,50063,50065,50072,50076,50085,50087,40753,50089,43631,50098,50102,50113,50118,50119,50126,50127,38766,50129,50139,50160,41426,50166,50171,50172,50176,50177,50180,50186,50192,50194,50195,50204,50213,50214,50216,50219,41140,50221,50223,50225,50227,38897,38766,50234,50237,50241,50244,42839,50248,50253,50258,50260,50267,50272,38766,50275,50281,50288,38766,50289,50292,50303,50311,50314,50326,50328,50341,50344,50356,50359,50446,43631,50456,50464,50465,50470,50474,41140,50475,50477,50485,41140,50490,50494,50504,50509,50522,50524,42839,48040,41351,40092,50525,50532,50537,50539,50545,50550,50553,50558,50566,50580,50583,50584,50588,50591,50592,50598,50605,46226,50610,50615,50616,40092,50617,50626,50633,50637,50648,50657,38854,50662,39811,50666,50667,50672,50675,50677,50682,50691,50693,50698,50706,50713,50717,50723,50727,50733,50739,50742,50752,50762,50768,50769,50776,50792,50793,38897,38854,50796,50798,50802,44781,38986,40055,50811,50814,50819,50826,50827,50829,50846,50849,50855,50859,50864,50868,50875,50878,38854,50885,50889,50891,50893,50900,50911,50912,50913,50925,50927,50940,50954,50962,50969,50978,50980,50986,50987,50993,41140,50994,50995,51005,51007,51011,51019,51020,40753,51025,51037,51044,51054,51069,51075,38766,51087,51089,51090,51097,51101,51107,51118,41140,51124,51130,51134,51135,51140,41140,51141,51143,51144,42839,51157,51163,51167,51173,51177,51182,51183,51191,51206,51210,51213,51221,51222,39811,51227,51230,51236,51240,51244,51250,51251,51253,51259,51266,51278,51284,51291,51295,51300,51308,51314,51321,51328,51340,51349,51353,51354,38766,51369,51379,38854,51381,51384,40044,51387,51397,51399,51405,51407,40122,51408,51415,41140,51417,41140,51421,51430,51432,40122,51440,51450,51460,51462,51464,40753,51470,43631,39043,51476,51484,51496,42649,51500,51502,51512,51516,51517,51525,41140,38897,38766,51529,51535,51548,51550,42839,48040,51551,51558,39043,51560,51575,51583,51585,43526,51595,39810,51607,51613,49119,51615,51628,51637,51639,51644,51653,51660,51671,38854,51682,51683,40044,51687,51695,43631,51704,51716,51722,51728,51731,51739,51752,51755,51759,51764,51771,51778,51782,51793,51801,51808,51811,51820,51823,51824,51830,51834,51840,51845,51852,51862,51866,51869,51871,51876,51887,51890,40122,41140,51902,51914,51946,51951,42839,48040,51551,51952,51957,51965,51975,51978,38766,51983,51986,51993,51994,51999,52000,52003,46334,52010,52011,52015,52022,52023,52027,52028,42839,52029,52033,52037,44538,52047,52049,52053,38854,52066,52070,52074,52078,52084,52087,52091,52092,38766,52095,52101,41140,52105,52111,52114,46226,52122,52126,52132,52138,52144,52156,52169,52174,52181,52182,45069,52189,52201,41140,38897,52208,52212,52227,52233,52235,52242,52247,52250,52254,52256,52266,52275,52280,52283,52291,52293,52294,46165,52304,52317,52329,52332,52340,52358,52361,52372,52404,52407,52415,52424,52436,52439,52444,52453,52464,52466,52472,52482,52483,41099,52486,52491,52493,52501,52509,52516,41140,52519,52524,52530,52534,52541,43631,52548,52553,52554,52562,52565,52575,52624,52626,52635,52642,52653,52656,52658,41140,52667,39739,52671,52677,52681,52687,52692,52699,44538,52712,52713,38766,52718,52732,52734,52736,52741,52743,42649,38766,52746,52753,52759,52764,52766,52771,52774,52781,40044,52784,40055,52797,44166,39043,52809,52812,50289,52813,52823,52824,52829,52831,41140,52837,39739,52840,52846,52857,52860,52861,52864,52865,40044,52867,52870,52879,49183,52883,52885,52888,52898,52941,52945,52947,52950,52955,38854,38766,52961,52966,41140,52972,52974,52983,52987,52990,52997,53002,53013,53021,53023,38766,53029,53036,53040,53043,53054,53058,53061,38897,53063,53073,53078,53085,44781,40044,53089,53096,53101,53113,53115,53116,53120,53127,53128,53135,53146,53156,53162,53163,38897,38854,53178,53179,53181,44781,53185,53186,53195,43631,53200,53203,53212,53213,46547,53222,53223,38766,43073,53233,53234,53236,53238,38854,53245,53247,53249,53253,41147,53263,38986,53266,53284,53294,53302,53308,53323,38766,53324,53325,53330,53335,53337,53341,53345,53347,53348,41140,53350,53357,53365,53368,53369,53376,53382,45413,40092,53390,53403,53406,38766,53418,53422,53429,43692,53438,53448,38854,53449,53451,53459,41140,53462,53464,53466,53472,53479,43631,53487,53494,53495,41140,53498,53505,53517,53518,53528,53533,38854,53537,53538,53546,53548,53549,53550,53553,53559,40055,53567,53573,53576,53587,53588,53590,53594,53595,53600,53595,53604,53608,53615,40702,53619,53631,53636,53637,53639,53641,40055,53646,53652,53663,53675,40122,53676,53686,53691,53695,53698,53705,53722,53725,53734,53739,53742,53747,53753,53762,53765,53772,38986,40055,53781,53782,53785,53799,53803,53806,53807,53809,53810,53816,53818,45742,53825,53833,53837,38897,53838,53843,53852,53854,53856,53859,42839,53862,53865,53867,39043,53875,53889,53893,38854,53901,53909,53910,53914,53922,53928,53930,38766,41140,53932,53933,53935,53938,53947,53952,53957,53968,53969,53975,53988,38766,53990,54001,54002,54003,41140,54014,54022,54028,54030,54038,54045,54048,54050,44781,40044,54053,54062,54071,44538,54083,54088,54093,54099,54106,54117,54119,54120,41140,54124,54128,54129,54136,54140,54148,54158,54160,54161,54169,54170,54176,54187,54188,54196,54200,54203,54206,54207,54213,54220,38843,54226,54234,54239,54245,54246,54253,54264,54303,54306,42839,54314,54317,54323,54324,54331,54345,54357,54361,54366,54367,54380,54381,54383,54385,54386,54396,54402,54408,54412,54421,54424,54436,54441,54443,40753,54446,54447,54460,54469,54477,38766,54480,54492,54493,54495,54501,54503,54511,54517,54520,50827,54525,54526,54527,54533,54540,52028,54549,54553,41351,40092,54557,54567,54583,54586,54587,54598,54601,54602,38854,54617,54621,54623,53595,54631,54636,54650,54652,42839,54663,54668,43631,54675,54684,54686,54691,38766,54694,54703,54710,54712,54719,54731,54733,54740,54742,41140,54747,54751,39739,54755,54760,54782,54788,54792,54793,39043,54798,54804,54805,54807,54814,54815,38766,54817,54826,49217,54833,54837,54844,54857,54861,54865,54868,40753,54873,54876,40092,54881,54883,38766,41140,54892,54898,47665,54907,53595,54912,54922,54926,54926,54927,54998,38897,55002,55007,55013,55024,55026,55030,55033,40044,55034,55042,55050,42867,55054,55060,38766,55063,55070,55075,55077,55078,55084,55085,55087,41140,55094,55095,55098,55101,42839,55107,55113,55115,55121,55133,55140,55141,43668,55149,55158,55163,55173,55175,55181,55185,46547,55190,55191,55194,41140,55197,55198,55202,55213,41351,42865,55219,55228,55232,55238,55243,55248,38854,55250,55257,55260,41140,55261,55267,55275,55277,38854,55282,55285,55289,40055,55296,55300,55307,55316,55329,55341,55345,55349,55352,55361,55377,40122,55385,55393,42649,38766,55398,55399,41140,55402,55405,55412,55413,41351,55470,55474,55483,55487,55495,55498,38854,55505,55509,55514,55516,55519,55525,55530,55532,55534,55536,55537,55545,55547,55550,55555,55559,42839,55563,55568,55575,43631,55580,55590,55594,55595,38854,55598,55600,55601,55602,55608,55611,38897,55612,55618,55622,38854,55626,55631,55632,40055,55643,55644,55652,55653,55654,41140,55668,55677,55680,50827,55686,55692,38854,55693,55695,55698,55718,55720,55728,41147,40044,55730,55735,55743,44538,55754,55759,55761,55762,55770,55776,55777,55780,55785,55787,55788,55796,55800,55808,55810,55815,55936,56029,56053,56141,56150,56203,56255,56311,56346,56451,56509,56516,56578,56630,56734,56813,56887,56934,57041,57083,57175,57246,57319,57391,57470,57541,57657,57744,57837,57925,58000,58017,58044,58082,58114,58130,58151,58199,58222,58233,58259,58289,58325,58337,58366,58392,58222,58406,58419,58433,58436,58457,58479,58491,58502,58259,58531,58544,58556,58571,58579,58586,58591,58617,58648,58683,58715,58754,58771,58791,58800,58812,58815,58831,58859,58868,58887,58902,58913,58924,58955,58966,58982,58995,59009,59012,59028,59033,59038,59051,59068,59079,59093,59097,58924,59104,59127,59137,59140,59146,59153,59155,59158,59168,59170,59179,59195,59205,59219,59225,59227,59229,59230,59239,59254,59260,59267,59272,59179,59285,59304,59311,59321,59327,59336,59347,59432,59439,59449,59472,59474,59476,59494,59507,59514,59527,58715,59535,59554,59556,59570,59581,59599,59605,59607,59618,59622,59626,58924,59630,59643,59647,59651,59655,59657,59660,59661,59674,59689,59693,59710,59718,59731,59776,59782,59783,59799,59808,59808,59820,59828,59835,59851,59854,59158,59179,59868,59873,59891,59902,59915,59920,59158,59925,59938,59945,59953,59958,59960,59966,59976,59986,60002,58715,60013,60022,59179,60028,60030,60041,60043,59179,60052,60055,60061,60076,60095,60115,60125,59179,60136,60144,60156,60173,59158,60185,60191,60194,60198,60209,60219,60239,60250,60260,60264,60266,60275,60276,60278,60286,60288,60290,60292,60295,60310,60315,60322,60324,60333,60346,60355,60357,60372,60378,60387,60388,60391,60392,60397,59195,60415,60416,60422,60440,59158,60453,60456,60466,60470,60473,60474,60485,59179,60486,60492,60503,60506,60528,60537,60538,60541,60542,59179,60548,59158,60553,60563,60568,60569,60577,60013,60580,59158,60584,60585,60589,60598,60599,60603,60605,59179,60621,60625,58715,60013,60629,59179,60641,60648,60650,60652,60654,60662,60599,60663,60747,60755,60784,60784,60819,60851,60875,60902,60939,60974,60989,61016,61042,61082,61112,61130,61141,61154,61170,61183,61195,61206,61218,61224,61230,61242,61263,61275,61336,61350,61365,61388,61392,61400,61429,61447,61461,61474,61486,61491,61497,61206,61524,61549,61552,61558,61568,61577,61590,61598,61602,61618,61631,61643,61663,61670,61681,60939,61705,61710,61711,61732,61743,61755,61766,61778,61795,61801,61804,61206,61817,61834,61854,61868,61879,61885,61897,61910,61916,61944,61950,61956,61968,61974,61980,61989,61993,61998,62008,62020,62031,62037,62052,62059,62064,62073,62074,62084,62088,62094,62102,62117,62120,62127,62135,62144,62145,62161,62163,62191,62197,62201,62202,62212,62219,62232,62239,62250,62265,62278,61910,62282,62290,62309,62314,61154,62317,62322,62330,61206,62340,62348,62352,62031,62354,62366,62381,61154,62409,60784,62434,62442,60902,61910,62447,62455,62467,62483,62489,62495,62501,62515,62523,62537,62544,62553,61154,62202,62558,62569,62575,62584,62585,61879,62588,62598,62606,62617,62625,62639,62640,62652,62661,62669,62202,62673,62681,62683,62684,62693,62697,62707,62711,62718,62727,62744,62763,62773,60902,61910,62784,62813,62824,62830,62834,61206,62839,62841,62854,62871,62877,62890,62895,62909,62911,62920,62932,62943,62954,62974,62977,63001,63011,63016,62202,63021,63030,61154,63040,63042,63046,63061,61154,62202,63067,63081,63083,63088,63097,60819,62954,63109,60902,63112,63120,63127,63136,63142,63152,63163,63166,63173,63190,63197,63203,63210,63220,63229,63332,63339,63343,61643,63345,63350,63354,63365,63379,63392,63396,63403,63414,63427,63432,63436,62202,63439,63447,63469,61154,62031,63472,63474,63488,63493,63501,63514,63522,63523,63538,63550,63563,63573,63579,63587,63596,63609,63620,63633,63638,63658,63663,63669,63674,63686,63695,63712,63716,63727,63731,63742,63750,63756,63763,63777,63787,63789,63797,63808,63812,63819,63826,63833,63841,63847,63856,62202,63865,63875,61154,63880,63887,63889,62278,61910,63897,63915,63919,63921,63926,63934,63937,63946,63948,63958,63961,63968,63975,63976,64083,64088,64097,64108,64117,64122,64140,64154,64160,64166,64181,64182,64189,64196,64201,64210,61042,64217,64232,64239,64245,64246,64257,64261,64286,64288,64289,64298,64310,60902,60939,64314,64323,62202,64327,64329,64333,64338,64351,64351,64354,64368,64371,64372,64380,64391,64393,64401,64407,64417,64426,61643,64428,64434,64445,64455,64467,64471,64477,64490,64494,64496,61206,64508,64523,64534,64535,62163,64539,62575,64540,64547,64556,64563,64574,64577,64578,64581,64587,64591,64597,64604,64609,64616,64618,64626,64636,61206,64642,64647,64651,64658,64666,64667,64669,64677,64689,64706,61910,64713,64721,64739,64742,64753,64768,64773,62202,64778,64789,64790,64792,64794,64802,64807,64808,64811,60784,64828,64832,64844,64852,64864,64877,64881,64885,64897,64913,64918,64920,64926,64939,64948,64952,62031,64955,64966,64971,64977,64986,60784,62763,64998,65012,65016,60939,65021,65028,62202,65031,65046,65049,62202,65053,65065,65067,65176,65178,65186,65201,65207,65209,65216,62763,65221,65240,65243,65250,65258,65259,65263,65270,65279,65284,65292,65294,65300,61206,65306,65312,65320,61711,65326,65331,62575,65361,65362,65373,65379,62278,65381,65385,65391,65402,65405,61154,65416,65424,65427,62684,65435,65442,65444,65453,65463,65471,65478,65488,61868,61879,65497,65509,65513,65517,65537,65553,65566,65567,65572,65587,65590,65593,62911,65606,65618,65630,62031,65638,65639,62575,65642,61868,60819,65647,65650,60902,65657,65667,65673,62202,65682,65691,61154,62202,65693,65699,61206,65708,65713,65722,65730,65731,65739,65760,62763,65766,60902,61910,65774,65786,65795,65800,65802,65803,65326,65804,65805,65815,62575,65820,65827,65828,65838,65839,65848,60784,65854,65861,60902,61910,65910,65922,65929,65930,65938,65944,65953,65804,65962,65963,65693,65968,65977,65983,65989,65995,65998,66011,66020,62954,66028,66029,66038,66045,66053,66064,66072,66077,66083,66095,66101,66104,66106,66128,66130,66133,62202,66144,66152,66157,66162,66168,62763,66171,66179,61910,66180,66197,66203,66209,66214,62575,66223,62202,66237,66245,61154,66252,61206,66271,66280,66286,66291,60784,66297,62763,66308,66316,62954,66335,60902,60939,66344,66346,66353,66361,66371,66374,66376,66379,66382,66383,65804,66386,66392,66397,66401,66405,66410,61643,66417,66423,66425,66436,66450,66458,66468,66477,66481,66484,66493,66502,66508,65693,66513,66520,66527,66537,66540,66557,61868,60819,66562,66572,60902,66573,66586,66588,66594,66604,66607,66619,66621,61154,66637,66639,66641,62202,66652,66660,66669,60784,61879,66677,66678,66683,66684,66692,66700,66702,66703,61154,66705,66714,61206,66721,66725,61154,66732,66738,66746,62031,65804,66769,66780,66781,66783,66785,66787,62954,66790,66795,60939,66804,66808,66813,66815,66822,66828,66834,61154,66843,66844,66851,62202,66862,66873,61154,66877,66900,61643,66906,66909,66910,66918,66928,66938,66943,66955,61206,66958,66960,66969,66977,66984,61206,67020,67025,67029,67035,65802,67042,60784,67052,67062,60902,67069,67077,67085,62202,67088,67095,67099,67106,62202,67117,67130,67138,67146,67149,67164,66540,67182,61868,60819,67189,67204,67221,67225,67235,67241,67245,67248,67259,67263,67271,67275,67283,67288,67297,61154,62202,62684,67303,67313,67329,61868,67335,67337,67342,67353,67357,67360,67379,67386,62911,61154,67395,67397,67399,61206,67413,67417,67422,62031,67429,67435,67444,67472,67473,61879,67478,67485,61910,67496,67503,67509,67510,67513,67520,67530,65567,67539,67545,67553,67555,67560,62202,67572,67577,67583,67584,67596,67597,67605,67611,67612,67618,67625,67636,67642,67649,61206,67657,62202,67670,67679,61154,62202,67682,67685,67694,67701,67705,67711,61643,67718,67725,67734,67746,67755,67762,67765,61154,67774,67785,67786,62202,67795,67804,61154,62202,62684,67813,67829,67838,64986,67839,67872,62278,67874,67879,67894,67898,67906,67907,67913,61206,67917,67924,67930,67933,67935,62202,67939,67946,67961,67982,67984,67997,68014,68015,68028,68034,68037,68048,68064,68077,68082,61206,68089,68095,68107,68116,68118,68123,62575,68125,62031,68131,68134,68136,68158,68161,68162,68166,62278,61910,68174,68187,68188,68191,61154,68199,68231,68234,62202,68246,68257,68261,68264,68265,68270,68277,68285,68297,68299,60784,68304,68311,60902,68314,68322,68327,68330,68332,68337,61206,68341,68344,68347,68351,68352,68356,68360,68372,68375,68379,68380,61879,68381,62278,61910,67612,68392,68400,62202,68403,68409,68415,68424,65804,68530,68545,68548,62031,68553,68555,68561,68572,61154,68576,68582,68604,68608,60902,61910,68615,68627,62202,68631,68633,62575,68643,65804,68649,68660,68664,68665,62202,68666,68680,61206,68685,68686,68692,68695,68700,68707,61910,68713,68724,68728,68732,68743,68754,62911,68759,61804,68768,68775,68782,68793,68800,68806,62202,68811,68822,65567,68826,68827,62763,68842,68852,68854,68861,68871,65259,61206,68874,68882,68884,68891,61154,68893,68894,68897,62202,68901,68913,62163,68918,60784,68919,68920,68927,68934,68943,68952,68957,68960,68965,68972,61154,62202,68981,68987,68990,68997,62684,69008,61042,69012,69025,69034,61154,69039,60784,69053,69063,60902,61910,69078,69090,69098,61206,69102,69114,69126,69127,69136,69145,69146,69152,62202,69167,69176,62163,69182,62074,69187,69190,69199,69200,69205,69208,69211,69216,69227,69240,69252,62684,69259,62202,69265,69275,61154,62202,61206,69281,69287,69292,69301,61879,69305,62088,69306,69311,69318,69325,69328,69329,69331,69338,61206,69346,62202,69353,69359,61206,62031,69365,62145,69413,69418,69422,69423,69425,69428,69429,61910,69434,69440,69452,69457,62202,69458,69464,69469,69471,61804,62684,69475,69486,69493,69494,69495,69509,61206,69519,67473,60819,69523,69527,61910,69532,69535,69542,69548,69559,69565,61206,69572,62202,69580,69587,61154,69594,61206,69600,69607,69613,69618,69620,61643,69627,69632,69642,69654,69662,69671,69674,69676,69684,61206,69691,69694,69700,69710,69715,62202,69718,69725,69733,69749,64986,69750,69756,62278,69764,67612,69773,69787,69792,69798,69815,69817,69821,69822,69826,69836,69841,69842,69847,69857,69863,62163,69869,69881,62763,69885,69890,69894,69898,69913,69926,69927,61206,69932,69937,65567,69942,61206,69947,69960,62145,69963,69965,69971,69979,69982,69983,69984,62074,69992,69999,60902,70006,70007,70011,70020,70025,70033,70042,61154,62202,70043,70045,70052,70058,62202,70059,70062,70070,70077,70087,64986,70088,70098,70106,70112,67612,70119,70130,70148,70149,70151,61206,70156,70163,70169,70175,70177,62202,70186,70195,70198,70206,64986,70224,70227,62278,70231,67612,70235,70243,62202,61206,70252,70269,70270,70272,65567,70289,61206,70291,70297,70308,70309,70315,70317,70326,70333,62074,70338,70339,60902,61910,70343,70351,62640,61206,70355,70361,70364,70369,61154,70379,70384,62031,70385,70389,70396,70399,70405,70414,70423,62954,70437,60902,70441,70457,70468,70472,61042,61154,70478,70479,70483,70490,61206,70508,70521,70533,62575,70535,70537,62202,70545,70550,70554,70561,70562,60819,70566,70669,61910,70676,70680,70686,70689,61154,70693,70694,70698,62911,70703,70706,70710,62202,70711,70718,70720,70725,70735,70738,61643,64428,60902,70751,70769,70775,70784,61206,70794,70806,62145,70813,70816,70821,70923,70933,70942,62202,70947,70956,70967,70968,64986,61879,70979,62278,70980,66684,70990,70997,71000,62145,71004,71007,71011,71013,71021,71031,61154,71035,71037,71041,71044,71048,71050,71052,60784,71056,62954,71059,71060,71061,71070,71074,71082,71083,71087,71089,71091,71092,61206,71099,71106,71123,62031,71129,71134,61206,71140,67473,60819,71147,71161,71163,71169,71175,71176,71184,62145,71195,71199,71200,61206,71202,71210,71213,62031,71214,71219,71223,71296,61868,60819,71303,71310,71321,67612,71326,71337,71348,71356,71413,71416,71418,71424,71429,71441,71448,71450,71451,71465,61206,71467,71470,61154,71475,61206,71478,61868,61879,71486,62278,71491,67612,71496,71601,71608,71609,71620,71632,71641,71649,71654,71658,71660,71661,71664,71668,71684,71688,71693,71695,71699,62954,71708,71714,71718,61910,71724,71732,71737,61206,71745,71755,71764,64182,71772,71774,71777,71783,62202,71792,71803,61154,71812,60784,71817,71821,71828,71829,71832,71837,71839,71841,71843,71849,71851,71859,71860,71865,62911,71870,71879,61154,71887,71894,71903,71919,71925,62585,71932,61643,71938,71942,61910,71954,71955,69458,71957,71959,71968,71973,71978,71979,71992,61206,62031,71994,72002,72010,72011,72013,72041,72045,62954,72053,72064,60939,72073,72077,62640,72078,72082,72083,63042,61206,72084,72091,72096,62202,72101,72104,72109,72114,72117,72123,72126,61879,72127,72129,60902,60902,72139,72145,72150,72152,62145,72158,72159,68665,72163,72166,72173,72175,62202,61206,72179,72192,72197,72201,60784,72213,72214,72220,72226,72240,72242,72245,72246,72247,72253,72255,72264,72266,72267,72269,72286,72287,72296,62202,72304,72309,61154,72314,72316,72322,62954,72335,60902,72342,72361,72369,72370,72372,72373,72374,72375,61206,72387,72399,72411,72412,64088,72415,72424,72496,64986,72502,61643,72507,60902,67874,72517,72529,72534,72538,72543,72551,61154,62202,72552,72556,72561,61206,72566,72569,72570,72585,61206,72592,72597,60819,72605,72611,72614,72620,72624,72636,72639,72644,72650,72652,72654,62202,72665,72674,72677,72685,72691,65804,72695,72697,72699,72710,61868,61879,72715,62278,72718,72724,72732,72739,72749,62684,72751,72761,72767,72769,72771,61154,72776,72777,62031,72783,72791,72800,72803,72804,72805,72811,72817,72821,72823,60939,72828,72829,62202,72835,72836,72837,72843,61206,72847,72852,72853,62202,61206,72864,72868,72873,72878,72886,72887,72887,72894,72895,72901,72902,60939,72914,72925,72929,72939,62684,72954,72960,72963,72968,72972,72981,61206,62031,72988,61154,72991,72993,73002,73003,60784,62763,73012,73021,73026,60939,73094,73097,62202,73100,73103,73104,73105,61206,73111,73113,73118,65804,62202,73123,73134,73138,73142,73153,73163,62954,73176,60902,73182,73188,73193,73195,69965,73196,73201,73206,73215,61206,73218,73224,65804,65804,73225,73234,73241,73248,73254,69423,73260,73273,73276,73283,73292,73300,73306,61950,73311,61154,73313,61206,73315,62202,73322,73330,73333,73336,73342,73351,73361,73362,73367,73370,73371,73373,73378,73393,60902,73399,73409,73417,73428,73432,73433,73435,62202,73438,73444,73448,73455,62202,73456,73458,73469,73474,73475,73484,73495,73504,60902,73506,73508,73516,73520,61042,73524,73532,73534,61711,73535,73538,73542,73547,61042,61206,73551,73563,73573,61154,73574,60784,62763,73577,73586,73589,73597,73605,73606,73608,73615,73618,73620,73105,61206,73626,73632,73633,62202,61206,73635,73642,73660,69984,73668,61643,73670,60902,61910,73673,73683,73688,61206,73694,73703,73709,70272,62163,73722,73724,73728,73736,73744,62031,73745,73754,73755,73759,73761,73763,61643,73769,73776,61910,66910,73782,73787,73795,69458,61154,73805,73822,61206,73830,73839,73847,73855,61206,62031,71839,61154,73857,73859,73861,73862,61879,73866,62278,73868,67612,73879,73885,62202,73892,73895,66540,73907,73909,73911,73914,73923,73932,73939,73940,62202,73942,73949,62163,73950,60784,62763,73958,73970,73972,60939,74012,74016,62202,74019,74020,74024,74027,62911,74035,74039,61154,74045,62202,74057,74064,74067,74069,70414,60819,74076,74079,74083,74087,74097,74103,74108,74113,74120,74125,74172,74178,73105,74183,74194,74209,61154,74218,74226,74231,74237,61154,74240,60784,62763,74248,74257,74259,60939,74263,74275,65804,61154,74277,61206,74283,62202,74285,74290,74291,74296,62202,74304,74308,74311,74312,70735,74318,74327,74333,74336,74352,74358,74364,74376,62202,62684,74384,74392,74403,74408,61206,74415,74419,62163,74425,74428,62031,65804,74430,74437,74444,74445,74455,61879,74459,74460,61910,67612,74471,74476,74478,74485,74497,74506,74513,74514,74521,74532,74535,74548,74549,74556,74563,74564,74567,69423,61879,74570,62278,61910,67612,74577,74587,74595,74598,61950,62202,74606,74617,62575,62163,62202,61206,74621,74629,66383,74630,74635,74641,74647,74650,74657,74666,74672,74676,60784,74678,74684,74698,74700,74707,74708,74710,62911,74716,74730,74731,74732,61206,68403,61154,74742,74743,74746,74747,61154,74758,74760,74772,74776,74778,74787,60819,62763,74789,62954,64428,74795,60902,61910,74803,60902,74804,61910,60939,74814,68188,62202,74820,61206,74829,74835,62684,62163,74843,62202,69458,61154,74853,61206,74856,74857,74859,74865,66540,74884,64986,60784,74886,74903,74908,74910,60939,74917,74922,62202,61154,74928,74933,74937,74947,74948,74949,74955,74959,62145,74963,62202,61154,74972,74984,74987,74989,74993,74994,60784,74996,75001,62954,75011,60902,75012,75024,75036,75047,75054,75062,75064,61154,75069,75076,75083,75088,75093,75096,75105,62202,75111,75115,61206,75119,75120,75125,75134,75136,75140,75151,75158,75161,75163,75168,61804,75174,75177,75180,62575,75181,75183,69458,61154,75192,75199,75200,75203,75204,61154,75210,75217,75219,75223,75227,60784,75236,75240,75247,75248,75253,75257,75267,75269,75276,66619,75282,75292,61206,75294,75299,61206,75300,75314,75318,62202,61206,75334,75346,75347,64669,60784,75351,75356,75360,75361,75367,75377,75382,75390,62202,61206,75399,75407,67907,75409,61206,75414,75419,75431,62684,75437,75441,65567,75447,75448,75454,75458,75464,75468,62278,75474,67612,75483,75490,75492,75493,75499,61206,75501,75504,75508,75515,61154,75525,75526,75535,75541,61154,75543,60784,62763,75547,75559,75564,75570,75577,75580,62202,75587,75592,75599,75603,75611,61154,75623,75631,75633,61206,61206,75637,75648,75650,62202,75656,75657,75661,75668,61206,61154,75673,75676,60784,75685,75688,75697,62278,60902,75700,61910,75704,75717,75725,62202,61206,75736,75744,75747,75752,75759,75760,75767,75777,75784,75789,61206,75792,75801,75805,75807,75808,75817,62954,75822,75829,75830,75836,75843,75846,75850,75856,75868,75876,61154,75880,75881,75889,75894,75899,62031,75903,75910,64790,75937,61868,61879,75946,75947,75951,75952,75956,75961,75970,62202,75972,75979,75981,61206,75983,75988,75991,61154,75994,76000,76004,62031,76013,61206,76020,76032,76043,76049,76054,76058,76060,61879,76063,62278,76071,67612,76087,76095,65804,76103,76110,62202,76115,76127,76129,61154,76130,62202,61206,76134,76138,61154,62314,62202,76141,76145,61154,76150,76157,60819,76160,62278,76168,76172,76176,76188,62202,76189,76196,76198,76199,62640,62911,76209,76214,61154,76215,76221,76226,76237,61154,76242,76246,62074,76255,76256,62278,76259,76266,76269,76273,76282,65804,76287,63638,76291,61206,76292,76293,75181,76294,61206,62031,76297,61154,76302,76306,76311,76320,61879,61643,76326,76327,60902,61910,76333,76337,76343,76346,62163,76425,62575,76434,76438,76449,76452,76455,74955,61206,76459,62031,76463,76464,61154,76478,76490,62684,61154,76496,76503,60784,61879,61879,76509,61643,76510,76519,76520,76525,76526,76534,76548,76555,76565,76568,76614,64790,76619,76622,76627,74020,76635,76639,76642,76646,76658,73755,76664,76669,76678,76680,76687,76689,61910,76696,76706,76714,76717,62911,76723,76727,61154,62202,76730,76740,62575,76763,62031,76764,76775,76784,61206,76798,61868,69750,76801,62278,76806,76809,76815,76822,62202,76826,76834,76838,76839,76840,76850,76856,76858,76860,76866,76868,76871,76876,76881,76885,76890,76896,76909,76914,76917,76925,76927,76930,76937,76942,76953,76958,76963,61154,76972,61206,76974,76975,76979,76990,76992,77003,66540,77007,77010,77021,61643,77023,77027,61910,77036,77044,77045,61206,77054,77069,77074,77078,73138,77086,75526,77090,77092,77093,77097,77104,77106,61868,61879,77112,62278,77120,77121,67612,77133,68188,77141,77146,77147,77150,77153,77156,77159,77171,77171,77183,77187,62684,77191,77198,61206,77200,77211,77214,77215,77216,77223,62954,77232,77238,77249,77255,77264,77265,61154,77270,77272,77273,77275,77283,77289,61154,77290,77291,77299,77306,61154,77317,77318,77325,77330,77337,61910,67612,77346,77347,62202,67149,77349,77352,77358,77366,62202,61206,77382,77396,77400,62202,61206,77405,77411,77420,77424,60784,77426,77431,62278,77439,77440,77449,77456,77463,61206,77466,77469,77472,77476,67907,77478,61206,77488,77494,77495,77506,61206,77524,62585,77529,61643,77533,60902,61910,77535,77540,77542,62202,77547,77551,77560,61206,77564,62202,77567,77574,77575,62202,77578,77584,77589,77596,77599,77601,60784,60819,77606,77607,77615,60902,60939,77629,77634,77637,61154,77646,65805,77650,77654,77656,77660,77664,62031,77665,61154,77673,77680,61854,69984,60784,77685,76510,77702,77713,77714,77718,77741,77751,77758,69458,62202,77763,77776,61154,62202,61206,77786,77795,77797,77798,61206,77801,77811,77813,64986,77814,62763,77817,77826,77827,60939,77835,77842,62640,77843,77854,77856,77857,61711,77864,77873,77874,62031,77878,61154,77891,62911,77899,61868,77908,61643,77915,60902,77920,60902,61910,77922,77929,76215,61206,77931,77939,77942,77946,77947,77953,77955,77961,77962,61206,77969,77974,77978,77983,60784,62763,62954,77985,77986,77991,78008,68188,78090,78091,78096,78110,78112,62202,78113,78118,78123,78132,62202,64790,78139,78143,78144,78148,78151,78158,78159,61643,64428,78170,61910,78176,78186,78187,62202,78192,78196,67907,78197,78199,78208,78216,78217,78219,78224,61154,78237,78241,61206,78242,78244,78253,78264,78266,78278,78282,60902,78288,78293,78297,62202,78298,78304,78305,78311,78314,78316,78322,78327,78332,62202,61206,78338,78341,78346,62684,78348,78350,61879,78353,78360,78361,61910,78371,78374,78378,61206,78386,78399,78400,78404,78406,61154,78415,61206,78418,78419,61206,78426,78438,61206,78444,64669,70414,61879,78454,78461,78469,61910,67612,78470,78475,64182,78480,78486,78495,78498,78499,78500,61154,78516,78522,61206,78527,78531,78534,62031,65804,78537,78543,78548,78549,78551,78557,69984,78566,78576,78578,78584,78592,78593,61910,78602,60939,78611,78614,78615,62202,62202,61154,78630,78633,78635,78636,78637,62911,78644,78651,61206,61154,78652,65804,61154,78654,66540,78656,78658,62585,60784,60819,78665,78667,60902,78676,78678,78692,62120,62202,78695,78706,78717,61206,78722,78723,78733,78740,78748,78754,78757,78758,62031,78759,67907,78768,61206,78781,64986,60784,78788,78795,78799,61910,78807,78809,78818,78823,78831,78845,78855,61154,62202,78856,78862,78869,78871,78873,62684,78874,78878,78881,78883,60784,68919,78892,78896,60902,78900,78905,78906,78909,78913,78917,78922,78939,78941,78942,62202,78948,78958,61206,61154,62031,78959,78965,78975,78984,78985,78993,78994,60784,79000,62954,79005,79016,79018,79024,79029,79031,79032,79036,79041,79050,79051,79052,79064,62911,79072,62031,79075,79080,73755,79083,64986,79088,61643,79092,79103,60902,79109,79117,61950,79118,79124,79125,79133,79135,79140,69965,61154,79148,61206,62031,79151,79152,79156,62911,79176,61868,79181,79182,79187,60902,79190,60939,79201,79205,79206,79209,79228,79233,79238,72246,61154,79239,64790,79243,62031,61206,79256,79264,79270,79274,79289,60819,79293,62278,79294,61910,79301,79306,79307,76130,62202,79316,79318,73206,79319,61206,79321,79326,61154,74747,62202,79327,79329,79332,79337,79339,79342,73373,79350,67874,67612,79364,79374,62202,79379,79382,79393,79395,79398,79400,79402,79418,79421,62684,79427,62202,79430,79432,79438,61206,79439,79442,62074,79445,79450,79456,79457,79465,79468,60939,79487,79489,79493,61154,79503,73535,61461,62202,79507,79509,79513,79517,64182,61154,79522,61206,79525,79531,61879,61643,79538,74804,79539,79544,79550,79551,79552,79553,79554,61206,79557,61042,79558,79559,79560,62031,79568,79570,79573,79576,61206,79579,64986,79595,79600,79604,79611,60902,79612,79614,79621,79625,61154,79633,61206,79641,61711,79643,79647,61206,62031,79557,79648,79660,79661,79679,79680,79686,79692,79695,79701,60902,79702,79713,79720,79722,74067,79725,79728,79736,79737,62163,79743,79748,61206,79756,62202,79768,79776,79784,79789,79790,79797,66781,79799,79801,61879,79807,79808,79809,61910,79811,79812,79814,62202,79815,79822,78144,79828,61206,79831,79843,61154,79848,79851,79860,79867,79870,79872,79876,79879,79886,79892,61910,66425,79898,79909,79910,79920,79929,79930,79931,79932,62911,79934,79937,79943,61154,63042,62202,79948,79953,67545,79955,79957,79960,79962,79971,61910,67612,79979,79986,62202,61206,79989,79992,79999,80006,80009,80015,73755,80017,80020,61206,80022,80027,80029,80031,60784,62763,80036,80039,60902,80040,80042,62120,80043,80044,80053,80058,61206,80060,80063,80071,80079,61042,62202,80080,80084,80106,62684,80112,80114,80116,80121,80127,80132,80134,80134,80137,62763,80143,62278,60902,64160,79612,80147,80155,80157,62202,62202,80162,80166,80167,80169,62202,80170,80171,80172,62031,80175,62669,80190,80192,80207,64986,60784,62763,62954,80218,80226,80231,80235,80241,80250,80254,80264,80276,80281,61206,62145,61804,62202,61154,80290,66540,80292,61711,62911,80303,80312,80317,80319,60784,80324,63523,80334,80341,80344,80351,80357,80358,80363,61154,80374,61206,61154,80375,62202,61154,80377,62575,80379,80385,62202,80386,80392,80399,62911,61206,62163,80403,80543,80588,80638,80677,80701,80790,80798,80838,80883,80934,80965,80984,81025,81041,81138,81177,81231,81283,81357,81457,81509,81575,81623,81667,81744,81821,81915,81955,82045,82054,82095,82112,82151,82196,82265,82295,82351,82440,82514,82567,82636,82722,82829,82922,82994,82995,83006,83006,83033,83068,83094,83137,83156,83190,83222,83233,83254,83259,83288,83314,83328,83340,83357,83376,83398,83409,83420,83425,83433,83446,83409,83449,83462,83503,83532,83584,83599,83636,83668,83701,83723,83760,83779,83790,83800,83813,83830,83839,83849,83855,83866,83760,83877,83790,83879,83890,83941,83960,83992,84008,84030,84075,84095,84125,84149,84154,84165,84177,84189,84207,84209,84218,84240,84257,84278,84287,84314,84338,84347,84354,84358,84368,84388,84401,84406,84411,84417,84418,84420,84423,84425,84430,84431,84433,84418,84435,84436,84441,84436,84418,84445,84418,84447,84453,84457,84463,84433,84469,84472,84478,84479,84483,84486,84489,84493,84457,84494,84496,84494,84497,84506,84418,84508,84509,84512,84494,84514,84523,84530,84531,84538,84514,84539,84540,84541,84545,84551,84562,84563,84564,84566,84567,84445,84568,84436,84418,84433,84572,84574,84575,84576,84418,84578,84580,84581,84582,84568,84583,84584,84586,84590,84494,84592,84418,84436,84593,84601,84604,84617,84619,84620,84621,84622,84436,84418,84623,84626,84627,84633,84634,84418,84469,84568,84433,84635,84636,84637,84638,84494,84639,84641,84418,84433,84418,84647,84531,84592,84648,84649,84494,84651,84436,84661,84690,84418,84695,84494,84494,84698,84418,84699,84700,84494,84418,84701,84568,84433,84702,84494,84436,84700,84494,84703,84494,84568,84436,84704,84705,84706,84592,84714,84715,84719,84433,84722,84726,84436,84730,84734,84436,84736,84740,84592,84748,84749,84750,84703,84756,84762,84763,84765,84766,84768,84769,84773,84592,84774,84780,84783,84786,84494,84592,84494,84436,84568,84787,84789,84793,84797,84798,84799,84418,84801,84805,84807,84494,84418,84418,84436,84808,84494,84494,84812,84819,84820,84821,84823,84824,84740,84730,84828,84830,84831,84833,84839,84418,84842,84843,84844,84494,84497,84436,84858,84497,84859,84861,84862,84864,84865,84867,84494,84417,84873,84494,84497,84719,84874,84494,84494,84875,84876,84433,84704,84877,84879,84700,84494,84880,84418,84884,84885,84568,84436,84886,84892,84494,84592,84436,84893,84894,84494,84494,84508,84436,84895,84483,84897,84899,84900,84901,84902,84903,84904,84906,84915,84916,84917,84919,84921,84925,84494,84578,84494,84497,84926,84418,84494,84884,84927,84436,84494,84433,84497,84928,84436,84418,84932,84934,84418,84768,84936,84494,84937,84494,84494,84938,84436,84939,84941,84730,84942,84946,84950,84951,84954,84955,84568,84957,84962,84963,84969,84457,84972,84436,84418,84418,84976,84983,84985,84989,84494,84494,84957,84991,84726,84992,85002,85003,84433,85007,84469,85015,84463,85016,84436,85017,85021,85024,85026,84469,84436,84436,84719,84494,84578,85032,84418,84494,84469,85033,85035,85037,85041,85043,84496,84496,84820,84821,84436,84436,85050,85053,85055,84494,84497,84497,85058,84991,85059,84820,85063,85064,84483,84494,84514,85066,85067,85071,84483,84514,85073,85076,85077,84494,85078,85082,84972,85085,85090,84805,85092,85093,84436,85095,85043,85043,85097,84463,84726,84821,85098,84457,85100,85101,85102,85103,84531,85104,85108,84514,85112,85114,84469,84494,84722,85115,85116,85117,84469,85120,85122,85007,85126,84576,84812,85127,85128,85129,85131,85095,84436,85132,84925,84436,84568,84417,84436,85136,85137,84483,84453,85104,84497,84496,84469,84436,85144,85147,85151,84768,85152,84821,85153,85154,85158,85159,85163,84864,85170,84514,85172,85174,84899,84768,84508,84445,84445,85175,85176,84568,84641,85181,85182,85186,84859,85189,85191,85192,85026,85197,85210,85211,84496,85212,84494,85213,85214,85215,85216,85217,85218,84820,85050,85221,85224,85225,85228,85235,84418,85241,85241,85243,84568,85248,85249,85254,85255,85258,85259,85260,84700,84805,85263,85265,85266,84976,85267,84469,85270,85272,85280,85282,84494,84494,85285,85286,84453,85288,84436,85290,84494,85292,85294,85296,84895,84469,84469,85299,84730,85300,85301,85302,85097,85303,85303,85306,85307,85312,85314,84950,85315,85317,84578,84483,85318,85319,84812,85322,84433,84821,84436,84494,84472,85323,85104,84576,84946,85329,85224,84453,85331,85332,85333,85336,85337,85348,85349,85353,84463,84496,85355,85360,84969,85104,85361,85361,85363,85364,85367,84418,85368,85373,85374,84584,85378,84430,85379,84972,85381,85385,84934,84730,85392,84972,85395,84864,85397,85398,84469,85399,85401,85409,85411,85412,85021,85413,85414,84436,84867,84472,85066,85066,85415,84436,85416,85418,85419,85425,85428,84469,85432,85433,84489,84463,85436,84895,85441,85443,85445,85449,85450,85452,84436,84463,84436,84972,84418,85453,84497,84592,84453,85053,85454,85066,84730,85456,85457,85458,85463,85464,85465,84578,85467,85469,84833,85470,85476,85482,84494,85483,85490,85491,84469,85493,85494,84514,85147,85499,85502,85503,84423,84494,84946,85504,84821,84453,85483,84494,85221,85511,84433,85513,84436,84895,84494,85517,85520,84436,85521,85526,85248,85527,85419,85528,84496,85530,85535,85537,85538,85539,85540,85544,85546,84469,85547,84989,85445,84433,85549,85554,84497,85555,85097,84457,84494,85453,85453,85557,85558,84494,84494,85538,85561,84496,84469,84497,84463,85562,84436,84831,84972,85563,84578,84592,84859,84821,85565,85566,85572,85108,85577,84483,84972,84497,85578,84820,85580,84541,84805,85581,85585,84906,85586,85587,85097,84531,85591,85592,85599,85604,85608,85612,85613,85614,85336,85617,84463,85026,85591,85619,85562,84469,85620,84479,85622,85623,84950,84821,85627,85629,85630,84494,84445,84496,84937,85631,84884,85634,84972,84578,85635,84433,85639,84568,84531,84436,85450,84417,85640,84436,85397,85026,85641,84496,85645,84972,84514,85147,85650,85654,84469,85656,85657,85659,85661,85021,84568,85662,85381,84494,85663,85667,85668,85670,85674,84805,84494,85675,85677,85681,84592,85661,85401,85175,85685,85686,84722,85687,85688,84793,84950,85690,84756,85691,84884,85695,85696,85697,85699,84453,84436,85701,84469,85704,84463,84875,85706,84494,85707,85619,85708,85712,84472,85530,84895,85716,84457,85717,84821,85718,85367,85719,85433,85720,85721,85662,85722,85381,85723,85724,85725,85726,85727,85728,85248,85731,85733,85734,84436,85735,85736,85737,84494,85307,84722,85740,85741,84899,85742,85744,85745,85746,85747,84463,85748,85558,84463,85761,84895,84494,84469,85765,85769,85772,85773,84568,85774,85775,85783,84497,85784,84436,84483,84445,84430,85318,84568,84805,84884,85476,85024,85785,84514,85786,84906,84989,85787,84453,84991,85670,84983,84417,85147,85791,85221,85591,85792,85793,85797,84592,85798,85800,85802,84457,84457,85805,85221,85806,85807,84730,85808,85809,85812,85813,84568,85826,85827,85828,84730,84457,85830,85832,85695,85842,85355,84592,85530,85708,85843,85849,85850,85851,84972,85852,84821,85855,85857,85859,85860,85221,85861,85043,85863,84494,84436,84436,84821,84417,84433,85147,85864,85041,85865,85731,85866,85041,85868,85872,85108,85873,84494,84496,85875,85876,85877,85879,84635,84531,85108,85661,85880,84494,85221,85095,84497,85411,84436,85017,84950,85092,84821,85886,84418,85888,85889,84418,85893,84483,85894,85895,84436,85104,85896,85899,84457,85097,84463,85147,84793,85900,85147,84469,85806,85905,84508,85908,85912,84418,85913,84469,85740,85415,85558,85916,85411,85917,85765,84483,85670,84494,85919,84436,84497,84453,85740,85920,84436,84433,84494,85921,84925,85294,84418,85397,85922,84453,84453,84514,84989,85923,84453,85924,85147,84483,84418,84497,84469,85926,85147,84514,85927,85214,84494,84483,84820,84423,85932,84418,85939,85941,84541,84592,84820,84859,85591,85942,84483,85950,85951,85952,85411,84494,84463,84592,85953,85954,84514,84453,85955,84768,84418,85956,85957,85191,85797,85960,85964,84578,85769,84494,85965,85967,85968,84879,84722,84514,85972,85974,85979,85981,85983,84418,85987,84989,85765,84469,84586,84469,85401,85217,85476,85290,86000,84494,84436,84433,84592,84436,85224,85021,86003,86004,85708,85367,85432,84496,86005,86010,84494,86011,84621,86012,85530,86013,86014,86018,86019,84989,84494,86023,85290,84486,86026,86027,86028,86033,84494,84436,86037,84989,85097,84463,84575,85893,86038,86045,86046,85661,84821,84893,84436,84578,84494,86047,84951,84453,84545,84578,86048,86050,84496,86051,84469,84469,84469,84418,86053,86054,85385,86059,85591,84812,86064,84483,86071,85272,85530,86075,86076,86077,86078,84592,86079,85147,86037,84592,86081,84436,84494,86088,86089,84700,85175,85614,84972,84972,86094,86095,85385,86096,84592,86097,86098,84496,86099,84436,84494,86100,86101,84453,86105,84494,86106,85102,84821,86107,84436,84564,84418,86110,86115,84418,86117,84578,85097,84463,85058,84469,86118,84489,84950,86120,86123,86124,84730,84463,85215,84497,86126,84508,84494,85677,86127,85413,85432,86129,86132,86133,84641,85415,86134,86135,85661,85097,86136,84989,86142,85432,86143,84436,86144,85095,84463,84722,86145,84531,85363,85221,84592,84496,86149,86150,84494,85007,84756,84899,86152,85972,84545,86005,86153,84592,86165,86169,84494,86172,84418,86173,86174,86175,84494,84592,85189,85224,86178,86180,84494,84494,85614,84433,84497,84895,84494,85701,86184,86185,85612,86186,86188,84568,86194,84486,85591,84436,85385,84436,86195,84494,85337,86196,86197,84496,85097,85299,84496,86198,86199,86203,84463,84884,86204,84514,86208,86107,84469,85085,85137,86209,84494,86214,85731,84592,84586,86216,84867,86217,84541,84812,86219,84463,86220,86231,86232,84469,86234,84906,86235,84483,85735,86237,86241,85225,86242,85095,84722,86246,84469,86247,84991,86248,84989,86252,85147,86253,84494,86255,85800,85708,84417,84576,84514,84433,84545,86256,86257,84592,84972,86258,86259,84453,85181,84463,85381,86260,85681,84957,85299,86261,85667,86270,86271,84496,85381,84418,85411,86275,84457,86279,84494,85591,86280,86281,85097,85476,86282,84989,84568,84497,85101,84774,84463,84418,86286,84719,86287,86288,84821,86294,86295,84730,86296,86297,84926,84812,84514,84497,84730,86298,86301,86302,85806,84436,86305,84453,84457,86306,84436,85832,86307,86013,85381,84436,86308,84494,86309,84989,84769,86310,84494,85554,84899,85483,86312,84592,84494,85221,86316,84483,86317,85299,84453,86318,86319,86320,84514,86321,84514,84494,86324,84531,84508,86326,86331,84592,84719,84483,85731,86332,86333,84469,84436,85191,84821,84497,86334,84895,86337,86341,84568,85832,84436,86342,84483,86348,84722,86349,84436,86350,84820,85097,86358,85785,85913,84497,85224,84497,86362,85092,85147,86363,86364,85147,84436,86365,86367,85620,84494,84821,85972,86368,84514,84457,86372,84950,86287,84821,85591,86373,84494,85147,86374,85102,84483,85017,84820,84469,84859,85483,84514,84436,84494,84494,86375,84592,85677,86286,84494,86377,86379,85562,84418,85591,84494,84494,85807,84483,84497,86380,86381,84576,84433,86382,84469,86383,84494,86385,84436,85191,86387,84418,86388,86208,84514,84494,84641,84469,84508,86390,86037,84453,85221,84463,86392,86404,86405,86412,86208,86413,86414,85294,86350,86415,86416,86417,84494,84514,84895,86421,84483,85032,84514,85367,84769,86425,86426,84494,84989,86427,86429,85483,86431,84568,86432,86436,85026,85294,86004,84494,84436,86441,84494,84469,86442,86444,86445,84483,86446,86449,84436,85908,84457,86450,84494,84436,86385,85254,86452,86453,86457,84472,85097,86460,84463,86100,85299,84469,84496,84972,84418,85685,84722,86461,86462,86463,86464,84418,84722,86465,84453,86466,84453,86467,84972,85397,86473,85147,86474,86475,86477,84494,84514,86478,85097,86479,86449,84494,86487,84545,84496,86488,84494,86493,84972,84722,84497,85662,85294,86494,86497,84991,84469,84989,85381,85221,86498,86499,84592,86003,85893,86501,84483,86037,84906,86479,84592,86502,85591,86504,86505,84719,84875,86506,86507,86508,86509,86513,84418,85381,86515,86517,84805,86518,86286,85191,86522,85097,86523,84472,86527,86532,84469,86534,86535,84479,86537,86538,86541,86545,85097,84820,86546,84989,85224,84989,84972,86548,84820,85411,84578,86549,86550,84463,86551,86552,84508,85037,84592,86553,84494,85667,86556,86557,84423,84875,86552,86561,86037,86563,86564,84568,84763,86565,84862,84463,86286,85411,85381,86566,86568,86574,86576],"time":[380.999167,383.703167,384.888042,385.904167,386.900667,387.898333,388.899917,389.905583,390.903125,391.903667,392.908417,393.916167,394.909292,395.900125,396.918583,397.891292,398.897917,399.901292,400.914583,401.896333,402.916208,403.875583,404.902875,405.895417,406.92,407.894167,408.913875,409.915292,410.908375,411.899792,412.894125,413.921667,414.904708,415.8985,416.913,417.909667,418.915375,419.910333,420.898958,421.908542,422.920833,423.913417,424.907708,425.916625,426.9105,427.916083,428.907958,429.9095,430.920208,431.911875,432.912042,433.920375,434.907875,435.927792,436.915917,437.887917,438.927917,439.8735,440.931958,441.851167,442.935542,443.913167,444.91475,445.918917,446.921542,447.909333,448.92475,449.740042,450.966958,451.897833,452.926,453.917375,454.919667,455.910208,456.916167,457.924,458.918,459.921667,460.922167,461.926417,462.920708,463.940792,464.928792,465.929875,466.92975,467.933458,468.937417,469.932333,470.938667,471.931167,472.931292,473.939042,474.931583,475.934,476.93375,477.93725,478.937792,479.935208,480.934208,481.942375,482.905333,483.9465,484.93825,485.934458,486.941375,487.9325,488.94375,489.9325,490.93775,491.941167,492.9125,493.918708,494.935167,495.936542,496.939917,497.935542,498.94225,499.938833,500.942833,501.934542,502.937958,503.94325,504.935042,505.941042,506.936208,507.917417,508.94875,509.935917,510.935833,511.942625,512.941083,513.944083,514.938333,515.946833,516.935542,517.944792,518.942958,519.943583,520.938875,521.943833,522.925792,523.919958,524.945125,525.944958,526.936333,527.942792,528.943042,529.942833,530.939917,531.947792,532.944042,533.939708,534.9475,535.918625,536.947875,537.946208,538.946083,539.941083,540.948,541.941417,542.943458,543.941958,544.942958,545.945125,546.943292,547.949,548.941167,549.941625,550.942333,551.943833,552.940292,553.94425,554.949458,555.955667,556.947458,557.923958,558.928958,559.95325,560.9475,561.944083,562.950083,563.94975,564.944125,565.911375,566.960292,567.939125,568.954917,569.950375,570.951958,571.949167,572.950125,573.948917,574.949875,575.944208,576.954208,577.95225,578.950042,579.948292,580.949833,581.951083,582.949292,583.943,584.950708,585.946083,586.920208,587.9535,588.948625,589.949208,590.947917,591.948333,592.949042,593.948875,594.948917,595.947708,596.9495,597.948083,598.950042,599.947708,600.952208,601.94575,602.952667,603.951667,604.948333,605.951333,606.957292,607.955,608.948208,609.951333,610.950792,611.954375,612.949042,613.953042,614.947458,615.951958,616.947667,617.952625,618.953625,619.950208,620.957875,621.956875,622.955458,623.957875,624.951417,625.954917,626.948958,627.958417,628.956125,629.950625,630.953125,631.952875,632.95825,633.959875,634.951125,635.954917,636.958708,637.954958,638.95875,639.952917,640.959667,641.956333,642.95425,643.953,644.957333,645.952417,646.956917,647.953583,648.961917,649.960125,650.952417,651.958167,652.958208,653.955833,654.9615,655.959792,656.95625,657.958292,658.958458,659.954583,660.958042,661.953917,662.962583,663.955625,664.957458,665.959833,666.95575,667.955583,668.956542,669.960875,670.956,671.965,672.961917,673.937875,674.962458,675.961208,676.960083,677.95,678.954583,679.960333,680.954583,681.961542,682.966333,683.9525,684.962917,685.960708,686.95925,687.962292,688.961833,689.960875,690.963375,691.957458,692.966958,693.957625,694.968208,695.956958,696.95975,697.967542,698.962292,699.964208,700.960958,701.960708,702.962583,703.943042,704.96725,705.947333,706.966583,707.939667,708.975,709.960333,710.965375,711.960625,712.964167,713.966292,714.962417,715.960125,716.968375,717.95975,718.965125,719.963625,720.964208,721.962542,722.964375,723.963958,724.966375,725.960833,726.964292,727.963333,728.963083,729.963,730.960125,731.964542,732.964333,733.96525,734.942125,735.969542,736.96275,737.963,738.963875,739.966125,740.965625,741.956292,742.938,743.944458,744.973792,745.965083,746.967417,747.966292,748.972,749.966917,750.971875,751.963708,752.972,753.967125,754.966167,755.965292,756.970667,757.96525,758.968667,759.967833,760.968625,761.975208,762.966708,763.969542,764.968958,765.973458,766.971042,767.967917,768.966417,769.974167,770.968208,771.971875,772.97275,773.965792,774.957958,775.968292,776.946542,777.980375,778.952083,779.952042,780.976917,781.97275,782.970792,783.970208,784.973917,785.972458,786.969458,787.970458,788.968208,789.973,790.947958,791.976542,792.794333,794.019125,794.916042,795.981708,796.968042,797.980875,798.971708,799.9715,800.972,801.978375,802.97475,803.9715,804.976375,805.975,806.97825,807.971625,808.973625,809.976333,810.97975,811.972375,812.97425,813.974583,814.976875,815.973667,816.972125,817.974292,818.974833,819.982208,820.976167,821.977,822.981375,823.97975,824.973458,825.97725,826.973792,827.981083,828.978583,829.982,830.979042,831.980792,832.978708,833.981208,834.97675,835.977625,836.98225,837.974625,838.98375,839.977792,840.982667,841.982083,842.979667,843.97725,844.980958,845.977458,846.984125,847.977667,848.95725,849.992708,850.979667,851.955917,852.987042,853.9805,854.983583,855.978875,856.987292,857.980292,858.98125,859.979875,860.98,861.98575,862.985083,863.986125,864.97775,865.98775,866.984292,867.982958,868.984333,869.987833,870.979,871.982292,872.98475,873.98425,874.979125,875.983833,876.98375,877.983,878.989,879.9845,880.98825,881.987625,882.981833,883.986667,884.982,885.984458,886.989875,887.984792,888.982,889.985042,890.985,891.990208,892.979833,893.990375,894.989833,895.987625,896.991458,897.985375,898.984333,899.984708,900.985417,901.988625,902.99125,903.990125,904.983167,905.992333,906.990875,907.984625,908.988333,909.988792,910.984958,911.99125,912.979208,913.991917,914.98725,915.993125,916.986792,917.987208,918.990667,919.99275,920.989875,921.990292,922.991208,923.991583,924.985292,925.994042,926.98975,927.969208,928.969917,929.968208,930.986375,931.993917,932.987708,933.985375,934.992667,935.989,936.989958,937.993917,938.99325,939.988833,940.9895,941.998583,942.986458,944.000042,944.991042,945.98575,946.998375,947.987375,948.995375,949.988583,950.9975,951.987583,952.994458,953.992583,954.994042,955.988667,956.995042,957.988083,958.994792,959.992458,960.9915,961.996542,962.996833,963.989208,965.001333,965.993875,966.99725,967.996583,968.99125,969.996083,970.996042,971.991458,972.997958,973.99325,974.997792,975.992375,977.000333,977.990042,978.994708,979.992125,980.99375,981.993208,982.993417,983.99275,984.993125,985.993625,986.993333,988.001083,988.990375,990.002458,990.994417,991.99375,992.994542,994.000583,994.999958,995.99625,996.997625,997.99525,998.998417,999.994042,1000.997417,1001.999292,1002.997125,1003.994958,1004.996333,1005.9995,1006.973792,1008.015792,1008.990833,1009.976708,1011.001792,1012.001708,1012.99975,1013.997833,1015.005375,1016.016042,1017.000083,1017.995333,1019.002,1019.997875,1020.995875,1022.005167,1023.003292,1024.002417,1024.998292,1026.002958,1026.997875,1028.004083,1028.998708,1030.002833,1031.00425,1032.004625,1032.997792,1034.005292,1035.000542,1036.000417,1037.005125,1038.005333,1039.005708,1040.008042,1041.003375,1041.9985,1043.004042,1044.001167,1045.005667,1046.00425,1047.00625,1048.004,1049.002292,1050.003042,1051.000833,1052.002333,1053.01025,1053.9965,1055.008875,1056.007042,1057.006708,1058.001667,1059.001583,1060.004792,1061.002833,1062.00525,1063.00725,1064.000708,1065.011833,1066.007708,1067.003,1068.004583,1069.005958,1070.003667,1071.0085,1071.988958,1073.006625,1073.9855,1075.028583,1075.999875,1077.003375,1078.0075,1079.008125,1080.009,1081.003917,1082.011958,1083.004375,1084.006125,1085.0055,1086.005958,1087.005792,1088.00925,1089.004333,1090.012458,1091.002208,1092.008583,1093.008542,1094.006208,1095.01325,1096.009958,1097.006375,1098.009958,1099.009458,1100.007458,1101.00425,1102.008833,1103.009125,1104.0105,1105.008333,1106.007708,1107.011875,1108.007292,1109.01275,1109.986333,1111.0165,1112.007417,1113.00875,1114.01625,1115.013542,1116.00925,1117.009125,1118.017417,1119.024833,1120.004917,1121.01125,1122.008292,1123.010833,1124.011208,1125.010667,1126.0105,1127.011708,1128.011625,1129.009333,1130.010583,1131.010917,1132.009792,1133.009958,1134.012458,1135.011542,1136.012,1137.010125,1138.01275,1139.010417,1140.009958,1140.991375,1142.029042,1143.0085,1143.9905,1145.016958,1146.022208,1147.01125,1148.01275,1149.013167,1150.01275,1151.017375,1152.011958,1153.020875,1154.014708,1155.014583,1156.012333,1157.021583,1158.009792,1159.012875,1160.016958,1161.018917,1162.019292,1163.01625,1164.015833,1165.013875,1166.014042,1167.022542,1168.011125,1169.025208,1170.013958,1171.017583,1172.0125,1173.02625,1174.017417,1175.020875,1176.020083,1177.02075,1178.021583,1179.015833,1180.015125,1181.015833,1182.021792,1183.016583,1184.01725,1185.019417,1186.016042,1187.016042,1188.020292,1189.022417,1190.01825,1191.020083,1192.017042,1193.013833,1194.023292,1195.022083,1196.015792,1197.016667,1198.01625,1199.02375,1200.017333,1201.01675,1202.014708,1203.017875,1204.017625,1205.024625,1206.014125,1207.022875,1207.995958,1209.046458,1210.009,1211.00125,1212.02225,1213.003583,1214.026833,1215.018875,1216.021042,1217.014833,1218.024208,1219.016875,1220.026292,1221.019083,1222.0205,1223.020083,1224.021125,1225.020667,1226.028125,1227.017792,1228.023792,1229.02075,1230.022167,1231.024833,1232.023333,1233.027,1234.020042,1235.026167,1236.023917,1237.023292,1238.020042,1239.0215,1240.023167,1241.028583,1242.025542,1243.021708,1244.023333,1245.026083,1246.0295,1247.028417,1248.020458,1249.026917,1250.025542,1251.02325,1252.023583,1253.022875,1254.030417,1255.024333,1256.028083,1257.02875,1258.026292,1259.025792,1260.0255,1261.029542,1262.0235,1263.033667,1264.021833,1265.027958,1266.02925,1267.031083,1268.023125,1269.029292,1270.030042,1271.028458,1272.030167,1273.023792,1274.028458,1275.027125,1276.0265,1277.033167,1278.023708,1279.003667,1280.043458,1280.999917,1282.029833,1283.030792,1284.025792,1285.031792,1286.025542,1287.02875,1288.031292,1289.025833,1290.029,1291.029625,1292.027583,1293.029167,1294.030042,1295.033792,1296.025542,1297.028042,1298.032458,1299.03275,1300.03025,1301.034042,1302.026375,1303.0325,1304.028458,1305.029083,1306.033875,1307.033875,1308.025667,1309.029958,1310.029208,1311.030542,1312.029042,1313.03025,1314.034083,1315.029208,1316.0355,1317.030375,1318.034667,1319.030625,1320.033917,1321.028167,1322.039792,1323.027875,1324.032667,1325.034417,1326.031125,1327.038833,1328.037417,1329.029625,1330.0315,1331.030917,1332.03975,1333.03175,1334.0355,1335.037583,1336.032083,1337.032875,1338.039208,1339.030917,1340.0355,1341.039875,1342.032375,1343.040625,1344.032333,1345.039208,1346.016625,1347.05625,1348.025875,1349.055583,1350.028125,1351.037583,1352.039,1353.0395,1354.041667,1355.036583,1356.035125,1357.038958,1358.037625,1359.034667,1360.0335,1361.038792,1362.035333,1363.037542,1364.035042,1365.036667,1366.036583,1367.026708,1368.035708,1369.031417,1370.035583,1371.043792,1372.033833,1373.041,1374.040583,1375.0355,1376.035667,1377.037333,1378.041875,1379.037208,1380.039458,1381.039833,1382.040542,1383.037583,1384.042208,1385.036417,1386.043375,1387.037125,1388.038792,1389.04325,1390.03975,1391.037875,1392.038958,1393.041875,1394.037458,1395.043417,1396.039958,1397.0435,1398.037542,1399.047708,1400.038083,1401.019542,1402.061667,1403.03975,1404.042208,1405.0415,1406.044833,1407.045875,1408.037333,1409.042417,1410.042,1411.048458,1412.039042,1413.048167,1414.043083,1415.042,1416.040292,1417.045458,1418.04075,1419.049375,1420.044417,1421.040708,1422.040417,1423.052917,1424.043042,1425.042375,1426.048708,1427.041292,1428.044417,1429.046,1430.045208,1431.047083,1432.04625,1433.042167,1434.049667,1435.042875,1436.044458,1437.044917,1438.055208,1439.047792,1440.044875,1441.044333,1442.050583,1443.042333,1444.044042,1445.050958,1446.049583,1447.043833,1448.019083,1449.057125,1450.045667,1451.046417,1452.046375,1453.050875,1454.014875,1455.059458,1456.04225,1457.05575,1458.044125,1459.049583,1460.051542,1461.047042,1462.0495,1463.048417,1464.054625,1465.050417,1466.0495,1467.047875,1468.051208,1469.048542,1470.04975,1471.054417,1472.050708,1473.045625,1474.050708,1475.051333,1476.025833,1477.073792,1478.044583,1479.031042,1480.053042,1481.054875,1482.054375,1483.048375,1484.051667,1485.049917,1486.054583,1487.051792,1488.050208,1489.0475,1490.052083,1491.049917,1492.053625,1493.053458,1494.048708,1495.056458,1496.052833,1497.048542,1498.056917,1499.054292,1500.052792,1501.054625,1502.050167,1503.05425,1504.053875,1505.051083,1506.059,1507.054542,1508.052125,1509.058208,1510.050292,1511.059958,1512.048875,1513.052667,1514.060333,1515.055375,1516.057042,1517.052083,1518.053042,1519.058042,1520.055,1521.053792,1522.060208,1523.048417,1524.056458,1525.056292,1526.052042,1527.059292,1528.052917,1529.053625,1530.055625,1531.053,1532.054917,1533.055,1534.053083,1535.056792,1536.054542,1537.056083,1538.056917,1539.055,1540.055917,1541.056625,1542.053917,1543.03275,1544.050042,1545.052667,1546.054917,1547.055208,1548.058917,1549.054208,1550.055625,1551.057208,1552.0595,1553.063042,1554.052167,1555.066833,1556.059208,1557.060542,1558.057292,1559.066708,1560.059708,1561.063792,1562.0615,1563.061792,1564.057292,1565.06525,1566.063625,1567.065833,1568.058667,1569.06375,1570.062292,1571.062875,1572.059542,1573.069333,1574.064167,1575.065208,1576.064708,1577.059708,1578.068667,1579.061167,1580.065458,1581.061542,1582.070792,1583.06775,1584.062,1585.063958,1586.063208,1587.058833,1587.997833,1589.082083,1590.062417,1591.06525,1592.065167,1593.062083,1594.076,1595.062125,1596.070458,1597.061125,1598.066875,1599.070083,1600.067167,1601.06425,1602.070125,1603.069583,1604.063042,1605.073833,1606.068333,1607.066458,1608.06325,1609.065708,1610.071792,1611.080875,1612.064708,1613.079833,1614.063125,1615.068542,1616.074125,1617.065417,1618.068625,1619.065083,1620.070125,1621.068917,1622.06725,1623.07175,1624.07,1625.072083,1626.06825,1627.068833,1628.043792,1629.072792,1630.073042,1631.0745,1632.07575,1633.066958,1634.075792,1635.064417,1636.073292,1637.068458,1638.069917,1639.072583,1640.067875,1641.068667,1642.072583,1643.069875,1644.077625,1645.074333,1646.067625,1647.078792,1648.069125,1649.070375,1650.076375,1651.0695,1652.071917,1653.073417,1654.077125,1655.075792,1656.070542,1657.077042,1658.076667,1659.07125,1660.07275,1661.074375,1662.074375,1663.072625,1664.071792,1665.073667,1666.075417,1667.075833,1668.048583,1669.055833,1670.072583,1671.073125,1672.081125,1673.073042,1674.075875,1675.050167,1676.06775,1677.061042,1678.098625,1679.070417,1680.05825,1681.080208,1682.08225,1683.07375,1684.065792,1685.081208,1686.077917,1687.083542,1688.074958,1689.083583,1690.0785,1691.080583,1692.076417,1693.073333,1694.083208,1695.08225,1696.081375,1697.075667,1698.086708,1699.081292,1700.085125,1701.079542,1702.07525,1703.080875,1704.084667,1705.079,1706.086042,1707.085083,1708.084458,1709.076167,1710.088458,1711.078083,1712.085,1713.079208,1714.087208,1715.085583,1716.08075,1717.048792,1718.091167,1719.084208,1720.087792,1721.080125,1722.084083,1723.08075,1724.086417,1725.084458,1726.086875,1727.08475,1728.084833,1729.0815,1730.08725,1731.078,1732.089083,1733.083542,1734.088708,1735.081292,1736.085375,1737.079875,1738.085417,1739.086542,1740.083875,1741.082667,1742.089042,1743.081875,1744.064208,1745.103917,1746.076208,1747.09975,1748.080833,1749.087208,1750.089042,1751.089083,1752.082625,1753.089458,1754.090625,1755.084292,1756.084167,1757.088167,1758.084167,1759.09,1760.086083,1761.085583,1762.087125,1763.087708,1764.084542,1765.084833,1766.089542,1767.082917,1768.084417,1769.085125,1770.09,1771.089792,1772.089208,1773.084792,1774.087958,1775.09225,1776.085125,1777.085958,1778.093083,1779.0855,1780.088875,1781.093458,1782.092,1783.092125,1784.087,1785.088417,1786.093458,1787.087375,1788.089375,1789.091875,1790.088458,1791.096667,1792.086125,1793.089792,1794.093292,1795.095,1796.087958,1797.091417,1798.092833,1799.089958,1800.09375,1801.088417,1802.092417,1803.072042,1804.11375,1805.080875,1806.091625,1807.094708,1808.094042,1809.08975,1810.095833,1811.097708,1812.08925,1813.091958,1814.0915,1815.091333,1816.091167,1817.097208,1818.095333,1819.091708,1820.091708,1821.090875,1822.091083,1823.092667,1824.096458,1825.08975,1826.098208,1827.094125,1828.094833,1829.095875,1830.089917,1831.095583,1832.098625,1833.091208,1834.100292,1835.090542,1836.095625,1837.094875,1838.092167,1839.099375,1840.092,1841.093542,1842.093208,1843.100583,1844.093625,1845.097792,1846.091458,1847.098208,1848.095083,1849.102833,1850.096625,1851.100708,1852.09425,1853.102,1854.092,1855.102833,1856.0705,1857.103958,1858.092375,1859.088167,1860.098542,1861.097458,1862.094,1863.099625,1864.092875,1865.097833,1866.101,1867.092208,1868.097333,1869.099417,1870.099458,1871.103042,1872.094833,1873.102833,1874.100583,1875.095583,1876.096542,1877.104083,1878.0965,1879.103458,1880.093875,1881.102542,1882.09625,1883.104083,1884.096958,1885.103375,1886.102958,1887.105125,1888.097083,1889.10125,1890.101875,1891.104167,1892.0995,1893.1025,1894.098708,1895.105875,1896.094875,1897.107833,1898.099333,1899.099542,1900.098833,1901.101292,1902.104917,1903.101292,1904.101125,1905.105083,1906.099,1907.1055,1908.099708,1909.103875,1910.099083,1911.106583,1912.098125,1913.104542,1914.10375,1915.104333,1916.101958,1917.102917,1918.103458,1919.1045,1920.108417,1921.10325,1922.106292,1923.105,1924.100167,1925.104625,1926.101583,1927.10675,1928.104417,1929.101042,1930.10375,1931.104083,1932.105375,1933.101417,1934.109333,1935.107125,1936.1035,1937.103167,1938.111208,1939.108708,1940.103625,1941.104792,1942.111917,1943.114667,1944.103708,1945.109583,1946.107,1947.103958,1948.112583,1949.1055,1950.110458,1951.11125,1952.107167,1953.103708,1954.112042,1955.107042,1956.107625,1957.099542,1958.113375,1959.109375,1960.107917,1961.107375,1962.107333,1963.111208,1964.113167,1965.1035,1966.111708,1967.109333,1968.111875,1969.1035,1970.113,1971.10825,1972.112167,1973.111708,1974.108667,1975.111333,1976.104708,1977.113542,1978.111125,1979.106042,1980.112083,1981.107042,1982.114708,1983.111125,1984.112458,1985.106917,1986.115292,1987.110083,1988.111625,1989.111875,1990.109292,1991.109375,1992.111083,1993.10825,1994.107958,1995.087958,1996.092083,1997.000042,1998.116208,1999.104792,2000.098208,2001.092042,2002.10825,2003.1135,2004.108958,2005.111667,2006.112083,2007.113458,2008.110792,2009.110875,2010.111208,2011.113917,2012.112625,2013.111542,2014.115,2015.110042,2016.119083,2017.111958,2018.092667,2019.0945,2020.11875,2021.112917,2022.113167,2023.117125,2024.112833,2025.115208,2026.119833,2027.115125,2028.119333,2029.117208,2030.110875,2031.119417,2032.115292,2033.118292,2034.117417,2035.1175,2036.113292,2037.12,2038.112583,2039.122,2040.117708,2041.118208,2042.118583,2043.118625,2044.114583,2045.11725,2046.112708,2047.120833,2048.115958,2049.1185,2050.117667,2051.118417,2052.1195,2053.120708,2054.114083,2055.121958,2056.123625,2057.122542,2058.121333,2059.119083,2060.121792,2061.117375,2062.116792,2063.120583,2064.116875,2065.119917,2066.115375,2067.119375,2068.11825,2069.116167,2070.119833,2071.120292,2072.117375,2073.123667,2074.119708,2075.117583,2076.120708,2077.123583,2078.123542,2079.120333,2080.118375,2081.119875,2082.124042,2083.117083,2084.12375,2085.119333,2086.125,2087.121833,2088.124708,2089.12325,2090.123458,2091.117833,2092.12875,2093.117583,2094.121167,2095.123958,2096.126167,2097.116708,2098.123792,2099.120708,2100.1235,2101.126417,2102.124667,2103.12425,2104.122958,2105.121417,2106.123917,2107.126292,2108.11125,2109.130833,2110.122375,2111.125,2112.120375,2113.146417,2114.095917,2115.132083,2116.121542,2117.1235,2118.1215,2119.124,2120.123208,2121.12575,2122.128375,2123.121833,2124.104083,2125.105417,2126.129792,2127.12375,2128.123542,2129.124708,2130.125417,2131.12175,2132.125292,2133.12425,2134.124125,2135.12325,2136.125292,2137.125667,2138.124542,2139.124583,2140.124417,2141.124083,2142.105208,2143.148,2144.119917,2145.122333,2146.127292,2147.128667,2148.125167,2149.125583,2150.127125,2151.127167,2152.132667,2153.131083,2154.129375,2155.126083,2156.128458,2157.1315,2158.124917,2159.131667,2160.126708,2161.134458,2162.125458,2163.128375,2164.114958,2165.134,2166.127,2167.076,2168.144083,2169.125042,2170.133125,2171.128208,2172.134125,2173.128667,2174.130125,2175.131708,2176.128,2177.133,2178.134542,2179.128667,2180.133167,2181.126375,2182.136875,2183.126667,2184.128292,2185.132042,2186.130375,2187.133208,2188.134292,2189.128792,2190.1315,2191.136042,2192.128875,2193.131625,2194.132208,2195.134042,2196.147583,2197.1275,2198.1325,2199.133083,2200.132875,2201.130375,2202.136875,2203.135292,2204.129583,2205.13375,2206.132333,2207.136292,2208.131375,2209.112958,2210.1555,2211.107375,2212.157458,2213.129292,2214.134542,2215.135292,2216.131417,2217.133917,2218.131792,2219.132083,2220.132792,2221.135792,2222.134708,2223.133458,2224.132917,2225.135625,2226.133417,2227.132958,2228.137,2229.134333,2230.136875,2231.13775,2232.134375,2233.135583,2234.1365,2235.137917,2236.136875,2237.134667,2238.135208,2239.141417,2240.123917,2241.125458,2242.12375,2243.132958,2244.143708,2245.141167,2246.139458,2247.140583,2248.140375,2249.148042,2250.1375,2251.1395,2252.121375,2253.149833,2254.115917,2255.167458,2256.108875,2257.151458,2258.14675,2259.143917,2260.143917,2261.144708,2262.141417,2263.151292,2264.143833,2265.14975,2266.143375,2267.152167,2268.142625,2269.162667,2270.11475,2271.160042,2272.145458,2273.122542,2274.155458,2275.156375,2276.136125,2277.09525,2278.1355,2279.120917,2280.144708,2281.150083,2282.151458,2283.145917,2284.153083,2285.14475,2286.154375,2287.151167,2288.143667,2289.146,2290.150083,2291.145708,2292.1485,2293.1435,2294.160625,2295.124792,2296.153833,2297.144583,2298.159333,2299.143625,2300.152708,2301.152625,2302.149042,2303.149208,2304.147542,2305.150083,2306.147542,2307.150625,2308.150417,2309.15325,2310.147625,2311.1545,2312.1475,2313.147125,2314.1545,2315.149542,2316.155458,2317.15,2318.149292,2319.153917,2320.149875,2321.150958,2322.151208,2323.147125,2324.152042,2325.155292,2326.148417,2327.155333,2328.155125,2329.153292,2330.155583,2331.148667,2332.156167,2333.152875,2334.152208,2335.159833,2336.153208,2337.153583,2338.15475,2339.154833,2340.154542,2341.155458,2342.151625,2343.159208,2344.15225,2345.158708,2346.158,2347.15775,2348.159292,2349.151833,2350.155833,2351.153542,2352.1575,2353.161958,2354.161208,2355.155417,2356.158833,2357.158375,2358.151458,2359.162708,2360.156417,2361.156083,2362.156708,2363.155833,2364.154958,2365.155,2366.145917,2367.160208,2368.145708,2369.145417,2370.158542,2371.155625,2372.139125,2373.142208,2374.163042,2375.153792,2376.154917,2377.160667,2378.159667,2379.155,2380.16425,2381.15825,2382.162667,2383.155417,2384.161792,2385.162042,2386.162958,2387.159375,2388.159333,2389.163292,2390.161875,2391.163417,2392.155708,2393.157833,2394.160792,2395.157375,2396.157542,2397.165792,2398.158167,2399.164667,2400.156417,2401.152417,2402.160083,2403.161917,2404.160792,2405.165875,2406.16275,2407.164,2408.160083,2409.160833,2410.143583,2411.169,2412.140208,2413.187708,2414.130792,2415.159042,2416.160458,2417.161042,2418.166333,2419.182958,2420.156125,2421.158792,2422.163958,2423.164042,2424.168958,2425.160875,2426.170458,2427.159875,2428.169083,2429.159667,2430.164292,2431.167458,2432.1645,2433.164292,2434.169625,2435.15975,2436.170833,2437.160417,2438.164958,2439.163208,2440.17025,2441.162333,2442.168917,2443.163625,2444.165375,2445.166917,2446.163042,2447.17075,2448.162542,2449.169583,2450.1635,2451.169125,2452.167542,2453.164167,2454.17325,2455.170917,2456.162542,2457.170542,2458.173625,2459.163583,2460.167333,2461.168583,2462.168083,2463.166208,2464.170125,2465.167375,2466.171917,2467.167417,2468.167042,2469.169208,2470.165833,2471.175042,2472.166083,2473.173333,2474.173708,2475.167167,2476.175958,2477.167875,2478.167917,2479.171,2480.165167,2481.174458,2482.167833,2483.14925,2484.177958,2485.164958,2486.173667,2487.169458,2488.173958,2489.167167,2490.17,2491.171958,2492.16825,2493.16925,2494.179583,2495.171083,2496.168458,2497.172625,2498.16925,2499.175667,2500.171292,2501.170708,2502.169417,2503.173,2504.173458,2505.168542,2506.176083,2507.170708,2508.176375,2509.167667,2510.172,2511.181583,2512.173792,2513.170583,2514.172333,2515.174833,2516.173083,2517.1695,2518.172208,2519.173125,2520.173417,2521.172292,2522.172792,2523.171458,2524.17775,2525.170542,2526.173625,2527.174833,2528.176083,2529.172958,2530.179625,2531.170833,2532.1785,2533.1695,2534.174125,2535.173542,2536.178917,2537.173333,2538.178042,2539.172958,2540.178542,2541.158833,2542.183,2543.154167,2544.179708,2545.176583,2546.176875,2547.158375,2548.186958,2549.170583,2550.176125,2551.173458,2552.182542,2553.179,2554.175375,2555.175833,2556.179958,2557.174542,2558.177958,2559.177042,2560.175958,2561.176208,2562.1775,2563.177667,2564.178167,2565.178958,2566.178708,2567.174667,2568.176167,2569.178583,2570.178333,2571.176708,2572.177833,2573.178417,2574.177792,2575.178208,2576.178208,2577.180125,2578.178042,2579.179542,2580.179417,2581.18525,2582.184292,2583.179458,2584.18475,2585.180083,2586.183125,2587.178792,2588.183917,2589.18775,2590.179875,2591.184125,2592.179333,2593.163708,2594.173875,2595.185125,2596.183667,2597.181167,2598.182167,2599.18675,2600.181917,2601.185,2602.189167,2603.184083,2604.187125,2605.181292,2606.187,2607.183958,2608.187,2609.182542,2610.166333,2611.165958,2612.167125,2613.18725,2614.161375,2615.184667,2616.196458,2617.183417,2618.191292,2619.187833,2620.162,2621.18275,2622.18375,2623.184125,2624.187625,2625.188625,2626.163667,2627.188917,2628.185375,2629.188417,2630.187833,2631.193208,2632.186292,2633.188083,2634.194125,2635.187292,2636.192875,2637.187583,2638.193667,2639.192542,2640.186792,2641.187917,2642.19075,2643.185417,2644.174958,2645.190417,2646.187208,2647.192833,2648.189333,2649.192917,2650.189583,2651.188833,2652.191542,2653.194375,2654.188417,2655.194583,2656.187625,2657.191167,2658.194208,2659.187792,2660.193083,2661.190958,2662.1915,2663.195375,2664.188208,2665.197417,2666.193625,2667.188417,2668.173458,2669.171333,2670.191708,2671.199708,2672.193125,2673.196,2674.19675,2675.18875,2676.192625,2677.191667,2678.19075,2679.1825,2680.191125,2681.170208,2682.196,2683.182917,2684.184792,2685.154417,2686.208125,2687.192167,2688.199667,2689.191917,2690.197958,2691.204167,2692.207917,2693.171333,2694.191667,2695.174958,2696.192292,2697.1945,2698.202917,2699.197125,2700.203458,2701.19075,2702.183792,2703.203333,2704.195667,2705.1945,2706.195417,2707.200417,2708.200375,2709.19725,2710.195042,2711.200125,2712.195167,2713.196667,2714.203875,2715.200458,2716.197625,2717.1985,2718.199125,2719.180875,2720.180042,2721.202792,2722.199875,2723.197042,2724.203667,2725.201375,2726.196875,2727.199833,2728.200417,2729.198958,2730.198292,2731.198125,2732.2005,2733.197833,2734.20225,2735.200417,2736.2005,2737.2045,2738.206667,2739.200333,2740.205208,2741.210417,2742.202625,2743.210792,2744.177125,2745.213917,2746.200167,2747.210583,2748.200083,2749.204167,2750.204458,2751.20425,2752.200833,2753.20525,2754.201417,2755.206667,2756.202792,2757.203708,2758.205083,2759.203583,2760.204917,2761.210708,2762.209083,2763.200042,2764.206292,2765.204917,2766.208542,2767.207958,2768.208875,2769.212208,2770.18325,2771.209,2772.205042,2773.203417,2774.211958,2775.203208,2776.210125,2777.201375,2778.210792,2779.208083,2780.210083,2781.204167,2782.205875,2783.210458,2784.211125,2785.204458,2786.20975,2787.203833,2788.21525,2789.209333,2790.210792,2791.206417,2792.210333,2793.203917,2794.2115,2795.207208,2796.216125,2797.205208,2798.214792,2799.211292,2800.21075,2801.212708,2802.212542,2803.207958,2804.209125,2805.209375,2806.213875,2807.208333,2808.210667,2809.214833,2810.21575,2811.207958,2812.215083,2813.20875,2814.214833,2815.215458,2816.212,2817.207208,2818.211375,2819.211375,2820.211667,2821.206083,2822.213542,2823.20875,2824.208958,2825.210042,2826.211083,2827.207958,2828.212792,2829.2165,2830.212417,2831.216083,2832.210375,2833.215292,2834.209833,2835.214542,2836.215708,2837.208625,2838.214542,2839.217833,2840.18925,2841.231292,2842.209958,2843.192625,2844.195333,2845.21825,2846.210583,2847.21725,2848.213,2849.215833,2850.215458,2851.213958,2852.215333,2853.217458,2854.218333,2855.2115,2856.212208,2857.208167,2858.193333,2859.2185,2860.212833,2861.216958,2862.21325,2863.215125,2864.221583,2865.217917,2866.21925,2867.214667,2868.222875,2869.21525,2870.214208,2871.218542,2872.213125,2873.218208,2874.222417,2875.215417,2876.218583,2877.218167,2878.219417,2879.212417,2880.2195,2881.217708,2882.219208,2883.217167,2884.21825,2885.219,2886.218708,2887.214708,2888.226792,2889.213208,2890.225375,2891.214917,2892.220708,2893.218125,2894.219583,2895.219792,2896.215917,2897.223208,2898.216417,2899.220042,2900.217208,2901.218417,2902.219833,2903.22125,2904.217708,2905.221417,2906.222792,2907.196833,2908.239375,2909.213208,2910.223208,2911.2145,2912.225917,2913.220042,2914.218083,2915.225625,2916.212625,2917.2225,2918.132625,2919.242292,2920.215917,2921.223875,2922.224875,2923.224958,2924.223167,2925.21725,2926.220375,2927.222083,2928.226958,2929.222958,2930.22525,2931.221042,2932.223458,2933.221,2934.228375,2935.228708,2936.222833,2937.229583,2938.2305,2939.224208,2940.231125,2941.222917,2942.223375,2943.230875,2944.222458,2945.228167,2946.226042,2947.231042,2948.22475,2949.226208,2950.229083,2951.223125,2952.232792,2953.223917,2954.231917,2955.224875,2956.232167,2957.225042,2958.227625,2959.2295,2960.231708,2961.22475,2962.229458,2963.229583,2964.225833,2965.225458,2966.229,2967.2285,2968.227958,2969.222292,2970.211,2971.226583,2972.2325,2973.223958,2974.233208,2975.236042,2976.226292,2977.229,2978.231417,2979.227625,2980.235292,2981.227875,2982.229375,2983.227833,2984.234083,2985.227542,2986.228792,2987.228167,2988.235208,2989.2315,2990.231083,2991.23575,2992.227667,2993.237167,2994.213458,2995.213583,2996.232708,2997.23325,2998.228833,2999.233542,3000.232125,3001.2335,3002.232458,3003.234958,3004.226,3005.23825,3006.226833,3007.236042,3008.228292,3009.233167,3010.237292,3011.234167,3012.236583,3013.233208,3014.227917,3015.237,3016.226417,3017.213042,3018.239667,3019.216458,3020.243042,3021.233833,3022.23775,3023.238,3024.237042,3025.239333,3026.233167,3027.238083,3028.239708,3029.237,3030.231417,3031.239333,3032.237,3033.234833,3034.238667,3035.234833,3036.234208,3037.238375,3038.2395,3039.239167,3040.235333,3041.234417,3042.234417,3043.240667,3044.220167,3045.24,3046.234917,3047.218708,3048.25525,3049.239917,3050.24875,3051.22875,3052.228875,3053.243333,3054.214542,3055.243292,3056.235375,3057.235333,3058.232208,3059.237833,3060.243375,3061.235208,3062.241167,3063.241417,3064.241125,3065.240667,3066.236375,3067.2375,3068.237833,3069.215042,3070.245792,3071.240292,3072.237208,3073.238833,3074.238792,3075.2375,3076.245792,3077.235417,3078.242792,3079.223,3080.222167,3081.24425,3082.240167,3083.241667,3084.246208,3085.24125,3086.243,3087.238792,3088.245417,3089.237875,3090.247083,3091.236625,3092.246292,3093.239125,3094.254,3095.242542,3096.240708,3097.247583,3098.244625,3099.244792,3100.241208,3101.243625,3102.241375,3103.245833,3104.238792,3105.244458,3106.241875,3107.247625,3108.247375,3109.247792,3110.241708,3111.241542,3112.24375,3113.244958,3114.247375,3115.244917,3116.249792,3117.244625,3118.242458,3119.251,3120.242958,3121.222,3122.228125,3123.225208,3124.243042,3125.22225,3126.256583,3127.224542,3128.249,3129.234625,3130.227958,3131.248542,3132.245667,3133.242917,3134.246125,3135.246125,3136.246875,3137.246292,3138.247333,3139.2465,3140.244792,3141.245042,3142.247167,3143.247083,3144.246958,3145.244125,3146.249083,3147.246542,3148.251792,3149.245417,3150.247542,3151.24425,3152.249208,3153.247083,3154.24925,3155.248375,3156.248542,3157.248583,3158.246917,3159.248583,3160.248125,3161.247708,3162.255375,3163.247625,3164.253083,3165.243458,3166.249917,3167.250333,3168.249875,3169.249792,3170.256042,3171.250125,3172.2545,3173.249625,3174.251042,3175.251292,3176.25,3177.25,3178.252208,3179.248583,3180.250708,3181.227917,3182.261083,3183.226833,3184.241083,3185.251917,3186.252333,3187.250458,3188.252792,3189.249292,3190.252625,3191.253917,3192.25125,3193.254,3194.252958,3195.249583,3196.232292,3197.257792,3198.227958,3199.237667,3200.241625,3201.23325,3202.240792,3203.25775,3204.233875,3205.259208,3206.2515,3207.2545,3208.256292,3209.257167,3210.252958,3211.256208,3212.257083,3213.255792,3214.253958,3215.259167,3216.236333,3217.265417,3218.254542,3219.257833,3220.264125,3221.241,3222.236583,3223.242667,3224.266125,3225.259333,3226.258208,3227.260208,3228.260875,3229.262208,3230.2495,3231.263875,3232.259667,3233.261958,3234.261958,3235.24625,3236.244083,3237.269125,3238.23425,3239.250917,3240.25625,3241.239542,3242.268083,3243.261792,3244.264958,3245.265292,3246.265875,3247.266458,3248.264875,3249.269417,3250.248958,3251.252667,3252.275375,3253.2665,3254.271125,3255.267125,3256.270542,3257.269542,3258.244417,3259.254333,3260.251917,3261.251458,3262.277,3263.246,3264.253667,3265.273083,3266.272417,3267.283042,3268.273583,3269.158,3270.292,3271.120042,3272.284667,3273.093458,3274.295458,3275.071208,3276.294708,3277.236042,3278.284333,3279.25225,3280.262875,3281.251917,3282.263875,3283.253458,3284.289917,3285.269208,3286.281208,3287.27675,3288.283917,3289.277458,3290.277542,3291.246417,3292.285708,3293.257167,3294.265333,3295.286333,3296.276625,3297.283583,3298.280333,3299.267042,3300.2845,3301.279792,3302.284708,3303.278292,3304.283167,3305.281292,3306.260625,3307.265375,3308.282083,3309.283542,3310.282208,3311.282375,3312.284542,3313.283542,3314.284708,3315.265083,3316.264667,3317.2685,3318.279458,3319.255,3320.276667,3321.294,3322.3,3323.282083,3324.268292,3325.287042,3326.287958,3327.266708,3328.295542,3329.266208,3330.285958,3331.288125,3332.289458,3333.287583,3334.292833,3335.27375,3336.273542,3337.269958,3338.26725,3339.282417,3340.277958,3341.271417,3342.2975,3343.292333,3344.269042,3345.281333,3346.182792,3347.323583,3348.263833,3349.296583,3350.285292,3351.280167,3352.305292,3353.295,3354.302208,3355.280833,3356.294458,3357.300583,3358.29225,3359.299125,3360.284958,3361.306583,3362.2955,3363.302167,3364.301792,3365.278375,3366.306375,3367.300125,3368.301333,3369.294,3370.316708,3371.309625,3372.297583,3373.298375,3374.28025,3375.30675,3376.301292,3377.304792,3378.304042,3379.302042,3380.301458,3381.303667,3382.3025,3383.304417,3384.298,3385.304542,3386.315917,3387.269042,3388.311375,3389.275042,3390.310875,3391.316792,3392.298958,3393.283667,3394.295333,3395.317917,3396.313125,3397.302208,3398.283417,3399.314375,3400.279417,3401.278042,3402.291375,3403.286,3404.298667,3405.285667,3406.295417,3407.292625,3408.290958,3409.290042,3410.287125,3411.251333,3412.300167,3413.303625,3414.2875,3415.310542,3416.309,3417.284167,3418.327125,3419.317708,3420.291,3421.286125,3422.316875,3423.323625,3424.312667,3425.312708,3426.308583,3427.296042,3428.320125,3429.312042,3430.311958,3431.310125,3432.299292,3433.317833,3434.306583,3435.319292,3436.289167,3437.2965,3438.321167,3439.305667,3440.305292,3441.293333,3442.301375,3443.288417,3444.304417,3445.161417,3446.33475,3447.315875,3448.1665,3449.325542,3450.299125,3451.302542,3452.296042,3453.305208,3454.226667,3455.321625,3456.2915,3457.303833,3458.290042,3459.306667,3460.295125,3461.30975,3462.302917,3463.307,3464.312083,3465.204,3466.339625,3467.292917,3468.303042,3469.326125,3470.298708,3471.1785,3472.286167,3473.307,3474.300375,3475.337417,3476.337792,3477.337375,3478.325333,3479.340125,3480.322083,3481.328375,3482.323333,3483.326875,3484.327458,3485.325542,3486.333833,3487.335,3488.328375,3489.328833,3490.33125,3491.328583,3492.33025,3493.329,3494.324042,3495.332333,3496.323833,3497.326542,3498.326167,3499.334542,3500.304833,3501.334125,3502.329958,3503.315167,3504.330125,3505.305958,3506.311542,3507.334958,3508.330208,3509.328833,3510.325583,3511.332542,3512.327792,3513.326542,3514.337,3515.329417,3516.327375,3517.337417,3518.308917,3519.340375,3520.330333,3521.330958,3522.304,3523.349625,3524.326917,3525.334875,3526.32925,3527.330333,3528.331667,3529.334042,3530.329917,3531.330667,3532.335958,3533.331958,3534.331917,3535.3345,3536.337875,3537.328208,3538.341667,3539.328958,3540.337375,3541.332875,3542.339625,3543.340708,3544.331417,3545.337458,3546.338458,3547.331167,3548.318958,3549.314042,3550.3145,3551.338458,3552.3355,3553.332042,3554.337125,3555.336458,3556.339167,3557.339167,3558.33725,3559.334417,3560.336417,3561.339875,3562.331375,3563.333542,3564.341542,3565.336125,3566.336833,3567.338042,3568.335583,3569.337,3570.33775,3571.313917,3572.346417,3573.311292,3574.341417,3575.337042,3576.333667,3577.33725,3578.338625,3579.345167,3580.341375,3581.334875,3582.339833,3583.341083,3584.343333,3585.343208,3586.344333,3587.3335,3588.346292,3589.335917,3590.343292,3591.336958,3592.339292,3593.343958,3594.338417,3595.341875,3596.344458,3597.344292,3598.340042,3599.341958,3600.343833,3601.339917,3602.3435,3603.339708,3604.346625,3605.342417,3606.3445,3607.341792,3608.344875,3609.336167,3610.344833,3611.34425,3612.343833,3613.337458,3614.349083,3615.345125,3616.341333,3617.338542,3618.347833,3619.324125,3620.323417,3621.350375,3622.343333,3623.343292,3624.34275,3625.343083,3626.322667,3627.322958,3628.34675,3629.345083,3630.345375,3631.345208,3632.348375,3633.341333,3634.344333,3635.348042,3636.343792,3637.34875,3638.346208,3639.347167,3640.347625,3641.34475,3642.352917,3643.340458,3644.3475,3645.347125,3646.352,3647.344208,3648.355667,3649.320042,3650.356542,3651.342458,3652.350833,3653.349042,3654.348583,3655.349,3656.347042,3657.348,3658.345625,3659.351208,3660.350042,3661.347667,3662.345917,3663.353292,3664.344917,3665.351542,3666.353208,3667.346667,3668.353083,3669.345917,3670.353167,3671.348292,3672.354917,3673.348958,3674.327375,3675.334292,3676.345417,3677.355167,3678.348,3679.357042,3680.347833,3681.350042,3682.324708,3683.354833,3684.34975,3685.350083,3686.356167,3687.352375,3688.351375,3689.355458,3690.34875,3691.355583,3692.355708,3693.355542,3694.348958,3695.358,3696.34675,3697.355417,3698.357292,3699.353333,3700.35825,3701.327333,3702.337,3703.361417,3704.355417,3705.354125,3706.357583,3707.354292,3708.351125,3709.332042,3710.36475,3711.330292,3712.376083,3713.342958,3714.336417,3715.337417,3716.366542,3717.352792,3718.351375,3719.355292,3720.35675,3721.358,3722.35625,3723.362083,3724.352167,3725.356083,3726.353083,3727.360292,3728.356375,3729.358042,3730.353042,3731.355375,3732.357125,3733.35375,3734.353875,3735.357625,3736.358542,3737.35575,3738.360208,3739.358125,3740.36075,3741.356125,3742.356042,3743.358833,3744.356,3745.355708,3746.356375,3747.358167,3748.36775,3749.355875,3750.368083,3751.34975,3752.336417,3753.36325,3754.341833,3755.345125,3756.361167,3757.363,3758.35775,3759.365333,3760.367708,3761.359333,3762.365708,3763.361417,3764.361875,3765.367583,3766.36525,3767.368042,3768.363417,3769.361167,3770.364167,3771.3615,3772.363792,3773.364083,3774.36525,3775.360292,3776.366667,3777.36325,3778.36475,3779.365125,3780.364875,3781.362167,3782.366083,3783.353792,3784.370083,3785.366917,3786.339792,3787.267292,3788.3385,3789.368167,3790.334292,3791.347375,3792.34725,3793.34175,3794.360417,3795.352542,3796.368375,3797.363375,3798.370458,3799.360958,3800.366542,3801.364625,3802.3665,3803.364292,3804.36425,3805.363458,3806.358208,3807.345583,3808.368125,3809.366167,3810.365333,3811.365417,3812.345792,3813.352417,3814.343208,3815.345917,3816.34825,3817.352333,3818.351208,3819.369583,3820.373542,3821.371625,3822.375208,3823.372333,3824.375625,3825.365667,3826.3745,3827.37025,3828.373417,3829.37325,3830.371667,3831.375583,3832.37475,3833.370583,3834.369917,3835.369917,3836.372708,3837.366375,3838.368792,3839.376792,3840.350875,3841.3535,3842.389792,3843.369792,3844.37725,3845.371125,3846.349583,3847.379792,3848.373,3849.376792,3850.375208,3851.37525,3852.373583,3853.375583,3854.370917,3855.374083,3856.372167,3857.380792,3858.37,3859.376792,3860.376417,3861.38125,3862.371792,3863.377458,3864.376792,3865.378708,3866.37675,3867.384208,3868.3745,3869.38025,3870.379,3871.38175,3872.374833,3873.382958,3874.376875,3875.376,3876.380042,3877.3765,3878.38175,3879.377875,3880.374958,3881.380792,3882.377708,3883.3815,3884.38125,3885.377958,3886.386917,3887.376792,3888.386333,3889.37875,3890.376417,3891.380417,3892.38225,3893.374417,3894.381417,3895.382583,3896.376917,3897.381917,3898.377292,3899.380292,3900.378792,3901.380375,3902.385042,3903.383125,3904.386375,3905.386875,3906.382708,3907.385958,3908.387208,3909.379875,3910.383708,3911.38075,3912.386083,3913.37825,3914.38575,3915.385667,3916.380958,3917.3825,3918.38025,3919.382875,3920.383875,3921.384125,3922.380667,3923.37325,3924.3835,3925.388375,3926.384792,3927.388667,3928.390208,3929.3895,3930.3825,3931.390542,3932.386292,3933.38575,3934.382708,3935.386292,3936.387083,3937.384,3938.385375,3939.3865,3940.386,3941.389792,3942.380667,3943.388833,3944.384875,3945.392042,3946.383625,3947.393583,3948.38275,3949.387958,3950.389417,3951.389583,3952.385083,3953.394583,3954.384875,3955.391958,3956.387125,3957.392042,3958.383833,3959.39375,3960.387083,3961.39375,3962.385958,3963.393042,3964.392708,3965.387708,3966.384958,3967.39525,3968.385292,3969.3895,3970.394833,3971.393708,3972.3895,3973.373792,3974.397083,3975.391833,3976.364125,3977.371167,3978.394458,3979.387667,3980.390083,3981.397958,3982.387833,3983.396167,3984.390542,3985.389958,3986.393417,3987.392958,3988.396917,3989.390583,3990.392042,3991.39375,3992.395708,3993.389958,3994.388042,3995.398708,3996.393208,3997.392292,3998.382208,3999.399292,4000.394,4001.392083,4002.392583,4003.394917,4004.398042,4005.394167,4006.39625,4007.3905,4008.397875,4009.3945,4010.397833,4011.3935,4012.396333,4013.391458,4014.393917,4015.395958,4016.400167,4017.389,4018.392583,4019.3925,4020.390958,4021.39775,4022.398083,4023.381458,4024.40125,4025.374042,4026.310917,4027.384125,4028.374375,4029.377708,4030.39975,4031.405,4032.396875,4033.397042,4034.395208,4035.401917,4036.401042,4037.395958,4038.4005,4039.394,4040.40325,4041.39425,4042.362458,4043.404458,4044.396542,4045.396292,4046.394625,4047.397542,4048.377417,4049.406333,4050.391333,4051.378375,4052.381208,4053.404,4054.396833,4055.40425,4056.403708,4057.397583,4058.4025,4059.398167,4060.400125,4061.406042,4062.394292,4063.405458,4064.396542,4065.40075,4066.399708,4067.398833,4068.401917,4069.401333,4070.400958,4071.399708,4072.400708,4073.380542,4074.411292,4075.40225,4076.404083,4077.401,4078.406875,4079.401875,4080.403333,4081.398917,4082.405083,4083.400792,4084.406542,4085.398583,4086.402625,4087.416583,4088.397625,4089.404083,4090.406542,4091.406292,4092.398042,4093.400583,4094.404708,4095.382292,4096.404917,4097.401667,4098.39725,4099.382958,4100.391417,4101.383417,4102.387458,4103.407333,4104.393208,4105.386292,4106.399375,4107.309417,4108.411667,4109.41325,4110.382,4111.410458,4112.35975,4113.364875,4114.417708,4115.372958,4116.400917,4117.411583,4118.380417,4119.406583,4120.405292,4121.403833,4122.386,4123.395875,4124.418542,4125.405583,4126.404292,4127.410333,4128.411083,4129.409542,4130.412875,4131.406,4132.412167,4133.405333,4134.406833,4135.405,4136.39175,4137.410667,4138.384333,4139.412083,4140.407375,4141.412083,4142.41075,4143.408625,4144.386083,4145.414333,4146.382333,4147.388667,4148.393792,4149.393458,4150.412333,4151.408375,4152.409542,4153.411667,4154.408667,4155.412667,4156.409708,4157.414,4158.408917,4159.413125,4160.409042,4161.413208,4162.416667,4163.418208,4164.416875,4165.416125,4166.410833,4167.407167,4168.41275,4169.418875,4170.415667,4171.4105,4172.42025,4173.413583,4174.416667,4175.417292,4176.410542,4177.423542,4178.41725,4179.421958,4180.410708,4181.418792,4182.414458,4183.421292,4184.418417,4185.414333,4186.418,4187.419417,4188.412208,4189.41975,4190.412583,4191.416083,4192.412917,4193.4195,4194.41825,4195.418125,4196.421292,4197.420417,4198.414083,4199.42325,4200.413875,4201.419042,4202.418417,4203.422333,4204.419042,4205.415333,4206.414625,4207.393542,4208.254917,4209.417208,4210.415667,4211.378125,4212.399708,4213.352667,4214.395708,4215.409333,4216.40675,4217.268208,4218.410667,4219.394917,4220.387292,4221.423417,4222.375542,4223.396708,4224.398875,4225.404042,4226.376833,4227.427375,4228.350458,4229.34925,4230.437458,4231.416083,4232.425417,4233.419417,4234.427458,4235.423042,4236.419917,4237.4225,4238.424708,4239.423,4240.425958,4241.429167,4242.42925,4243.424625,4244.428458,4245.43425,4246.417708,4247.42925,4248.420458,4249.4295,4250.419875,4251.424167,4252.422917,4253.420417,4254.424333,4255.424458,4256.425458,4257.422917,4258.423417,4259.428292,4260.42925,4261.429042,4262.423958,4263.427792,4264.423,4265.426875,4266.411333,4267.434583,4268.401375,4269.438417,4270.4215,4271.428125,4272.402542,4273.430917,4274.422917,4275.427667,4276.424583,4277.424833,4278.427042,4279.427,4280.427708,4281.425667,4282.42575,4283.427083,4284.425917,4285.433,4286.426625,4287.4315,4288.431208,4289.432625,4290.431667,4291.425083,4292.431875,4293.432333,4294.431333,4295.428583,4296.434208,4297.426333,4298.431042,4299.43325,4300.427958,4301.430458,4302.428458,4303.4305,4304.426833,4305.426292,4306.42825,4307.4275,4308.43075,4309.429625,4310.429333,4311.435167,4312.426458,4313.430208,4314.424792,4315.429667,4316.413917,4317.40225,4318.424833,4319.420417,4320.433333,4321.430542,4322.425125,4323.403542,4324.37725,4325.44175,4326.429917,4327.437458,4328.404583,4329.433375,4330.433708,4331.436333,4332.435667,4333.427375,4334.4365,4335.41725,4336.445,4337.43425,4338.436708,4339.432792,4340.437708,4341.435375,4342.433375,4343.410292,4344.446625,4345.432542,4346.433,4347.436833,4348.4335,4349.439917,4350.433167,4351.437958,4352.431542,4353.436208,4354.432583,4355.441083,4356.43675,4357.436375,4358.434583,4359.435,4360.434708,4361.438417,4362.43725,4363.4335,4364.436125,4365.436667,4366.434417,4367.439208,4368.416,4369.42825,4370.43525,4371.414292,4372.441167,4373.438792,4374.435958,4375.437,4376.435833,4377.455292,4378.409417,4379.444,4380.43625,4381.436792,4382.437958,4383.4395,4384.437667,4385.43925,4386.440333,4387.438958,4388.4405,4389.437375,4390.439375,4391.439417,4392.437667,4393.441458,4394.439875,4395.441667,4396.438292,4397.441125,4398.438875,4399.440958,4400.439875,4401.440125,4402.443083,4403.441,4404.447583,4405.438875,4406.417292,4407.458083,4408.43525,4409.42,4410.428083,4411.421208,4412.444792,4413.441333,4414.441,4415.446708,4416.439958,4417.446542,4418.440208,4419.443875,4420.442833,4421.443458,4422.442708,4423.447625,4424.442583,4425.445,4426.449083,4427.441625,4428.448,4429.44125,4430.444167,4431.446292,4432.4495,4433.446458,4434.442625,4435.443333,4436.449625,4437.442042,4438.446042,4439.44875,4440.450708,4441.443542,4442.44975,4443.449875,4444.448708,4445.441042,4446.447125,4447.44975,4448.270083,4449.493083,4450.432708,4451.448083,4452.449333,4453.446667,4454.777125,4456.045083,4456.956042,4457.994917,4458.990875,4459.974958,4460.9695,4462.000167,4462.976458,4463.996417,4464.918958,4466.013917,4466.985,4467.97,4468.999708,4469.997167,4470.997958,4471.994083,4473.0,4473.998708,4474.998917,4475.991542,4476.996583,4477.996917,4478.994875,4479.994833,4480.970583,4482.006292,4482.990958,4484.004167,4484.993583,4485.996917,4487.0,4487.998917,4488.996542,4489.997208,4491.001667,4491.999833,4492.997375,4493.9965,4494.999208,4495.9965,4496.996875,4497.995083,4499.0065,4499.994,4500.999083,4501.998417,4503.001125,4503.997375,4504.997792,4505.996708,4507.002667,4508.002667,4508.994042,4509.999458,4510.999042,4511.999833,4512.99525,4513.999792,4514.999625,4515.999708,4516.998167,4517.999375,4519.000083,4519.999708,4520.9955,4522.001792,4522.998875,4524.0015,4525.000667,4526.001875,4527.008708,4527.999792,4529.0035,4530.005042,4531.001583,4532.005833,4532.99625,4534.007625,4535.005542,4535.999875,4537.0045,4538.005125,4539.001458,4540.002583,4541.00575,4542.009,4543.005583,4544.007875,4545.00725,4546.007417,4546.999542,4548.009917,4549.000875,4550.003833,4550.999958,4552.008375,4553.001375,4554.003583,4555.005417,4556.002,4557.008292,4558.006792,4559.008917,4560.008875,4561.00925,4562.005792,4563.004208,4564.009958,4565.002792,4566.008958,4567.019792,4567.977708,4569.023583,4569.999167,4571.007667,4572.000125,4573.004042,4574.011417,4575.006458,4576.002917,4577.003583,4578.010042,4579.009125,4580.002833,4581.009292,4582.00775,4583.00425,4584.00625,4585.008625,4586.006583,4587.006167,4588.004125,4589.008875,4590.006458,4590.984708,4591.844333,4593.092583,4594.044792,4595.062625,4596.053208,4597.033208,4598.060083,4599.04375,4600.063042,4601.052875,4602.058833,4603.040167,4604.068458,4605.060125,4606.062917,4607.06425,4608.058167,4609.060042,4610.065375,4611.060542,4612.060708,4613.059167,4614.061292,4615.047708,4616.042583,4617.065333,4618.061417,4619.060792,4620.045542,4621.043583,4622.043625,4623.063958,4624.043542,4625.068917,4626.067542,4627.062375,4628.061708,4629.063417,4630.06275,4631.062875,4632.06425,4633.065667,4634.060875,4635.063083,4636.064292,4637.065458,4638.064375,4639.065583,4640.041417,4641.0715,4642.063458,4643.06525,4644.065583,4645.07075,4646.06675,4647.069125,4648.066125,4649.068625,4650.066333,4651.062958,4652.071708,4653.049417,4654.056375,4655.067792,4656.059333,4657.085917,4658.071792,4658.892625,4660.069833,4661.044208,4662.055708,4663.047542,4664.050667,4665.087333,4666.076458,4667.044292,4668.056917,4669.050125,4670.042125,4671.068833,4672.021417,4673.034167,4674.06,4675.044208,4676.078458,4677.046792,4678.080917,4679.002875,4680.070375,4681.071292,4682.077208,4683.069875,4684.081708,4685.0625,4686.075375,4687.077458,4688.074083,4689.073333,4690.085625,4691.073375,4692.085958,4693.074042,4694.078333,4695.07675,4696.081875,4697.075958,4698.0805,4699.088875,4700.0855,4701.055,4702.078125,4703.083292,4704.071833,4705.079583,4706.050208,4707.082917,4708.073958,4709.078375,4710.082,4711.076833,4712.077167,4713.074042,4714.08725,4715.0885,4716.082583,4717.0815,4718.078708,4719.08075,4720.076417,4721.083875,4722.076083,4723.076542,4724.082042,4725.082083,4726.077958,4727.086208,4728.08325,4729.078583,4730.083792,4731.077167,4732.086042,4733.079208,4734.083708,4735.080792,4736.080583,4737.081667,4738.078958,4739.08725,4740.089917,4741.084042,4742.079,4743.087417,4744.08175,4745.085667,4746.079833,4747.059792,4748.063917,4749.0835,4750.065583,4751.070917,4752.059375,4753.103458,4754.078792,4755.080708,4756.057083,4756.932667,4758.093917,4759.079542,4759.919625,4761.080333,4761.942708,4762.989167,4764.086542,4765.090375,4766.085917,4767.084458,4768.091417,4769.082583,4770.088083,4771.081708,4772.086625,4773.084458,4774.065833,4775.070333,4776.08925,4777.08525,4778.087292,4779.083375,4780.091875,4781.082875,4782.093333,4783.0855,4784.089625,4785.084958,4786.087375,4787.087125,4788.108917,4789.087292,4790.087833,4791.09375,4792.084542,4793.086125,4794.092458,4795.086792,4796.089083,4797.098,4798.093125,4799.091125,4800.085792,4801.089667,4802.091417,4803.092458,4804.086875,4805.089583,4806.088667,4807.095625,4808.088208,4809.089917,4810.092,4811.088458,4812.093625,4813.087125,4814.0875,4815.09125,4816.093958,4817.095,4818.069792,4819.111333,4820.085667,4821.07225,4822.092542,4823.0975,4824.088875,4825.092625,4826.088667,4827.095417,4828.095125,4829.089833,4830.091292,4831.094583,4832.096042,4833.090667,4834.097375,4835.087458,4836.095167,4837.0925,4838.094667,4839.089875,4840.090958,4841.0905,4842.092042,4843.092208,4844.09475,4845.091292,4846.095417,4847.093667,4848.094375,4849.09775,4850.093458,4851.095167,4852.098917,4853.098833,4854.090375,4855.09575,4856.0935,4857.076875,4858.048,4859.020958,4860.083208,4860.978208,4862.058667,4863.094542,4863.911042,4865.126042,4866.056583,4867.088167,4868.086792,4869.062,4870.106792,4871.098167,4872.097583,4873.078708,4874.116333,4875.09575,4876.083375,4877.100917,4878.094125,4879.105292,4880.042083,4881.112458,4882.099583,4883.100167,4884.099375,4885.101042,4886.098292,4887.105458,4888.092708,4889.105292,4890.097708,4891.10175,4892.099583,4893.101833,4894.097958,4895.106292,4896.101667,4897.099708,4898.10575,4899.101083,4900.100375,4901.102917,4902.101625,4903.100708,4904.103292,4905.098,4906.106042,4907.099417,4908.106583,4909.101833,4910.101125,4911.110375,4912.099583,4913.108417,4914.10225,4915.102833,4916.103333,4917.106,4918.099583,4919.109,4920.1035,4921.102958,4922.104042,4923.105375,4924.108417,4925.105417,4926.099417,4927.110625,4928.107375,4929.1005,4930.109042,4931.102292,4932.110208,4933.100708,4934.104833,4935.106667,4936.107708,4937.107042,4938.112417,4939.102042,4940.1065,4941.108375,4942.111042,4943.107833,4944.104958,4945.111,4946.110625,4947.093792,4948.110167,4949.08525,4950.107958,4951.088083,4952.111625,4953.106,4954.114542,4955.105958,4956.10875,4957.006167,4958.111542,4959.1045,4960.092708,4961.082542,4962.094667,4963.081958,4964.09325,4965.106292,4966.106125,4967.111583,4968.089917,4969.102375,4970.060833,4971.083458,4972.120042,4973.104917,4974.112667,4975.120208,4976.08125,4977.094167,4978.082292,4979.119708,4980.108583,4981.117042,4982.112042,4983.108,4984.1115,4985.114792,4986.150125,4987.10425,4988.116292,4989.113792,4990.109458,4991.114125,4992.114167,4993.110167,4994.112917,4995.115042,4996.108167,4997.11875,4998.101958,4999.121833,5000.107792,5001.112625,5002.116083,5003.142208,5004.110958,5005.114417,5006.085333,5007.121542,5008.113208,5009.122417,5010.120042,5011.112792,5012.1155,5013.118667,5014.118292,5015.117583,5016.111167,5017.117667,5018.091,5019.099417,5020.122833,5021.111875,5022.097,5023.119292,5024.13025,5025.1115,5026.11475,5027.11625,5028.115917,5029.115667,5030.1155,5031.11725,5032.117417,5033.11775,5034.115125,5035.118125,5036.101833,5037.103917,5037.944292,5039.123083,5040.108292,5041.090708,5042.078917,5043.103,5044.120917,5045.122042,5046.116083,5047.118292,5048.119208,5049.124542,5050.11475,5051.097917,5052.106708,5053.130833,5054.1165,5055.128083,5056.118875,5057.121042,5058.117417,5059.121375,5060.121375,5061.123125,5062.119042,5063.122,5064.120083,5065.118917,5066.120458,5067.122708,5068.122458,5069.123792,5070.120417,5071.122958,5072.122542,5073.123917,5074.12275,5075.121667,5076.12075,5077.121167,5078.119417,5079.1235,5080.121625,5081.122042,5082.100042,5083.143708,5084.118042,5085.118,5086.123208,5087.125208,5088.123625,5089.123417,5090.122042,5091.124292,5092.129042,5093.1245,5094.124833,5095.128125,5096.123583,5097.134208,5098.097,5098.96375,5100.163125,5101.104458,5101.969292,5103.213292,5104.1575,5105.177042,5106.162042,5107.045708,5108.173417,5109.172833,5110.101458,5111.194083,5112.172875,5113.171917,5114.181208,5115.160917,5116.170875,5117.178125,5118.202583,5119.2015,5120.17225,5121.195792,5122.194042,5123.197875,5124.194583,5125.197083,5126.190167,5127.190958,5128.19575,5129.188667,5130.200083,5131.191458,5132.198958,5133.192208,5134.198792,5135.195292,5136.196917,5137.173625,5138.213292,5139.191333,5140.19525,5141.190958,5142.171958,5143.182667,5144.203875,5145.190292,5146.195708,5147.193792,5148.194125,5149.198,5150.194375,5151.201333,5152.193542,5153.198042,5154.19525,5155.201208,5156.199208,5157.214958,5158.166917,5159.207375,5160.196833,5161.199208,5162.195083,5163.197708,5164.198625,5165.197167,5166.176542,5167.202417,5168.195667,5169.1985,5170.1955,5171.200417,5172.197167,5173.199042,5174.197375,5175.198875,5176.198917,5177.198875,5178.197667,5179.198292,5180.202333,5181.199083,5182.199333,5183.179167,5184.183333,5185.182,5186.186792,5187.204792,5188.203292,5189.2005,5190.200583,5191.207583,5192.199333,5193.198292,5194.202542,5195.202417,5196.154958,5197.206875,5198.180125,5199.191667,5200.206333,5201.189292,5202.207125,5203.195458,5204.183333,5205.095625,5206.208542,5207.175458,5208.202292,5209.179125,5210.201,5211.202167,5212.20275,5213.203458,5214.203333,5215.198875,5216.204375,5217.204125,5218.200958,5219.206875,5220.202292,5221.201875,5222.205,5223.205917,5224.20725,5225.204917,5226.203958,5227.206083,5228.203708,5229.203833,5230.206083,5231.204792,5232.206,5233.208667,5234.207167,5235.207,5236.213583,5237.203792,5238.209333,5239.209958,5240.206708,5241.215292,5242.213125,5243.205125,5244.207958,5245.210958,5246.198333,5247.195833,5248.14125,5249.198417,5250.20525,5251.176917,5252.193292,5253.1895,5254.212917,5255.205542,5256.210125,5257.207125,5258.212208,5259.215,5260.215917,5261.216083,5262.208458,5263.211042,5264.211667,5265.2105,5266.216417,5267.200375,5268.212958,5269.208583,5270.210625,5271.192583,5272.205375,5273.215667,5274.201792,5275.2145,5276.213292,5277.210167,5278.211125,5279.212667,5280.210333,5281.210667,5282.211875,5283.212583,5284.213458,5285.212833,5286.218875,5287.209833,5288.212667,5289.21,5290.213167,5291.215167,5292.218125,5293.2125,5294.214792,5295.214167,5296.21425,5297.217042,5298.211292,5299.173917,5300.224542,5301.209792,5302.212833,5303.219958,5304.215417,5305.219833,5306.216792,5307.217958,5308.215875,5309.215167,5310.211833,5311.220375,5312.212958,5313.178875,5314.225458,5315.212542,5316.215667,5317.218417,5318.21875,5319.217375,5320.2155,5321.221167,5322.217042,5323.216667,5324.224083,5325.218917,5326.219833,5327.223583,5328.220292,5329.216292,5330.224583,5331.217208,5332.222333,5333.217167,5334.2185,5335.222542,5336.21725,5337.220833,5338.198417,5339.221375,5340.217458,5341.070625,5342.254083,5343.173667,5344.169708,5345.1685,5346.214125,5347.192125,5348.111333,5349.228458,5350.091083,5351.124583,5352.209,5353.055208,5354.264,5355.181125,5356.227917,5357.222125,5358.219875,5359.222125,5360.220833,5361.22375,5362.220042,5363.222292,5364.220417,5365.22125,5366.220542,5367.222792,5368.193,5369.213,5370.210292,5371.219583,5372.200792,5373.218125,5374.228458,5375.221833,5376.220375,5377.226292,5378.222375,5379.222917,5380.225583,5381.220333,5382.229625,5383.22075,5384.224583,5385.226083,5386.229875,5387.225208,5388.228708,5389.225792,5390.231708,5391.2235,5392.229208,5393.2275,5394.225125,5395.222208,5396.224542,5397.226208,5398.222667,5399.228292,5400.223583,5401.233042,5402.223583,5403.227083,5404.226,5405.226375,5406.229333,5407.228833,5408.229208,5409.225375,5410.233542,5411.232083,5412.228333,5413.224667,5414.203708,5415.233125,5416.22925,5417.224875,5418.228042,5419.200875,5420.200125,5421.235917,5422.052125,5423.256125,5424.202833,5425.211667,5426.21325,5427.062708,5428.242917,5429.219042,5430.229958,5431.229458,5432.230583,5433.229917,5434.230333,5435.228,5436.231708,5437.226083,5438.227042,5439.231708,5440.230708,5441.228875,5442.232,5443.228167,5444.230958,5445.215958,5446.232625,5447.207458,5448.214167,5449.224792,5450.23325,5451.228292,5452.233667,5453.229625,5454.2385,5455.232125,5456.232667,5457.233292,5458.212958,5459.211542,5460.241458,5461.09425,5462.248167,5463.202083,5464.245542,5465.220708,5466.223292,5467.253667,5468.207958,5469.242292,5470.251708,5471.213125,5472.257792,5473.203625,5474.229333,5475.221375,5476.272042,5477.201583,5478.260458,5479.205667,5480.227542,5481.265583,5482.203167,5483.223875,5484.22125,5485.212875,5486.241833,5487.240208,5488.215208,5489.216583,5490.245667,5491.235125,5492.244917,5493.239042,5494.243833,5495.242208,5496.243708,5497.241667,5498.245333,5499.243083,5500.242583,5501.238042,5502.24525,5503.220458,5504.245667,5505.239875,5506.235167,5507.227333,5508.255667,5509.216542,5510.248708,5511.246667,5512.252417,5513.214375,5514.258042,5515.234083,5516.231292,5517.256,5518.249417,5519.248042,5520.232208,5521.262125,5522.22925,5523.234958,5524.16475,5525.262958,5526.119792,5527.280917,5528.226208,5529.260708,5530.237417,5531.252042,5532.230583,5533.220083,5534.166583,5535.229917,5536.257542,5537.253083,5538.256958,5539.259167,5540.250625,5541.25275,5542.259625,5543.259417,5544.2665,5545.254667,5546.258208,5547.253708,5548.261875,5549.257625,5550.235583,5551.259333,5552.251167,5553.257833,5554.253333,5555.2545,5556.257,5557.256292,5558.25625,5559.25975,5560.262375,5561.259083,5562.232958,5563.261,5564.257458,5565.266458,5566.23525,5567.268125,5568.25525,5569.242625,5570.264708,5571.258292,5572.26,5573.25775,5574.265958,5575.256167,5576.263458,5577.259417,5578.26575,5579.25775,5580.265667,5581.26375,5582.266125,5583.25275,5584.2665,5585.237458,5586.246292,5587.245833,5588.26775,5589.269,5590.265667,5591.272708,5592.262667,5593.259542,5594.264208,5595.2635,5596.261375,5597.266208,5598.260875,5599.2625,5600.252042,5601.241708,5602.127417,5603.365833,5604.318792,5605.308708,5606.347667,5607.559917,5608.37425,5609.585542,5610.540542,5611.515292,5612.457292,5613.568,5614.537625,5615.5685,5616.567375,5617.560667,5618.570708,5619.564375,5620.568667,5621.561667,5622.565375,5623.564542,5624.574458,5625.562917,5626.567458,5627.5505,5628.566042,5629.547375,5630.582833,5631.568333,5632.543458,5633.552417,5634.549417,5635.547292,5636.573875,5637.566875,5638.568,5639.566125,5640.5675,5641.566333,5642.56425,5643.567083,5644.567417,5645.570708,5646.573167,5647.573208,5648.576833,5649.562292,5650.568333,5651.565667,5652.549875,5653.549583,5654.572458,5655.572292,5656.56475,5657.572792,5658.571583,5659.566333,5660.570708,5661.569042,5662.569125,5663.568542,5664.569417,5665.573,5666.573375,5667.548375,5668.554458,5669.573833,5670.568375,5671.570333,5672.5715,5673.572917,5674.576792,5675.571167,5676.577333,5677.567542,5678.57675,5679.579458,5680.570417,5681.575417,5682.571125,5683.57125,5684.579167,5685.573917,5686.576042,5687.568625,5688.575917,5689.577417,5690.577875,5691.569958,5692.576,5693.570625,5694.581583,5695.575458,5696.57425,5697.578792,5698.585125,5699.562125,5700.562875,5701.558958,5702.559417,5703.562875,5704.580167,5705.567667,5706.578917,5707.578125,5708.578292,5709.580375,5710.57425,5711.3895,5712.615625,5713.533042,5714.568875,5715.548292,5716.563417,5717.466625,5718.586458,5719.56875,5720.547958,5721.591125,5722.574583,5723.58725,5724.577,5725.581292,5726.58825,5727.585167,5728.579333,5729.586333,5730.582958,5731.582667,5732.591708,5733.578833,5734.584292,5735.5835,5736.57625,5737.576333,5738.586583,5739.583917,5740.587833,5741.578792,5742.586083,5743.584042,5744.591667,5745.582292,5746.584167,5747.588042,5748.589958,5749.583125,5750.583625,5751.584167,5752.588,5753.582875,5754.584875,5755.584333,5756.58275,5757.592708,5758.582125,5759.590875,5760.582917,5761.588958,5762.588917,5763.5815,5764.568958,5765.591083,5766.585833,5767.586333,5768.586875,5769.58825,5770.592708,5771.585125,5772.593708,5773.590625,5774.591,5775.589458,5776.587083,5777.5935,5778.593,5779.5825,5780.594167,5781.5835,5782.563792,5783.592083,5784.59225,5785.59375,5786.592875,5787.587208,5788.5975,5789.591917,5790.58825,5791.592125,5792.5875,5793.596542,5794.593333,5795.584458,5796.59775,5797.584833,5798.591208,5799.58925,5800.595333,5801.593625,5802.59375,5803.587208,5804.597292,5805.586,5806.598708,5807.595875,5808.597083,5809.589292,5810.5985,5811.592375,5812.598208,5813.586875,5814.591042,5815.590542,5816.591083,5817.531917,5818.564542,5819.563375,5820.535625,5821.578375,5822.571333,5823.57225,5824.576458,5825.468083,5826.5835,5827.586083,5828.548125,5829.61225,5830.593583,5831.602042,5832.597917,5833.598958,5834.593208,5835.598542,5836.598458,5837.600417,5838.598417,5839.592833,5840.597083,5841.599167,5842.59275,5843.595625,5844.599583,5845.603208,5846.593292,5847.593833,5848.5955,5849.594708,5850.596958,5851.597708,5852.603792,5853.594708,5854.596458,5855.60025,5856.599042,5857.601458,5858.592708,5859.59825,5860.599708,5861.598375,5862.593542,5863.599625,5864.594917,5865.597042,5866.602,5867.597458,5868.600417,5869.598542,5870.596417,5871.599583,5872.597333,5873.59975,5874.597958,5875.599083,5876.601583,5877.592542,5878.599625,5879.600667,5880.596542,5881.598625,5882.599625,5883.600167,5884.599833,5885.597125,5886.602333,5887.576167,5888.609167,5889.598,5890.601083,5891.595792,5892.59975,5893.599875,5894.602125,5895.60575,5896.597583,5897.60325,5898.601125,5899.6,5900.600125,5901.606333,5902.604708,5903.599583,5904.578833,5905.607125,5906.601958,5907.612125,5908.598417,5909.602583,5910.602458,5911.611875,5912.600667,5913.609542,5914.600833,5915.591958,5916.612958,5917.600042,5918.6075,5919.605833,5920.606083,5921.610125,5922.608542,5923.610333,5924.613208,5925.606,5926.582125,5927.478583,5928.69875,5929.643542,5930.686917,5931.673958,5932.648792,5933.674667,5934.669458,5935.612,5936.686375,5937.5445,5938.715833,5939.641083,5940.688917,5941.668292,5942.681833,5943.67325,5944.706792,5945.701417,5946.691167,5947.695,5948.701917,5949.696375,5950.6955,5951.690208,5952.6965,5953.713125,5954.69275,5955.696125,5956.714,5957.690042,5958.692917,5959.70225,5960.698333,5961.701542,5962.696917,5963.703208,5964.702958,5965.698917,5966.697375,5967.697542,5968.695542,5969.704167,5970.69875,5971.696875,5972.703458,5973.701708,5974.700792,5975.694,5976.703542,5977.704667,5978.7045,5979.696833,5980.705083,5981.707,5982.702667,5983.702458,5984.705292,5985.682542,5986.70725,5987.701917,5988.701667,5989.698167,5990.702375,5991.695917,5992.702708,5993.705708,5994.706208,5995.70475,5996.704625,5997.702625,5998.701708,5999.698583,6000.700917,6001.70025,6002.704667,6003.702958,6004.666167,6005.706833,6006.630042,6007.646375,6008.658208,6009.638333,6010.581917,6011.606333,6012.69625,6013.676417,6014.701292,6015.7055,6016.709125,6017.710667,6018.703542,6019.706167,6020.705917,6021.708125,6022.705875,6023.707375,6024.704125,6025.710333,6026.7105,6027.705083,6028.705333,6029.705208,6030.708875,6031.713125,6032.687792,6033.712792,6034.708958,6035.704542,6036.712958,6037.709458,6038.708083,6039.705958,6040.717875,6041.704542,6042.7155,6043.70325,6044.715167,6045.705833,6046.711875,6047.710417,6048.710083,6049.715583,6050.712542,6051.712458,6052.711375,6053.71,6054.718083,6055.70675,6056.709458,6057.715708,6058.7115,6059.709542,6060.711792,6061.710167,6062.713292,6063.716542,6064.710667,6065.710417,6066.716458,6067.712833,6068.711583,6069.714167,6070.711708,6071.710875,6072.7185,6073.71425,6074.717458,6075.712917,6076.714917,6077.715292,6078.7145,6079.716292,6080.717917,6081.707583,6082.710667,6083.711458,6084.713625,6085.710708,6086.715625,6087.712042,6088.719333,6089.716833,6090.709792,6091.716083,6092.7185,6093.712875,6094.716,6095.7165,6096.715875,6097.717042,6098.718333,6099.720167,6100.718,6101.716833,6102.713833,6103.717917,6104.715333,6105.716208,6106.551292,6107.756,6108.704333,6110.192708,6111.44525,6112.376083,6113.421667,6114.408,6115.412875,6116.408167,6117.414042,6118.412958,6119.403042,6120.412,6121.410833,6122.41375,6123.428625,6124.371458,6125.421667,6126.405125,6127.415792,6128.410292,6129.415542,6130.405917,6131.416292,6132.415583,6133.411667,6134.406708,6135.411458,6136.415667,6137.406167,6138.412375,6139.408083,6140.409333,6141.410333,6142.411917,6143.410625,6144.412292,6145.411792,6146.414,6147.417625,6148.41925,6149.389375,6150.426792,6151.40325,6152.430792,6153.409625,6154.412083,6155.410792,6156.41025,6157.415083,6158.409208,6159.413667,6160.412708,6161.414958,6162.4105,6163.416083,6164.418542,6165.415917,6166.411958,6167.415125,6168.414042,6169.412625,6170.417,6171.412917,6172.412333,6173.417208,6174.412333,6175.420875,6176.409792,6177.417167,6178.414667,6179.420208,6180.422167,6181.411042,6182.420833,6183.413875,6184.415,6185.417,6186.41275,6187.423167,6188.415083,6189.4175,6190.418375,6191.421208,6192.413958,6193.421708,6194.416833,6195.423375,6196.418458,6197.415208,6198.417583,6199.418792,6200.416625,6201.424708,6202.413042,6203.281833,6205.425792,6206.675292,6207.560833,6208.631292,6209.531667,6210.639458,6211.855417,6212.820917,6213.835833,6215.05975,6216.298792,6217.250542,6218.158708,6219.260292,6220.286958,6221.255833,6222.2795,6223.25025,6224.285042,6225.2735,6226.275792,6227.272708,6228.279625,6229.275,6230.277167,6231.27925,6232.284542,6233.274458,6234.281833,6235.273958,6236.2795,6237.286583,6238.279875,6239.27925,6240.280583,6241.275708,6242.282708,6243.27475,6244.278708,6245.280417,6246.282333,6247.27475,6248.276083,6249.281083,6250.282208,6251.275375,6252.283333,6253.27875,6254.27775,6255.284542,6256.276833,6257.281292,6258.277167,6259.280875,6260.279792,6261.280833,6262.278542,6263.282,6264.278875,6265.283625,6266.275542,6267.279875,6268.28275,6269.280458,6270.2855,6271.282542,6272.285875,6273.2805,6274.280083,6275.280833,6276.280917,6277.280833,6278.280292,6279.284917,6280.281417,6281.28475,6282.28175,6283.281333,6284.284583,6285.2805,6286.28025,6287.283792,6288.27975,6289.279833,6290.2805,6291.281458,6292.280208,6293.282375,6294.282917,6295.283042,6296.279667,6297.283708,6298.284208,6299.283458,6300.283208,6301.279208,6302.285208,6303.283333,6304.286708,6305.283667,6306.274208,6307.281542,6308.256125,6309.261375,6310.203792,6311.309042,6312.251833,6313.25375,6314.268,6315.272708,6316.283125,6317.268167,6318.103042,6319.11525,6320.267917,6321.254667,6322.158167,6323.102083,6324.305875,6325.256792,6326.273542,6327.258167,6328.295042,6329.294667,6330.2905,6331.288375,6332.292958,6333.291708,6334.291042,6335.292042,6336.292875,6337.292875,6338.2925,6339.292792,6340.292083,6341.293667,6342.293958,6343.294875,6344.297792,6345.294542,6346.299875,6347.295125,6348.27475,6349.305792,6350.297083,6351.293583,6352.297,6353.302792,6354.295042,6355.295458,6356.297625,6357.296917,6358.297,6359.29975,6360.294333,6361.30075,6362.297083,6363.29475,6364.295625,6365.295875,6366.29775,6367.297208,6368.299083,6369.284917,6370.274125,6371.281917,6372.311375,6373.27525,6374.30625,6375.301792,6376.304375,6377.296625,6378.306708,6379.295708,6380.307167,6381.302333,6382.300708,6383.306625,6384.299042,6385.299875,6386.304583,6387.305208,6388.298167,6389.306875,6390.278125,6391.304875,6392.299417,6393.302667,6394.302167,6395.304875,6396.298417,6397.306417,6398.302375,6399.304875,6400.299292,6401.301,6402.305417,6403.301,6404.309,6405.300083,6406.302667,6407.306667,6408.299,6409.303917,6410.310208,6411.308,6412.308708,6413.3005,6414.303375,6415.308958,6416.303083,6417.284125,6418.283792,6419.277792,6420.284167,6421.311125,6422.312667,6423.2785,6424.107958,6425.191792,6426.314333,6427.347167,6428.419792,6429.401375,6430.411375,6431.30425,6432.387667,6433.360125,6434.392208,6435.421292,6436.413292,6437.395917,6438.41275,6439.406917,6440.420417,6441.409,6442.414833,6443.403625,6444.413375,6445.4075,6446.411167,6447.410208,6448.41025,6449.415042,6450.413167,6451.405917,6452.417167,6453.413583,6454.413375,6455.414917,6456.412083,6457.4095,6458.418833,6459.405708,6460.417125,6461.415458,6462.412917,6463.411,6464.4125,6465.411875,6466.410042,6467.411167,6468.41475,6469.4105,6470.412083,6471.411292,6472.4115,6473.408375,6474.414333,6475.410417,6476.412667,6477.411542,6478.415667,6479.412667,6480.411083,6481.412292,6482.4125,6483.41525,6484.413917,6485.41375,6486.41425,6487.414708,6488.413125,6489.431417,6490.368667,6491.408792,6492.391042,6493.41425,6494.401375,6495.402583,6496.394542,6497.41075,6498.421,6499.418292,6500.420292,6501.417875,6502.391542,6503.420583,6504.39175,6505.235417,6506.440208,6507.407625,6508.420875,6509.416833,6510.433458,6511.41225,6512.32425,6513.425875,6514.391625,6515.391417,6516.394042,6517.43975,6518.34725,6519.404917,6520.397,6521.395125,6522.278125,6523.421833,6524.4185,6525.420833,6526.423917,6527.423833,6528.425083,6529.420333,6530.428083,6531.423625,6532.428875,6533.420083,6534.425542,6535.419417,6536.428583,6537.420583,6538.426792,6539.420917,6540.4285,6541.421208,6542.424083,6543.42675,6544.423417,6545.417167,6546.428083,6547.42275,6548.427208,6549.424292,6550.424583,6551.422125,6552.403625,6553.432083,6554.426458,6555.401583,6556.425375,6557.429208,6558.412875,6559.432542,6560.434625,6561.425875,6562.424167,6563.427458,6564.4305,6565.429042,6566.423208,6567.424125,6568.429375,6569.432292,6570.426583,6571.423708,6572.428208,6573.425833,6574.428083,6575.428792,6576.429542,6577.428458,6578.431292,6579.426417,6580.432125,6581.426292,6582.427917,6583.431667,6584.424833,6585.429,6586.430833,6587.428042,6588.431375,6589.432958,6590.429042,6591.428125,6592.43,6593.426,6594.439333,6595.424042,6596.436417,6597.427208,6598.430458,6599.435667,6600.428708,6601.428667,6602.434292,6603.43275,6604.435167,6605.428042,6606.428667,6607.435125,6608.427292,6609.429083,6610.429292,6611.435875,6612.429917,6613.432375,6614.435792,6615.430583,6616.434542,6617.431625,6618.435333,6619.435542,6620.429792,6621.433,6622.437083,6623.42375,6624.439292,6625.430667,6626.430292,6627.413333,6628.442083,6629.420625,6630.439417,6631.429458,6632.438917,6633.432125,6634.413,6635.412,6636.529583,6637.568958,6638.637125,6639.647542,6640.67475,6641.789958,6642.77075,6643.751083,6644.786083,6645.654667,6646.729458,6647.76975,6648.768667,6649.793042,6650.782542,6651.787958,6652.784875,6653.790583,6654.784917,6655.788417,6656.785833,6657.790833,6658.781875,6659.788958,6660.788833,6661.787125,6662.783833,6663.789125,6664.788958,6665.788625,6666.786667,6667.786667,6668.787792,6669.764208,6670.792333,6671.792875,6672.778208,6673.793042,6674.776875,6675.793667,6676.791042,6677.768417,6678.769792,6679.790208,6680.787833,6681.789875,6682.79,6683.787625,6684.788333,6685.792708,6686.788375,6687.796292,6688.786458,6689.793,6690.792417,6691.795875,6692.801583,6693.764708,6694.798333,6695.787875,6696.791083,6697.793042,6698.79525,6699.79,6700.792958,6701.791375,6702.791667,6703.796542,6704.789917,6705.79075,6706.798083,6707.794375,6708.795208,6709.795083,6710.795625,6711.797417,6712.790125,6713.800292,6714.789,6715.796875,6716.790583,6717.794833,6718.789708,6719.798917,6720.791333,6721.794208,6722.791875,6723.799458,6724.796542,6725.792292,6726.793,6727.791917,6728.795958,6729.800958,6730.798583,6731.794167,6732.801542,6733.7985,6734.794875,6735.795125,6736.801875,6737.794625,6738.801375,6739.79425,6740.80125,6741.795,6742.802333,6743.792542,6744.797333,6745.798333,6746.772875,6747.617333,6748.642375,6749.801625,6750.693167,6751.772208,6752.802292,6753.711125,6754.785417,6755.808292,6756.7815,6757.772458,6758.663833,6759.809042,6760.775125,6761.636542,6762.807958,6763.777208,6764.780292,6765.802792,6766.798583,6767.799958,6768.801083,6769.80375,6770.80075,6771.804917,6772.802625,6773.799542,6774.80425,6775.810333,6776.800125,6777.805083,6778.8005,6779.807667,6780.800625,6781.807625,6782.796667,6783.79975,6784.799667,6785.805,6786.798917,6787.80675,6788.801,6789.799958,6790.806667,6791.799125,6792.809,6793.801542,6794.809708,6795.798875,6796.807417,6797.801583,6798.811167,6799.801208,6800.81325,6801.799083,6802.810958,6803.799417,6804.804542,6805.804333,6806.805208,6807.807542,6808.805333,6809.808333,6810.804875,6811.807958,6812.807667,6813.8045,6814.805125,6815.807292,6816.807958,6817.810333,6818.808833,6819.811917,6820.808792,6821.803375,6822.812708,6823.807583,6824.807042,6825.806875,6826.806583,6827.80625,6828.80825,6829.804458,6830.808583,6831.806083,6832.810333,6833.80375,6834.812417,6835.803208,6836.81525,6837.802542,6838.811792,6839.80425,6840.814417,6841.810417,6842.813292,6843.812333,6844.813417,6845.802375,6846.808583,6847.805792,6848.814125,6849.812125,6850.805875,6851.807875,6852.808167,6853.806417,6854.808708,6855.8085,6856.810042,6857.807167,6858.814,6859.810125,6860.805792,6861.812917,6862.808083,6863.810625,6864.813208,6865.815375,6866.808792,6867.810958,6868.787375,6869.707792,6870.598875,6871.662958,6872.742667,6873.8305,6874.759625,6875.76175,6876.79625,6877.798083,6878.789083,6879.794667,6880.685,6881.742167,6882.801,6883.784833,6884.80925,6885.817917,6886.820667,6887.815833,6888.824083,6889.820167,6890.818542,6891.818625,6892.817208,6893.824625,6894.815625,6895.821792,6896.816625,6897.821875,6898.815125,6899.818458,6900.818208,6901.817333,6902.81775,6903.818,6904.840375,6905.818958,6906.818917,6907.81575,6908.820583,6909.822458,6910.821125,6911.822125,6912.823208,6913.824708,6914.822875,6915.824542,6916.823667,6917.818875,6918.82625,6919.820458,6920.822708,6921.826083,6922.8245,6923.821708,6924.824792,6925.821167,6926.820542,6927.824375,6928.82375,6929.820083,6930.828583,6931.822417,6932.826125,6933.820667,6934.827042,6935.818625,6936.828167,6937.821,6938.825083,6939.818792,6940.82325,6941.821833,6942.828292,6943.821208,6944.819208,6945.822917,6946.827792,6947.8235,6948.801625,6949.805833,6950.82625,6951.82425,6952.825708,6953.829125,6954.824375,6955.826375,6956.824083,6957.831833,6958.825625,6959.827708,6960.825583,6961.829042,6962.8035,6963.80825,6964.836667,6965.827333,6966.831292,6967.822625,6968.832208,6969.82775,6970.828792,6971.82475,6972.826458,6973.830958,6974.804625,6975.831292,6976.826083,6977.831458,6978.82725,6979.829042,6980.824292,6982.107708,6983.356542,6984.229042,6985.24675,6986.514208,6987.340333,6988.475958,6989.337458,6990.438458,6991.442875,6992.408833,6993.433958,6994.438542,6995.461333,6996.467917,6997.460792,6998.46475,6999.46025,7000.463333,7001.44825,7002.446083,7003.471833,7004.464167,7005.472708,7006.464708,7007.4685,7008.475083,7009.462792,7010.474708,7011.468667,7012.469083,7013.470917,7014.470458,7015.468458,7016.470417,7017.46825,7018.465292,7019.448542,7020.451,7021.472875,7022.476167,7023.46725,7024.468958,7025.477292,7026.472792,7027.466958,7028.474667,7029.474083,7030.469417,7031.474958,7032.472417,7033.467958,7034.475292,7035.471042,7036.468125,7037.47025,7038.478458,7039.474625,7040.474333,7041.475083,7042.468167,7043.475375,7044.4705,7045.47125,7046.472042,7047.4765,7048.475875,7049.477167,7050.480792,7051.44525,7052.452542,7053.455792,7054.472583,7055.47525,7056.475958,7057.475583,7058.472583,7059.47025,7060.482625,7061.469583,7062.475417,7063.479917,7064.473,7065.476708,7066.476042,7067.472042,7068.476625,7069.477375,7070.482792,7071.4785,7072.468833,7073.45825,7074.478125,7075.475208,7076.48075,7077.477042,7078.4745,7079.476042,7080.477333,7081.476333,7082.482375,7083.478375,7084.478333,7085.474375,7086.477417,7087.478708,7088.478292,7089.476583,7090.47975,7091.474208,7092.48325,7093.466792,7094.458083,7095.484542,7096.477417,7097.479708,7098.476375,7099.477792,7100.481083,7101.473167,7102.445333,7103.457208,7104.476958,7105.466625,7106.315208,7107.383083,7108.496417,7109.429917,7110.6805,7111.6045,7112.482542,7113.66,7114.613125,7115.628208,7116.625375,7117.627125,7118.633083,7119.650667,7120.650208,7121.646833,7122.6435,7123.647375,7124.650667,7125.649458,7126.651167,7127.644375,7128.648833,7129.654333,7130.644708,7131.646208,7132.651292,7133.649833,7134.644792,7135.651708,7136.64975,7137.6515,7138.650542,7139.650042,7140.6555,7141.654667,7142.647667,7143.654375,7144.647625,7145.649167,7146.6445,7147.628917,7148.63225,7149.652625,7150.6545,7151.649875,7152.648583,7153.653333,7154.64575,7155.653792,7156.647667,7157.654042,7158.649583,7159.657417,7160.653958,7161.651792,7162.651958,7163.651458,7164.656417,7165.652667,7166.648375,7167.658958,7168.6505,7169.651917,7170.649917,7171.655167,7172.655542,7173.649458,7174.653667,7175.653042,7176.653083,7177.6585,7178.649167,7179.660875,7180.657083,7181.652458,7182.655958,7183.653375,7184.659833,7185.660292,7186.658,7187.659333,7188.65375,7189.658625,7190.651375,7191.658583,7192.652792,7193.659833,7194.657667,7195.660208,7196.650917,7197.65825,7198.659417,7199.658083,7200.65975,7201.657708,7202.654125,7203.660917,7204.655125,7205.651375,7206.656833,7207.661625,7208.6535,7209.663708,7210.656708,7211.662208,7212.663042,7213.650292,7214.633792,7215.618875,7216.60825,7217.6155,7218.560292,7219.654083,7220.45025,7221.697417,7222.625292,7223.652,7224.5485,7225.675333,7226.6675,7227.610083,7228.67725,7229.647583,7230.668375,7231.664542,7232.668833,7233.66825,7234.665958,7235.668792,7236.674042,7237.6675,7238.674958,7239.663792,7240.674458,7241.67,7242.672083,7243.670375,7244.674083,7245.66425,7246.666583,7247.670583,7248.677292,7249.665792,7250.667292,7251.670083,7252.670292,7253.6745,7254.665917,7255.669125,7256.670625,7257.669667,7258.670625,7259.673625,7260.675083,7261.665958,7262.670958,7263.667542,7264.676208,7265.668042,7266.67225,7267.668542,7268.67525,7269.674917,7270.671083,7271.675625,7272.673833,7273.67575,7274.667333,7275.672458,7276.676833,7277.671542,7278.678292,7279.673083,7280.671125,7281.67675,7282.675458,7283.6705,7284.677042,7285.651167,7286.674458,7287.651958,7288.654375,7289.676792,7290.6685,7291.673167,7292.673417,7293.678583,7294.671417,7295.675917,7296.675667,7297.680542,7298.673792,7299.671208,7300.677625,7301.677417,7302.67175,7303.675083,7304.671583,7305.604083,7306.670875,7307.571958,7308.676292,7309.629583,7310.687375,7311.647917,7312.654625,7313.651542,7314.65425,7315.686042,7316.65875,7317.646917,7318.980875,7320.21875,7321.040083,7322.21675,7323.008458,7324.22325,7325.164,7325.987042,7327.258625,7328.182292,7329.179667,7330.175333,7331.216417,7332.197458,7333.201,7334.207875,7335.195333,7336.208375,7337.199875,7338.207958,7339.196917,7340.205667,7341.203625,7342.208333,7343.208167,7344.202958,7345.205083,7346.206125,7347.203917,7348.209625,7349.210708,7350.205292,7351.20725,7352.211125,7353.204333,7354.212083,7355.205042,7356.213667,7357.203458,7358.21275,7359.206625,7360.211125,7361.204375,7362.212208,7363.204208,7364.210625,7365.211167,7366.208667,7367.206042,7368.207708,7369.206875,7370.205833,7371.207333,7372.202417,7373.203417,7374.207083,7375.207333,7376.212917,7377.204333,7378.178,7379.214,7380.207167,7381.20825,7382.215667,7383.205792,7384.217833,7385.183125,7386.196458,7387.210125,7388.21125,7389.210125,7390.213375,7391.209708,7392.209458,7393.206875,7394.211208,7395.2115,7396.208125,7397.213375,7398.214125,7399.211292,7400.21025,7401.21225,7402.217542,7403.211292,7404.218917,7405.212917,7406.217208,7407.214875,7408.213458,7409.213792,7410.210875,7411.216375,7412.214375,7413.214375,7414.217375,7415.217417,7416.212125,7417.210958,7418.216333,7419.209417,7420.216375,7421.210333,7422.213417,7423.217917,7424.218208,7425.21275,7426.218917,7427.212833,7428.221583,7429.206208,7430.220625,7431.212167,7432.215875,7433.213333,7434.222042,7435.212542,7436.2175,7437.211875,7438.213292,7439.218333,7440.217583,7441.215792,7442.218625,7443.216542,7444.215042,7445.217875,7446.215083,7447.221583,7448.212875,7449.216292,7450.221458,7451.213542,7452.214583,7453.218292,7454.214833,7455.219875,7456.213958,7457.216958,7458.2215,7459.194083,7460.233292,7461.216583,7462.194375,7463.199125,7464.197917,7465.221917,7466.214542,7467.221708,7468.219417,7469.196208,7472.549458,7473.800333,7474.752917,7475.596083,7476.778792,7477.755792,7478.729875,7479.604792,7480.668458,7481.695417,7482.616167,7483.6265,7484.770625,7485.739417,7486.773542,7487.768417,7488.765417,7489.769125,7490.771708,7491.762583,7492.774833,7493.762708,7494.768708,7495.767292,7496.767417,7497.76775,7498.773167,7499.767875,7500.775042,7501.766708,7502.775625,7503.769917,7504.772208,7505.765583,7506.770167,7507.769125,7508.771167,7509.77225,7510.773,7511.76875,7512.768833,7513.775875,7514.766167,7515.773583,7516.769583,7517.768,7518.772542,7519.771625,7520.772417,7521.776875,7522.765833,7523.779333,7524.773208,7525.77275,7526.770583,7527.772125,7528.776333,7529.752583,7530.781792,7531.769417,7532.775417,7533.748417,7534.773083,7535.7745,7536.776958,7537.7725,7538.767667,7539.751708,7540.753708,7541.772917,7542.784125,7543.775917,7544.779833,7545.78075,7546.791167,7547.7725,7548.752,7549.757,7550.75675,7551.758417,7552.758333,7553.75575,7554.763958,7555.757167,7556.758375,7557.758333,7558.758167,7559.759,7560.76075,7561.763583,7562.760792,7563.759875,7564.763375,7565.763875,7566.760542,7567.763167,7568.763542,7569.781583,7570.777625,7571.77225,7572.783833,7573.779375,7574.788208,7575.775125,7576.787292,7577.776542,7578.778583,7579.7805,7580.780042,7581.7805,7582.779292,7583.781792,7584.777833,7585.779125,7586.7805,7587.779917,7588.779125,7589.780458,7590.779792,7591.782875,7592.783958,7593.756458,7594.786125,7595.778458,7596.779417,7597.78125,7598.780292,7599.782917,7600.7815,7601.780708,7602.778875,7603.78925,7604.789333,7605.780333,7606.785833,7607.7915,7608.785625,7609.78875,7610.783292,7611.785083,7612.7905,7613.781917,7614.784458,7615.781542,7616.789083,7617.786667,7618.784417,7619.782042,7620.784167,7621.7845,7622.783583,7623.79025,7624.788875,7625.782958,7626.787167,7627.784625,7628.787292,7629.783583,7630.784417,7631.786708,7632.760917,7634.00375,7635.271958,7636.204208,7637.222083,7638.217458,7639.218292,7640.126333,7641.182917,7642.064583,7643.230542,7644.086667,7645.24925,7646.173292,7647.210083,7648.221417,7649.218375,7650.226,7651.219458,7652.223083,7653.218208,7654.223417,7655.220292,7656.218542,7657.22125,7658.223875,7659.226583,7660.224542,7661.226625,7662.226,7663.230125,7664.220042,7665.227708,7666.228625,7667.193417,7668.223875,7669.212708,7670.221083,7671.227667,7672.221417,7673.231292,7674.226625,7675.22275,7676.230667,7677.222792,7678.227667,7679.230792,7680.223542,7681.203125,7682.233125,7683.223,7684.207208,7685.209083,7686.205125,7687.232875,7688.202542,7689.208833,7690.229958,7691.226542,7692.229125,7693.2255,7694.220708,7695.233,7696.231125,7697.224792,7698.225625,7699.230125,7700.227792,7701.2075,7702.211917,7703.23725,7704.229333,7705.227458,7706.237875,7707.227708,7708.236333,7709.228875,7710.235417,7711.232917,7712.230542,7713.231583,7714.230417,7715.2335,7716.227833,7717.235667,7718.232958,7719.213542,7720.237333,7721.227417,7722.235833,7723.229333,7724.235208,7725.231292,7726.229958,7727.239583,7728.2375,7729.2295,7730.23575,7731.235125,7732.234167,7733.227458,7734.249667,7735.203833,7736.241917,7737.23025,7738.238875,7739.230458,7740.239583,7741.234167,7742.2335,7743.240125,7744.213333,7745.215958,7746.2415,7747.231375,7748.235208,7749.201708,7750.217542,7751.083542,7752.32675,7753.143417,7754.306917,7755.263917,7756.161625,7757.297125,7758.282458,7759.289375,7760.249833,7761.278792,7762.2805,7763.30475,7764.303292,7765.303458,7766.299,7767.304292,7768.299958,7769.301,7770.297917,7771.304542,7772.3105,7773.303583,7774.305417,7775.30675,7776.29975,7777.30325,7778.3065,7779.300917,7780.304708,7781.302958,7782.304167,7783.299958,7784.303542,7785.300542,7786.30275,7787.3005,7788.284375,7789.285542,7790.309458,7791.301792,7792.299583,7793.28025,7794.305958,7795.304375,7796.307125,7797.305542,7798.30425,7799.283083,7800.327875,7801.302292,7802.284292,7803.310083,7804.287333,7805.306458,7806.304333,7807.30525,7808.310042,7809.30225,7810.309333,7811.310583,7812.303417,7813.310042,7814.306583,7815.313417,7816.304917,7817.307708,7818.312167,7819.308167,7820.306417,7821.30725,7822.301708,7823.306375,7824.308458,7825.305833,7826.308542,7827.30475,7828.31175,7829.303542,7830.315333,7831.310583,7832.312583,7833.309042,7834.313667,7835.305167,7836.312042,7837.307833,7838.312,7839.312542,7840.315125,7841.308417,7842.314042,7843.311,7844.312125,7845.311375,7846.309292,7847.31225,7848.308708,7849.3125,7850.309208,7851.309875,7852.313208,7853.312208,7854.313625,7855.316083,7856.308125,7857.309333,7858.310042,7859.314417,7860.312542,7861.317917,7862.316875,7863.315375,7864.288,7865.295667,7866.216917,7867.198167,7868.271125,7869.126542,7870.305542,7871.307208,7872.346958,7873.274583,7874.245333,7875.346333,7876.343042,7877.33625,7878.310917,7879.321667,7880.342,7881.342583,7882.345208,7883.344958,7884.348542,7885.343167,7886.351958,7887.346292,7888.343917,7889.343,7890.348917,7891.33975,7892.347042,7893.342292,7894.345167,7895.341208,7896.344458,7897.348667,7898.344583,7899.345583,7900.34225,7901.347042,7902.350458,7903.354875,7904.340208,7905.345542,7906.351417,7907.3525,7908.350417,7909.345292,7910.344042,7911.35175,7912.351958,7913.3465,7914.351083,7915.35425,7916.351333,7917.348708,7918.34725,7919.356417,7920.34775,7921.34825,7922.349667,7923.326833,7924.356875,7925.328375,7926.33125,7927.365958,7928.324,7929.358375,7930.348708,7931.351542,7932.356125,7933.354833,7934.353208,7935.357958,7936.353125,7937.353417,7938.350042,7939.357708,7940.353958,7941.353958,7942.353625,7943.358875,7944.353958,7945.355042,7946.356083,7947.354375,7948.3635,7949.351625,7950.356542,7951.358,7952.354333,7953.35975,7954.354083,7955.35225,7956.361542,7957.357167,7958.352875,7959.356833,7960.3535,7961.358833,7962.352458,7963.357708,7964.360167,7965.360458,7966.351667,7967.362458,7968.353792,7969.354417,7970.361458,7971.35125,7972.361042,7973.366208,7974.361125,7975.355708,7976.354958,7977.357042,7978.364333,7979.357333,7980.36275,7981.355833,7982.359583,7983.354292,7984.346708,7985.506333,7986.748125,7988.030917,7989.300833,7990.109,7991.205583,7992.229042,7993.243708,7994.223667,7995.184292,7996.228042,7997.159583,7998.275208,7999.246833,8000.255,8001.232667,8002.254417,8003.231542,8004.229917,8005.255958,8006.247458,8007.2525,8008.246292,8009.244833,8010.2565,8011.251375,8012.255125,8013.244125,8014.248042,8015.254,8016.261333,8017.255458,8018.248708,8019.258458,8020.251875,8021.259333,8022.249083,8023.254625,8024.252708,8025.252042,8026.255417,8027.249583,8028.251292,8029.251375,8030.258583,8031.254667,8032.250542,8033.240667,8034.237417,8035.254875,8036.25725,8037.249167,8038.262542,8039.2515,8040.256167,8041.252,8042.2555,8043.254417,8044.236458,8045.258333,8046.257125,8047.25775,8048.252875,8049.257667,8050.256958,8051.251708,8052.259125,8053.252042,8054.253458,8055.261083,8056.254875,8057.263083,8058.257542,8059.258667,8060.261,8061.262375,8062.253292,8063.262917,8064.254125,8065.260125,8066.237458,8067.238583,8068.246125,8069.262417,8070.237708,8071.258458,8072.26625,8073.254667,8074.258,8075.25625,8076.257792,8077.258542,8078.258208,8079.257292,8080.256208,8081.25725,8082.260833,8083.265708,8084.253667,8085.261625,8086.26175,8087.267167,8088.26375,8089.264667,8090.261208,8091.263958,8092.261667,8093.261417,8094.237042,8095.263875,8096.258917,8097.263083,8098.265917,8099.237167,8100.267417,8101.267167,8102.2685,8103.2625,8104.27,8105.262958,8106.266708,8107.266208,8108.265458,8109.261833,8110.264375,8111.268625,8112.26475,8113.265958,8114.239667,8116.6825,8117.871083,8118.740458,8119.922417,8120.856,8121.758125,8122.757875,8123.901583,8124.857917,8125.872417,8126.889833,8127.874708,8128.90125,8129.90125,8130.894458,8131.901417,8132.875167,8133.907708,8134.899125,8135.885375,8136.908708,8137.903542,8138.898292,8139.903,8140.902792,8141.897792,8142.90175,8143.89925,8144.902583,8145.903167,8146.90175,8147.902458,8148.90075,8149.9025,8150.881083,8151.882042,8152.9055,8153.905417,8154.901,8155.9035,8156.903667,8157.908625,8158.907042,8159.901417,8160.889208,8161.909208,8162.900625,8163.900333,8164.793375,8165.932292,8166.892792,8167.904375,8168.906875,8169.90625,8170.90475,8171.903792,8172.907417,8173.905375,8174.907542,8175.903917,8176.882,8177.8885,8178.901833,8179.906125,8180.912333,8181.904958,8182.914083,8183.910083,8184.909583,8185.898042,8186.911875,8187.903042,8188.911375,8189.904583,8190.909667,8191.907125,8192.906958,8193.912458,8194.906125,8195.912125,8196.913125,8197.904333,8198.911042,8199.903333,8200.906292,8201.91025,8202.912208,8203.908125,8204.911167,8205.908708,8206.9105,8207.913542,8208.905583,8209.908208,8210.90825,8211.905167,8212.915125,8213.907,8214.916125,8215.912042,8216.909917,8217.913458,8218.9095,8219.909375,8220.911917,8221.908042,8222.913333,8223.916167,8224.908625,8225.9205,8226.910042,8227.915958,8228.909625,8229.915208,8230.9075,8231.912417,8232.917875,8233.892042,8234.9155,8235.890167,8236.901958,8237.918958,8238.909458,8239.915125,8240.913208,8241.916833,8242.891083,8244.019958,8245.21675,8246.156625,8247.237625,8248.127708,8249.219042,8250.205625,8251.214542,8252.219375,8253.210708,8254.21775,8255.209125,8256.226125,8257.215167,8258.214708,8259.246125,8260.2345,8261.23975,8262.238208,8263.241583,8264.235167,8265.238583,8266.244292,8267.23525,8268.244375,8269.240417,8270.242417,8271.246083,8272.243833,8273.235208,8274.244333,8275.234833,8276.241917,8277.236292,8278.239,8279.238583,8280.238833,8281.23975,8282.244208,8283.240083,8284.239542,8285.237542,8286.240708,8287.246083,8288.244458,8289.24125,8290.239,8291.243167,8292.244333,8293.246875,8294.244917,8295.246208,8296.241458,8297.240167,8298.241417,8299.246792,8300.245375,8301.241792,8302.244833,8303.24675,8304.240167,8305.242708,8306.243542,8307.240125,8308.241583,8309.243208,8310.239958,8311.245,8312.242833,8313.248375,8314.247542,8315.245,8316.242917,8317.243917,8318.252125,8319.246583,8320.2445,8321.243208,8322.245542,8323.246333,8324.244083,8325.249708,8326.242292,8327.2425,8328.245125,8329.251542,8330.246542,8331.248958,8332.244167,8333.250083,8334.245083,8335.24525,8336.249292,8337.244583,8338.24675,8339.252792,8340.250208,8341.249333,8342.253042,8343.250083,8344.245583,8345.250083,8346.254667,8347.244208,8348.248792,8349.251875,8350.248625,8351.25375,8352.245375,8353.250458,8354.254417,8355.247625,8356.255333,8357.248583,8358.253042,8359.244958,8360.248167,8361.249625,8362.069875,8363.214208,8364.255375,8365.277583,8366.270292,8367.234583,8368.296917,8369.26075,8370.269333,8371.26225,8372.110667,8373.082417,8374.209292,8375.30375,8376.279042,8377.288042,8378.291958,8379.285458,8380.289708,8381.285958,8382.289333,8383.292333,8384.282167,8385.289208,8386.293708,8387.283958,8388.298333,8389.287917,8390.294917,8391.285625,8392.299208,8393.285125,8394.29425,8395.28625,8396.296375,8397.285458,8398.289208,8399.29525,8400.290458,8401.288667,8402.279208,8403.274292,8404.300208,8405.28925,8406.286875,8407.295875,8408.289875,8409.299792,8410.290167,8411.297875,8412.288,8413.290875,8414.296625,8415.289208,8416.291833,8417.2885,8418.298083,8419.290292,8420.294875,8421.293125,8422.295625,8423.291542,8424.292,8425.2975,8426.299625,8427.289167,8428.300917,8429.289583,8430.2995,8431.291917,8432.301625,8433.293875,8434.299167,8435.29625,8436.294333,8437.298458,8438.29125,8439.29725,8440.295667,8441.293875,8442.298542,8443.298333,8444.299583,8445.298875,8446.293167,8447.299167,8448.292583,8449.297875,8450.300792,8451.297333,8452.301083,8453.301667,8454.296625,8455.302292,8456.300458,8457.296917,8458.30075,8459.295417,8460.301208,8461.302208,8462.30025,8463.301083,8464.29475,8465.308375,8466.297583,8467.306167,8468.297917,8469.299583,8470.30425,8471.306708,8472.308125,8473.302333,8474.305125,8475.306667,8476.300417,8477.304917,8478.295917,8479.301708,8480.269125,8481.296208,8482.294625,8483.282833,8484.296875,8485.290833,8486.147417,8487.342708,8488.269958,8489.3185,8490.302167,8491.306333,8492.302375,8493.307875,8494.301333,8495.307625,8496.310208,8497.304375,8498.306083,8499.313333,8500.310167,8501.3055,8502.308333,8503.3125,8504.3105,8505.305042,8506.30575,8507.310583,8508.312,8509.307583,8510.314417,8511.314375,8512.313333,8513.306792,8514.317167,8515.312042,8516.316042,8517.31175,8518.31725,8519.309375,8520.317458,8521.309833,8522.319,8523.309875,8524.317,8525.316958,8526.313958,8527.317042,8528.314667,8529.309917,8530.318875,8531.310917,8532.31875,8533.313542,8534.31275,8535.319292,8536.316333,8537.312917,8538.31475,8539.317083,8540.318708,8541.308417,8542.31375,8543.315625,8544.317333,8545.312125,8546.29375,8547.323292,8548.312333,8549.31775,8550.311083,8551.313042,8552.314542,8553.315542,8554.316083,8555.313042,8556.318833,8557.321417,8558.321042,8559.32275,8560.321417,8561.329875,8562.323958,8563.326458,8564.327042,8565.3225,8566.331625,8567.325625,8568.329708,8569.324542,8570.326875,8571.329708,8572.322417,8573.320917,8574.329417,8575.326292,8576.32675,8577.323625,8578.332917,8579.326417,8580.329792,8581.319292,8582.332875,8583.32075,8584.334125,8585.325333,8586.323583,8587.327792,8588.2925,8589.340542,8590.32025,8591.304417,8592.337625,8593.322333,8594.3315,8595.331875,8596.305792,8597.3065,8598.307333,8599.289083,8600.263042,8601.255875,8602.306625,8603.287333,8604.340625,8605.1775,8606.304708,8607.340542,8608.329458,8609.308375,8610.3135,8611.32725,8612.336292,8613.32725,8614.332333,8615.338333,8616.3295,8617.338083,8618.333292,8619.33325,8620.337042,8621.337292,8622.329417,8623.334667,8624.331417,8625.3355,8626.327583,8627.336958,8628.337167,8629.323458,8630.339375,8631.337,8632.343,8633.330625,8634.341125,8635.329833,8636.342333,8637.339292,8638.339417,8639.340375,8640.338875,8641.3375,8642.340333,8643.334,8644.336333,8645.347375,8646.333458,8647.342333,8648.33625,8649.315167,8650.342167,8651.334625,8652.335833,8653.336792,8654.334583,8655.339292,8656.334167,8657.337792,8658.340167,8659.338083,8660.344333,8661.340458,8662.342667,8663.340417,8664.339583,8665.341292,8666.35575,8667.343375,8668.335542,8669.342417,8670.339,8671.342208,8672.341042,8673.335417,8674.319917,8675.344875,8676.343792,8677.338,8678.344667,8679.343417,8680.33775,8681.346625,8682.346125,8683.342917,8684.341917,8685.346167,8686.341458,8687.342667,8688.344333,8689.342083,8690.345542,8691.346042,8692.343792,8693.349458,8694.341042,8695.351208,8696.34225,8697.341917,8698.341708,8699.345875,8700.318792,8701.345417,8702.341,8703.350458,8704.343625,8705.292542,8706.354708,8707.33925,8708.2775,8709.208875,8710.378875,8711.335542,8712.323375,8713.292875,8714.369375,8715.305167,8716.331042,8717.35775,8718.346917,8719.347083,8720.350167,8721.34425,8722.353167,8723.356417,8724.330208,8725.3545,8726.34725,8727.351333,8728.352625,8729.34425,8730.357042,8731.349458,8732.351042,8733.343375,8734.352875,8735.345625,8736.351625,8737.346583,8738.347625,8739.349167,8740.351833,8741.351083,8742.349375,8743.354083,8744.34875,8745.350625,8746.350667,8747.356208,8748.359542,8749.347958,8750.348083,8751.358333,8752.3505,8753.357167,8754.349708,8755.354292,8756.3555,8757.354375,8758.349917,8759.352542,8760.356458,8761.355667,8762.347542,8763.330417,8764.356708,8765.350833,8766.351083,8767.346917,8768.332167,8769.337417,8770.366833,8771.345083,8772.338333,8773.333083,8774.360167,8775.329792,8776.35875,8777.35725,8778.356333,8779.356542,8780.35775,8781.359208,8782.359042,8783.358458,8784.352208,8785.355292,8786.361208,8787.3545,8788.35475,8789.359625,8790.357375,8791.355792,8792.353917,8793.361583,8794.356958,8795.358417,8796.352542,8797.333583,8798.373958,8799.351,8800.373375,8801.349583,8802.34025,8803.360208,8804.355292,8805.355125,8806.356292,8807.357667,8808.357375,8809.355708,8810.355875,8811.35625,8812.359292,8813.356667,8814.359125,8815.361958,8816.356792,8817.359042,8818.359208,8819.36625,8820.353458,8821.360125,8822.358417,8823.362333,8824.361167,8825.3605,8826.3585,8827.356333,8828.281542,8829.291083,8830.237542,8831.367375,8832.333167,8833.338333,8834.282625,8835.220667,8836.338125,8837.348083,8838.330375,8839.343167,8840.36225,8841.357208,8842.367625,8843.361375,8844.364458,8845.369375,8846.370625,8847.365458,8848.366292,8849.370833,8850.363208,8851.362917,8852.367875,8853.361208,8854.342583,8855.39425,8856.358667,8857.360458,8858.366792,8859.362875,8860.364458,8861.366583,8862.365833,8863.362625,8864.364333,8865.36475,8866.370333,8867.365583,8868.369833,8869.372958,8870.36725,8871.370583,8872.365792,8873.388958,8874.342083,8875.374125,8876.372,8877.363417,8878.371458,8879.3745,8880.364708,8881.374542,8882.373667,8883.36725,8884.376292,8885.366958,8886.368292,8887.370792,8888.370083,8889.369958,8890.368958,8891.367125,8892.37175,8893.373708,8894.37225,8895.376042,8896.366542,8897.371542,8898.374458,8899.373208,8900.372042,8901.382583,8902.36775,8903.381375,8904.371708,8905.37625,8906.377417,8907.378667,8908.375,8909.376917,8910.380042,8911.375208,8912.381208,8913.346625,8914.382833,8915.37575,8916.381917,8917.381833,8918.374417,8919.384125,8920.374042,8921.378458,8922.376125,8923.37675,8924.377583,8925.380917,8926.375542,8927.382333,8928.374833,8929.380125,8930.376833,8931.375958,8932.378792,8933.378583,8934.384042,8935.374,8936.377458,8937.382708,8938.378958,8939.378542,8940.382917,8941.379917,8942.378,8943.382667,8944.378083,8945.380583,8946.385,8947.382875,8948.382625,8949.377125,8950.379292,8951.34475,8952.339583,8953.225042,8954.396625,8955.360542,8956.358917,8957.36275,8958.355,8959.227417,8960.394,8961.357333,8962.390792,8963.382625,8964.387625,8965.38175,8966.3805,8967.385333,8968.388042,8969.385417,8970.380375,8971.381417,8972.391292,8973.376208,8974.390958,8975.383458,8976.36475,8977.369542,8978.392083,8979.3845,8980.388833,8981.387083,8982.390458,8983.388292,8984.38625,8985.384417,8986.385,8987.385542,8988.393208,8989.382917,8990.391,8991.390208,8992.362792,8993.397833,8994.387625,8995.383333,8996.368875,8997.390417,8998.379875,8999.3825,9000.368333,9001.367833,9002.393833,9003.395792,9004.3925,9005.385833,9006.385,9007.388417,9008.390083,9009.38925,9010.38975,9011.391333,9012.395292,9013.392708,9014.387167,9015.393,9016.396833,9017.388167,9018.393875,9019.390875,9020.393083,9021.387583,9022.396083,9023.380083,9024.393542,9025.395958,9026.38975,9027.367833,9028.376583,9029.400167,9030.387875,9031.394458,9032.395208,9033.392042,9034.399958,9035.39275,9036.393167,9037.398042,9038.397875,9039.393833,9040.392542,9041.397667,9042.398583,9043.390625,9044.399542,9045.39575,9046.39675,9047.398292,9048.377542,9049.403458,9050.392458,9051.394375,9052.3945,9053.403917,9054.391083,9055.400833,9056.4,9057.395,9058.404542,9059.390375,9060.404375,9061.394792,9062.374042,9063.239583,9064.270083,9065.4085,9066.309083,9067.417417,9068.277542,9069.410875,9070.231042,9071.41925,9072.365292,9073.37825,9074.37575,9075.300375,9076.393,9077.390917,9078.375333,9079.382375,9080.384375,9081.393917,9082.371958,9083.407667,9084.399542,9085.402125,9086.3945,9087.403667,9088.401958,9089.405167,9090.404583,9091.402042,9092.405375,9093.397292,9094.400333,9095.406708,9096.400458,9097.401792,9098.388458,9099.401333,9100.403458,9101.404708,9102.401375,9103.408417,9104.397333,9105.407125,9106.408458,9107.403917,9108.388292,9109.407083,9110.404667,9111.398208,9112.409667,9113.392375,9114.387,9115.410583,9116.400833,9117.406042,9118.401958,9119.405708,9120.4055,9121.401167,9122.406583,9123.381917,9124.414375,9125.404833,9126.408375,9127.406417,9128.414458,9129.40575,9130.409833,9131.406917,9132.406,9133.4045,9134.405958,9135.404417,9136.406667,9137.408542,9138.406667,9139.406833,9140.407208,9141.409917,9142.411708,9143.411125,9144.408417,9145.416458,9146.404333,9147.414833,9148.386458,9149.422583,9150.405625,9151.394833,9152.413792,9153.382667,9154.395042,9155.386208,9156.412958,9157.418333,9158.406375,9159.414042,9160.408875,9161.413708,9162.409083,9163.410125,9164.411083,9165.410792,9166.416708,9167.413042,9168.41125,9169.410417,9170.409833,9171.417625,9172.4255,9173.407833,9174.417542,9175.417042,9176.417333,9177.411208,9178.419667,9179.411542,9180.415792,9181.389,9182.396583,9183.416917,9184.417583,9185.412708,9186.416042,9187.413667,9188.419708,9189.414833,9190.414125,9191.41725,9192.419417,9193.413875,9194.41575,9195.4125,9196.418375,9197.412167,9198.391167,9199.374833,9200.372208,9201.376125,9202.337917,9203.408542,9204.354917,9205.406167,9206.40225,9207.364417,9208.401083,9209.421708,9210.391292,9211.414,9212.238042,9213.654833,9214.900125,9215.856208,9216.874042,9217.84925,9218.869875,9219.875625,9220.871667,9221.875917,9222.866458,9223.8805,9224.870333,9225.875542,9226.871208,9227.872458,9228.871833,9229.86975,9230.871833,9231.870042,9232.868167,9233.871083,9234.8845,9235.867167,9236.871833,9237.87275,9238.872583,9239.848542,9240.877583,9241.878958,9242.871792,9243.87375,9244.880333,9245.867125,9246.875792,9247.8775,9248.878292,9249.874375,9250.872125,9251.876375,9252.872792,9253.881458,9254.871625,9255.872417,9256.879,9257.879958,9258.872833,9259.87325,9260.875417,9261.880292,9262.878125,9263.87525,9264.874417,9265.875917,9266.875625,9267.875208,9268.873792,9269.876625,9270.876417,9271.876958,9272.877917,9273.874958,9274.876792,9275.8755,9276.877417,9277.877167,9278.875833,9279.876458,9280.878,9281.877042,9282.877625,9283.878833,9284.874583,9285.878833,9286.876417,9287.879917,9288.87625,9289.879167,9290.881208,9291.872917,9292.884667,9293.876125,9294.884875,9295.87825,9296.880333,9297.886708,9298.885542,9299.880708,9300.860167,9301.894125,9302.877125,9303.898667,9304.876292,9305.862542,9306.864917,9307.888458,9308.878875,9309.882417,9310.883625,9311.880167,9312.883375,9313.888125,9314.882333,9315.880333,9316.890375,9317.88125,9318.887833,9319.889083,9320.886208,9321.883083,9322.889792,9323.883833,9324.884042,9325.887917,9326.884042,9327.890958,9328.883542,9329.88675,9330.890292,9331.886542,9332.885542,9333.89025,9334.885042,9335.88675,9336.828958,9338.048,9338.980292,9340.059667,9340.845417,9341.961083,9343.060333,9344.03975,9345.046708,9345.991917,9347.038167,9348.028167,9349.053708,9350.06525,9351.066792,9352.058958,9353.067917,9354.066792,9355.060083,9356.06375,9357.062417,9358.062542,9359.061083,9360.061917,9361.062917,9362.064083,9363.062708,9364.065875,9365.062667,9366.066167,9367.065333,9368.068792,9369.061625,9370.065583,9371.0625,9372.063333,9373.071375,9374.050292,9375.051042,9376.069125,9377.061667,9378.063875,9379.066917,9380.063375,9381.044125,9382.06975,9383.063375,9384.066,9385.068208,9386.069042,9387.067833,9388.069542,9389.067792,9390.070042,9391.072958,9392.070958,9393.073708,9394.06375,9395.070583,9396.067292,9397.067792,9398.066833,9399.069625,9400.071375,9401.068167,9402.0755,9403.07025,9404.074792,9405.067625,9406.066917,9407.073083,9408.072333,9409.068667,9410.072917,9411.070833,9412.069125,9413.074625,9414.073,9415.048583,9416.096417,9417.042167,9418.058792,9419.076917,9420.083208,9421.066708,9422.076167,9423.076125,9424.070958,9425.076292,9426.072542,9427.072417,9428.075375,9429.072875,9430.077417,9431.078458,9432.070917,9433.07775,9434.073708,9435.072042,9436.074458,9437.072625,9438.082042,9439.076208,9440.085875,9441.075458,9442.076417,9443.06975,9444.072167,9445.058208,9446.043917,9447.604,9448.787917,9449.678333,9450.818375,9451.798208,9452.794542,9453.816083,9454.8175,9455.798375,9456.718167,9457.84675,9458.791833,9459.8055,9460.824458,9461.821667,9462.830708,9463.820042,9464.823542,9465.827708,9466.815625,9467.824125,9468.817208,9469.822042,9470.821292,9471.827708,9472.820708,9473.827292,9474.818375,9475.827167,9476.826917,9477.82725,9478.819833,9479.801958,9480.824333,9481.828292,9482.80675,9483.805792,9484.830667,9485.822833,9486.82525,9487.826583,9488.822042,9489.825375,9490.830333,9491.824292,9492.827542,9493.828208,9494.824458,9495.822083,9496.832,9497.826417,9498.827583,9499.826542,9500.829958,9501.82425,9502.833625,9503.824708,9504.833583,9505.829167,9506.830542,9507.822708,9508.833042,9509.826833,9510.827667,9511.834,9512.835208,9513.830208,9514.826333,9515.828458,9516.834042,9517.830292,9518.8275,9519.83075,9520.833125,9521.827208,9522.829375,9523.830792,9524.836625,9525.824708,9526.83425,9527.831167,9528.834708,9529.834667,9530.832875,9531.83575,9532.83375,9533.827792,9534.831833,9535.831333,9536.836333,9537.829875,9538.8305,9539.828125,9540.833833,9541.834458,9542.826542,9543.834542,9544.837125,9545.833542,9546.830875,9547.832958,9548.833542,9549.834125,9550.829,9551.83525,9552.836833,9553.836583,9554.838792,9555.833833,9556.831458,9557.837542,9558.835625,9559.83825,9560.831375,9561.833042,9562.835958,9563.838833,9564.828875,9565.837292,9566.834792,9567.839792,9568.832625,9569.839917,9570.833333,9571.839625,9572.838875,9573.813083,9574.787708,9575.802542,9577.210875,9578.478583,9579.36325,9580.401333,9581.4075,9582.304208,9583.436667,9584.389583,9585.43675,9586.404333,9587.261417,9588.445792,9589.395958,9590.435958,9591.423458,9592.4305,9593.430042,9594.426292,9595.433458,9596.427708,9597.43725,9598.427583,9599.432792,9600.426542,9601.429583,9602.42925,9603.436583,9604.431958,9605.432708,9606.431708,9607.431875,9608.431,9609.431708,9610.433083,9611.431,9612.432167,9613.4355,9614.43,9615.435417,9616.4315,9617.431417,9618.433375,9619.431083,9620.43775,9621.433167,9622.43425,9623.425792,9624.440583,9625.431792,9626.442375,9627.433333,9628.437417,9629.429875,9630.435833,9631.443292,9632.439125,9633.431625,9634.439375,9635.432,9636.43675,9637.432167,9638.438125,9639.436,9640.44125,9641.430958,9642.439625,9643.432333,9644.43975,9645.43725,9646.433208,9647.441375,9648.432083,9649.439333,9650.438625,9651.433083,9652.441333,9653.441167,9654.435708,9655.442,9656.441833,9657.439125,9658.441083,9659.432292,9660.435292,9661.434583,9662.439625,9663.442333,9664.432375,9665.437292,9666.445042,9667.438375,9668.442958,9669.440583,9670.441458,9671.441167,9672.438375,9673.4425,9674.439625,9675.439708,9676.438833,9677.445208,9678.445917,9679.453,9680.439917,9681.440792,9682.4495,9683.443125,9684.440333,9685.444042,9686.438833,9687.444792,9688.437792,9689.4465,9690.437917,9691.447042,9692.444833,9693.443708,9694.441375,9695.41875,9696.443625,9697.444708,9698.440792,9699.445667,9700.44025,9701.447,9702.417958,9703.433,9704.420792,9705.2865,9706.484167,9707.401042,9708.399167,9709.298917,9710.4165,9711.441292,9712.298375,9713.45025,9714.418583,9715.410042,9716.424083,9717.445708,9718.443375,9719.445333,9720.454,9721.442458,9722.45375,9723.445208,9724.451958,9725.442875,9726.45625,9727.441833,9728.455458,9729.449583,9730.448375,9731.447042,9732.453,9733.443708,9734.454333,9735.44875,9736.450792,9737.446083,9738.452625,9739.442292,9740.455833,9741.441125,9742.452917,9743.45275,9744.447583,9745.455208,9746.445542,9747.449667,9748.449833,9749.448083,9750.448042,9751.453708,9752.449292,9753.456042,9754.450833,9755.45025,9756.45275,9757.449333,9758.452042,9759.449167,9760.447958,9761.45125,9762.451083,9763.447208,9764.4525,9765.448667,9766.449917,9767.453208,9768.427458,9769.474167,9770.420417,9771.472083,9772.447875,9773.434125,9774.456167,9775.427708,9776.453542,9777.413292,9778.464583,9779.462375,9780.453708,9781.453042,9782.45625,9783.454958,9784.456208,9785.451833,9786.459208,9787.450125,9788.469792,9789.453083,9790.457125,9791.456042,9792.451833,9793.459708,9794.453542,9795.454875,9796.455833,9797.453208,9798.456583,9799.457292,9800.455208,9801.460583,9802.459167,9803.457958,9804.463875,9805.452917,9806.465042,9807.458,9808.454333,9809.435333,9810.445375,9811.454333,9812.459083,9813.456958,9814.457333,9815.4665,9816.460917,9817.461708,9818.4555,9819.459667,9820.458708,9821.457042,9822.459125,9823.438125,9824.368167,9825.376667,9826.475583,9827.399958,9828.324583,9829.465292,9830.456,9831.4495,9832.310708,9833.494,9834.434708,9835.450833,9836.353375,9837.467583,9838.433958,9839.464,9840.358792,9841.482875,9842.455083,9843.464292,9844.462792,9845.463,9846.46125,9847.464958,9848.461042,9849.461875,9850.461917,9851.466333,9852.462667,9853.464292,9854.462667,9855.464958,9856.463292,9857.464542,9858.462667,9859.463708,9860.465458,9861.462083,9862.461792,9863.464125,9864.462292,9865.466,9866.461125,9867.466792,9868.466375,9869.465167,9870.466083,9871.465375,9872.465208,9873.466833,9874.466917,9875.467583,9876.467625,9877.467,9878.466917,9879.466417,9880.467292,9881.465292,9882.465417,9883.465167,9884.4675,9885.469458,9886.468208,9887.468208,9888.455958,9889.473583,9890.470375,9891.469667,9892.471458,9893.467583,9894.470833,9895.474375,9896.45,9897.473917,9898.484625,9899.475458,9900.470375,9901.471917,9902.328875,9903.354583,9904.481,9905.421625,9906.48625,9907.475417,9908.468292,9909.471875,9910.469333,9911.472625,9912.472333,9913.476042,9914.493042,9915.444375,9916.478,9917.470208,9918.43725,9919.336958,9920.508417,9921.462208,9922.477208,9923.464417,9924.464625,9925.452333,9926.455167,9927.47375,9928.441792,9929.290833,9930.470583,9931.474875,9932.451917,9933.485958,9934.481042,9935.477667,9936.459417,9937.484583,9938.488417,9939.482167,9940.481042,9941.492667,9942.485917,9943.487458,9944.45925,9945.485167,9946.491875,9947.484125,9948.464458,9949.465708,9950.482542,9951.489167,9952.486375,9953.461542,9954.482542,9955.486083,9956.48825,9957.4855,9958.484542,9959.46625,9960.492917,9961.486458,9962.488583,9963.461,9964.495208,9965.487958,9966.478167,9967.491042,9968.486375,9969.486958,9970.485083,9971.488292,9972.487458,9973.487125,9974.474458,9975.470125,9976.478417,9977.46725,9978.473042,9979.499708,9980.48825,9981.4685,9982.475875,9983.405708,9984.487042,9985.467,9986.506417,9987.458167,9988.341792,9989.426208,9990.366458,9991.362042,9992.4945,9993.439958,9994.377792,9995.406375,9996.485792,9997.471417,9998.493875,9999.494,10000.498292,10001.493792,10002.492833,10003.500042,10004.493875,10005.50175,10006.491667,10007.502333,10008.496042,10009.499333,10010.503083,10011.497083,10012.500167,10013.496417,10014.474917,10015.504667,10016.49625,10017.474083,10018.482292,10019.515708,10020.495333,10021.484708,10022.507667,10023.500917,10024.503625,10025.497667,10026.499292,10027.499667,10028.484042,10029.499875,10030.507958,10031.49925,10032.506667,10033.504167,10034.497042,10035.51125,10036.504333,10037.499458,10038.507208,10039.503542,10040.505708,10041.502125,10042.500667,10043.481917,10044.505167,10045.503583,10046.501792,10047.504875,10048.507708,10049.511708,10050.481167,10051.505667,10052.51,10053.502,10054.469167,10055.509833,10056.377208,10057.503917,10058.487583,10059.408417,10060.506,10061.478625,10062.482875,10063.481125,10064.46475,10065.498667,10066.508167,10067.486083,10068.529958,10069.504083,10070.514042,10071.485875,10072.495833,10073.489958,10074.512167,10075.512917,10076.50975,10077.518083,10078.505833,10079.513083,10080.50975,10081.492125,10082.495958,10083.489292,10084.515917,10085.511292,10086.519458,10087.516542,10088.519667,10089.494083,10090.496042,10091.524292,10092.521083,10093.51075,10094.520458,10095.514,10096.522167,10097.513292,10098.519,10099.517208,10100.519792,10101.517375,10102.52625,10103.498125,10104.519667,10105.523583,10106.516417,10107.522,10108.521458,10109.516292,10110.521042,10111.519958,10112.518042,10113.522167,10114.522833,10115.521167,10116.52225,10117.51375,10118.525625,10119.517167,10120.51975,10121.520708,10122.520042,10123.499625,10124.522208,10125.520417,10126.521958,10127.531417,10128.521583,10129.52175,10130.518875,10131.522042,10132.521458,10133.526292,10134.519167,10135.496917,10136.617208,10137.863417,10138.794,10139.825333,10140.794333,10141.805875,10142.783333,10143.8155,10144.708917,10145.834,10146.665708,10147.87125,10148.801083,10149.839625,10150.829542,10151.838583,10152.833833,10153.837083,10154.84125,10155.813833,10156.708792,10157.878375,10158.7555,10159.865958,10160.824875,10161.84275,10162.843,10163.813083,10164.830208,10165.81725,10166.843833,10167.845667,10168.838792,10169.84925,10170.84375,10171.842292,10172.842583,10173.852417,10174.787833,10175.859417,10176.81375,10177.855042,10178.843958,10179.846583,10180.849125,10181.846875,10182.848625,10183.842667,10184.849208,10185.825208,10186.851667,10187.842208,10188.852917,10189.848125,10190.846333,10191.8475,10192.856083,10193.844667,10194.828083,10195.831083,10196.852917,10197.843833,10198.85175,10199.846583,10200.848083,10201.847833,10202.845917,10203.845875,10204.846708,10205.852958,10206.841292,10207.8475,10208.856875,10209.853375,10210.834917,10211.857333,10212.850375,10213.84925,10214.849167,10215.850458,10216.846,10217.850708,10218.83325,10219.837792,10220.85225,10221.848667,10222.855792,10223.854417,10224.853875,10225.851125,10226.75,10227.847042,10228.825042,10229.861125,10230.838417,10231.708083,10232.878667,10233.845167,10234.832542,10235.771583,10236.698167,10237.873542,10238.829542,10239.83925,10240.859458,10241.862958,10242.852833,10243.860958,10244.860042,10245.857417,10246.833083,10247.852917,10248.862292,10249.865708,10250.829292,10251.842375,10252.862125,10253.8265,10254.8445,10255.866875,10256.770167,10257.847708,10258.868167,10259.857917,10260.876417,10261.862583,10262.840917,10263.868167,10264.862,10265.841042,10266.866708,10267.839292,10268.873167,10269.864542,10270.861708,10271.865667,10272.85875,10273.864667,10274.868292,10275.865667,10276.866625,10277.851458,10278.840083,10279.871542,10280.865125,10281.844167,10282.862625,10283.864542,10284.865583,10285.874833,10286.865625,10287.865208,10288.862667,10289.867417,10290.869667,10291.867333,10292.873667,10293.848833,10294.869875,10295.84325,10296.8695,10297.85275,10298.857833,10299.868833,10300.868833,10301.865708,10302.87475,10303.871583,10304.865792,10305.848458,10306.687083,10307.917625,10308.862375,10309.870208,10310.876458,10311.86675,10312.87275,10313.874042,10314.867833,10315.869083,10316.874958,10317.868,10318.876375,10319.877167,10320.8755,10321.87325,10322.865167,10323.878833,10324.874,10325.869,10326.692875,10327.92075,10328.859583,10329.854625,10330.819917,10331.692167,10332.916,10333.843583,10334.75425,10335.83575,10336.815958,10337.850042,10338.745917,10339.881458,10340.850875,10341.858542,10342.822125,10343.876292,10344.83825,10345.859208,10346.88775,10347.875875,10348.881167,10349.862375,10350.856792,10351.860083,10352.883208,10353.865,10354.884083,10355.886292,10356.853708,10357.879958,10358.887083,10359.891375,10360.882167,10361.88325,10362.88875,10363.877,10364.885917,10365.883875,10366.887083,10367.882167,10368.884958,10369.883,10370.885958,10371.883667,10372.888667,10373.89875,10374.886167,10375.880833,10376.890542,10377.884375,10378.885875,10379.889042,10380.865083,10381.901,10382.890917,10383.861333,10384.890125,10385.884708,10386.86775,10387.868458,10388.897167,10389.87525,10390.895458,10391.87125,10392.9035,10393.887417,10394.892542,10395.888542,10396.886708,10397.893125,10398.89575,10399.886292,10400.894958,10401.891417,10402.89325,10403.896333,10404.894167,10405.893583,10406.896917,10407.878875,10408.893083,10409.894667,10410.894958,10411.891792,10412.893542,10413.894958,10414.894583,10415.895667,10416.889167,10417.895,10418.889167,10419.89725,10420.894,10421.894667,10422.892542,10423.8985,10424.889333,10425.89525,10426.890042,10427.896833,10428.893917,10429.898,10430.897667,10431.897417,10432.886792,10433.899625,10434.892292,10435.894958,10436.895375,10437.900042,10438.899042,10439.898667,10440.899167,10441.895625,10442.894792,10443.897917,10444.897333,10445.901042,10446.901375,10447.892292,10448.8985,10449.903167,10450.894875,10451.9025,10452.897208,10453.903542,10454.903375,10455.899083,10456.901042,10457.895958,10458.895542,10459.903125,10460.898375,10461.900167,10462.900958,10463.901833,10464.895333,10465.902042,10466.893458,10467.908125,10468.894417,10469.905167,10470.898542,10471.904667,10472.897375,10473.907125,10474.906208,10475.877375,10476.862,10477.90275,10479.018042,10480.128292,10481.114958,10482.060167,10483.005667,10484.14175,10485.080125,10485.97175,10487.134917,10488.102542,10488.974792,10490.081125,10491.00475,10492.251917,10493.201833,10494.225125,10495.225958,10496.222917,10497.217083,10498.223583,10499.223167,10500.218958,10501.221917,10502.221167,10503.221958,10504.222167,10505.227042,10506.220167,10507.227917,10508.219083,10509.225917,10510.222625,10511.226375,10512.223542,10513.220792,10514.225667,10515.22425,10516.222042,10517.223333,10518.230833,10519.22375,10520.228833,10521.221042,10522.229042,10523.220375,10524.232042,10525.217625,10526.233542,10527.224708,10528.227167,10529.227333,10530.228125,10531.22375,10532.229667,10533.225583,10534.2285,10535.227125,10536.226542,10537.227833,10538.226875,10539.225792,10540.228458,10541.229583,10542.228667,10543.228583,10544.226833,10545.230625,10546.227,10547.22625,10548.234083,10549.224292,10550.234583,10551.233167,10552.211083,10553.21625,10554.242625,10555.218208,10556.2395,10557.23475,10558.236708,10559.232417,10560.237542,10561.233958,10562.235917,10563.233417,10564.238583,10565.235208,10566.238333,10567.233833,10568.239583,10569.23575,10570.238375,10571.231417,10572.242125,10573.229292,10574.243083,10575.24075,10576.234333,10577.236208,10578.2425,10579.23425,10580.238833,10581.237083,10582.218167,10583.258458,10584.222375,10585.222708,10586.245083,10587.234542,10588.243125,10589.235708,10590.242833,10591.23375,10592.238917,10593.175125,10594.256667,10595.213167,10596.243917,10597.157875,10598.206208,10599.246708,10600.200583,10601.080958,10602.23975,10603.203417,10604.077667,10605.275417,10606.230375,10607.245958,10608.23975,10609.239542,10610.239917,10611.2405,10612.247917,10613.241042,10614.242667,10615.241125,10616.243625,10617.244,10618.249125,10619.23675,10620.245292,10621.2175,10622.250583,10623.246917,10624.245542,10625.225792,10626.248583,10627.245958,10628.235542,10629.224167,10630.226917,10631.254208,10632.243167,10633.227458,10634.25275,10635.2465,10636.248042,10637.252167,10638.246083,10639.252667,10640.248833,10641.251,10642.247667,10643.252625,10644.253625,10645.247833,10646.254458,10647.247917,10648.249042,10649.250792,10650.253125,10651.251625,10652.248667,10653.255958,10654.243,10655.258333,10656.246292,10657.247708,10658.254958,10659.251958,10660.2535,10661.249375,10662.248625,10663.256958,10664.253458,10665.250375,10666.235958,10667.256667,10668.25675,10669.264208,10670.254833,10671.252,10672.253167,10673.25075,10674.258958,10675.248083,10676.257042,10677.254625,10678.257708,10679.254083,10680.258667,10681.252833,10682.253625,10683.25,10684.255958,10685.252625,10686.257667,10687.252458,10688.255667,10689.252042,10690.258375,10691.249583,10692.232708,10693.246708,10694.234583,10695.243208,10696.257917,10697.254208,10698.259167,10699.263833,10700.263208,10701.251125,10702.2565,10703.260208,10704.258417,10705.252875,10706.25425,10707.251708,10708.253667,10709.094833,10710.29375,10711.087417,10712.303167,10713.249208,10714.267667,10715.25425,10716.256625,10717.255917,10718.264875,10719.258083,10720.238125,10721.239667,10722.244,10723.262333,10724.265583,10725.257833,10726.266542,10727.257,10728.265125,10729.257417,10730.264375,10731.236458,10732.275208,10733.250417,10734.269542,10735.261042,10736.266542,10737.260667,10738.263333,10739.147625,10740.254917,10741.154833,10742.2875,10743.239208,10744.250833,10745.226333,10746.171542,10747.282875,10748.066208,10749.287875,10750.198167,10751.261958,10752.255625,10753.243708,10754.249042,10755.273167,10756.265333,10757.267458,10758.260417,10759.272042,10760.263208,10761.26375,10762.263625,10763.265833,10764.280333,10765.25825,10766.256833,10767.26525,10768.263875,10769.264083,10770.266458,10771.265833,10772.26325,10773.266208,10774.264125,10775.268667,10776.264833,10777.270417,10778.26825,10779.266333,10780.265625,10781.265208,10782.268333,10783.26425,10784.266792,10785.266958,10786.270625,10787.264333,10788.271667,10789.2795,10790.265417,10791.272917,10792.268625,10793.267792,10794.26975,10795.274083,10796.255625,10797.252042,10798.247667,10799.250333,10800.263375,10801.253208,10802.262875,10803.251917,10804.251625,10805.257833,10806.275875,10807.277125,10808.277125,10809.276417,10810.279083,10811.278667,10812.2755,10813.276583,10814.275167,10815.276917,10816.281625,10817.280583,10818.282708,10819.283167,10820.276167,10821.277833,10822.287792,10823.282958,10824.281417,10825.281542,10826.270333,10827.27275,10828.220875,10829.163208,10830.315875,10831.295667,10832.467667,10833.500417,10834.735042,10835.524,10836.775917,10837.699625,10838.723458,10839.722,10840.733167,10841.724625,10842.702042,10843.718375,10844.747083,10845.720875,10846.732708,10847.746417,10848.753833,10849.741083,10850.743833,10851.73,10852.751792,10853.722917,10854.755667,10855.744542,10856.74425,10857.75075,10858.748458,10859.752792,10860.727625,10861.765125,10862.748292,10863.754,10864.754917,10865.750792,10866.756917,10867.757625,10868.756042,10869.757,10870.751083,10871.754167,10872.758458,10873.755125,10874.752625,10875.749417,10876.756875,10877.729792,10878.762667,10879.750625,10880.731125,10881.740208,10882.765917,10883.731917,10884.763875,10885.748458,10886.7335,10887.738417,10888.759833,10889.755292,10890.764083,10891.751792,10892.761042,10893.761833,10894.757083,10895.761292,10896.751083,10897.737917,10898.738917,10899.754708,10900.760375,10901.761833,10902.759,10903.754542,10904.764958,10905.762583,10906.757917,10907.7575,10908.763875,10909.756667,10910.76575,10911.763125,10912.758542,10913.760667,10914.764417,10915.765167,10916.760792,10917.762458,10918.766167,10919.764042,10920.766042,10921.768625,10922.76375,10923.760458,10924.769208,10925.7605,10926.759625,10927.759917,10928.767417,10929.761625,10930.764792,10931.76125,10932.762458,10933.760958,10934.740417,10935.767167,10936.775583,10937.761708,10938.745292,10939.74325,10940.719917,10941.748667,10942.736833,10943.722833,10944.761125,10945.597292,10946.7725,10947.612208,10948.806667,10949.754667,10950.766583,10951.769458,10952.768375,10953.767375,10954.768125,10955.763667,10956.767667,10957.766042,10958.769875,10959.767167,10960.770042,10961.772375,10962.774125,10963.765083,10964.7735,10965.775458,10966.768125,10967.771167,10968.770958,10969.774125,10970.774167,10971.77525,10972.768917,10973.775083,10974.774583,10975.770167,10976.771125,10977.750042,10978.74525,10979.774,10980.751542,10981.773542,10982.761333,10983.77075,10984.770125,10985.779417,10986.768542,10987.768417,10988.771083,10989.777042,10990.772458,10991.776042,10992.775042,10993.776958,10994.771333,10995.774792,10996.77575,10997.776583,10998.773708,10999.774125,11000.77525,11001.77525,11002.758333,11003.754,11004.775125,11005.777542,11006.758292,11007.782292,11008.769583,11009.779333,11010.77025,11011.781333,11012.778667,11013.774667,11014.783417,11015.776417,11016.787583,11017.754167,11018.761333,11019.776708,11020.786042,11021.777667,11022.783042,11023.762167,11024.76325,11025.773417,11026.781667,11027.783208,11028.7755,11029.78575,11030.782375,11031.779583,11032.789167,11033.781083,11034.788125,11035.781958,11036.788583,11037.787833,11038.780875,11039.789583,11040.787708,11041.787625,11042.78125,11043.784125,11044.785958,11045.788458,11046.781917,11047.792042,11048.787708,11049.78925,11050.781417,11051.787792,11052.788,11053.788625,11054.782208,11055.771125,11056.788083,11057.782542,11058.769917,11059.7875,11060.619458,11061.629792,11062.597667,11063.658875,11064.635917,11065.799125,11066.678208,11067.743667,11068.622917,11069.814833,11070.659625,11071.809792,11072.780333,11073.790667,11074.773292,11075.76975,11076.774458,11077.767792,11078.791667,11079.78475,11080.789708,11081.793167,11082.783458,11083.79,11084.794625,11085.7855,11086.788833,11087.796042,11088.790167,11089.795917,11090.788875,11091.789833,11092.795208,11093.792833,11094.79,11095.797417,11096.790917,11097.797083,11098.7965,11099.795375,11100.800042,11101.78975,11102.800125,11103.789125,11104.79475,11105.795792,11106.7925,11107.770375,11108.804,11109.792792,11110.790083,11111.796875,11112.793583,11113.800667,11114.788125,11115.795042,11116.7985,11117.795875,11118.792292,11119.796,11120.795083,11121.798333,11122.80025,11123.795125,11124.798333,11125.791375,11126.804542,11127.79075,11128.798833,11129.80375,11130.793583,11131.79375,11132.798375,11133.795833,11134.796583,11135.796542,11136.803333,11137.800667,11138.803208,11139.790833,11140.77525,11141.8175,11142.788583,11143.79225,11144.802792,11145.796,11146.78175,11147.800833,11148.778792,11149.80275,11150.795958,11151.800292,11152.797583,11153.804,11154.796,11155.795917,11156.806042,11157.799167,11158.804333,11159.798625,11160.800708,11161.759958,11162.808542,11163.796792,11164.740292,11165.797542,11166.61325,11167.844,11168.647708,11169.830042,11170.791833,11171.798417,11172.778958,11173.807667,11174.798917,11175.801667,11176.799917,11177.804875,11178.804,11179.799125,11180.808667,11181.799833,11182.804333,11183.8085,11184.806208,11185.806333,11186.806667,11187.79775,11188.810917,11189.807333,11190.806417,11191.80425,11192.802458,11193.810167,11194.8075,11195.801667,11196.80275,11197.802708,11198.809667,11199.802125,11200.803167,11201.811208,11202.809542,11203.805083,11204.792375,11205.788125,11206.808417,11207.784,11208.80275,11209.81375,11210.808667,11211.802542,11212.811958,11213.806208,11214.809167,11215.814042,11216.803458,11217.808417,11218.805167,11219.813917,11220.813083,11221.809542,11222.813042,11223.811875,11224.805792,11225.810458,11226.811333,11227.815875,11228.808667,11229.807292,11230.810875,11231.812125,11232.806708,11233.809208,11234.810667,11235.810167,11236.809583,11237.807625,11238.808958,11239.8095,11240.807083,11241.808875,11242.811,11243.810167,11244.809542,11245.811708,11246.809583,11247.809958,11248.809875,11249.814667,11250.812458,11251.811375,11252.809958,11253.812375,11254.813167,11255.809167,11256.8115,11257.814333,11258.818542,11259.796208,11260.814083,11261.798417,11262.8265,11263.793083,11264.828958,11265.805542,11266.817875,11267.812958,11268.791375,11269.691958,11270.846042,11271.806625,11272.795958,11273.798667,11274.822,11275.814917,11276.729292,11277.819875,11278.807083,11280.082083,11281.354125,11282.265125,11283.098333,11284.358958,11285.25025,11286.285125,11287.298833,11288.295875,11289.27675,11290.280333,11291.276375,11292.280458,11293.315208,11294.292917,11295.275958,11296.305542,11297.304458,11298.301958,11299.299,11300.306542,11301.297375,11302.299875,11303.304875,11304.298833,11305.301917,11306.306792,11307.30675,11308.3,11309.301083,11310.302708,11311.301083,11312.299333,11313.299417,11314.301042,11315.300625,11316.301458,11317.302167,11318.303708,11319.302208,11320.299375,11321.308333,11322.315667,11323.303625,11324.313,11325.309167,11326.28675,11327.288583,11328.313083,11329.306375,11330.312167,11331.307833,11332.312958,11333.304042,11334.308667,11335.316208,11336.311167,11337.310833,11338.315333,11339.311,11340.319292,11341.320167,11342.301958,11343.2895,11344.309958,11345.309,11346.295333,11347.314542,11348.311125,11349.315875,11350.314,11351.312875,11352.316042,11353.286583,11354.319583,11355.3305,11356.303875,11357.316125,11358.297833,11359.298958,11360.33425,11361.145333,11362.264458,11363.290625,11364.305583,11365.289375,11366.192583,11367.206625,11368.180625,11369.213542,11370.29875,11371.231208,11372.320625,11373.2855,11374.268125,11375.302583,11376.241708,11377.31025,11378.329125,11379.276583,11380.311917,11381.216792,11382.347375,11383.313167,11384.326625,11385.319083,11386.330917,11387.311542,11388.325958,11389.322833,11390.329417,11391.324,11392.309375,11393.192167,11394.337542,11395.264667,11396.275625,11397.317083,11398.301208,11399.326625,11400.195167,11401.336458,11402.315917,11403.186292,11404.214917,11405.326,11406.293292,11407.336292,11408.299708,11409.307083,11410.332833,11411.320542,11412.33,11413.329792,11414.311792,11415.335833,11416.327417,11417.327958,11418.3305,11419.345292,11420.326958,11421.304375,11422.330583,11423.324708,11424.331167,11425.326958,11426.3305,11427.32725,11428.331833,11429.331083,11430.327958,11431.339875,11432.330833,11433.334042,11434.329125,11435.338,11436.332,11437.334042,11438.336417,11439.330708,11440.330292,11441.340958,11442.332,11443.329667,11444.340458,11445.33525,11446.332875,11447.335375,11448.333125,11449.333458,11450.339458,11451.328375,11452.33875,11453.335292,11454.338,11455.333167,11456.331958,11457.333,11458.338542,11459.332625,11460.340417,11461.334708,11462.334167,11463.332583,11464.335542,11465.338417,11466.338708,11467.33525,11468.341875,11469.338917,11470.335333,11471.33575,11472.338542,11473.334833,11474.340708,11475.33475,11476.34325,11477.336708,11478.342375,11479.338917,11480.335083,11481.338167,11482.341333,11483.339333,11484.336333,11485.339208,11486.339,11487.340125,11488.338333,11489.3285,11490.34575,11491.33825,11492.343458,11493.34425,11494.323417,11495.267583,11496.199208,11497.160833,11498.172958,11499.240583,11500.207167,11501.190708,11502.27325,11503.191042,11504.362417,11505.299167,11506.332208,11507.185875,11508.357333,11509.20925,11510.353333,11511.161042,11512.389333,11513.243292,11514.306708,11515.148292,11516.220042,11517.364375,11518.346875,11519.349667,11520.3515,11521.340125,11522.327,11523.349208,11524.355583,11525.343042,11526.348583,11527.344,11528.345958,11529.346167,11530.348583,11531.348,11532.350125,11533.345542,11534.346583,11535.349292,11536.352792,11537.335833,11538.351917,11539.3455,11540.344708,11541.34625,11542.351208,11543.196167,11544.367375,11545.147292,11546.227083,11547.354125,11548.337542,11549.189583,11550.230458,11551.351,11552.211625,11553.292542,11554.351167,11555.350583,11556.354125,11557.34025,11558.356958,11559.352167,11560.354917,11561.353542,11562.356917,11563.348958,11564.357667,11565.354542,11566.3545,11567.35675,11568.356417,11569.36175,11570.352458,11571.351125,11572.35975,11573.349833,11574.358542,11575.351042,11576.357375,11577.355042,11578.35525,11579.353958,11580.35425,11581.348792,11582.228167,11583.368542,11584.312542,11585.343292,11586.297917,11587.345125,11588.284292,11589.346917,11590.334542,11591.338125,11592.317167,11593.231542,11594.252125,11595.156458,11596.397208,11597.346167,11598.362458,11599.352458,11600.357917,11601.355,11602.36325,11603.35825,11604.358083,11605.359625,11606.355,11607.363375,11608.353125,11609.358833,11610.356625,11611.362667,11612.360333,11613.35825,11614.355542,11615.359083,11616.36225,11617.356875,11618.36675,11619.362458,11620.363625,11621.361042,11622.359083,11623.360667,11624.364083,11625.361458,11626.229792,11627.212,11628.215708,11629.198708,11630.396792,11631.232792,11632.2465,11633.243042,11634.174208,11635.372625,11636.17375,11637.201458,11638.369833,11639.332792,11640.197792,11641.274417,11642.24475,11643.382042,11644.358625,11645.364875,11646.363125,11647.363292,11648.360542,11649.3625,11650.362917,11651.364625,11652.365208,11653.367167,11654.361125,11655.361708,11656.365375,11657.368333,11658.36575,11659.362042,11660.366667,11661.365208,11662.367583,11663.360583,11664.369458,11665.365375,11666.373167,11667.365292,11668.365375,11669.362333,11670.36525,11671.364333,11672.367167,11673.364708,11674.350625,11675.175208,11676.201375,11677.307417,11678.3385,11679.368458,11680.271667,11681.361042,11682.266833,11683.383625,11684.336125,11685.268,11686.366667,11687.466667,11688.494542,11689.484125,11690.486667,11691.488125,11692.490542,11693.485958,11694.492792,11695.490625,11696.484167,11697.485708,11698.487333,11699.488,11700.494917,11701.484708,11702.4905,11703.492292,11704.484458,11705.490083,11706.489167,11707.487708,11708.493417,11709.489292,11710.498917,11711.485042,11712.495958,11713.490542,11714.491625,11715.488292,11716.49,11717.310458,11718.5025,11719.349375,11720.497375,11721.287583,11722.509583,11723.416542,11724.303958,11725.523125,11726.454542,11727.470958,11728.458167,11729.477417,11730.493792,11731.476917,11732.34425,11733.532958,11734.463083,11735.500083,11736.488417,11737.491125,11738.497875,11739.486958,11740.493417,11741.49425,11742.491708,11743.495667,11744.493083,11745.495417,11746.491042,11747.4925,11748.500083,11749.491125,11750.496708,11751.489583,11752.495125,11753.492083,11754.472167,11755.503167,11756.48175,11757.502375,11758.490458,11759.500542,11760.493708,11761.496792,11762.492833,11763.407958,11764.320583,11765.464458,11766.349792,11767.507708,11768.323917,11769.388833,11770.397042,11771.5015,11772.326083,11773.336958,11774.316542,11775.521875,11776.327417,11777.535833,11778.424,11779.40325,11780.461625,11781.505417,11782.496875,11783.496958,11784.494542,11785.500917,11786.499125,11787.497958,11788.499417,11789.498917,11790.497417,11791.504958,11792.494875,11793.505375,11794.497875,11795.498542,11796.500625,11797.497208,11798.500667,11799.505167,11800.496167,11801.503167,11802.49825,11803.502917,11804.497875,11805.504,11806.506458,11807.498542,11808.477083,11809.340292,11810.451042,11811.4805,11812.369667,11813.474,11814.335,11815.397708,11816.308208,11817.356042,11818.533167,11819.962458,11821.209583,11822.164708,11823.043875,11824.189333,11825.176417,11826.1815,11827.184667,11828.185458,11829.183083,11830.179708,11831.192583,11832.179417,11833.179625,11834.18825,11835.181708,11836.187917,11837.184833,11838.187042,11839.185208,11840.184708,11841.182125,11842.188625,11843.182,11844.18425,11845.188042,11846.180875,11847.185458,11848.180292,11849.185417,11850.159208,11851.177792,11852.044167,11853.209,11855.902667,11856.973917,11857.952667,11859.15275,11860.130917,11861.065792,11862.112208,11864.949167,11866.229833,11867.140333,11868.181125,11869.163083,11870.148917,11871.171208,11872.175125,11873.165208,11874.183583,11875.164583,11876.17075,11877.166542,11878.171792,11879.168958,11880.17875,11881.162208,11882.169792,11883.175833,11884.1675,11885.16725,11886.172083,11887.171,11888.168042,11889.1675,11890.170875,11891.020458,11892.198625,11893.114667,11894.083292,11895.2455,11896.267917,11897.159875,11898.327542,11899.611583,11901.757167,11903.016208,11903.828542,11904.995667,11905.954792,11906.965292,11907.977,11908.973208,11909.972917,11910.974625,11911.975292,11912.979042,11913.975375,11914.975083,11915.977208,11916.979333,11917.97525,11918.980542,11919.976542,11920.978458,11921.976125,11922.976125,11923.986292,11924.977375,11925.977917,11926.977667,11927.955875,11928.988583,11929.974208,11930.994083,11936.69,11941.1685,11942.196458,11943.41525,11944.360667,11945.376,11946.378792,11947.372375,11948.374667,11949.387917,11950.386333,11951.387,11952.390333,11953.386083,11954.386667,11955.387458,11956.387125,11957.38975,11958.387167,11959.388792,11960.387375,11961.388458,11962.387958,11963.389333,11964.387417,11965.388,11966.388083,11967.39,11968.3875,11969.255292,11970.265542,11971.203583,11972.313875,11973.377083,11974.596875,11978.252375,11979.417958,11980.328375,11981.4785,11983.049583,11984.299375,11985.238917,11986.273208,11987.267167,11988.268208,11989.265625,11990.26775,11991.271583,11992.265,11993.26725,11994.250458,11995.250042,11996.268417,11997.266917,11998.268875,11999.272333,12000.267292,12001.274167,12002.26675,12003.271208,12004.270208,12005.27425,12006.266125,12007.248708,12008.275208,12009.271792,12010.271375,12011.253958,12017.891292,12022.590417,12023.846792,12024.783667,12025.801375,12026.795583,12027.797542,12028.7905,12029.793625,12030.796375,12031.8135,12032.806333,12033.812,12034.808208,12035.812292,12036.8125,12037.80925,12038.810458,12039.815208,12040.809917,12041.810208,12042.808333,12043.811125,12044.813417,12045.816667,12046.809958,12047.808542,12048.810042,12049.819792,12050.786333,12051.811083,12052.803875,12053.818542,12054.811625,12055.813708,12056.664625,12057.816542,12058.760333,12059.803375,12060.718708,12062.055667,12063.506667,12064.639292,12065.720583,12066.628833,12067.69225,12068.967458,12069.897,12070.916167,12071.892208,12072.916375,12073.908625,12074.914625,12075.909625,12076.914583,12077.909333,12078.914333,12079.907,12080.913708,12081.911167,12082.911708,12083.911625,12084.909792,12085.923917,12086.912417,12087.915583,12088.911917,12089.915458,12090.91725,12091.910458,12092.9165,12093.911583,12094.919375,12095.886583,12096.897625,12097.917833,12098.914625,12099.911667,12100.916958,12101.915625,12103.23,12104.473833,12105.441583,12106.259458,12107.460667,12108.3595,12113.281292,12114.533667,12115.474167,12116.485417,12117.485,12118.501333,12119.500917,12120.497167,12121.500333,12122.500208,12123.502083,12124.496833,12125.497292,12126.501792,12127.50125,12128.501458,12129.505208,12130.497417,12131.5005,12132.502458,12133.499625,12134.500333,12135.501333,12136.502458,12137.500917,12138.50075,12139.501125,12140.501667,12141.500875,12142.482167,12145.5255,12147.76625,12149.012583,12149.954333,12150.8585,12151.846667,12152.998708,12153.967167,12154.972042,12155.973083,12156.973917,12157.970417,12158.973125,12159.97225,12160.96475,12161.9865,12162.984333,12163.987,12164.986125,12165.983792,12166.984875,12167.986417,12168.985208,12169.986125,12170.984792,12171.986792,12172.987,12173.986833,12174.987167,12175.985292,12176.987792,12177.987583,12178.993208,12179.966667,12181.012958,12181.984917,12182.97425,12183.991083,12184.98875,12185.991,12186.973875,12187.994958,12188.980875,12189.968125,12190.996333,12191.988542,12192.991333,12193.995792,12194.995083,12195.989125,12196.995667,12197.987792,12198.919708,12200.004083,12200.985333,12201.998,12202.990917,12203.989042,12204.988917,12205.990333,12206.994583,12207.991042,12208.99475,12209.881417,12211.020625,12211.987667,12212.995417,12213.990333,12214.991875,12215.995292,12216.989667,12217.99725,12218.994042,12219.997583,12220.992458,12221.990625,12222.997292,12223.997,12224.992292,12225.999542,12226.996417,12227.941917,12229.008125,12229.991417,12230.997792,12231.934167,12233.007833,12233.998,12234.9925,12235.997625,12236.996333,12237.992583,12239.000917,12239.992625,12241.001042,12241.993667,12242.999292,12243.998042,12244.997833,12245.997125,12246.999042,12247.996792,12248.99625,12249.978833,12250.998833,12251.977625,12252.979708,12253.989583,12254.998958,12255.999833,12256.840083,12257.803625,12259.078792,12259.883,12268.375417,12269.834167,12271.094917,12272.023167,12273.043042,12274.0375,12275.03875,12276.041542,12277.037875,12278.039208,12279.038625,12280.056292,12281.051333,12282.052917,12283.053833,12284.038667,12285.040917,12286.056333,12287.036833,12288.06,12289.0525,12290.037708,12291.0375,12292.035458,12293.063833,12294.053333,12295.032583,12296.067042,12297.051417,12298.065375,12299.054375,12300.05875,12301.057542,12302.055625,12303.060292,12304.056083,12305.056875,12306.056792,12307.027167,12308.066333,12309.056083,12309.991833,12310.901,12312.085583,12313.029875,12314.065875,12315.102042,12321.372083,12322.625875,12323.563667,12324.546,12325.577958,12326.5765,12327.571583,12328.580167,12329.577708,12330.580708,12331.601583,12332.585667,12333.591917,12334.586875,12335.59275,12336.590083,12337.591458,12338.593125,12339.589958,12340.592292,12341.59525,12342.591792,12343.582667,12344.594792,12345.592208,12346.592833,12347.592708,12348.5595,12349.603375,12350.586333,12351.593833,12352.569,12353.577292,12354.580917,12355.601,12356.603417,12357.591167,12358.573292,12359.581292,12360.592958,12361.598417,12362.592208,12363.599667,12364.593792,12365.597,12366.594083,12367.60125,12368.593792,12369.602375,12370.593792,12371.597875,12372.596292,12373.59725,12374.612625,12375.589375,12376.595708,12377.583625,12378.601125,12379.596083,12380.598083,12381.596708,12382.598375,12383.603792,12384.5965,12385.582583,12386.608917,12387.595833,12388.605458,12389.5995,12390.5685,12391.605125,12392.602125,12393.6045,12394.5975,12395.602708,12396.605792,12397.597208,12398.606083,12399.602792,12400.600458,12401.563583,12402.586833,12403.61,12404.603833,12405.5985,12406.60125,12407.5975,12408.601542,12409.598042,12410.600542,12411.603125,12412.60075,12413.604583,12414.599208,12415.603208,12416.609375,12417.600625,12418.582292,12419.608,12420.603,12421.6165,12422.6025,12423.617542,12424.597708,12425.606875,12426.600292,12427.588583,12428.609375,12429.598458,12430.606458,12431.60625,12432.606417,12433.604417,12434.604042,12435.602417,12436.609417,12437.604708,12438.603958,12439.604375,12440.603958,12441.61,12442.603583,12443.610083,12444.60625,12445.603583,12446.611208,12447.608833,12448.606583,12449.613417,12450.602042,12451.606625,12452.590333,12453.61425,12454.603458,12455.606792,12456.605833,12457.612208,12458.6095,12459.603667,12460.611875,12461.609625,12462.608208,12463.6115,12464.605417,12465.608292,12466.609958,12467.608208,12468.605583,12469.614417,12470.610417,12471.606708,12472.608708,12473.608083,12474.605625,12475.6085,12476.608917,12477.612,12478.6065,12479.612667,12480.615875,12481.612,12482.614792,12483.613292,12484.614625,12485.593333,12486.616375,12487.587667,12488.612083,12489.616125,12490.611,12491.61,12492.613917,12493.609042,12494.616292,12495.610458,12496.61525,12497.615042,12498.619542,12499.609667,12500.617333,12501.583792,12502.619875,12503.615083,12504.582,12505.625708,12506.608208,12507.617333,12508.609708,12509.615083,12510.613583,12511.618833,12512.611917,12513.614042,12514.610208,12515.615292,12516.618833,12517.613875,12518.612917,12519.619583,12520.612583,12521.613917,12522.615667,12523.619417,12524.618292,12525.615708,12526.61675,12527.614208,12528.593708,12529.621458,12530.613458,12531.614583,12532.618417,12533.613667,12534.616042,12535.620333,12536.620375,12537.616542,12538.620583,12539.616625,12540.619083,12541.612208,12542.615708,12543.622417,12544.620333,12545.620708,12546.616042,12547.617917,12548.622292,12549.614208,12550.595875,12551.638792,12552.584583,12553.635458,12554.612667,12555.619,12556.618125,12557.595417,12558.618083,12559.619333,12560.618167,12561.622542,12562.621917,12563.617792,12564.617417,12565.61925,12566.617333,12567.619792,12568.621792,12569.621292,12570.6225,12571.618917,12572.621125,12573.620875,12574.6235,12575.622625,12576.617917,12577.629917,12578.620125,12579.625167,12580.6265,12581.621208,12582.63,12583.621208,12584.627292,12585.629042,12586.628583,12587.623375,12588.629917,12589.621375,12590.625625,12591.630792,12592.623042,12593.6245,12594.626375,12595.629042,12596.630583,12597.626625,12598.624292,12599.625792,12600.622625,12601.626125,12602.64325,12603.625292,12604.625375,12605.627417,12606.624792,12607.630792,12608.625167,12609.626125,12610.624208,12611.630208,12612.632042,12613.630542,12614.623667,12615.629125,12616.631292,12617.607042,12618.648667,12619.625833,12620.610125,12621.633292,12622.634,12623.63025,12624.613708,12625.635625,12626.63225,12627.63125,12628.626958,12629.628417,12630.627542,12631.632458,12632.62925,12633.631208,12634.628417,12635.63,12636.628042,12637.636458,12638.629458,12639.63375,12640.629083,12641.631417,12642.632125,12643.6295,12644.631083,12645.630792,12646.634667,12647.628458,12648.636667,12649.632792,12650.634167,12651.632583,12652.638417,12653.632625,12654.640042,12655.63975,12656.633792,12657.640958,12658.631542,12659.6385,12660.640583,12661.636458,12662.61125,12663.649125,12664.629625,12665.638542,12666.636375,12667.63725,12668.64175,12669.636917,12670.542583,12671.6665,12672.633417,12673.63875,12674.637917,12675.637875,12676.640583,12677.638667,12678.635292,12679.63775,12680.644208,12681.635042,12682.642542,12683.634958,12684.639458,12685.635958,12686.637792,12687.63,12688.618458,12689.650333,12690.621875,12691.655208,12692.634292,12693.649458,12694.638458,12695.643292,12696.639125,12697.639708,12698.645,12699.640667,12700.644583,12701.637833,12702.623833,12703.6455,12704.637167,12705.640708,12706.638333,12707.647375,12708.644125,12709.640333,12710.643042,12711.643375,12712.640625,12713.643125,12714.644417,12715.646583,12716.609333,12717.649792,12718.640875,12719.6485,12720.647875,12721.640292,12722.648292,12723.646792,12724.648667,12725.643833,12726.639875,12727.648583,12728.643875,12729.647542,12730.644458,12731.643125,12732.650208,12733.643625,12734.644083,12735.647333,12736.64975,12737.648333,12738.647708,12739.642917,12740.649042,12741.643542,12742.645375,12743.646667,12744.649583,12745.651292,12746.649083,12747.644167,12748.644208,12749.646875,12750.64775,12751.625458,12752.651542,12753.650125,12754.650833,12755.645042,12756.647625,12757.651875,12758.647375,12759.627625,12760.652583,12761.649292,12762.62575,12763.656,12764.639958,12765.659167,12766.645083,12767.656125,12768.645917,12769.654833,12770.646792,12771.652792,12772.650708,12773.650042,12774.652,12775.653917,12776.648167,12777.650917,12778.65175,12779.655542,12780.650125,12781.648,12782.651875,12783.653833,12784.6485,12785.656792,12786.635,12787.654542,12788.655958,12789.652167,12790.651875,12791.65475,12792.654375,12793.624542,12794.659458,12795.650667,12796.656125,12797.649,12798.65925,12799.649542,12800.650458,12801.65975,12802.654875,12803.658125,12804.658292,12805.614958,12806.663375,12807.652917,12808.655,12809.656042,12810.651917,12811.66125,12812.657792,12813.652,12814.655333,12815.659917,12816.652708,12817.653667,12818.659167,12819.656417,12820.660958,12821.651792,12822.657583,12823.660875,12824.659917,12825.657917,12826.658917,12827.656083,12828.661917,12829.653875,12830.660375,12831.656917,12832.655125,12833.658333,12834.656667,12835.658625,12836.659292,12837.663667,12838.660583,12839.66225,12840.661417,12841.65725,12842.659625,12843.662417,12844.660208,12845.65675,12846.663625,12847.662125,12848.660708,12849.66125,12850.655833,12851.665875,12852.659542,12853.66625,12854.656917,12855.663292,12856.658708,12857.665667,12858.658083,12859.667,12860.65775,12861.665333,12862.658167,12863.664458,12864.665833,12865.665792,12866.659,12867.664292,12868.666583,12869.663417,12870.66225,12871.666708,12872.660417,12873.666458,12874.65825,12875.666042,12876.667958,12877.662042,12878.667917,12879.668,12880.663417,12881.664083,12882.664042,12883.669083,12884.662417,12885.66775,12886.662375,12887.666292,12888.66975,12889.667583,12890.666375,12891.668625,12892.668875,12893.649542,12894.673833,12895.661542,12896.672292,12897.6695,12898.666875,12899.665167,12900.666292,12901.672083,12902.663875,12903.670708,12904.670417,12905.671458,12906.665167,12907.670417,12908.665833,12909.664208,12910.667583,12911.666333,12912.667917,12913.666917,12914.666458,12915.667083,12916.667125,12917.669958,12918.666583,12919.670667,12920.664583,12921.668125,12922.671542,12923.672333,12924.668958,12925.668125,12926.673917,12927.668333,12928.658583,12929.675,12930.667042,12931.669208,12932.676042,12933.666542,12934.676542,12935.667625,12936.674833,12937.673083,12938.674125,12939.671125,12940.670333,12941.672708,12942.677875,12943.6745,12944.671375,12945.675333,12946.666833,12947.680083,12948.6545,12949.678292,12950.668833,12951.675542,12952.669417,12953.673417,12954.674208,12955.673833,12956.671167,12957.675833,12958.674208,12959.680042,12960.670625,12961.676417,12962.67075,12963.679667,12964.677,12965.67475,12966.671083,12967.678375,12968.672792,12969.676583,12970.674,12971.675917,12972.676583,12973.676167,12974.690708,12975.677333,12976.623208,12977.694125,12978.668292,12979.680292,12980.679917,12981.673,12982.675375,12983.678542,12984.680542,12985.678167,12986.678,12987.657542,12988.685708,12989.67975,12990.681917,12991.678125,12992.676083,12993.683167,12994.677375,12995.680833,12996.679208,12997.677292,12998.674958,12999.677917,13000.681167,13001.676917,13002.681292,13003.679458,13004.678417,13005.676833,13006.683,13007.679542,13008.680458,13009.677083,13010.657875,13011.683083,13012.684833,13013.674667,13014.667917,13015.683833,13016.679042,13017.678958,13018.683958,13019.67925,13020.688417,13021.632,13022.696,13023.679292,13024.684792,13025.678,13026.683917,13027.681458,13028.6785,13029.616583,13030.697667,13031.675375,13032.686042,13033.680833,13034.685,13035.679958,13036.684708,13037.679125,13038.684,13039.684333,13040.684875,13041.680708,13042.683792,13043.679375,13044.683708,13045.682417,13046.682083,13047.685417,13048.682125,13049.661792,13050.686125,13051.680708,13052.688208,13053.685167,13054.687292,13055.68475,13056.687792,13057.686083,13058.688333,13059.682042,13060.690167,13061.687708,13062.68925,13063.681875,13064.689833,13065.686083,13066.690042,13067.681417,13068.692417,13069.683375,13070.686375,13071.683917,13072.68125,13073.685375,13074.686042,13075.653083,13076.696458,13077.685875,13078.686083,13079.687333,13080.686458,13081.689333,13082.687292,13083.692458,13084.684167,13085.690042,13086.685625,13087.691,13088.691667,13089.69225,13090.687542,13091.688875,13092.689333,13093.692333,13094.692917,13095.690083,13096.685417,13097.695042,13098.682208,13099.69575,13100.692333,13101.690417,13102.690792,13103.691667,13104.689292,13105.692542,13106.687667,13107.693917,13108.693917,13109.693792,13110.688667,13111.694417,13112.6875,13113.696375,13114.689833,13115.694458,13116.690375,13117.696417,13118.688042,13119.690458,13120.692875,13121.690125,13122.689667,13123.692667,13124.689833,13125.693542,13126.693458,13127.689542,13128.691625,13129.692667,13130.690792,13131.694167,13132.699458,13133.687667,13134.693292,13135.69225,13136.692042,13137.697625,13138.697292,13139.692375,13140.698583,13141.691958,13142.693833,13143.692458,13144.648083,13145.704375,13146.688667,13147.6945,13148.662,13149.700708,13150.692458,13151.692792,13152.651875,13153.704958,13154.691292,13155.695875,13156.692458,13157.6995,13158.692458,13159.694333,13160.693708,13161.699333,13162.695583,13163.693875,13164.697667,13165.699875,13166.6945,13167.696125,13168.6945,13169.695625,13170.694333,13171.695708,13172.700167,13173.698042,13174.694458,13175.699708,13176.69875,13177.66525,13178.706333,13179.694875,13180.697375,13181.701708,13182.695792,13183.696792,13184.703,13185.700958,13186.675625,13187.705375,13188.698542,13189.699667,13190.700333,13191.696125,13192.704167,13193.69975,13194.698042,13195.698542,13196.705208,13197.663917,13198.713042,13199.694625,13200.681958,13201.682667,13202.704667,13203.528083,13204.745333,13205.687292,13206.704,13207.700292,13208.700875,13209.705625,13210.700917,13211.699333,13212.679292,13213.708208,13214.701375,13215.703125,13216.702625,13217.706458,13218.699542,13219.703208,13220.703417,13221.700833,13222.699417,13223.676042,13224.714583,13225.700708,13226.701667,13227.708792,13228.704458,13229.697792,13230.704792,13231.703958,13232.707458,13233.709375,13234.703542,13235.702708,13236.706542,13237.70225,13238.7035,13239.704708,13240.706458,13241.704042,13242.702417,13243.705875,13244.708,13245.702333,13246.706417,13247.707833,13248.710542,13249.705917,13250.702667,13251.708125,13252.707917,13253.688708,13254.710875,13255.704458,13256.70825,13257.683417,13258.705375,13259.706417,13260.705167,13261.707542,13262.707042,13263.707375,13264.705875,13265.711833,13266.706875,13267.710375,13268.706042,13269.708708,13270.709542,13271.707583,13272.708958,13273.712333,13274.708417,13275.695542,13276.714458,13277.712042,13278.714292,13279.708958,13280.713,13281.709958,13282.709458,13283.711708,13284.715292,13285.7085,13286.710542,13287.712625,13288.715458,13289.713833,13290.715083,13291.712333,13292.711792,13293.7135,13294.715208,13295.709458,13296.716667,13297.709542,13298.717583,13299.708,13300.711625,13301.711833,13302.710292,13303.725917,13304.706708,13305.71825,13306.71275,13307.713333,13308.714083,13309.710375,13310.712667,13311.71375,13312.7105,13313.718042,13314.711875,13315.7135,13316.718833,13317.709833,13318.713,13319.717708,13320.714167,13321.719542,13322.718417,13323.710875,13324.715875,13325.712542,13326.714958,13327.713125,13328.71325,13329.7125,13330.7215,13331.714917,13332.709917,13333.714458,13334.715167,13335.719333,13336.719333,13337.715208,13338.721208,13339.719667,13340.719042,13341.697458,13342.7225,13343.717917,13344.717875,13345.71925,13346.719167,13347.717875,13348.720208,13349.718792,13350.719458,13351.718792,13352.720375,13353.720583,13354.713292,13355.722667,13356.720458,13357.72525,13358.71775,13359.72075,13360.721875,13361.723333,13362.718375,13363.723125,13364.720667,13365.724958,13366.727125,13367.721958,13368.727792,13369.702333,13370.7405,13371.718375,13372.704042,13373.704708,13374.710333,13375.702292,13376.675917,13377.726417,13378.700458,13379.734667,13380.719583,13381.741042,13382.72525,13383.722083,13384.725833,13385.723417,13386.727667,13387.722833,13388.72625,13389.722125,13390.72575,13391.725542,13392.725083,13393.728083,13394.729042,13395.725333,13396.726333,13397.7315,13398.723917,13399.725208,13400.725125,13401.725375,13402.726833,13403.724917,13404.724375,13415.10325],"weight":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"weightType":"samples","threadCPUDelta":[6930,262,880,1002,900,999,937,1000,1002,996,958,990,957,893,1040,912,934,926,1009,896,984,817,840,963,1025,927,948,968,968,953,920,983,959,819,1090,877,1060,936,931,966,1015,874,1004,1040,939,977,972,941,1004,970,948,1031,957,974,975,949,1013,897,1035,903,1046,973,964,982,993,944,997,772,1213,898,1015,977,979,952,967,1016,959,973,987,986,973,967,993,933,960,997,960,969,975,974,975,949,979,971,992,996,957,979,971,986,877,1053,978,957,995,981,957,957,984,967,981,964,980,976,964,983,957,957,977,1002,968,971,959,994,973,938,1031,970,964,973,983,968,982,958,989,963,987,964,968,892,968,760,1199,1003,917,988,971,963,1004,949,999,972,953,972,993,963,975,1000,974,939,998,984,978,957,972,993,930,998,970,953,991,982,955,947,904,962,992,1003,948,995,950,978,963,937,1014,949,994,988,969,981,952,992,969,970,1007,988,940,1014,930,1015,955,953,1007,960,940,998,973,977,947,1009,958,972,996,959,1000,972,983,981,996,962,983,991,958,981,993,964,1002,982,976,972,974,997,967,951,958,978,990,967,993,995,970,995,935,990,957,985,968,1007,964,965,997,994,942,1000,963,950,975,992,952,991,956,979,977,978,999,969,984,988,978,957,1000,975,966,963,988,984,957,994,1000,951,1006,953,979,1004,985,965,969,981,991,971,973,914,1033,970,984,998,930,983,975,950,992,935,1011,971,993,961,996,976,986,946,1005,987,985,976,963,974,1009,951,966,1009,948,985,982,983,1009,948,995,972,1000,988,988,985,944,993,964,988,968,984,1009,975,996,973,963,966,981,997,962,978,992,980,963,1015,949,1000,955,990,992,964,956,986,905,969,963,953,1008,951,1012,963,981,935,1001,953,998,971,993,978,958,977,962,1016,948,1001,978,948,998,950,971,989,981,984,997,929,975,963,972,1005,953,968,973,968,958,977,981,983,988,931,982,983,946,996,757,1220,864,999,965,1006,963,974,963,998,963,1004,958,981,974,1006,975,966,1009,941,1006,986,988,969,951,1001,962,1020,933,981,981,973,977,982,1007,976,952,1013,949,983,1003,978,970,982,975,960,1001,960,967,974,1007,945,990,970,978,977,999,994,932,974,972,942,1011,964,967,971,993,1006,956,998,961,984,974,969,1002,967,991,993,949,999,951,1004,978,974,966,1005,962,986,967,997,987,964,981,1012,964,974,1007,962,968,984,959,1001,959,973,1010,964,979,987,956,1006,994,977,952,985,983,978,1006,955,1001,981,954,980,1001,997,921,984,997,962,965,974,1003,973,956,985,997,959,968,940,1038,967,984,972,994,952,994,971,981,1004,983,956,965,1021,945,993,1000,968,958,1008,986,947,1007,956,987,983,964,994,940,995,992,946,994,991,983,953,1009,983,962,968,963,992,976,998,976,969,988,957,956,969,1007,981,978,947,978,979,988,991,981,957,992,966,994,961,1004,967,970,997,969,965,998,982,980,975,976,985,967,1028,943,981,1014,947,975,1004,962,1008,981,960,991,963,956,985,978,983,1013,981,980,950,987,954,980,1014,947,1008,954,989,967,1012,958,976,990,978,993,975,948,974,945,971,989,1003,949,993,995,958,995,972,949,990,955,984,1011,959,971,974,982,976,985,982,981,989,966,962,995,979,1000,939,998,1006,966,965,983,981,996,976,986,974,1011,980,978,957,970,998,1000,962,990,983,983,980,984,1001,974,962,989,965,966,985,994,976,976,982,989,978,980,1011,947,973,1001,996,942,979,1013,947,1012,959,1001,983,970,1009,981,970,962,1005,951,1009,970,968,977,1017,944,983,973,1035,931,980,1003,994,977,955,984,995,974,980,989,967,982,999,996,969,972,968,1004,960,1008,963,969,992,1000,958,986,949,1010,962,974,1003,979,946,1008,954,987,1003,960,1008,949,1015,957,963,980,1005,959,998,957,980,945,1002,975,970,974,968,968,982,987,965,987,956,1004,963,959,924,1083,913,958,993,960,968,971,1004,959,966,985,979,952,1010,967,971,999,995,959,966,1009,974,972,953,976,979,999,993,971,985,945,976,979,1002,940,952,996,989,966,961,962,995,987,958,971,1011,981,951,1017,945,1001,966,978,980,996,988,970,970,1005,950,1016,969,954,1003,948,991,958,1014,970,984,959,996,932,1022,947,1005,956,991,984,975,984,961,1018,950,1000,1001,955,974,985,1010,955,970,981,987,965,1009,967,989,958,964,964,987,997,956,999,964,970,1009,975,979,952,985,973,992,969,989,977,990,977,965,994,985,951,988,1004,974,981,935,1009,952,980,984,992,972,987,975,997,944,1061,925,1001,971,1022,951,975,985,975,1014,954,993,963,1000,973,958,986,974,1004,958,999,991,947,954,1007,948,961,994,948,985,989,968,978,983,1002,964,976,1003,964,978,993,964,988,1009,970,948,989,969,985,1003,955,971,993,977,876,1082,979,968,979,993,989,968,987,990,989,953,972,996,962,971,1001,974,965,1007,975,951,988,972,997,947,980,987,996,964,1016,976,953,1015,943,1010,948,979,946,979,983,1006,958,976,988,953,982,929,1012,977,1003,950,1013,873,1065,942,971,1002,993,968,951,986,978,1002,967,973,994,981,974,992,962,991,954,964,990,969,1046,906,993,984,1002,976,992,963,1011,952,988,968,972,1006,990,981,962,1004,953,977,1000,996,976,973,975,995,953,962,971,1001,976,966,1011,956,1003,963,978,970,977,972,983,1005,988,963,960,929,985,997,944,1006,961,1004,951,987,1006,972,961,977,988,978,1006,958,1008,970,978,979,961,998,949,1007,952,1006,975,975,979,986,962,962,986,987,976,955,990,964,997,950,998,973,983,945,955,986,987,968,969,972,988,986,973,1001,959,1009,957,979,1008,984,971,970,1012,944,972,910,1033,967,1009,948,980,987,1000,982,962,960,970,1015,947,1007,983,961,996,944,978,975,994,998,930,1006,958,978,986,987,978,1005,964,1010,954,978,988,985,954,967,971,796,1123,901,966,1000,904,1002,956,958,981,978,970,969,977,1008,959,1007,975,942,999,983,949,976,995,977,954,980,979,969,972,994,989,987,955,1010,946,1001,976,965,978,980,959,978,967,1005,947,954,931,913,976,1032,898,994,991,943,997,957,981,972,988,986,976,1008,932,991,985,950,999,977,948,963,999,949,959,932,959,1006,978,979,952,996,949,991,974,973,979,970,978,950,878,1087,950,1000,976,950,980,973,1000,983,962,985,953,968,991,968,953,967,1008,962,972,978,969,993,972,997,964,862,1087,961,960,987,966,993,963,992,965,979,983,969,1004,960,986,962,983,960,974,969,996,972,977,973,949,998,953,979,966,983,1006,944,976,978,998,962,980,1001,942,980,983,987,991,965,979,985,975,972,984,975,999,952,997,992,971,955,967,1006,952,979,976,995,954,985,989,961,983,991,974,959,973,993,950,975,981,987,966,996,985,975,941,985,931,978,983,970,986,968,957,978,971,982,999,943,985,989,959,989,960,976,993,953,998,978,983,950,975,1001,979,968,954,916,1028,949,974,1002,941,989,972,941,1007,939,952,970,999,943,1002,951,1004,934,959,981,949,969,999,942,980,970,967,974,999,939,1001,981,973,963,974,987,946,969,1006,927,1011,961,949,968,979,964,984,960,983,999,938,1000,965,949,972,987,953,972,970,998,966,997,970,974,971,957,980,948,971,987,956,986,972,965,967,986,974,980,971,971,973,986,974,957,982,945,1004,954,955,997,970,970,974,961,990,956,969,952,976,1000,909,982,927,998,957,962,1002,970,932,1002,963,951,963,1007,958,1006,970,944,987,930,1007,956,957,986,945,1011,960,961,981,961,983,963,968,999,948,966,970,966,958,987,896,1088,947,949,923,1024,990,938,998,953,982,979,961,996,981,981,961,973,958,964,960,991,965,975,992,970,923,1003,967,980,937,972,997,938,1005,959,960,979,990,956,974,957,1001,968,940,990,960,998,964,970,949,998,951,983,959,974,954,954,971,1010,942,1003,948,978,961,973,1000,944,969,1003,968,954,989,949,963,964,1004,933,980,977,972,956,970,984,964,948,999,955,983,978,942,939,975,982,966,994,950,1000,951,976,951,996,950,997,972,941,996,946,1000,962,950,977,1000,974,952,982,976,967,990,964,945,997,953,958,996,981,944,974,973,977,972,1001,963,987,930,976,994,951,970,989,956,987,949,973,988,969,976,975,974,1001,957,970,959,979,984,956,950,941,996,951,971,967,1005,956,983,961,977,969,999,914,890,1043,960,993,960,989,949,969,996,945,1001,946,985,980,953,975,965,968,986,963,998,966,992,942,992,962,997,975,946,980,960,988,958,970,1000,983,957,964,964,981,965,971,970,987,951,995,988,989,981,955,965,980,937,978,999,952,997,934,982,971,968,1013,939,985,991,984,968,953,1004,928,966,981,941,969,964,939,983,935,946,992,959,978,946,978,938,952,967,915,1019,895,973,991,980,944,958,992,963,990,982,971,958,1000,990,867,1042,943,973,991,984,923,934,1019,923,969,983,964,959,961,981,964,974,965,969,998,963,959,990,961,948,996,958,981,977,978,958,995,988,958,992,935,981,1001,940,1000,953,967,993,945,953,1007,932,972,1005,981,973,980,947,979,956,968,1007,938,977,967,969,1005,944,982,993,953,976,999,943,957,1002,977,946,968,998,977,937,975,966,951,984,976,948,980,989,996,959,932,1007,958,978,962,963,991,980,944,982,952,879,1003,948,987,965,964,969,965,1003,938,967,1000,972,954,959,991,968,940,994,954,996,962,952,966,975,1004,971,966,987,941,983,967,996,943,975,998,974,947,972,995,986,875,1052,985,931,945,1013,986,960,956,976,960,965,1009,943,979,997,968,963,990,941,990,983,947,973,977,989,965,953,979,971,996,960,976,989,970,983,970,958,991,962,960,999,957,980,961,982,949,1008,949,969,990,984,949,975,979,944,995,968,957,976,985,962,1001,949,1001,929,1003,933,1001,971,936,979,994,931,1021,949,1007,950,992,937,1007,935,970,975,983,996,977,949,992,982,949,993,979,965,991,947,966,974,968,994,968,991,933,997,954,943,975,964,977,982,972,983,892,965,989,953,981,984,988,947,1000,951,993,936,1002,969,982,963,990,947,1001,944,975,945,998,937,985,985,994,952,947,970,994,971,971,950,973,963,1006,972,950,974,966,958,996,991,960,973,949,1000,975,969,969,984,941,991,982,954,982,990,945,1012,945,987,981,925,992,966,936,981,953,994,932,988,934,956,969,1004,953,974,982,980,992,979,936,962,997,901,976,1000,923,936,997,1012,889,1015,1004,927,988,989,948,948,985,976,982,959,906,1005,986,949,988,971,950,962,1007,947,1005,944,993,941,968,993,968,946,980,981,960,976,972,977,967,1003,956,980,994,978,944,974,995,948,993,945,962,973,968,977,959,972,928,1033,971,953,992,960,952,951,995,965,937,970,949,985,966,951,958,944,1017,952,966,973,961,981,981,842,1019,944,977,941,998,980,939,1003,944,1004,952,962,970,996,965,990,967,961,960,1001,950,994,971,953,979,943,969,984,965,999,971,973,962,976,1006,963,971,947,977,993,959,1002,953,1001,934,964,967,1014,927,922,917,1059,932,980,992,940,998,937,994,957,966,993,977,971,976,954,974,1014,975,960,979,953,959,953,973,982,963,983,986,962,961,966,979,979,961,974,991,962,988,964,951,967,1011,963,987,956,958,969,963,993,984,939,984,968,988,951,1001,960,972,955,944,985,965,1003,967,981,968,966,986,940,1014,982,965,952,975,966,962,974,958,970,997,946,978,963,975,975,1002,941,971,1013,964,981,937,966,979,994,944,1016,934,976,969,1012,941,1001,976,957,980,984,950,985,973,951,968,970,962,969,969,963,989,964,967,995,970,956,957,996,966,949,985,958,997,946,994,966,953,982,943,993,965,987,960,994,967,962,1006,955,982,955,965,991,951,971,996,976,938,996,946,980,985,1000,974,932,936,938,973,968,1011,944,983,969,937,993,954,958,865,1084,953,1022,962,960,984,935,1005,972,949,971,1001,963,909,997,962,961,962,1012,966,966,966,966,983,998,932,1003,945,1000,981,972,940,995,983,964,978,968,962,955,974,949,991,960,983,977,962,935,1004,969,940,997,908,1018,994,949,982,968,990,948,998,972,958,990,951,996,954,964,987,946,1009,932,985,978,982,984,957,953,1005,941,977,1000,938,1010,964,973,951,982,959,966,988,948,1011,968,958,985,932,1004,937,876,1076,963,995,948,978,969,992,975,959,963,1012,940,963,1015,934,972,989,947,973,964,985,990,959,968,967,946,975,995,975,960,984,997,927,961,949,987,961,991,963,966,928,1006,950,964,1000,957,1001,968,974,981,954,943,999,936,995,965,965,973,984,960,1003,950,985,970,998,962,981,980,943,980,959,970,987,962,988,951,1005,971,949,976,987,962,1007,974,952,974,967,998,953,1002,941,979,992,968,992,962,970,985,962,979,957,990,956,966,960,973,964,942,997,924,1007,933,992,986,960,952,989,961,986,993,979,945,965,987,971,959,969,963,984,970,982,997,962,941,982,968,1001,950,975,998,973,946,974,934,992,923,988,926,976,965,929,985,954,943,958,958,931,960,958,986,967,969,977,933,1026,933,976,981,965,970,979,995,949,1000,982,980,979,938,977,974,879,1073,990,942,971,945,945,962,951,978,966,958,941,1001,966,951,979,996,828,985,957,985,939,960,979,898,996,937,979,954,990,960,952,956,961,966,954,944,892,1061,935,952,902,1011,979,938,913,994,940,944,938,997,924,789,1161,934,966,934,949,886,968,922,1042,981,949,953,949,984,992,960,952,809,1143,778,1046,831,1174,693,1196,853,1028,907,988,905,1001,913,995,976,926,962,979,996,931,924,1026,934,952,1021,940,998,938,988,962,943,995,943,977,958,941,957,996,953,995,940,1005,964,957,988,914,993,992,902,976,1008,993,948,923,923,971,962,998,940,928,915,973,960,931,978,904,1047,906,968,862,1054,1002,914,953,969,846,1101,905,928,985,975,979,956,992,954,995,876,1031,944,977,995,954,949,990,973,992,942,997,970,946,917,966,938,984,961,979,977,957,977,969,948,975,984,966,977,959,873,974,828,1107,953,951,962,988,974,913,925,988,985,878,888,1050,990,998,909,1003,952,963,966,858,914,1012,889,896,986,998,882,1033,949,928,852,971,954,906,977,922,919,1003,953,980,940,971,983,907,981,946,978,942,982,917,942,927,801,981,804,1065,892,779,1045,906,877,929,920,844,953,866,920,878,956,877,992,882,882,921,793,1060,809,902,957,868,801,1057,958,902,1010,972,961,968,994,948,985,966,975,1009,942,1008,948,982,958,998,956,960,992,942,978,957,999,959,951,975,871,1059,997,942,952,980,996,955,999,941,968,972,962,1003,965,941,952,974,987,958,968,879,1012,1000,954,997,969,939,987,955,980,955,1004,981,942,999,960,953,967,1011,938,992,991,936,977,967,971,979,922,998,994,982,941,997,960,986,942,998,969,968,987,937,992,985,941,995,944,990,984,966,972,962,919,1054,931,960,1005,952,991,969,963,950,952,981,968,1007,929,1004,949,970,979,962,972,972,1006,951,971,986,981,937,983,976,940,1007,937,993,975,940,984,954,975,975,987,996,936,1004,962,964,975,895,1051,942,998,934,979,883,1072,948,968,988,939,969,998,942,976,1002,963,938,998,964,990,958,963,984,972,1011,890,982,963,985,993,946,974,976,985,948,1006,930,999,934,964,980,981,991,970,933,966,976,997,940,1004,983,966,923,1013,962,936,988,951,976,965,890,1008,1008,934,989,976,926,1007,960,964,972,964,998,960,951,977,1004,951,949,835,1109,995,962,1004,961,940,1003,940,1009,926,1026,910,980,934,1022,989,976,982,978,958,947,999,958,945,975,1004,940,1008,961,957,989,951,998,955,962,989,996,971,947,995,972,950,985,974,944,981,1016,977,935,976,942,999,947,932,1006,977,924,968,969,987,965,991,945,979,980,1010,957,963,995,940,1001,936,967,953,980,917,982,978,948,971,978,969,958,973,274,613,935,1118,831,998,891,971,958,956,999,940,986,946,980,974,953,968,934,994,935,985,991,955,972,973,940,775,1069,1012,907,1005,973,960,970,965,974,963,974,938,1012,936,1002,944,1000,938,960,991,974,964,983,757,1135,972,943,898,1096,936,965,945,972,1005,938,984,965,966,966,999,959,965,968,940,947,1000,962,970,938,986,991,938,993,980,970,954,1007,962,965,952,977,944,1001,941,959,1007,960,947,958,999,957,943,955,983,990,932,947,989,976,952,976,978,952,977,966,949,981,966,973,975,965,986,954,950,969,962,990,946,992,968,949,1009,950,951,977,1001,978,942,963,990,952,974,985,956,1011,945,979,992,967,954,998,963,956,973,947,970,986,966,952,975,994,980,960,964,992,974,971,940,968,974,989,949,968,967,966,980,974,974,973,971,946,1000,981,959,958,977,1008,971,906,979,969,991,936,919,1077,956,965,1003,951,994,964,970,989,930,991,951,981,964,932,969,951,982,973,1002,964,983,962,981,959,991,953,962,984,971,962,976,992,954,996,962,964,986,944,963,986,975,942,977,978,985,985,838,946,952,942,1000,1010,940,975,975,960,995,950,945,990,958,978,991,895,1022,964,970,972,968,963,1014,889,983,973,986,955,992,991,945,965,998,975,978,965,966,964,960,963,992,983,944,998,977,978,924,1000,954,988,967,993,968,967,951,979,951,997,945,1006,959,976,941,941,970,962,985,962,879,1045,987,1053,965,844,1012,942,952,1024,885,1019,780,1082,997,810,1120,886,974,1075,832,987,973,952,979,967,965,938,971,978,976,953,975,1008,945,974,975,983,957,974,995,958,949,950,1005,964,986,949,970,885,1076,972,965,955,952,1055,945,996,971,949,999,985,958,993,956,969,1018,975,963,953,967,1021,881,984,990,977,970,954,974,966,987,984,960,987,972,953,1008,969,961,1003,963,983,950,975,970,974,994,958,980,951,977,1012,939,996,975,977,978,960,999,969,954,961,1528,326,958,1118,827,1120,771,1012,972,1442,378,1024,950,903,1077,825,972,972,1055,871,1087,817,937,1052,929,978,974,981,932,990,975,994,972,966,984,973,940,962,986,958,1017,961,960,994,946,1007,960,949,976,972,971,980,964,964,975,1005,958,1005,974,964,977,983,982,992,950,783,1206,948,1010,949,1005,972,983,953,975,975,1008,942,981,969,1003,981,952,993,949,997,970,960,1010,972,945,1006,982,951,955,971,975,982,970,958,972,982,981,992,973,971,968,955,983,1048,930,946,975,994,942,1033,1035,797,1000,968,1020,819,1064,978,931,974,961,1000,983,973,990,949,979,986,978,1012,898,1013,981,993,976,945,986,972,979,991,962,993,971,976,995,954,984,978,998,946,940,976,1011,940,981,970,988,963,934,1017,980,940,966,975,980,932,1019,967,1007,970,967,999,978,962,976,981,989,997,935,985,973,979,1007,946,988,1000,956,972,980,983,977,982,979,940,1027,979,959,970,943,1033,1001,955,1007,975,943,976,1002,976,961,976,978,961,984,969,999,940,979,1018,944,970,972,981,979,980,968,985,981,981,999,973,982,949,958,991,794,789,1194,889,1012,957,2289,28,1215,793,1110,1048,1021,840,1046,894,959,933,837,1125,965,1006,954,962,973,1011,945,1014,934,1005,988,960,963,957,1025,956,976,962,944,975,1004,958,976,973,1010,912,994,974,965,1011,945,990,995,983,953,1022,957,993,968,957,987,894,963,1008,976,935,977,981,999,951,996,982,987,948,953,975,981,1005,947,970,972,987,961,962,974,994,947,972,965,999,969,943,981,991,963,972,1008,952,988,944,995,945,1003,933,993,960,971,967,986,969,938,978,1009,947,1005,974,949,973,995,989,932,1016,945,994,935,1007,971,964,981,943,1013,977,932,1006,954,964,978,985,960,971,969,976,977,809,20,1231,867,1035,932,833,1075,923,1000,953,1050,895,968,977,982,992,958,972,980,940,973,964,1008,947,966,1008,974,966,964,930,1022,988,939,985,977,1004,944,997,977,964,956,996,951,981,991,981,937,974,961,976,959,1000,968,954,981,981,976,972,935,978,962,410,1259,938,976,959,972,756,1152,869,1003,923,983,806,850,710,908,962,911,1030,779,994,992,920,1012,906,1002,869,1041,981,982,967,982,930,989,930,977,968,942,968,999,960,952,977,971,969,991,950,959,984,953,996,948,963,838,1118,934,1002,934,965,1000,935,990,1009,940,996,953,977,955,1019,937,993,969,983,952,989,959,971,989,936,983,971,976,976,979,958,995,969,980,954,973,951,991,942,989,954,978,1038,842,915,1008,1030,873,965,955,882,1092,958,719,1052,706,1131,1057,975,933,983,1003,964,965,943,980,972,921,957,989,972,953,990,964,949,978,941,985,973,989,977,1004,949,936,1019,957,946,992,973,954,983,977,959,982,992,941,996,935,970,979,992,932,968,1000,979,972,940,965,1011,965,910,991,1012,939,960,977,970,941,1000,948,971,970,1009,935,1000,953,971,966,977,988,985,974,944,983,942,998,944,980,979,956,979,953,973,1006,963,987,952,972,813,715,922,1256,697,1334,729,802,911,653,1336,801,1061,756,1086,1020,941,989,946,1023,957,923,910,940,959,920,1071,951,927,993,936,954,975,980,980,937,968,998,946,971,977,969,965,1008,945,985,983,971,976,911,995,942,990,970,956,975,996,923,978,964,981,973,990,985,978,936,998,960,1002,966,947,988,964,983,933,990,983,943,962,979,1002,938,973,967,999,976,953,1002,935,992,957,1000,935,960,976,965,983,1002,961,952,1008,1194,563,924,1021,989,847,1033,957,929,970,880,825,828,919,773,1014,906,790,888,786,839,851,826,858,942,1015,854,776,868,896,881,842,829,849,946,994,905,850,856,834,792,887,791,943,942,978,784,733,755,882,787,985,813,884,1006,934,875,780,943,838,978,839,801,825,1110,993,950,1006,968,946,999,974,958,980,973,974,956,971,989,996,968,1530,233,1078,928,1022,874,1011,936,957,951,988,955,939,973,1027,906,979,985,984,950,975,986,958,971,1006,941,1009,983,940,986,987,964,987,962,970,973,967,1004,945,966,1002,932,1008,938,983,982,987,970,954,1001,964,952,1007,938,976,982,987,1000,983,938,972,955,788,1098,1616,84,1061,907,973,808,969,935,819,789,1002,807,914,992,896,1042,896,970,957,991,988,910,975,956,976,956,965,991,969,944,977,997,960,978,952,978,717,1258,954,1017,942,938,999,905,970,957,970,971,985,985,958,958,990,951,1006,944,1020,906,1013,996,956,947,995,962,964,930,952,984,957,965,983,928,971,993,944,1001,943,996,973,956,1003,943,947,975,1048,990,975,967,985,966,983,957,985,946,1083,650,1046,893,962,959,964,1044,957,924,918,932,946,985,962,956,948,995,929,945,981,945,981,976,991,969,965,949,987,985,985,983,975,958,950,976,976,997,956,963,984,970,958,1014,934,975,994,992,957,954,1028,1000,1143,633,972,876,953,983,854,1047,976,992,972,949,972,994,953,997,974,961,989,954,925,984,948,993,972,977,924,972,993,981,971,948,1006,943,964,999,957,984,977,999,924,973,969,998,967,945,980,961,961,1002,981,941,957,996,958,970,1005,940,1010,934,995,980,952,977,937,968,921,1007,993,977,945,985,953,991,958,963,998,954,978,983,977,974,961,980,983,989,943,983,997,941,1001,900,1000,1316,212,1248,1046,800,959,932,975,872,1097,729,1056,965,760,1164,903,966,951,998,972,952,992,942,967,970,986,950,983,922,993,956,965,959,926,996,932,1003,955,946,997,948,977,965,997,968,995,945,984,975,936,988,988,963,973,949,996,963,985,963,976,951,1002,908,983,961,965,983,989,935,1000,972,982,949,990,851,1070,958,982,1075,932,844,1601,171,1181,925,920,871,864,1145,932,1016,972,951,982,985,986,986,953,953,1001,946,969,969,963,971,973,1002,917,986,948,989,992,959,994,970,989,963,935,974,967,983,842,1104,873,1018,885,1034,980,843,1059,971,917,1046,817,1086,673,1227,948,1018,939,975,1006,869,874,1047,859,985,957,901,893,993,957,966,964,1004,962,949,975,958,978,1004,954,876,930,1068,939,946,897,1031,885,815,1102,994,871,1013,787,1121,986,875,1005,935,931,990,1169,605,1579,277,1136,928,996,949,869,913,956,796,1069,930,968,971,976,950,976,998,940,970,1001,984,921,974,912,974,979,968,961,974,945,975,969,969,988,957,1010,832,1092,975,965,955,988,926,956,997,985,965,952,972,966,998,962,983,941,985,995,946,1001,978,953,979,945,948,966,1011,960,954,984,952,967,969,939,980,969,976,1789,109,1164,914,1767,176,1093,732,1073,937,262,1531,1112,933,943,1001,956,995,961,986,957,969,950,980,981,960,975,951,941,991,966,970,858,1063,948,1016,959,976,965,973,945,966,999,980,944,998,946,979,984,944,966,984,981,962,985,965,955,994,952,982,970,988,950,997,975,948,974,989,965,972,994,944,999,944,973,995,946,1003,971,975,947,998,951,972,971,983,980,969,932,1011,927,973,980,962,1009,980,952,966,989,980,981,946,987,969,949,967,975,995,854,1563,195,1166,886,957,816,1039,752,1040,944,944,983,949,1009,911,981,954,989,971,982,970,938,1012,935,998,1045,876,990,979,955,968,962,993,965,965,973,982,1000,948,1001,971,958,978,938,980,994,954,1018,958,987,937,991,956,993,967,965,1007,949,1005,959,952,974,974,987,978,957,973,994,988,950,975,967,942,978,994,966,964,992,988,946,989,966,933,980,977,933,991,936,998,975,957,983,950,983,949,992,951,978,983,958,980,975,978,976,964,964,1163,820,1003,1016,786,904,961,908,979,877,762,1190,827,994,989,962,968,995,945,952,996,977,940,976,993,946,983,998,958,982,941,962,1005,969,959,972,1015,932,982,975,990,975,963,986,931,999,938,1004,970,961,976,964,948,1000,949,967,986,994,959,983,966,960,1007,978,943,1001,944,980,982,997,956,978,994,964,999,925,979,974,980,1012,954,927,987,985,967,945,992,904,716,1194,951,1017,952,964,960,1007,957,961,991,962,1013,938,1003,933,1000,950,936,1009,963,928,1549,92,939,923,928,1017,864,941,897,782,1120,814,1217,761,916,1118,907,926,999,982,934,1001,952,999,959,980,942,1024,953,946,1029,924,980,973,960,951,980,980,976,968,995,953,966,984,987,952,1015,960,945,964,991,976,993,955,998,955,994,1002,969,931,946,959,998,967,981,933,1020,937,990,945,984,977,997,942,1000,967,963,1051,909,1266,803,1003,752,961,795,889,1161,863,952,1012,974,946,981,960,979,962,982,946,963,1008,971,960,950,979,977,966,975,992,970,977,942,975,1009,965,959,952,1009,958,993,940,1016,945,972,997,971,956,941,985,986,958,951,994,977,948,966,1005,983,983,964,960,989,971,947,971,978,955,1011,938,1006,974,944,988,981,977,974,931,986,985,933,969,973,998,949,1006,930,988,987,968,963,930,970,964,998,948,1009,973,944,994,946,1085,141,1211,2363,75,1127,946,993,959,980,916,1001,967,955,974,949,974,1052,647,1220,993,970,978,992,953,950,1011,965,949,1006,972,933,992,993,938,969,984,996,967,942,982,977,980,980,996,947,981,976,975,998,939,973,990,937,1010,964,968,958,977,1004,971,950,961,972,971,1005,944,1015,965,970,937,986,969,982,972,955,943,978,1003,950,972,1001,960,955,970,1004,959,965,976,982,974,974,972,991,976,949,1265,2438,71,1388,598,1331,1653,32,950,817,2140,42,1164,969,1008,870,982,978,961,977,992,957,938,973,978,978,994,969,979,939,1007,939,1002,971,944,977,1002,964,986,937,976,983,936,970,974,992,952,972,972,988,956,980,1000,983,964,954,982,984,991,978,950,990,940,1004,959,969,1001,953,960,974,1008,961,957,998,972,978,981,961,976,977,982,969,994,980,961,950,967,982,991,947,1002,951,962,1015,948,977,972,997,970,965,974,1007,946,967,928,1277,568,1062,956,924,1034,973,943,956,778,1082,981,1366,1114,61,1273,716,1209,892,983,972,970,984,984,936,971,987,944,972,969,989,969,944,972,962,993,978,948,964,974,996,942,972,987,965,991,960,971,972,978,975,962,969,960,982,945,969,972,988,992,893,997,976,950,873,1057,999,917,983,962,969,1015,963,945,1002,946,1010,968,950,968,989,959,972,995,953,979,984,942,985,963,963,1002,939,1000,974,953,969,1010,937,969,982,981,983,960,1002,963,974,977,988,980,847,1040,996,939,805,376,427,587,188,1017,980,1379,499,527,817,995,885,1118,881,951,987,957,977,982,986,950,971,983,960,951,972,1000,958,978,951,985,958,954,1000,944,988,961,976,970,992,961,1005,957,975,960,947,971,991,963,965,989,955,954,971,987,999,956,986,967,970,966,979,980,1000,940,1075,804,963,1004,987,942,943,943,1000,974,930,1001,965,915,985,946,837,1120,950,1016,962,981,1223,624,1056,961,982,839,619,840,899,1052,1368,294,1115,919,981,962,977,994,948,986,977,993,966,969,951,964,967,1008,949,953,991,959,992,980,919,988,1002,945,969,992,965,954,1012,958,939,986,948,989,975,975,962,949,1003,969,984,959,989,969,972,936,1001,947,990,976,961,972,994,942,1003,943,976,975,978,967,1007,933,994,975,969,941,969,995,940,1015,954,973,982,982,946,984,981,975,960,944,972,988,963,952,1006,940,1009,941,965,979,977,992,960,975,996,957,967,962,1000,976,943,973,974,996,956,985,971,944,974,991,593,506,752,864,398,956,1095,883,961,455,1576,864,971,984,964,958,981,974,995,961,968,956,1005,941,1013,935,992,960,957,981,1004,946,986,967,965,1000,949,993,982,950,964,968,919,1008,1003,948,974,991,983,955,996,986,977,972,957,971,991,931,962,982,955,1008,944,992,978,945,972,984,952,967,1001,968,947,965,984,987,989,946,988,956,998,982,956,947,1011,957,951,970,994,954,973,984,982,990,947,982,980,1003,931,994,967,949,987,950,1005,933,977,1010,937,982,986,628,755,451,983,734,873,1154,647,805,1032,991,873,886,1014,991,729,1243,806,705,1248,974,1005,927,991,952,985,982,941,981,932,970,1004,951,979,970,975,960,977,957,1003,942,1011,959,969,942,972,978,998,951,966,988,967,987,976,1009,931,993,957,1005,941,990,960,995,943,990,941,969,979,1004,940,966,992,965,957,979,973,1001,955,991,964,937,1002,944,985,998,958,950,937,992,978,957,968,993,957,959,979,977,990,959,972,983,960,998,944,964,1006,944,982,959,975,1002,972,941,999,946,962,976,972,986,971,974,975,839,1221,764,666,620,1242,712,781,1038,908,889,1043,899,699,1177,845,958,978,969,966,961,1019,961,976,942,990,932,974,971,955,981,956,997,953,990,976,976,931,1005,954,984,950,983,1004,964,977,935,988,953,968,1011,960,989,970,939,1008,953,979,971,961,971,982,982,948,983,975,995,952,956,988,942,968,996,980,959,979,915,966,998,903,952,965,977,958,971,1009,972,962,957,1011,948,955,953,968,960,862,1119,958,947,960,985,980,976,964,951,971,911,1044,943,977,977,992,1326,179,1390,1512,21,1592,426,1333,580,898,1059,864,837,761,1173,973,923,880,1071,983,952,983,984,987,956,979,967,969,952,982,966,960,1001,961,959,970,966,911,946,1000,951,970,996,955,953,1008,934,980,968,998,979,929,964,945,988,935,1003,956,1003,956,975,949,986,938,1005,975,965,982,1005,918,934,927,987,987,943,1007,938,985,966,983,955,971,937,988,953,978,983,947,996,961,1008,936,931,1037,945,995,972,952,978,993,967,952,975,983,968,959,990,954,956,983,962,973,943,988,961,958,998,940,972,756,906,1069,836,1086,894,780,967,647,4,1241,1290,334,1003,888,956,805,1171,943,951,973,973,997,963,945,1011,934,965,980,977,970,986,931,1001,963,953,963,969,960,1005,949,969,1008,967,972,944,961,938,1000,992,973,945,985,987,955,964,922,961,971,1001,943,967,1010,944,1022,937,967,982,969,989,980,977,965,931,964,1004,944,1006,935,986,969,999,962,952,1012,964,979,941,987,987,961,967,932,971,1003,941,982,970,967,962,1008,969,940,974,977,986,947,1008,933,984,980,966,977,986,388,979,866,1188,466,727,38,1238,846,994,832,985,1149,630,1031,893,1008,933,978,988,934,996,967,1000,944,964,989,985,955,1003,944,996,967,955,997,937,990,971,969,986,945,976,1005,975,954,974,998,963,959,959,999,947,991,952,998,948,966,969,968,972,961,1013,956,982,967,943,988,997,962,959,971,987,934,899,1032,974,954,991,955,1000,927,989,955,984,960,980,955,1008,954,968,997,237,464,352,547,432,468,356,460,700,728,897,964,2088,100,1195,732,1157,770,1176,905,775,1241,845,817,456,1604,951,968,981,954,973,988,968,937,963,973,984,977,958,995,948,966,1001,953,968,973,996,920,994,968,969,974,991,951,985,954,986,975,971,1006,966,937,1002,976,969,977,948,914,954,975,944,989,935,1001,978,966,968,957,1021,938,978,970,1004,967,950,977,981,999,984,959,945,1000,971,945,999,975,981,996,959,992,987,945,976,974,1006,978,947,1009,1003,969,906,980,1006,949,975,996,958,996,979,948,1013,949,994,952,986,982,965,954,988,1000,975,942,975,1009,947,982,978,977,1006,947,985,974,985,994,960,964,975,1006,975,949,972,978,987,983,1020,921,985,981,929,998,998,954,1003,929,5,1236,924,702,1286,1033,903,514,1273,1557,367,727,1159,889,1048,1002,948,998,939,989,977,960,956,981,990,949,974,982,981,999,955,1000,949,979,977,976,992,985,960,972,990,954,996,958,998,967,967,981,996,924,978,964,991,955,970,993,963,996,991,948,997,793,1154,947,1012,934,987,955,1004,927,1000,948,997,960,955,962,947,900,1077,932,1045,951,991,986,1013,968,889,1085,904,1081,971,981,1003,978,939,1019,1012,971,966,956,1010,940,1019,949,982,998,962,985,973,983,977,988,1008,960,976,984,974,1010,953,984,1007,959,976,1003,956,964,977,986,982,1011,959,974,967,992,968,984,980,1010,970,983,934,1004,958,963,977,972,977,989,950,975,974,960,967,994,957,1011,949,950,970,919,623,2,1240,912,987,1044,892,892,931,275,1142,774,1097,922,994,988,954,955,964,1013,942,986,968,983,962,976,970,949,992,970,972,972,992,997,216,1680,953,940,1006,935,988,948,997,952,945,965,976,993,813,1145,948,982,963,1004,975,985,939,1010,986,972,985,972,983,944,956,957,1003,930,968,966,1020,956,957,987,999,970,986,951,984,965,1002,967,939,964,990,956,983,999,961,964,1004,937,990,956,996,976,940,983,998,949,977,1009,816,1131,957,963,954,988,953,996,934,976,984,993,932,958,891,1747,44,1694,316,1138,323,336,1038,950,966,930,870,1067,966,966,986,948,980,1008,946,963,1012,953,974,988,946,998,962,990,969,931,998,941,1002,943,1002,953,1000,949,982,1015,924,972,975,956,958,978,1001,984,885,1059,955,973,1005,939,971,1006,951,961,953,988,989,953,995,940,1000,954,1006,955,975,970,985,989,972,943,977,996,943,1004,942,1012,969,946,976,1013,962,969,983,976,952,994,962,975,976,1007,951,974,950,974,1002,953,961,999,948,978,954,966,969,976,999,981,947,977,983,618,1171,984,599,1678,170,998,588,1193,674,887,1151,950,868,829,879,1153,969,991,958,990,950,1000,951,1000,975,951,969,970,976,973,968,971,991,969,978,953,988,958,970,970,984,968,978,968,1011,958,954,980,962,1000,971,974,955,950,978,954,989,955,970,986,887,1036,977,853,1101,965,968,977,979,998,949,962,942,1000,980,951,993,971,967,945,965,999,941,1009,958,979,960,979,949,988,970,962,1002,954,925,1005,950,962,1010,942,974,963,1012,928,997,949,982,990,941,985,977,984,960,976,991,971,960,815,954,2008,114,2351,10,1562,399,1057,980,1020,851,997,1122,499,1047,922,964,981,1001,927,915,1064,932,974,994,937,1015,933,1013,937,994,969,950,1005,888,990,963,968,952,1003,962,973,977,977,967,949,978,989,967,972,943,995,967,970,1018,954,940,967,992,985,963,998,951,966,975,1000,934,971,992,934,973,986,971,968,966,987,965,973,972,985,962,991,977,994,960,1011,944,973,954,999,953,967,1004,947,1007,942,973,1001,948,1016,937,929,987,952,979,983,1012,896,937,913,947,997,968,968,996,906,1001,984,956,995,951,949,1002,968,968,973,953,979,1005,976,2109,298,1391,287,1160,837,858,1077,1030,871,904,712,1064,954,986,920,1009,917,984,982,950,1007,964,936,989,987,951,972,945,964,987,978,966,933,992,790,1160,976,966,942,992,982,938,979,997,940,978,967,958,871,1080,920,982,999,971,940,987,987,954,964,938,949,943,1001,986,944,979,982,967,965,979,966,967,970,973,976,960,982,1016,946,952,983,960,958,984,951,1005,966,944,995,975,958,997,948,971,1003,954,968,963,959,978,1004,951,967,970,978,993,948,1009,954,1002,970,938,973,982,962,1004,973,957,979,945,975,1008,934,1013,941,971,1692,233,1248,492,1448,628,849,980,892,980,936,1019,915,968,909,882,1056,962,1006,938,1012,962,981,945,973,975,974,974,979,972,998,954,960,984,987,965,989,946,988,983,941,979,992,954,1010,951,959,968,984,961,969,980,977,972,976,952,971,956,974,1011,937,983,950,975,967,982,994,959,958,994,962,996,943,995,983,974,967,980,1000,947,984,971,984,900,1000,945,989,968,972,940,1008,967,961,975,942,977,1016,932,981,989,958,969,982,969,992,960,1002,938,974,989,959,996,973,966,957,980,960,976,1768,411,917,815,1056,903,887,1022,946,991,931,785,918,801,1245,955,969,1000,944,980,960,986,981,977,971,992,960,986,947,1001,972,928,982,990,957,956,964,994,975,952,994,960,859,1115,949,985,941,999,999,943,1003,964,960,992,934,985,964,952,959,1013,968,952,942,976,957,1004,936,974,980,995,955,947,979,1000,941,974,1009,929,970,981,955,980,975,949,1009,938,991,939,1004,937,978,980,935,984,987,926,983,956,968,998,976,930,998,959,951,959,973,994,958,949,976,978,1001,959,979,942,929,1006,1076,804,1027,946,867,997,962,771,1189,917,1012,938,985,984,982,930,978,973,974,978,947,976,1010,976,945,972,959,985,973,950,972,968,972,983,969,983,967,971,941,982,957,1006,961,986,878,1009,942,960,1002,939,994,942,994,947,1010,949,1012,934,971,983,980,1002,925,1010,960,963,969,1003,967,965,956,981,978,974,958,1007,952,933,867,1033,967,954,979,972,988,975,960,950,994,975,941,986,1006,963,954,985,975,951,962,985,975,989,946,966,954,1008,966,964,982,896,1043,913,906,1051,951,1008,975,907,984,694,987,1083,644,1083,846,1026,789,1088,1008,920,943,908,1074,980,963,956,1015,941,982,1001,942,966,981,968,1004,742,1190,889,995,952,963,987,933,1008,943,979,960,995,962,973,983,954,1002,955,955,990,950,980,956,1003,763,1201,937,981,1001,964,953,977,995,951,982,1019,930,987,956,1004,962,945,985,946,990,977,950,1008,951,943,945,982,967,946,962,969,997,959,974,968,961,968,972,964,970,1010,942,956,1012,925,1010,916,994,956,947,858,1092,942,1011,1007,745,1051,1127,773,798,1229,825,1082,855,1102,748,936,1000,930,994,962,958,978,1011,955,963,990,972,944,968,1019,950,990,976,947,986,954,992,939,988,956,1002,942,972,989,987,973,953,980,986,941,1020,937,981,1006,960,965,989,952,966,961,993,929,984,979,995,945,976,963,974,997,879,1002,906,1015,830,1141,968,990,952,954,973,950,981,950,975,992,941,972,998,973,950,956,985,950,980,966,936,1034,935,989,993,951,969,974,1001,960,962,970,962,972,969,996,960,983,965,975,981,982,988,976,975,946,988,1003,765,997,1242,912,1103,480,1067,944,921,691,1117,1045,1068,888,775,1130,956,961,974,998,973,940,935,990,976,952,1008,941,983,767,1167,958,1003,981,940,977,980,1004,958,974,950,1000,955,961,1015,944,985,981,998,911,1013,982,951,1006,943,961,979,1003,938,985,977,954,1001,945,981,969,994,974,964,959,981,995,932,975,971,991,963,952,976,971,980,1001,962,945,982,958,1008,975,920,1013,937,983,980,969,989,953,1004,956,962,991,935,971,972,961,999,940,1006,973,943,976,973,961,1010,948,979,979,994,975,933,1000,942,974,967,794,941,961,1136,685,790,1221,895,989,984,1480,333,945,1032,958,976,989,972,970,988,984,930,986,986,993,921,983,963,994,935,963,973,959,1009,977,932,1001,969,970,991,953,956,998,951,969,991,1000,959,953,989,979,986,980,897,1052,941,979,994,944,999,958,1003,948,969,1005,946,1003,948,980,957,994,960,1000,957,958,973,971,1010,940,34,1918,1018,918,1010,965,946,984,1003,966,958,1001,962,950,971,964,943,1003,968,927,1007,943,975,997,962,956,981,930,992,998,938,995,927,993,959,932,384,412,1309,675,1521,439,1396,341,1211,722,976,950,907,1017,945,1024,963,978,976,905,1031,972,992,900,1015,937,996,938,961,1009,969,946,999,959,969,974,959,994,974,948,988,925,992,968,945,885,1116,921,988,953,955,956,1038,920,981,974,1002,968,930,978,960,988,990,963,974,948,980,985,965,990,955,1001,949,1000,957,978,995,955,969,968,994,942,997,947,993,935,1033,931,953,968,975,909,982,936,1005,937,952,968,992,930,965,1003,958,941,973,986,953,963,983,977,944,1006,948,981,971,992,971,963,947,977,990,946,988,978,979,945,990,993,967,941,1003,979,941,997,905,1135,987,969,1119,664,1107,650,1041,1096,812,994,973,908,800,2265,26,1218,866,1002,823,1096,977,936,997,944,992,961,986,996,963,1003,946,1007,940,985,975,942,955,980,974,990,957,1001,980,938,1003,969,925,1002,966,1000,949,995,954,965,982,983,955,992,954,1005,965,969,947,974,970,1000,959,967,978,984,956,1001,949,983,1002,981,937,1009,948,1004,944,1003,948,998,959,960,1001,946,1021,952,960,978,967,962,981,949,969,1020,944,987,997,852,1055,888,990,964,977,960,1008,964,966,969,956,984,1006,968,950,971,982,980,973,947,1005,942,976,986,959,966,992,929,1002,967,972,970,975,997,1624,283,1085,767,1750,514,675,1011,850,1061,840,1004,825,1037,987,942,999,944,995,956,966,974,982,940,972,976,979,1004,950,992,966,957,1011,961,970,958,983,964,941,968,951,946,983,991,942,956,1003,946,962,991,941,995,969,931,1003,947,1012,944,989,949,975,989,962,954,1004,973,962,962,968,999,945,1004,964,980,968,962,963,971,977,973,1028,883,995,1014,928,969,983,965,995,940,984,1006,943,996,944,1013,951,950,937,976,1000,970,974,974,1001,949,1007,938,957,1061,2231,71,1183,835,1042,998,873,885,982,932,843,1134,921,997,971,943,980,974,979,980,982,977,941,970,962,1014,933,987,946,992,959,994,981,831,1101,963,938,943,1005,970,991,961,977,959,973,1000,973,940,1007,921,1018,891,969,980,970,982,958,976,984,985,961,960,1009,976,972,952,1007,966,954,946,1010,947,953,960,963,933,957,982,961,958,1002,927,981,968,967,977,998,955,999,947,994,991,964,962,947,973,988,968,999,926,983,965,971,1002,939,967,972,977,975,986,969,958,953,980,965,972,985,996,922,1000,965,951,961,977,1003,943,967,823,763,2252,34,1350,679,1032,985,872,945,1079,1004,1018,728,1144,921,987,971,991,951,997,937,1005,955,993,974,938,972,971,963,998,966,942,948,1010,948,1007,943,954,1000,941,970,961,991,948,991,994,946,1003,943,970,948,984,989,974,965,962,961,981,973,971,985,976,967,974,949,980,983,952,972,1012,967,926,996,942,984,990,954,970,974,1002,959,973,1001,948,957,970,992,949,1003,932,975,991,932,976,1008,936,997,944,977,1005,935,1003,965,1002,937,974,964,977,1009,927,962,971,1006,944,996,963,957,949,943,983,793,1130,976,995,964,914,1014,848,880,1474,333,1176,791,1015,1025,933,1376,365,1015,938,772,666,1268,943,974,988,948,983,1007,934,1003,985,946,962,978,1015,939,1001,939,981,957,977,979,962,959,1009,937,978,969,969,1008,936,1002,948,998,965,952,988,987,972,987,989,960,947,972,994,944,1010,950,994,972,943,1019,932,995,971,982,989,965,975,931,975,922,1078,959,967,980,971,935,1010,930,975,960,1022,923,974,1009,941,966,968,974,1001,940,976,974,983,982,981,1005,959,941,989,963,1005,939,889,1039,972,993,953,1012,931,967,971,977,1012,939,966,765,833,694,1261,1261,460,955,993,897,740,1121,937,1081,762,1081,916,955,881,1110,917,992,972,978,977,1012,965,948,977,992,960,1009,947,980,974,995,950,969,977,969,980,986,938,1009,955,975,952,975,981,987,985,972,955,984,1010,952,979,975,1001,950,969,972,979,983,996,951,969,981,1009,939,976,967,968,1007,919,989,933,982,972,716,569,1008,1107,870,1079,928,959,993,961,991,947,1015,984,899,1042,708,183,254,1163,933,1005,940,890,947,1003,1006,1590,259,1001,642,788,1410,957,963,975,951,950,956,962,972,962,958,853,1056,976,1002,917,1006,932,958,974,988,890,977,964,971,970,973,972,996,954,908,1021,937,986,983,1000,964,980,948,991,977,948,824,1114,951,936,1002,973,775,1061,295,924,1091,963,749,898,908,1021,879,1181,1207,508,833,1224,844,1090,941,990,970,954,939,999,971,950,956,991,946,952,981,938,1000,901,1000,985,909,750,1240,925,954,984,977,967,954,935,989,957,935,975,977,975,939,973,993,941,969,970,959,991,978,928,966,964,976,991,971,984,932,934,979,988,931,974,1323,484,1027,982,789,1099,819,789,925,1002,871,980,967,965,989,946,925,1033,814,1114,992,986,974,964,960,933,972,663,1268,956,963,978,971,965,975,924,1024,967,968,975,968,985,991,953,996,970,968,957,986,957,971,984,960,992,945,1000,967,962,945,1005,945,968,973,961,968,966,975,969,968,985,958,983,1021,942,973,953,989,981,948,997,1044,96,1310,834,1021,387,1225,1162,1331,63,1368,139,1207,610,1202,909,976,894,960,968,975,798,1145,847,1073,943,937,1008,916,933,739,1223,926,959,970,989,938,995,970,895,1007,945,1006,926,957,964,964,956,971,981,968,980,959,1007,942,995,952,974,970,964,957,980,978,947,968,1010,946,996,945,960,1033,908,976,1012,936,965,1011,903,994,951,976,981,979,939,981,964,910,950,1014,951,1039,265,1337,865,971,952,823,1076,961,1077,497,870,1187,864,961,946,1015,928,989,987,950,956,921,968,939,765,1169,953,921,953,1025,674,957,1193,956,977,980,943,995,959,959,995,961,971,1006,911,974,982,995,933,963,1013,961,929,994,936,1005,971,952,978,976,1001,938,966,979,1009,935,982,970,982,779,1157,956,977,960,975,974,998,939,964,863,862,1217,917,972,967,977,1003,952,1004,966,975,943,985,968,1003,930,970,982,971,885,842,1192,888,1194,707,809,1237,925,874,1000,776,669,1059,980,974,882,642,1289,796,571,1356,984,941,492,1298,149,1941,924,965,966,884,1046,951,966,975,972,943,941,976,961,982,986,971,942,979,993,962,917,966,952,971,950,1010,981,960,978,934,983,941,985,888,1008,1043,933,975,970,987,958,969,1010,945,999,951,960,977,983,961,984,1000,941,1011,876,1017,932,973,1006,948,981,976,950,971,987,972,988,940,999,950,975,997,973,961,970,986,941,1000,975,917,984,990,955,968,996,952,970,997,941,981,964,974,963,1013,932,958,1016,975,985,950,982,999,945,972,974,953,977,1000,951,992,970,974,962,935,1005,950,979,991,952,999,919,976,508,1700,580,605,1034,1044,1194,439,1124,896,864,896,1161,871,1843,41,1023,996,993,999,964,939,987,975,982,971,957,977,974,976,978,957,950,970,999,936,995,970,964,962,966,973,974,973,974,969,930,963,1004,945,991,956,996,943,973,1004,950,975,1013,959,960,975,905,989,965,984,947,999,944,982,984,969,1010,929,985,1016,906,797,1216,880,1026,927,982,959,992,959,997,984,954,991,957,1002,957,953,968,967,1011,926,1000,966,1003,953,979,999,963,970,916,1099,882,997,955,998,962,1003,968,948,1162,709,1166,847,1133,867,899,940,1001,870,1097,1432,307,1095,937,992,951,969,1003,932,1007,964,972,965,980,951,1002,938,982,911,1083,938,984,1000,954,1000,958,976,952,954,959,974,972,980,991,982,932,969,977,1008,923,982,956,980,981,989,964,957,982,982,979,1011,923,989,1003,960,950,1004,966,975,956,961,974,987,966,960,974,963,991,956,1018,936,992,957,985,985,955,956,982,983,962,956,979,977,975,998,937,971,985,951,971,973,952,994,954,999,960,950,985,961,1000,960,967,967,960,922,1000,815,1123,796,1149,952,991,945,965,956,984,991,918,1012,977,970,981,980,974,971,990,968,995,869,1033,934,992,979,954,890,1423,458,1355,535,1158,859,970,1017,546,739,1330,1183,628,1081,905,757,1197,974,994,937,985,953,1000,967,943,1002,957,973,949,977,970,942,980,1007,933,978,971,1016,937,967,990,956,997,938,980,959,975,970,1001,937,1005,970,927,973,973,957,1008,961,937,932,973,829,1111,959,981,889,1019,1009,979,940,973,1001,944,960,991,950,988,971,979,941,973,987,935,969,982,929,889,1017,963,1246,1225,294,1987,394,1216,11,1933,32,1268,841,952,929,231,1707,885,949,953,956,972,940,938,961,995,960,980,606,1277,943,950,924,977,1005,930,988,948,987,984,972,939,978,982,986,936,970,992,954,969,958,969,990,966,937,965,992,945,630,1301,912,949,883,1125,948,1008,929,988,969,1000,952,980,968,995,962,958,1009,914,962,968,995,960,967,939,974,999,948,960,997,981,940,981,964,989,975,949,983,974,982,956,971,960,963,1013,972,965,411,976,1033,789,974,1000,960,892,647,1127,1153,997,866,896,920,1104,553,1354,933,949,1000,979,962,969,955,981,964,989,929,975,969,957,975,937,991,949,1016,942,971,1014,943,983,974,1006,937,969,989,926,978,991,966,974,973,956,1003,947,958,1003,948,977,995,969,963,947,1005,953,983,963,1007,958,959,964,985,982,978,952,985,955,997,972,950,1006,934,1024,938,978,966,911,1046,987,933,977,985,892,1052,950,1010,915,979,974,971,999,969,982,935,968,1010,926,979,982,967,1007,968,949,1001,957,990,946,1013,925,989,972,965,967,983,682,919,979,1611,847,948,271,851,833,1385,546,1225,818,1067,840,1101,906,1013,972,932,994,862,1118,961,944,970,961,973,969,974,990,952,960,978,984,943,1000,942,973,997,950,1016,936,976,979,970,973,970,980,984,977,924,982,982,954,1001,955,994,951,992,954,998,975,963,944,973,977,929,975,963,1017,934,959,977,1001,970,945,960,1002,943,993,971,998,949,741,1202,982,968,998,924,991,980,939,1004,962,958,940,981,997,944,991,977,977,938,1136,790,1024,866,557,950,833,1009,882,1115,327,1583,957,999,974,1002,950,973,980,961,987,931,1008,944,971,977,972,937,1003,966,943,1003,972,944,1004,936,970,995,982,950,986,983,981,965,947,981,981,959,990,973,963,964,987,952,982,997,945,1005,941,980,978,994,975,967,968,987,979,984,958,929,977,998,946,972,982,997,959,977,976,974,948,963,992,957,971,1011,936,998,972,961,976,1001,969,953,981,963,996,988,982,917,978,951,978,944,986,943,982,973,976,824,1131,922,987,989,967,1303,620,1033,1730,0,1013,262,1323,1153,848,1061,905,981,843,960,521,1093,1321,912,964,1008,947,1002,962,978,939,994,990,924,990,983,938,958,975,975,1000,962,973,965,948,994,965,933,951,954,976,971,958,969,961,967,921,1009,971,996,967,968,970,966,987,1011,931,1011,955,961,983,898,800,1140,945,986,956,969,1007,926,971,1007,873,1036,888,899,1083,868,952,965,331,1482,1018,967,857,650,549,318,338,522,320,416,403,297,193,379,328,632,470,607,554,1044,939,983,966,985,961,995,972,979,965,863,46,316,107,409,350,326,99,374,971,922,908,940,452,669,1282,889,1058,970,945,1027,969,917,1024,933,977,960,970,995,955,949,964,967,991,952,970,1007,932,982,986,959,999,944,1015,966,978,966,937,1001,948,966,971,988,953,962,960,1008,941,1015,932,993,990,968,952,978,970,1001,959,1017,931,995,989,957,978,974,970,970,972,1001,976,960,963,1009,951,1006,920,980,978,999,951,974,983,982,978,1000,969,986,922,999,920,985,985,907,121,22,150,281,646,778,731,746,456,393,285,491,298,515,431,776,536,744,586,761,569,735,370,953,976,1003,960,938,995,985,960,987,968,990,988,985,981,980,975,993,981,987,938,1009,983,977,987,988,434,739,438,908,845,435,626,782,659,530,441,762,979,986,929,994,975,983,979,994,983,988,989,979,990,986,989,970,983,990,975,1000,978,990,985,941,986,991,963,656,723,156,194,359,344,255,593,670,616,646,625,679,669,1034,928,999,953,988,987,988,985,984,977,982,990,966,997,983,989,987,987,986,991,978,982,996,978,989,978,982,991,992,980,629,486,839,420,794,309,707,749,734,961,523,713,786,755,624,823,761,584,963,990,987,982,981,987,988,993,976,990,976,997,974,989,984,993,992,990,978,972,992,980,995,975,981,985,983,990,983,988,949,769,16,176,156,546,677,795,726,146,185,18,184,967,1005,980,991,960,990,984,990,983,983,991,994,977,980,974,995,985,980,996,980,977,985,974,977,970,999,989,980,990,988,691,859,755,886,612,809,529,648,801,460,240,147,421,245,576,473,311,843,1007,978,987,985,970,989,989,979,990,986,993,988,984,995,980,988,975,998,979,962,1013,958,1008,976,995,977,994,990,546,72,96,261,810,389,686,772,854,489,815,719,392,168,684,147,169,730,1027,979,990,979,998,983,979,988,987,985,996,976,1003,977,993,979,981,993,988,972,990,988,980,988,997,983,925,457,5,251,718,501,799,571,751,578,741,212,20,741,603,636,789,967,992,974,984,976,988,996,975,984,995,983,993,965,987,986,981,985,991,975,992,987,979,995,985,989,574,709,579,791,36,335,324,876,588,619,137,9,796,860,1025,971,976,1013,965,977,997,964,991,984,992,987,992,965,992,987,985,986,992,987,982,990,993,748,761,293,22,36,54,82,302,37,33,106,274,1133,938,999,1006,980,978,993,923,996,975,989,993,988,982,988,979,993,971,981,997,977,988,990,975,982,974,447,95,29,125,1182,928,1001,988,977,989,1005,976,987,990,985,990,992,990,987,986,991,988,992,982,991,983,987,982,993,988,537,407,571,715,431,26,21,157,39,64,6,1148,914,1011,983,987,988,988,990,980,986,974,993,974,981,988,994,986,992,981,981,995,989,976,972,1012,984,983,391,47,0,1202,920,994,962,988,982,979,985,1004,980,990,987,989,980,981,987,988,971,994,981,996,988,989,992,987,974,992,963,987,953,998,984,987,213,54,12,180,54,7,11,655,277,172,5,1176,903,998,956,1014,977,985,984,1000,976,990,971,993,986,988,989,988,995,976,987,975,989,987,985,987,984,990,947,1004,998,982,986,991,249,7,355,281,47,58,197,3,1219,927,966,977,999,986,987,990,986,992,982,978,992,985,988,995,982,980,986,983,993,989,984,984,988,984,984,990,352,92,13,474,109,82,135,0,111,526,972,985,990,988,984,970,1002,985,993,980,916,984,996,982,988,980,875,988,988,991,979,991,988,986,957,1028,956,975,985,1000,991,972,990,930,978,1012,977,985,990,979,978,991,907,907,1058,967,776,974,990,985,994,989,983,991,866,1128,953,999,987,977,992,983,992,983,990,980,976,993,983,988,989,798,928,1046,977,933,917,1063,963,986,993,984,984,986,987,991,978,990,961,988,981,988,982,983,972,651,966,999,988,997,986,685,3,154,248,86,0,454,917,1005,979,989,993,985,982,989,1008,983,988,992,972,984,868,962,1005,964,780,910,976,1007,963,959,1007,975,1001,963,989,987,979,978,982,988,926,951,1034,976,358,85,42,190,19,39,23,1204,869,957,1016,981,987,998,993,975,1005,964,991,976,996,985,992,984,980,989,996,845,972,1002,990,989,928,948,1032,979,993,954,995,985,1015,938,939,947,988,959,997,980,993,982,990,987,988,980,992,973,991,984,990,987,914,851,842,999,982,983,984,988,993,904,969,1010,976,995,963,946,1031,978,986,979,990,990,974,995,985,958,945,1006,991,1002,985,989,981,868,974,990,991,991,984,987,995,993,980,974,983,974,1003,964,997,967,995,984,980,1010,972,996,984,973,960,984,986,993,981,989,987,977,990,979,994,978,988,998,984,984,990,978,986,971,1003,981,995,994,994,981,980,991,987,986,992,984,991,988,834,973,999,983,987,989,978,989,992,987,985,980,992,988,977,990,979,911,962,968,967,970,992,974,959,989,983,994,979,992,986,985,981,948,953,1023,967,953,1031,974,987,980,992,989,989,984,992,984,993,991,984,983,989,970,980,982,989,986,980,994,927,966,1013,975,990,990,989,982,994,987,981,989,982,986,984,986,992,989,985,985,986,998,980,972,1049,918,1031,966,996,955,910,980,991,980,993,979,985,982,986,982,992,992,980,989,977,988,996,982,979,984,998,978,992,988,983,993,985,987,989,987,984,990,972,996,857,969,986,994,993,983,983,832,963,976,987,1009,967,989,989,983,993,850,978,980,994,984,986,977,994,984,942,1025,962,975,1002,964,977,977,997,985,990,984,988,980,990,985,990,988,992,981,993,984,991,982,994,989,982,988,995,988,976,990,984,987,990,993,971,997,983,985,997,976,995,993,944,963,1014,963,996,978,985,992,804,894,1111,950,988,990,989,987,987,981,992,993,969,954,981,993,986,993,978,975,842,953,1024,962,828,974,986,980,980,990,983,976,875,966,1008,980,990,978,1002,975,982,989,986,987,965,982,984,944,1025,979,985,991,980,999,983,987,857,984,1001,980,993,975,986,992,980,991,993,983,985,986,981,990,978,993,980,989,986,979,850,983,994,949,958,1015,991,986,984,980,991,873,961,1018,981,967,1017,951,1005,975,997,984,994,983,992,977,989,971,987,983,989,984,991,972,981,981,990,980,921,962,1010,986,987,988,977,980,945,1028,977,992,978,1000,978,980,997,980,989,976,938,1038,973,988,987,988,854,1004,985,984,986,985,991,983,985,984,982,995,989,988,856,983,986,993,979,989,987,983,986,986,986,986,989,981,987,985,983,985,990,985,979,993,982,985,994,972,998,984,988,975,997,981,984,988,997,978,973,980,989,987,986,986,988,985,985,992,989,983,988,980,997,989,976,988,983,981,993,984,989,985,989,977,988,990,983,980,986,910,966,1006,977,1000,986,975,989,990,989,978,993,986,989,980,986,987,980,994,987,991,985,941,986,990,991,984,836,982,981,995,994,981,987,985,925,976,1005,980,992,989,982,996,981,986,975,982,984,990,992,969,979,978,989,977,924,955,1016,975,996,986,991,989,983,984,994,991,974,960,1007,979,996,985,984,986,986,977,994,982,991,989,987,1008,856,927,1056,964,995,971,982,988,987,982,990,941,959,1011,979,991,989,979,994,977,984,983,975,958,991,993,978,985,980,990,985,990,948,988,940,967,1019,977,903,978,1004,988,980,982,981,833,927,1045,971,727,974,999,981,964,926,1065,959,1001,980,991,987,986,985,993,983,984,987,992,978,990,981,988,992,990,969,1006,982,994,979,987,979,992,980,990,980,995,981,990,987,988,990,990,977,997,979,989,977,969,990,806,948,1030,964,990,993,993,983,982,982,982,990,984,994,979,986,978,993,988,988,980,980,982,867,973,996,985,984,988,990,989,995,979,986,984,985,985,990,984,995,965,978,985,984,982,990,972,984,986,985,985,989,989,985,981,988,978,993,989,975,992,988,983,964,986,983,996,980,990,978,942,1044,960,977,954,1028,979,965,939,1026,960,991,974,993,981,994,988,993,990,990,988,987,991,986,976,992,970,999,975,999,981,993,960,949,1032,978,982,991,980,986,996,984,961,1012,975,1001,974,988,991,976,983,986,973,941,1035,963,976,988,954,813,1203,930,1008,981,989,989,984,916,968,1018,980,989,987,994,987,988,988,979,962,961,1026,963,986,997,906,977,994,987,990,977,986,994,991,980,987,989,989,978,995,993,988,981,992,988,992,982,981,994,943,957,1007,980,988,966,985,991,981,994,988,987,981,991,966,960,981,999,983,986,991,986,910,974,1003,984,993,983,991,988,987,987,988,984,987,991,988,985,986,979,984,980,985,985,989,984,994,824,984,994,983,1000,964,1002,985,978,989,985,996,977,982,996,983,986,998,978,989,991,987,991,844,860,988,975,994,980,988,984,999,893,982,987,992,990,987,987,992,987,930,953,1018,983,980,987,992,985,992,984,985,984,993,851,978,954,982,995,979,993,989,989,979,993,982,992,986,984,990,966,1016,969,971,992,970,861,808,980,943,1032,972,1004,975,983,942,977,985,990,988,957,1008,986,986,983,988,994,961,972,978,979,993,990,990,989,504,6340]},"stackTable":{"length":86577,"prefix":[null,0,1,2,3,4,5,6,7,4,9,10,11,12,13,14,12,16,17,12,19,12,21,22,11,24,25,26,27,28,12,30,11,12,33,26,12,36,37,12,39,12,41,42,43,44,45,46,47,12,9,50,51,52,53,54,55,56,57,52,59,60,61,62,63,64,65,66,67,68,69,53,71,72,73,74,75,76,77,78,50,80,81,82,83,9,85,86,87,88,89,90,91,92,86,94,95,96,97,98,99,100,101,85,103,104,105,106,107,108,109,110,111,112,113,85,115,116,117,118,119,120,121,122,123,124,125,126,121,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,122,151,152,153,154,155,156,157,158,159,160,151,162,163,164,165,166,167,168,169,170,171,172,173,174,175,163,177,178,179,180,181,182,183,184,185,186,151,188,189,190,191,192,193,194,195,196,197,198,151,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,122,223,224,225,226,227,228,229,230,231,232,233,234,235,236,128,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,128,267,268,269,270,271,272,273,274,275,128,277,278,279,280,281,282,283,284,285,286,287,288,289,117,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,327,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,345,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,367,386,387,388,389,390,391,392,393,394,123,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,415,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,151,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,200,527,528,529,530,531,532,533,534,535,536,310,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,543,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,200,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,122,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,538,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,656,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,267,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,267,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,655,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,658,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,656,825,826,827,828,829,830,831,832,833,834,835,787,837,838,839,840,841,842,660,844,845,846,847,848,849,850,851,852,853,854,855,404,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,278,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,238,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,658,950,951,952,953,954,955,956,957,958,959,960,961,962,826,964,965,966,967,968,969,970,971,972,973,272,975,976,977,978,951,980,981,982,983,984,985,675,987,988,989,990,991,992,993,994,995,996,997,998,999,676,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,825,1026,1027,1028,1029,1030,1031,744,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,115,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,281,1060,1061,1062,1063,1064,1065,1066,1067,1036,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,933,1089,1090,1091,1092,1093,1094,1095,1096,1097,278,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1116,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1138,1169,1170,1171,1172,1173,1174,1175,1176,1163,1178,1179,1180,1181,311,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1196,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,744,1270,1271,1272,1273,1274,1275,1276,1073,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,618,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,278,1324,1325,1326,1327,1089,1329,1330,1331,1327,1333,1334,1335,1336,1337,1338,618,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,618,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,239,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1386,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1437,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1471,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1429,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1527,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1566,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1526,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1563,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1566,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1653,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1533,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1569,1711,1712,1713,1714,1715,1716,1717,1718,1719,1602,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1325,1738,1739,1740,1741,1742,1743,1744,1745,1411,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1460,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1494,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1508,1812,1813,1814,1815,1816,1817,1818,1539,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1583,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1609,1845,1846,1847,1848,1849,1850,1851,1633,1853,1854,1855,1856,1857,1660,1859,1860,1861,1566,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1687,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1545,1916,1917,1918,1919,1667,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1727,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1395,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1759,1984,1985,1986,1987,1988,1989,1990,1991,1992,1791,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,1508,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,1529,2023,2024,2025,2026,2027,2028,2029,2030,2031,1711,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,1608,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,1700,2066,2067,2068,2069,2070,2071,2072,2073,1901,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,1608,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,1895,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,1702,2117,2118,2119,2120,2121,2122,2123,2124,2125,1936,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,1949,2145,2146,2147,2148,2149,2150,2151,600,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2166,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2194,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2179,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2249,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2287,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2290,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2276,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2304,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2304,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2348,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2362,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2388,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,243,2485,2486,2487,2488,2489,2490,2491,2492,130,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2531,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2558,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2522,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2610,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2638,2685,2686,2687,2688,2689,2690,2691,2692,2622,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2646,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2646,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2609,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2643,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2743,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2788,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,128,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2839,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,224,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2920,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2945,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,2911,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3011,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3038,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3013,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3039,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3074,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3010,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3035,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3068,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3167,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,239,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,1387,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3240,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3231,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3315,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3354,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3363,3391,3392,3393,3343,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3357,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3371,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3371,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3406,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3373,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3452,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,618,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3553,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3578,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3545,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3635,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3664,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3629,3713,3714,3715,3716,3717,3718,3719,3720,3659,3722,3723,3724,3725,3683,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3676,3744,3745,3746,3747,3748,3644,3750,3751,3752,3753,3754,3755,3683,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3691,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,1739,3802,3803,3804,3805,3806,122,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,223,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3843,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,744,3901,3902,3903,3904,1074,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3937,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3925,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4004,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4000,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4101,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4131,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,1074,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,128,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,3964,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,3980,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4038,4300,4301,4302,4303,4304,4305,4053,4307,4308,4106,4310,4311,4312,4313,4314,4315,4316,4317,4318,4138,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4331,4337,4338,4339,4340,4341,4342,4343,4344,4232,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,278,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,1325,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4379,4389,4390,4391,4392,4393,4394,1325,4396,4397,4398,4399,4400,280,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,128,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4414,4438,4439,4440,4441,4442,4422,4444,4445,4446,4447,4448,4449,4450,4451,4452,239,4454,933,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4456,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,932,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4482,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,239,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4514,4520,4521,4522,4513,4524,4525,4526,4527,4528,4529,4530,4531,1313,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,1380,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4558,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,1410,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4626,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4630,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4653,4686,4687,4688,4637,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,1747,4701,4702,4703,4704,4705,4706,4707,4648,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,115,4745,4746,4747,124,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4812,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4778,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4849,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4902,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4845,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4972,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,4758,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,1327,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,4549,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,4559,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,4582,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,4576,5100,5101,5102,5103,5104,5105,5106,5107,5108,4620,5110,5111,5112,5113,5114,5115,5116,4552,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,4584,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5037,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,4589,5165,5166,5167,5168,5169,5170,5171,5172,5036,5174,5175,5176,5177,5178,5179,5180,5181,5182,5083,5184,5185,5186,5187,5188,5189,5190,5191,5135,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,4560,5212,5213,5214,5215,4601,5217,5218,5219,5220,5221,5222,5223,5224,4550,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,5249,5250,4599,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5037,5324,5325,5326,5327,5328,5329,5330,5331,5332,5064,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,5354,4552,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5053,5376,5377,5378,5379,5380,5138,5382,5383,5384,5385,5386,5387,5388,4693,5390,5391,5392,5393,5394,5395,4653,5397,5398,5399,5400,5401,5402,5403,4693,5405,5406,5407,4653,5409,5410,5411,5412,5413,5414,5415,5416,4728,5418,5419,5420,5421,5422,5423,5424,3226,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,4713,5439,5440,5441,5442,4627,5444,5445,5446,5447,5448,5449,5450,4728,5452,5453,5454,5455,5456,5457,5458,5459,5460,5445,5462,5463,4728,5465,5466,5467,5468,5469,5470,5471,4673,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,5489,5490,5491,5492,4641,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5462,5505,5506,4688,5508,4672,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5410,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,4699,5535,5536,5537,4654,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552,5393,5554,5555,5556,4688,4691,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,1382,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,4641,5587,1387,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,4730,5646,5647,5648,5649,5650,5651,5652,5429,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,4712,5665,5666,5667,5668,5669,5670,5671,5672,5673,3232,5675,5676,5677,5678,5679,5680,5681,5682,5648,5684,5685,5686,5687,5484,5689,5690,5691,5692,5693,5694,4643,4627,5697,5698,5699,5700,5701,4654,5703,5704,4674,5706,5707,5708,5709,5710,5495,5712,5713,5714,5715,5716,5717,5718,5719,4691,5721,5722,5723,5724,5725,5726,5727,5728,5729,5703,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5724,5743,5744,5745,5746,5747,5541,5749,5750,5751,5752,5753,5754,5755,5756,5757,4709,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,3215,5772,5773,5774,5775,5776,5777,5452,5779,5780,5781,5782,5783,5784,5785,1387,5787,5788,5789,5790,5791,5792,5793,5794,5795,4729,5797,5798,5799,5800,5801,5802,5803,5804,5655,5806,5807,5808,5809,5810,5811,5812,5813,5439,5815,5816,5817,5818,5819,5462,5821,5822,5823,5824,5467,5826,5827,5828,5829,5830,5823,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,4653,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5483,5855,4637,5857,5406,5859,4654,5861,4712,5863,5864,5865,5866,5867,5787,5869,5465,5871,5872,5873,3226,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5419,5891,5892,5893,5894,5895,5896,5897,5449,4729,5900,5901,5902,5903,5904,5905,5906,5907,5908,5909,5910,5911,5912,4631,5914,4642,5916,5700,5918,4654,5920,5921,1386,5923,5924,5925,5926,5927,4637,5929,5930,5931,5932,5933,5934,5935,5936,130,5938,5939,5940,5941,5942,5943,5944,5945,1089,5947,5948,5949,5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,5996,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,5962,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6030,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6081,6112,6113,6114,6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,6149,6026,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6171,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,280,6235,6236,6237,6238,6239,6240,6241,224,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,1103,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6012,6277,6278,6279,6280,6281,6282,6283,6152,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6067,6298,6299,6300,6301,6302,6303,6304,6305,6101,6307,6308,6309,6310,6311,6312,6313,6314,6315,6157,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6364,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,5955,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,6404,6405,6406,6010,6408,6409,6410,6411,6412,6413,6414,6020,6416,6417,6418,6419,6030,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,6434,6076,6436,6437,6438,6439,6440,6441,6442,6145,6444,6445,6446,6330,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6454,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,932,6475,6476,6477,6478,6479,6480,6481,6482,1325,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,280,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,718,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,5787,6523,6524,6525,6526,6527,6528,6529,6530,6531,1410,6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6540,6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6534,6610,6611,6612,6613,6614,6615,6616,6617,6618,6541,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629,6630,6631,6534,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6539,6653,6654,6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,6689,6690,6691,6692,6693,6568,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6529,6712,6713,6714,6715,6716,6717,6718,6621,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6573,6742,6743,6744,6745,4638,6747,6748,6749,6750,6751,6733,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6698,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6655,6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6604,6801,6802,6803,6804,6805,6806,6807,6808,6809,6810,6811,6523,6813,6814,6815,6816,6558,6818,6819,6820,6573,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,5712,6833,6834,6835,6836,6837,6755,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6570,6869,6870,6871,6872,6873,6874,6875,6876,6534,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6588,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6637,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6667,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,6989,6990,6991,6992,6772,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,6523,7005,7006,7007,7008,7009,7010,7011,7012,7013,6621,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,6802,7032,7033,7034,7035,7036,6613,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,6568,7055,7056,7057,7058,5774,7060,7061,7062,7063,6978,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,6770,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,7094,7095,7096,6527,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,7124,6858,6705,7127,7128,7129,7130,7131,6890,7133,7134,7135,7136,7137,7138,7139,7140,7141,6577,7143,7144,7145,6782,7147,7148,7149,7150,7151,7152,7153,7076,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,7169,7170,6873,7172,7173,7174,7175,7176,5789,7178,7179,7180,7181,7182,7183,5930,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7191,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,5863,7231,7232,7233,7234,7235,7236,7237,7238,7239,4716,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,4653,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,5876,7268,7269,7270,7271,4637,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7273,7302,7303,7304,7305,7306,4728,7308,7309,7310,4710,7312,7313,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,5843,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,5484,7359,7360,7361,7362,7363,7364,7284,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,7291,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,5419,7394,7395,7396,7397,7398,4688,7400,1381,7402,7403,7404,7405,7406,7407,7408,7409,7410,7215,7412,7413,7414,7415,7416,7417,7418,7419,7413,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,5418,7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7318,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,5733,7466,7467,7468,7469,7470,7471,7472,7473,5857,7475,7277,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7369,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,4712,7516,7517,7258,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7270,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7369,7543,7544,7545,7546,7547,7548,7549,7550,7284,7552,7553,7554,7555,7556,7557,7558,4731,7560,7561,7562,7563,7564,7565,4641,7567,7568,7569,7570,7571,7572,7573,7574,7575,7466,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,7603,7604,4679,7606,7607,7608,7609,7610,7506,7612,7613,7614,7615,7616,7617,7618,7619,7371,7621,7622,7623,7624,7625,7626,7627,4728,7629,7630,7631,7632,7633,7634,7635,7636,7637,5704,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,5791,7666,7667,7668,7669,7670,7671,7672,7673,7674,7215,7676,7677,7678,7679,7680,7215,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,4642,7694,7695,7696,7697,7698,7699,4732,7701,7702,7703,7704,7705,5398,7707,7708,7709,7710,7711,7712,7713,7714,5429,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7552,7732,7733,7734,7305,7736,7737,7738,7739,7740,7741,4729,7743,7744,7745,7746,7747,7748,7749,7750,7751,7752,4688,7754,4656,7756,7757,7758,7759,7760,7761,7762,7763,7199,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7187,7776,7777,7778,7779,7780,7495,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794,7795,7796,7797,7798,7799,7800,7239,4654,7803,7804,7805,7806,7807,7808,7809,7270,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7391,7824,7825,7826,7827,7552,7829,7830,7831,7832,7833,7834,7835,7836,7837,7560,7839,7840,7841,7842,7843,4644,7845,7639,7847,7848,7849,7850,7851,7852,7187,7854,7855,7856,7855,7858,7859,7860,7861,7862,7863,7864,7865,7866,5665,7868,7869,7870,7871,7872,7873,7874,4716,7876,7877,7694,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888,7889,7890,7891,7892,7893,5832,7895,7896,7897,7898,7899,7900,7901,7902,7500,7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983,7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999,8000,8001,8002,7506,8004,8005,8006,8007,8008,8009,5798,8011,8012,8013,5498,8015,8016,8017,8018,8019,8020,5733,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031,8032,5445,8034,8035,8036,8037,8038,8039,8040,8041,7391,8043,8044,8045,8046,8047,8048,8049,8050,8051,8052,8053,7391,8055,8056,8057,8058,8059,8060,7243,8062,8063,8064,8065,8066,8067,5738,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,5431,8082,8083,8084,8085,5929,8087,8088,8089,7302,8091,8092,8093,8094,8095,8096,8097,8098,7310,8100,7475,8102,8103,5738,7858,8106,8107,8108,8109,8110,8111,7855,8113,8114,8115,8116,8117,8118,8119,8120,8121,5857,8123,8124,8125,8126,8127,8128,7245,8130,7884,8132,8133,8134,8135,8136,8137,8138,5822,7276,8141,8142,8143,8144,8145,8146,8147,8148,8149,8150,8151,7508,8153,8154,8155,8156,8157,8158,8011,8160,8161,8162,8163,8164,8165,8166,7335,8168,7756,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,7866,8120,8192,7508,8194,8195,8196,8197,8198,8199,8200,5714,8202,8203,8204,8205,8206,8207,4658,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,5431,8228,8229,8230,7204,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,7422,8244,8245,5418,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,7696,7639,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,7855,7855,8278,8279,4725,8281,8282,8283,8284,8285,8286,8287,8288,8289,5916,5698,8292,8293,8294,8295,8296,8297,7552,8299,8300,8091,8302,8303,8304,7629,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,4637,8321,8322,8323,8324,5541,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,7774,7858,8338,7475,5817,8341,8342,8343,5749,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,5655,8365,8366,8367,8368,8369,8370,8371,8143,8373,8374,7209,8376,8377,8378,8379,8380,8381,8382,8383,8384,5863,8386,8011,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,4654,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,5511,8415,8416,8417,8418,8419,8420,7288,8422,8423,8424,8425,8426,7366,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,5648,8439,8440,8441,8442,8443,8444,8445,8446,8447,7754,7645,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,4627,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,8045,8474,8475,8476,7391,8478,8479,8480,8481,8482,8483,8484,1410,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,7335,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,5790,8523,8524,8525,7215,8527,8528,8529,8530,8531,8532,8533,8534,8535,7218,8537,5863,8539,8540,7629,8542,8543,8544,8545,8546,8547,7707,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,4669,8565,8566,8567,8043,8569,8570,8571,8572,8573,8574,8575,8576,8577,7391,8579,8580,8581,5864,8583,5846,8585,8586,8587,8588,8589,8590,4454,8592,8593,7683,8595,8596,8597,8598,7208,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8321,8618,8619,8620,7561,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,5846,8633,8634,8635,4631,8637,8638,8639,7287,8641,8642,8643,8644,8645,8646,8647,8648,7510,8650,8651,5419,8653,8654,8655,8656,8657,8658,8659,8660,8661,7696,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,5734,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8115,8703,8704,7612,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,7372,8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,7313,8731,4657,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,5878,8749,8750,8751,8752,8753,8754,8755,8756,8757,7553,8759,8760,8761,8145,8763,8764,7310,7696,8767,8768,8769,8770,4654,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,4678,8783,8784,8785,8786,7506,8788,8789,8790,8791,8792,8793,8794,8795,8796,7372,8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,4724,8809,8810,8811,8812,8813,8814,8815,7577,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,5869,8832,8833,8834,8835,8836,8837,8838,8602,8840,8841,8842,8843,7766,8845,8846,8847,8848,8849,8850,8851,8656,8853,8854,8855,8856,8857,8858,8859,8860,8861,7243,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,5411,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,7270,8893,8894,8895,8896,8897,8898,8899,8900,8901,7824,8903,8904,8905,8906,8907,8908,7305,8910,8911,8912,8913,8914,8915,8916,8917,4728,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,5470,8931,8932,8933,8934,8935,8499,8937,8938,8939,8940,8941,8942,8943,8944,8945,5483,8947,8948,8949,8950,8951,8952,8953,8791,8955,8956,8957,7506,8959,8960,8961,8962,8963,8964,8965,8966,7697,8968,8969,8970,8971,5541,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,7532,8994,8995,8996,8997,8998,7392,9000,9001,9002,9003,9004,9005,8145,9007,9008,9009,9010,9011,9012,9013,9014,8100,8670,9017,9018,9019,9020,7586,5477,9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,8959,9064,9065,9066,9067,8428,9069,9070,9071,9072,9073,9074,9075,7310,5733,9078,9079,9080,9081,9082,1389,9084,9085,9086,9087,9088,7412,9090,9091,9092,9093,9094,7685,9096,9097,9098,9099,5857,9101,9102,4732,9104,9105,9106,9107,9108,9109,9110,9111,8103,5832,8959,9115,7277,9117,9118,9119,9120,9121,9122,9123,9124,4728,9126,9127,9128,9129,9130,9131,5467,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9101,5446,9148,8581,8581,8491,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,4686,9171,9172,9173,9174,1382,9176,9177,9178,9179,9180,9181,8609,9183,9184,8851,9186,9187,7310,9189,7310,9191,4688,5486,9194,9195,9196,7391,9198,9199,9200,9201,9202,9203,9204,9205,7294,9207,9208,9209,9210,9211,7315,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,9223,5500,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,7522,9244,9245,9246,9247,9248,9249,9250,9251,9252,9253,9254,7191,9256,9257,9258,9259,9260,9261,9262,9263,9264,8386,9266,9267,9268,9269,9270,9271,9272,7254,7258,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,7270,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,7293,9303,7305,9305,5891,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,4722,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,8551,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,5833,9356,9357,9358,9359,9360,9361,9362,9363,9364,8143,9366,8005,9368,9369,9370,9371,9372,9373,8011,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,5843,9397,9398,8175,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,7866,7185,9415,9416,9417,9418,9419,9420,9421,9422,9423,8007,9425,9426,9427,9428,9429,9430,9431,9432,9433,4717,9435,9436,9437,9402,9439,9440,9441,9442,9443,9444,9445,9446,9447,5431,9449,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,8381,9461,9462,9463,9464,9465,9466,9467,9468,7421,9470,9471,9472,9473,5818,9475,9476,9477,4729,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,5499,9491,9492,9493,9494,5824,8581,9497,9202,9499,9500,9501,9502,7316,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,7710,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9244,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,8278,9547,9548,9549,9550,7614,9552,9553,9554,9555,5798,9557,9558,9559,9560,9561,9562,9563,9564,7466,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,7060,9578,9579,9580,9581,7765,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9071,9595,9596,9597,9598,9599,9600,9601,8043,9603,5714,9605,8633,9607,9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,7403,9635,9636,9637,7218,8843,9640,9641,9642,9643,9644,9645,9646,9647,9557,9649,9650,9651,9652,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,8015,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,5444,9683,9684,9685,8043,9687,9688,9689,9690,8581,9157,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,5508,5571,9712,9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,9733,9640,9735,9736,9737,9738,9739,9740,9741,9742,9743,7203,9745,9746,9747,9748,9749,9750,5779,9752,9753,9754,9755,9756,9757,9758,9759,8286,9761,9762,9763,9764,9765,8103,8035,9768,7495,9770,7284,9772,9773,9214,9775,9776,9777,9778,9779,9780,8469,8048,9783,9784,9785,9786,9787,8143,9789,9790,9791,9792,5872,9794,9795,8016,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,9808,9809,7882,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9747,9837,9838,9839,9840,9841,9842,9843,8845,9845,5891,9847,9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,5508,5698,9864,7552,9866,7276,9868,9869,9870,9871,9872,9873,9874,9875,8543,9877,9878,9879,9880,9881,9882,9883,9884,9885,9886,5410,9888,9889,9890,9891,8739,9893,9894,9895,9896,9897,9898,9899,7776,9901,9902,9903,9904,8103,8790,9907,9908,9909,9910,8388,9912,9913,8686,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,7668,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,7218,9957,8600,9959,9960,9189,7432,9963,9964,9965,9966,9967,9968,9969,9970,5450,7372,9973,9974,9975,8238,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,5716,9988,9989,9990,9991,4729,9993,9994,9995,9996,9997,9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,9337,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021,10022,5444,10024,10025,9784,10027,10028,8482,10030,10031,10032,7320,10034,10035,4688,10037,4706,10039,10040,10041,10042,10043,10044,10045,8602,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,8845,10058,10059,10060,10061,10062,10063,8789,10065,10066,10067,10068,5712,10070,10071,10072,10073,10074,8209,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,10094,7717,10096,10097,10098,10099,10100,10101,10102,7276,10104,7412,10106,10107,10108,10109,7380,10111,4653,10113,5832,10115,10116,10117,7829,10119,10120,10121,8381,10123,10124,10125,10126,10127,4730,10129,10130,10131,10132,10133,4654,10135,10136,10137,10138,10139,10140,10141,10142,10143,121,10145,10146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10150,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249,10250,128,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261,10262,5942,10264,10265,10266,10267,10268,10269,10270,10271,10272,10265,10274,10275,10276,715,10278,10279,10280,10281,10282,10283,10284,10285,6880,10287,10288,6621,10290,10291,10292,10293,10294,7089,10296,10297,10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,4627,10309,8959,10311,10312,10313,10314,10315,10316,9595,9995,10319,10320,10321,10322,7756,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,10338,7532,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354,10111,8643,10357,10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,4731,10369,10370,5934,10372,10373,10374,10375,5732,10377,10378,10379,10380,8279,10382,7278,8707,10385,10386,10387,10388,10389,8202,10391,10392,10393,10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,5543,10405,10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,8752,10418,10419,10420,10421,10422,10423,10424,7288,10426,10427,10428,10429,10430,10431,10432,10433,10434,10435,10436,10437,9308,10439,10440,10441,10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,7315,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,10470,10471,10472,744,10474,10475,10476,10477,10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,884,10499,10500,10501,10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,10519,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10546,10602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,10614,10615,10602,10617,10618,10619,10620,10621,10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10620,10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,10686,10687,10688,10689,10602,10691,10692,10693,10694,10695,10696,10697,10698,10699,10700,10701,10604,10703,10704,10705,10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,10746,10747,10748,10728,10750,10751,10752,10753,10754,10755,10539,10757,10758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,10818,10819,10502,10821,10822,10823,10824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10821,10841,10842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,10842,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,1099,10907,10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,10926,10927,10928,10929,10589,10931,10932,10933,10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10609,10945,10946,10947,10948,10949,10950,10951,10952,10642,10954,10955,10956,10957,10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10618,10970,10971,10972,10973,10974,10975,10976,10977,10978,10666,10980,10981,10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10707,10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,10740,11017,11018,11019,10535,11021,11022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,11090,10830,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,10844,11103,11104,11105,11106,11107,11108,11109,11110,10859,11112,11113,11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,11126,1315,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,1325,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,11154,11155,4552,11157,11158,11159,11160,11161,11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,11174,4620,11176,11177,11178,11179,11180,11181,11182,11183,9087,11185,11186,11187,11188,11189,11190,9191,9931,11193,7245,11195,11196,11197,7406,11199,11200,11201,11202,11203,11204,9127,11206,11207,11208,11209,11210,11211,5590,11213,11214,11215,11216,11217,11218,11219,11220,11221,5428,11223,11224,11225,11226,11227,7840,11229,5397,11231,11232,11233,11234,11235,11236,11237,11238,5699,11240,5712,11242,11243,11244,11245,11246,11247,11248,11249,11250,4701,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,11262,11263,11264,4654,11266,11267,11268,11269,11270,11271,8418,11273,11274,11275,7315,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,239,11289,11290,9963,11292,11293,11294,11295,8549,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,7359,11310,11311,11312,11313,11314,7754,7717,11317,11318,11319,11320,11321,11322,11277,7467,11325,11326,11327,11328,11329,11330,11331,11332,5483,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,8585,11345,11346,11347,11348,5941,11350,11351,11352,11353,11354,11355,4798,11357,11358,11359,11360,11361,11362,11363,11364,11365,11366,11367,11368,11369,4831,11371,11372,11373,11374,11375,11376,11377,11378,11379,11380,11381,4946,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395,11396,4849,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410,11411,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425,11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,4849,11437,11438,11439,11440,11441,11442,11443,4951,11445,11446,11447,11448,11449,11450,11451,11452,11453,4993,11455,11456,11457,11458,11459,11460,11461,11462,4993,11464,11465,11466,11467,5014,11469,11470,5030,11472,5040,11474,11475,11476,5377,11478,11479,11480,11481,11482,5224,11484,11485,5227,11487,11488,11489,11490,11491,11492,11493,11494,11495,11496,11497,11498,11499,4589,11501,11502,4582,11504,11505,11506,11507,11508,11509,11510,5212,11512,11513,11514,11515,5157,11517,11518,11519,11520,11521,11522,5083,11524,11525,11526,11527,5243,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,4601,11541,11542,11543,11544,11545,11546,5370,11548,11549,11550,11551,11552,11553,4576,11555,11556,11557,11558,11559,11560,11561,11562,11563,11564,11565,11566,4584,11568,11569,5155,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,5047,11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,11606,11607,5200,11609,11610,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622,4557,11624,11625,11626,11627,11628,11629,11630,11631,11632,5201,11634,11635,11636,11637,11638,11639,11640,11641,11642,11643,5160,11645,11646,11647,11648,11649,11650,11651,11652,11653,5349,11655,11656,11657,11658,11659,11660,11661,4586,11663,11664,11665,11666,11667,11668,11669,5484,11671,11672,10037,7362,11675,11676,11677,8168,11679,11680,11681,5514,11683,11684,11685,11686,11687,11688,7333,11690,11691,11692,11693,11694,5514,11696,11697,11698,11699,11700,11701,4654,11703,11704,11705,11706,5480,11708,11709,11710,11711,11712,11713,11714,11715,11716,8550,11718,11719,11720,11721,11722,11723,11724,11725,5698,11727,6837,11729,5823,11731,11732,5857,11734,9148,11736,9213,11738,11739,11740,11741,11742,4669,11744,11745,11746,11747,11748,5833,11750,11751,11752,11753,11754,10347,4647,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,5429,11819,11820,11821,11822,11823,11824,11825,11289,11827,11828,11829,5769,11831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890,11891,8346,11893,11894,11895,11896,11897,5727,11899,11900,11901,11902,11903,11904,11905,11906,11907,5409,11909,11910,11911,11912,11913,11914,11915,11916,11917,11918,5724,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,11930,11931,11932,11933,11934,11935,11936,9813,11938,11939,11940,11941,11942,11943,11944,8619,11946,11947,8876,11949,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,11920,5540,11968,11969,11927,11971,11972,11973,11974,11975,11976,11977,11978,11979,11266,11981,11982,11983,11984,11985,11986,11987,11988,11989,11990,4699,11992,5703,11994,11995,11996,11997,11998,11999,12000,12001,12002,4694,12004,12005,12006,12007,8589,12009,12010,12011,12012,12013,12014,4637,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,12038,12039,12040,8015,12042,12043,12044,12045,12046,12047,4693,8491,12050,4694,12052,12053,12054,12055,12056,10326,12058,7359,12060,12061,12062,12063,12064,12065,12066,12067,9335,12069,12070,12071,5445,12073,8321,12075,8783,12077,12078,12079,12080,12081,12082,9104,12084,12085,12086,12087,12088,12089,12090,11187,12092,12093,4723,8523,12096,12097,12098,12099,12100,12101,4716,12103,12104,12105,12106,12107,7406,12109,12110,12111,12112,12113,4713,12115,12116,12117,12118,12119,7060,12121,12122,12123,12124,1379,12126,4712,12128,12129,12130,12131,12132,12133,1381,12135,12136,12137,12138,12139,12004,12141,12142,12143,12144,12145,12146,12147,12148,5704,12150,12151,12152,12153,12154,12155,12156,12157,12158,12159,11920,12161,7754,5727,12164,9336,12166,12167,12168,12169,4699,12171,8125,5832,12174,12175,8666,12177,12178,12179,4704,12181,12182,12183,5712,12185,12186,12187,5411,12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,12206,5489,12208,12209,12210,12211,12212,12213,12214,12215,9105,12217,12218,12219,8326,12221,12222,12223,12224,12225,12226,5727,12228,12229,12230,7640,12232,12233,12234,12235,12236,12237,12238,12239,8367,12241,12242,12243,12244,12245,7242,12247,12248,12249,12250,12251,12252,12253,5916,4630,12256,12257,12258,12259,8102,12261,7258,12263,5537,7641,12266,12267,12268,12269,12270,12271,12272,12273,12274,8041,11734,12266,12278,12279,12280,12281,12282,12283,12284,12017,12286,12287,12288,12289,12290,12291,12292,12293,7709,11820,12296,7310,12298,5499,12300,12301,5934,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,12320,11258,12322,5563,7256,12325,12326,12327,12328,12329,12330,9356,12332,12333,12334,12335,7239,7641,12338,12339,12340,12341,12342,12343,12344,12345,12346,10037,7668,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,7868,12363,12364,12365,12366,12367,12368,5409,12370,12371,12372,12373,12374,12375,12376,12377,5484,12379,12380,12381,7309,8875,12384,12385,12386,12387,12388,12389,12390,12391,4693,12393,12325,12395,12396,12397,12398,12399,12400,12401,12402,8639,12298,7519,12406,12407,12408,12409,12410,12411,12412,12413,12414,4692,12416,12417,12418,8170,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,7270,12432,5871,12434,12435,12436,12437,11704,12439,12440,12441,12442,12443,12444,5484,12446,12447,12448,12449,12450,12451,12452,12453,12454,5398,12456,12457,12458,12459,9087,12461,12462,12463,12464,5893,12466,12185,12468,12469,12470,12471,12472,12473,7902,4730,12476,12477,12408,12479,12480,12481,12482,12483,12484,11971,12486,12487,12488,12489,12490,12491,7640,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,5807,12509,12510,12511,12512,12513,12514,12515,12516,5685,12518,12519,12520,12521,4656,12523,12524,12525,12526,12527,7433,12529,11266,12531,12532,12533,12534,12535,12536,12537,12538,12539,5395,12541,12542,11894,12544,5462,12546,12547,12548,12549,12550,12249,12552,12553,12554,12555,12556,12557,12558,12559,12560,8734,12562,12563,12564,12565,12566,5537,12267,12569,12570,12571,12572,12573,8038,9566,12576,4628,12578,12579,12580,12581,12582,7717,12584,12585,12586,12587,9191,4653,12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,9683,12606,12607,12608,9215,12610,12611,12612,11912,12614,12615,12616,12617,5391,12619,12620,12621,7756,12623,12624,12625,12626,10346,12628,12629,12630,12631,12632,12633,9995,12635,12636,12637,12638,4653,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,8415,12652,12653,12654,12655,12656,12657,7310,5411,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12020,12671,8733,12673,12674,12675,12676,12677,5821,5816,12680,12681,12682,12683,8734,12685,12686,12687,12688,12689,12690,12691,12692,12693,5727,12695,12696,12697,8498,12699,12700,12701,12702,12703,12704,12705,9295,12707,12708,12709,12710,9479,12712,12713,12714,4688,11684,12717,12718,12306,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12182,12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,7258,12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,12758,12759,12760,12761,12762,5444,12764,12765,4717,12767,5541,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,12782,12783,12784,12785,12786,12418,9079,12789,12790,12791,12792,12793,5655,12795,12796,12797,5455,12799,12800,12801,12802,12803,12187,12805,12806,12807,12808,12809,5487,12811,12812,12813,12814,12815,12816,12817,12610,12819,12820,12821,12822,12823,12824,12825,12826,5735,12828,12829,12830,5405,12832,12833,12834,12835,4654,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,7717,12848,12849,12850,12851,12852,12853,12854,11278,12856,12857,12858,12859,4688,5479,12862,12863,12864,12865,12866,12867,12868,12869,12870,9492,12872,12873,9084,12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12767,7567,5445,12177,12890,12891,12892,12893,12894,12895,5411,12897,12898,12899,12900,12901,12902,5542,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,7270,12915,12916,12917,12918,12919,12920,8323,12922,8818,12924,12925,12926,12581,12928,12929,12930,12931,12932,12933,12934,7707,12936,12937,12938,12939,12940,12941,12350,12943,12944,12945,12946,12947,12948,12372,12950,12951,12952,12953,12954,12955,9864,7243,12958,12959,12960,12961,12962,12963,12593,12965,12966,12967,12968,8417,12970,12971,5496,12973,12974,12975,11226,12977,12978,7243,12980,12981,12982,12983,5714,12985,12986,12987,12988,12989,12990,12991,12992,12606,5932,12995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,4454,13007,13008,13009,13010,13011,8133,13013,13014,13015,13016,13017,13018,13019,13020,11335,13022,12084,13024,7258,13026,13027,13028,13029,13030,13031,13032,13033,13034,12017,13036,13037,13038,10324,13040,13041,13042,13043,7270,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,13058,13059,9217,13061,13062,13063,13064,11703,13066,13067,13068,13069,13070,13071,8947,13073,13074,13075,13076,13077,4653,13079,13080,13081,13082,13083,13084,13085,13086,11217,13088,13089,13090,13091,13092,5541,13094,13095,13096,13097,13098,13099,13100,13101,13102,13103,9148,13105,9154,13107,13108,13109,13110,12314,13112,13113,5450,7630,13116,13117,10044,13119,13120,13121,11900,13123,13124,13125,13126,13127,12661,13129,13130,4681,13132,13133,13134,13135,12084,13137,13138,12661,13140,13141,13142,13143,13144,13145,13146,13147,7519,13149,13150,13151,13152,13153,13154,13155,13156,8639,9308,13159,13160,13161,5749,13163,13164,13165,13166,13167,13168,13169,13170,13171,12487,13173,13174,13175,13176,13177,13178,13179,13180,13181,12266,13183,13184,13185,13186,13187,13188,13189,13190,13191,13192,13193,10145,13195,13196,13197,13198,13199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,10262,13291,13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,13322,3841,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382,13383,13384,13359,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,13418,13339,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,13442,13443,13424,13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,13466,13424,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13510,13518,13519,13520,13521,13522,13523,13524,13420,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,13554,13572,3839,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,600,13586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13611,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13591,13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13668,13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13679,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13756,13762,13763,13764,13765,13766,13665,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,13774,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,13862,13863,13864,599,13866,13867,13868,13869,13870,13871,13872,13873,13874,13875,13876,13877,13878,13369,13880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13404,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,13423,13911,13912,13913,13914,13456,13916,13917,13918,13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13476,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,13970,13971,13972,13973,13974,13967,13976,13977,13978,13546,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,13994,13995,13996,13997,13998,13559,3815,14001,14002,14003,14004,14005,14006,14007,14008,14009,14010,3814,14012,14013,14014,14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,14066,14067,3813,14069,14070,14071,14072,14073,14074,14075,14076,14077,14078,14079,14080,14081,14082,14072,14084,14085,14086,14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14084,14111,14084,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,14069,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,14163,14175,14176,14177,889,14179,14180,14181,14182,14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,10487,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,14234,14235,1089,14237,14238,14239,14240,14241,14242,14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,14270,14271,14272,14273,3546,14275,14276,14277,14278,14279,14280,14281,14282,14283,14284,14285,4745,14287,14288,13011,14290,14291,14292,14293,4508,14013,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,14306,14307,14308,228,14310,14311,14312,14313,14314,14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,244,14326,14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,14342,14343,14344,14345,14346,14347,14125,14349,14350,14351,14352,14353,14354,14355,14356,14357,3546,14359,14360,14361,14362,14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14369,14386,14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,14394,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,1104,14422,14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,14438,14439,6257,14441,14442,14443,14444,14445,14446,14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14459,14486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14454,14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,14452,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,14558,14559,14560,14561,14562,14563,14486,14565,14566,14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,14507,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,14451,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,14460,14652,14653,14654,14655,14656,14657,14658,14659,14660,14490,14662,14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,14675,4379,14677,14678,14679,14680,14462,14682,14683,14684,14685,14686,14687,14688,14689,14690,14691,14692,14693,14694,14695,14495,14697,14698,14699,14700,14665,14702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,14642,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14581,14750,14751,14517,124,14754,14755,14756,14757,14758,14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,6258,14770,14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,14810,14811,14441,14813,14814,14815,14816,14817,14818,14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,14855,124,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,6270,14870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,14815,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,14906,10279,14908,755,14910,14911,14912,14913,14914,14915,14916,14917,14918,14919,14920,14921,10283,14923,744,14925,14926,14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14936,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,14917,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,15002,14976,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,15014,15015,755,15017,15018,15019,15020,15021,15022,15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,15038,15039,15040,6275,15042,15043,15044,15045,15046,15047,15048,15049,200,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,15098,15099,15089,15101,15102,15103,15104,15105,15106,15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,15117,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,15158,15159,15160,15161,15162,15163,15148,15165,15166,15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15087,15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15210,15230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,15266,15267,15268,15269,15270,15235,15272,15273,15274,15275,15276,15230,15278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,15302,15303,15304,15305,15306,15307,15230,15309,15310,15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,15319,15336,15337,15338,15339,15340,15341,15342,15343,15209,15345,15346,15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,15218,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,15289,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,15289,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15327,15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15321,15454,15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,15470,15471,15472,15473,15474,15340,15476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,15494,15495,15496,15363,15498,15281,15500,15501,15502,15503,15504,15505,15506,15507,15508,15323,15510,15511,15512,15513,15514,15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,15431,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,15542,15343,15544,15203,15546,15547,15548,15549,15550,15551,15552,15553,15554,15555,15556,15557,15256,15559,15560,15561,15562,15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15247,15578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,15590,15591,15323,15593,15594,15595,15596,15597,15598,15599,15600,15601,15602,15340,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,15614,15615,15616,15617,15618,15078,15620,15621,15622,15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,15639,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15659,15686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15627,15718,15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,15746,15747,15748,15749,15736,15751,15752,15753,15754,15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15727,15790,15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15752,15806,15807,15757,15809,15810,15752,15812,15813,15814,15815,15816,15817,15758,15819,15820,15821,15822,15823,15824,15812,15826,15827,15828,15829,15830,15831,15832,15833,15766,15835,15836,15837,15838,15839,15840,15841,15842,15843,15844,15845,15643,15847,15848,15849,15850,15851,15852,15853,15854,15855,15660,15857,15858,15859,15860,15861,15862,15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15689,15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15727,15902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,15914,15915,15916,15753,15918,15919,15920,15921,15922,15923,15924,15925,15926,15927,15928,15929,15930,15764,15932,15933,15934,15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,15815,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,15962,15963,15964,15965,15966,15967,15772,15969,15970,15971,15972,15732,15974,15975,15976,15977,15919,15979,15980,15981,15982,15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,15998,15999,15937,16001,16002,16003,16004,16005,16006,16007,16008,16009,16010,16011,16012,16013,16014,15741,16016,16017,16018,16019,16020,16021,16022,16023,16024,15756,16026,15938,16028,16029,15653,16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,16043,15706,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,16058,16059,16060,16061,15653,16063,16064,16065,16066,16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,16079,15753,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,15936,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,15827,16114,16115,16116,15788,15796,16119,15921,16121,16122,16123,16124,16125,15757,16127,16128,16129,16130,16131,16132,16133,15954,16135,16136,16129,16138,16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,15642,16150,16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,15676,16166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,15691,16187,16188,16189,16190,16191,16192,16193,16194,15959,16196,15970,16198,16199,16200,16201,16202,16203,16204,16205,16206,15737,16208,16209,16210,16211,16212,16213,16214,16215,16216,16217,16218,15768,16220,16221,16222,16223,16224,16225,16226,16227,16228,15936,16230,16231,16232,16233,16234,16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,15922,16246,16247,15936,16249,16250,16251,16018,16253,16254,16255,16256,16257,16258,16259,16260,16261,16262,15768,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,16002,16275,16276,16277,16278,15658,16280,16281,16282,16283,16284,16285,16286,16287,16288,16289,16290,16291,15699,16293,16294,16295,16296,16297,16298,16299,16300,16301,16302,16303,15791,16305,16306,16307,15928,16309,16310,16311,15937,16313,16314,16315,16316,16317,16318,16319,16115,16321,15788,15739,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,16334,16335,16336,16337,16338,15784,16340,16341,16342,16343,16344,16345,16346,16347,15732,16349,16350,16351,16352,16353,16354,16355,16356,16357,16358,16359,16360,16361,15930,15938,16364,16365,16366,16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,16382,15651,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,16394,16395,16396,16397,16168,16399,16400,16401,16402,16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,16191,16419,16420,16421,16422,15827,16424,16425,15753,16427,15905,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,16232,16443,16444,16445,16446,16447,16448,16424,16450,16451,15784,16453,16454,16455,16456,16457,16458,16254,16460,16461,16462,16463,16464,16465,16466,16467,16468,16469,16470,16471,15784,16473,16474,16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,15634,16486,16487,16488,16489,16490,16491,16492,16493,15862,16495,16496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,16514,15894,16516,16517,16518,16519,16520,16521,16522,16523,16210,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,16538,15937,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,16550,16121,16552,15936,16554,16555,16556,16557,16558,16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,15959,16570,16571,16572,16573,16574,16575,16576,15773,16578,16329,16580,16581,16582,16583,16584,16585,16586,16587,16578,15622,16590,16591,16592,16593,16594,16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,15862,16606,15878,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,15909,16622,16623,16624,16625,16626,16627,16628,16629,15993,16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16231,16135,16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,16718,15787,16720,16327,16722,16723,16724,16725,16726,16727,16728,16729,16730,16578,16305,16733,16734,16366,16736,16737,16738,16739,16385,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,15662,16762,16763,16764,16765,16766,16767,15886,16769,16770,16771,16772,16773,16774,16775,16776,16777,16778,15812,16780,16781,16782,16473,16784,16785,16786,16787,16788,16789,16790,16723,16792,16793,16794,16795,16796,16797,16798,16799,16800,16198,16802,15819,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,15826,16815,16816,16817,16818,16455,16820,16821,16822,16823,16018,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,16838,16839,16840,16841,15784,16843,16844,16845,16846,16847,16848,16849,16850,16851,15641,16853,16854,16855,16856,16857,15662,16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,15884,16872,16873,16874,16875,16876,16877,16878,16879,16880,16326,16882,16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,16898,16899,16900,16901,16902,16225,16904,16905,15751,16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,16922,16923,16924,16925,16926,16365,16928,16929,16930,16713,16932,16933,16934,16935,16936,16937,15784,16939,16940,16941,16942,16943,16944,15739,16946,16947,16948,16949,16950,16951,16271,16953,16954,16955,15937,16957,16958,16959,16287,16961,16962,16963,16964,16965,16966,16967,16968,16191,16970,16971,15791,16973,15993,16975,16976,16977,16978,15936,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16424,16994,16995,16996,16997,16998,16999,17000,17001,17002,15787,16723,17005,17006,17007,17008,17009,17010,17011,16578,15751,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,16002,17026,17027,17028,17029,17030,17031,17032,17033,16751,15694,17036,17037,17038,17039,17040,17041,17042,16995,17044,15788,16327,17047,17048,17049,17050,17051,15768,17053,17054,17055,17056,16128,17058,17059,17060,17061,17062,17063,15956,17065,15823,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,16019,17078,17079,17080,17081,17082,17083,15778,17085,17086,17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,15849,17124,17125,17126,16505,17128,17129,17130,17131,17132,17133,17134,17135,17136,15890,17138,17139,17140,17141,17142,17143,17144,17145,17146,17147,15737,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,17058,17160,16003,17162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,16552,17174,15939,17176,17177,17178,17179,17180,15816,17182,15769,17184,17185,17186,17187,17188,15737,17190,17191,17192,17193,17194,17195,17196,17197,17198,17199,17200,17201,15758,17203,15937,17205,17206,17207,17208,17209,17210,17211,17212,17213,17214,16286,17216,15692,17218,17219,17220,17221,17222,17223,15802,17026,17226,17227,17228,17229,17230,17231,17232,17233,17234,17235,17236,16135,17238,17239,17240,17241,17242,17243,17244,17245,17246,17247,17248,17249,17250,16340,17252,17253,17254,17255,17256,17257,17258,17259,17048,17261,17262,17263,17264,17265,17186,17267,17268,17269,17270,17271,17272,16542,17274,17275,17276,17277,17278,17279,17280,17281,17282,17283,17244,17285,17286,17287,17288,17289,17290,17291,17292,16097,17294,17295,17296,17297,17298,17299,17300,17301,16162,17303,17304,17305,17306,17307,17308,17309,17310,17311,16411,17313,17314,17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,17327,16051,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,17342,17343,17344,17345,17346,16829,17348,17349,17350,16474,17352,17353,17354,17355,17356,17357,17358,15793,17360,17361,17362,17363,17364,17365,17366,17367,15919,17369,17370,16557,17372,17373,17374,17375,17376,17377,17378,16825,17380,17381,17382,17383,17384,17385,17386,17387,17388,16845,17390,17391,17392,17393,17394,17395,17396,17397,16625,17399,17400,17401,17402,17403,16555,17405,17406,17407,17408,17409,17410,17411,17412,16036,17414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,17340,17427,17428,17429,16072,17431,17432,17433,16552,16554,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17065,17447,17448,17449,17450,17451,17452,17453,17454,17455,16266,17457,17150,17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,16542,17470,17471,17472,15921,17474,17475,17476,17477,17478,17479,17480,17481,17482,16251,17484,15074,17486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,15071,17542,17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17563,17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17611,17630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17657,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,17702,17703,17704,17705,17688,17707,17708,17709,17710,17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,17834,17835,17836,17837,17838,17839,17649,17841,17842,17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,17858,17859,17860,17848,17862,17863,17864,17865,17866,17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,17894,17895,17873,17897,17898,17899,17900,17901,17902,17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,17885,17979,17980,17981,17982,17983,17862,17985,17986,17987,17988,17989,17990,17991,17899,17993,17994,17995,17996,17997,17998,17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,17899,18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,18035,17853,18037,18038,18039,18040,18041,17883,18043,18044,18045,18046,18047,18048,18049,18050,18051,17899,18053,18054,18055,18056,18057,18058,18059,18060,17885,18062,18063,18064,18065,18066,18067,17551,18069,18070,18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,18086,18087,18088,18089,18090,17553,18092,18093,18094,18095,18096,18097,18098,18099,18100,17613,18102,18103,18104,18105,18106,18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,17644,18118,18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,18131,17683,18133,18134,18135,18136,18137,18138,18139,17709,18141,18142,18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,17849,18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,17876,18228,18229,18230,18231,18232,18233,18234,18235,18236,18053,18238,18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,17982,18264,18265,17989,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,17998,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,18290,18291,18024,18293,18294,18295,18296,18297,18298,18299,18300,18301,18302,18303,18304,18274,18306,18307,18308,17880,18310,18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18024,18326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,18338,18339,18340,18341,18342,17994,18344,18345,18346,18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,17544,18360,18361,18362,18363,18364,18365,18366,18367,17580,18369,18370,18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,18383,17620,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,18398,18399,18400,18401,17677,18403,18404,18405,18406,18407,18408,18409,18410,18411,18412,18413,18414,17695,18416,18417,18418,18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,17718,18432,18433,18434,18435,18436,18437,18438,18439,18267,18441,18442,18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18315,18458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,18024,18471,18472,18473,18474,17995,18476,18477,18478,18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,18494,18495,18496,18497,18452,18499,18500,18501,18502,18238,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,18530,18531,18018,18533,18534,18535,18536,18537,18538,18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,18566,18567,18270,18569,18570,18571,18572,18573,18574,18575,17868,18577,18578,18579,18580,18581,18241,18583,18584,18585,18586,18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18063,18599,18600,18601,18602,18603,18078,18605,17562,18607,18608,18609,18610,18611,18612,18613,18614,18615,18616,18617,18618,18619,17625,18621,18622,18623,18624,18625,17665,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,17700,18646,18647,18648,18649,18650,18651,18652,18653,18654,17719,18656,18657,18658,18659,18660,18661,18662,18663,18664,18665,18666,18667,18270,18669,18670,18671,18672,18673,17885,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,18328,18687,18688,18689,18690,18691,18692,18490,18694,18695,18696,18697,18698,18699,18700,18701,18702,18703,18452,18705,18706,18707,18708,18709,18710,18518,18712,18713,18714,18715,18716,18717,17869,18705,18720,18488,18722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,18734,18024,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,18746,18747,18748,18749,18750,17595,18752,18753,18754,18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18366,18793,18794,17599,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,18806,18807,18808,17631,18810,18811,18812,18813,18814,18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18404,18830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,18854,18855,18856,18857,17709,18859,18860,18861,18862,18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18436,18890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,18902,18446,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18722,18923,18924,18925,18926,18927,18928,18929,18930,18931,18736,18933,18934,18935,18936,18937,18938,18939,18940,18941,18942,18211,18944,18945,18946,18947,18948,17876,18950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,18962,18963,18516,18965,18966,18967,18968,18969,18970,18971,18972,18973,18974,18975,18533,18977,18978,18979,18980,18981,18982,18983,18984,18985,18986,18987,18988,18499,18990,18991,18992,18993,18494,18995,18996,18997,18998,18999,19000,18738,19002,19003,19004,19005,19006,19007,19008,19009,19010,19011,18785,19013,19014,19015,19016,19017,19018,19019,19020,19021,19022,19023,18361,19025,19026,19027,19028,19029,19030,18804,19032,19033,19034,19035,18823,19037,19038,19039,19040,19041,19042,18839,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,19058,19059,18861,19061,19062,19063,19064,19065,19066,19067,19068,19069,19070,18436,19072,19073,19074,19075,19076,19077,19078,18270,19080,19081,19082,19083,19084,19085,19086,17996,19088,19089,19090,19091,19092,19093,19094,19095,19096,19097,19098,18538,19100,19101,19102,19103,19104,19105,19106,17986,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,19118,18675,19120,19121,19122,19123,18023,19125,19126,19127,19128,19129,19130,19131,19132,19133,18317,19135,19136,19137,19138,19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19081,19153,19154,19155,19156,19157,17899,19159,19160,19161,18979,19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,18078,19178,19179,19180,19181,19182,19183,19184,19185,18094,19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,18798,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,17632,19222,19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,19051,19239,19240,19241,19242,19243,19244,19245,19246,19064,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,19259,18892,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,19274,19113,19276,19277,19278,17998,19280,19281,19282,19283,19284,19285,19286,19287,19288,19289,18473,19291,17843,19293,19294,19295,19296,19297,19298,19299,19300,19301,19302,19303,18578,19305,19306,19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,18513,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,18233,19334,19335,19336,19337,19338,19339,18446,19341,19342,19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,18722,19354,19355,19356,19357,19358,19359,19360,19361,19362,19363,18736,19365,19366,19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,19379,18078,19381,19382,19383,19025,19385,19386,19387,17580,19389,19390,19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,18812,19406,19407,19408,19409,19410,19411,19412,19413,19414,19415,18833,19417,19418,19419,19420,19421,19422,18874,19424,19425,19426,19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,18436,19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,19454,18705,19456,19457,19458,19459,19460,19461,19462,19463,18723,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,18741,19478,19479,19480,19481,19482,19483,19484,19485,19486,19487,18205,19489,19490,19491,19492,19493,19494,19495,19496,19497,18579,19499,19500,19501,19502,19503,19504,19329,19506,19507,19508,18235,19510,19511,19512,18452,19514,19515,19516,19517,19518,19519,19520,19521,19468,19523,19524,19525,19526,19480,19528,19529,19530,19531,19532,19533,19534,19535,19536,17607,19538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19386,19562,19563,19564,19393,19566,19567,19568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19412,19582,19583,19419,19585,19586,19587,19588,19589,19590,19591,18875,19593,19594,19595,19596,19597,19442,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,19610,19081,19612,19613,19614,19615,19616,19617,19618,19619,18600,19621,18241,19623,19624,19625,19335,19627,19628,19629,19630,19631,19114,19633,19634,19635,18483,19637,19638,19639,19640,19641,19642,19643,19644,18029,19646,19647,19648,19649,19650,19651,19652,18205,19654,19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,18233,19668,19669,19670,19671,17912,19673,19674,19675,19676,19677,19678,19679,19680,19681,19682,19683,19684,19685,17885,19687,19688,19689,19690,19691,18069,19693,19694,19695,19696,19697,19698,19699,19700,19701,18609,19703,19704,19705,19706,19707,19708,19709,18622,19711,19712,19713,18634,19715,19716,17700,19718,19719,19720,19721,19722,19723,19724,17719,19726,19727,19115,19729,19730,19688,19732,19733,19734,19735,19736,19737,18979,19739,19740,19741,19742,19743,19744,19138,19746,19747,19748,19749,19750,19751,19752,19082,19754,19755,19756,19757,17996,19759,19760,19761,19762,18026,19764,19765,19766,19767,19768,18205,19770,19771,19772,19773,19774,19775,19776,19777,19778,19779,19780,19781,17862,19783,19784,19785,19786,19787,19788,19789,19790,19791,18712,19793,19794,19795,19796,19797,19798,19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,18579,19810,19811,18074,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,19826,19827,19198,19215,19830,19831,19832,19833,19834,19835,19836,19837,19838,19839,18810,19841,19842,19843,19844,19845,19846,19847,19848,19849,19850,19851,19852,19050,19854,19855,19856,19857,18865,19859,19860,19861,19862,19074,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,19874,19614,19876,19877,19878,19879,19880,19881,19089,19883,19884,19885,19886,19165,19888,19889,19890,19891,19892,19893,19894,19895,19082,19897,19898,19899,19145,19901,19902,19903,19904,18473,18520,19907,19908,19909,19910,19911,19912,19913,19914,19915,18446,19917,19918,19919,19920,19921,19793,19923,19924,19925,18950,19927,19928,19929,18078,19931,19932,19933,19934,19935,19936,19937,17553,19939,19940,19941,19942,19943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,17616,19955,19956,19957,19958,17644,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,17691,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,18144,19982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,18216,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,18233,20006,20007,20008,20009,20010,18241,20012,20013,20014,20015,20016,20017,20018,20019,20020,20021,20022,19335,20024,20025,20026,18913,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,18925,20042,20043,20044,20045,20046,18744,20048,20049,20050,20051,20052,20053,20054,20055,20056,19778,20058,20059,20060,20061,20062,20063,20064,20065,19500,20067,20068,20069,20070,20071,20072,20073,20074,20075,18712,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,19889,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,19818,20099,20100,20101,20102,20103,20104,20105,18092,20107,20108,20109,20110,18110,20112,20113,20114,18123,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,17679,20127,20128,20129,20130,20131,20132,20133,20134,18150,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,19998,20158,20159,20160,20161,18233,20163,20164,20013,20166,20167,20168,20169,20170,20171,20172,20173,20174,20175,20176,20177,20178,20179,18600,20181,19730,17998,20184,20185,20186,20187,18027,20189,20190,20191,20192,20193,20194,20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,17986,20210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,17883,20223,20224,20225,20226,20227,20228,19677,20230,20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,20243,19690,19816,20246,20247,20248,20249,20250,20251,20252,20253,20254,18609,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,20270,20271,20272,20273,20274,17625,20276,20277,20278,20279,20280,18631,20282,20283,20284,20285,20286,17701,20288,20289,20290,20291,20292,17709,20294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,20318,19660,20320,20321,20322,20323,20324,20024,20326,20327,20328,20329,18241,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,18065,20350,20351,19113,20353,20354,20355,19354,20357,20358,20359,20360,20361,20362,20363,20364,20365,20366,20367,20368,18742,20370,20371,20372,20373,20374,20375,20376,20377,20378,20379,20380,20381,18712,20383,20384,20385,20386,20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,20462,19113,20464,20465,20466,20467,19637,20469,20470,19646,20472,20473,20474,20475,20476,18071,20478,20479,20480,20481,20482,20483,20484,20485,20486,20487,17543,20489,20490,20491,20492,20493,20494,20495,20496,19203,20498,20499,20500,20501,20502,20503,20504,20505,20506,18816,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,20522,20523,20524,20525,20526,20527,18410,20529,20530,20531,20532,19061,20534,20535,20536,20537,20538,20539,20540,20541,20542,17717,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,20570,18452,20572,20573,20574,20575,20576,20577,20578,20579,19907,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,20591,19739,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,19153,20606,20607,20608,20609,20610,19142,20612,20613,20614,20615,20616,20617,20618,20619,18024,20621,20622,18353,20624,20625,18501,20627,18520,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,19739,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,20654,20247,20656,20657,20658,19830,20660,20661,19845,20663,20664,20665,20666,20667,20668,20669,20670,20671,19419,20673,20674,20675,20676,20677,20678,20679,20680,19061,20682,20683,20684,20685,20686,20687,20688,20689,20550,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,20702,20703,18269,20705,18000,20707,20708,20709,20710,20711,20712,20713,18736,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,18214,20726,20727,20728,20729,20730,20731,20732,20733,19668,20735,20736,19794,20738,20739,20740,18950,20742,20743,20744,18452,20746,20747,20748,20749,20750,20751,20752,19525,20754,20755,20756,20757,20051,20759,20760,19544,20762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,19386,20787,20788,20789,20790,20791,20792,20793,17580,20795,20796,20797,20798,20799,17625,20801,20802,20803,20804,20805,20806,20807,17663,20809,20810,20811,20812,17700,20814,20815,20816,20817,20818,18435,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,20834,18270,20836,20837,20838,18676,20840,20841,20842,20843,19126,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,19146,20859,20860,20861,20862,19081,20864,20865,20866,20867,20868,20869,17996,20871,20872,20873,20874,20875,20876,20877,20878,20879,18543,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,20891,19897,20893,20894,20895,20896,20897,20898,20899,20900,19690,20902,20903,20904,19165,20906,20907,20908,20909,20910,20911,20912,20913,20914,18324,20916,20917,20918,18078,20920,20921,20922,20923,20924,20925,20926,18609,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,17626,20942,17659,20944,20945,20946,20947,20948,20949,20950,20951,17691,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,18142,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,18217,20979,20980,20981,20982,20983,19927,20985,20986,20987,20988,20989,20990,18713,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,21002,21003,20593,21005,21006,21007,21008,21009,21010,21011,21012,21013,19153,21015,21016,21017,21018,21019,19148,18473,21022,19294,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,21035,18909,21037,21038,21039,19795,21041,21042,21043,21044,21045,21046,21047,21048,21049,21050,18229,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,21062,21063,21064,21065,21066,18073,21068,21069,21070,21071,21072,21073,21074,21075,21076,21077,19941,21079,21080,21081,21082,21083,21084,21085,21086,21087,18110,21089,21090,21091,18121,21093,21094,21095,21096,21097,21098,18134,21100,21101,21102,20150,18215,21105,21106,21107,21108,21109,18579,21111,21112,21113,21114,21115,21116,21117,21118,17885,21120,21121,21122,21123,18473,18310,21126,21127,21128,21129,21130,21131,21132,18501,18521,21135,21136,21137,21138,21139,18542,21141,21142,21143,21144,21145,21146,21147,21148,21149,21150,21151,19876,21153,21154,21155,21156,20843,18536,21159,21160,21161,21162,21163,21164,20840,19178,21167,21168,21169,20274,21171,17625,21173,21174,21175,21176,21177,20282,21179,21180,21181,21182,21183,21184,17698,21186,21187,21188,21189,21190,21191,20970,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,20694,21207,21208,21209,21210,21211,21212,21213,21214,18500,18716,21217,21218,21219,21220,21221,21222,21223,21224,18579,21226,18707,21228,21229,21230,18723,21232,21233,21234,21235,18745,21237,21238,21239,21240,21241,21242,21243,18218,21245,21246,21247,21248,21249,20990,21251,21252,18586,21254,21255,18233,21257,20100,21259,21260,18610,21262,21263,21264,21265,21266,21267,21268,21269,21270,21271,18625,21273,21274,20945,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,21314,21315,21316,21317,21318,21319,20959,21321,21322,20966,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,20726,21346,21347,21348,21349,21350,21351,21352,19668,21354,21355,21356,18244,21358,21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,21374,21375,21376,17883,21378,21379,21380,21381,21382,21383,21384,21385,21386,21387,17986,21389,21390,21391,21392,18722,21394,21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,19366,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,18217,21422,21423,21424,21425,21426,21427,21428,18579,21430,21431,18715,21433,21434,21435,21436,21437,21438,21439,21440,17864,21442,21443,18078,19190,21446,21447,21448,21449,21450,19209,21452,21453,21454,21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,19413,21468,21469,21470,19588,21472,21473,21474,21475,21476,19425,21478,21479,21480,21481,21482,21483,21484,18890,21486,21487,21488,21489,21490,21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,20030,21503,21504,21505,21506,21507,21508,21509,21510,21396,21512,21513,21514,21515,21516,21517,21518,21519,21520,21521,18736,21523,21524,21525,21526,21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,17986,21538,21539,21540,21541,21542,18063,21544,21545,21546,21547,21548,21549,21550,21551,21552,17915,21554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,20918,19613,21568,21569,21570,21571,21572,19092,21574,21575,21576,21577,21578,21579,21580,21581,21582,18979,21584,21585,21586,21587,20101,21589,21590,21591,18093,21593,21594,21595,21453,21597,21598,20513,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,21614,21615,21616,20529,21618,21619,21620,21621,21622,20685,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21207,21635,21636,21637,21638,21639,21640,21641,21642,19081,21644,21645,21646,21647,21648,21649,21650,21651,19760,21653,21654,21655,21656,21657,21658,21659,21660,21661,21662,18027,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,21674,20726,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,21686,21687,19501,21689,21690,21691,21692,21693,21694,21695,20740,21697,21586,21699,21700,21701,21702,21703,21704,21705,18209,21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,19305,21720,21433,21722,21723,21724,21725,21726,21727,21728,19368,21730,21731,21732,21733,21734,21735,21736,21737,21738,18761,21740,21741,21742,21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,21758,21759,19028,21761,21762,21274,17652,21765,21766,21767,21768,21769,21770,21771,21772,21773,21774,21775,19063,21777,21778,21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21488,21790,21791,21792,21793,21794,21795,21796,21797,21798,21799,20574,21801,21802,21803,21804,21805,19747,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,21818,20231,21820,21821,21544,21823,21824,21825,21826,19277,21828,21829,20470,21831,21832,21833,21834,21835,21836,21529,21838,21839,21840,21841,21842,21843,21346,21845,21846,21847,21848,21849,21850,21851,21852,21853,19510,21855,18252,21857,21858,21859,21860,21861,21862,21863,21864,21865,21866,21867,17883,21869,21870,21871,21872,21873,20103,21081,21876,21877,21878,18102,21880,21881,21882,21883,21884,18120,21886,21887,21888,21889,21890,21891,21892,21893,19586,21895,21896,21897,21898,21899,21900,21901,20535,21903,21904,21905,21906,21907,21908,21909,21910,20544,21912,21913,21914,21915,21916,21917,21918,21919,18270,21921,21922,21923,21924,21925,21926,21927,21928,17998,21930,21931,21932,21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,21943,19768,21945,21946,21947,21948,19655,21950,21951,21952,21953,21954,21955,18234,21957,21958,21959,21960,19318,21962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,18233,21975,21976,21977,21978,21979,21676,21981,21982,21983,21984,21985,17876,21987,21988,20014,21990,21991,21992,21993,21994,21995,21996,21997,21998,21999,21378,22001,22002,22003,22004,18076,22006,22007,22008,22009,21262,22011,22012,22013,22014,22015,22016,22017,22018,22019,19956,22021,22022,22023,22024,22025,22026,22027,22028,17652,22030,22031,22032,22033,22034,22035,22036,22037,22038,22039,20954,22041,22042,22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,20966,22118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,20727,22138,22139,22140,22141,22142,22143,22144,22145,20735,22147,22148,22149,18244,22151,22152,22153,22154,22155,22156,22157,22158,21544,22160,22161,22162,22163,22164,22165,22166,22167,20354,22169,21831,22171,22172,22173,22174,22175,22176,22177,22178,22179,18745,22181,22182,22183,22184,22185,22186,22187,18947,22189,17864,22191,22192,22193,20082,22195,22196,22197,22198,22199,22200,19500,22202,22203,22204,22205,22206,22207,22208,18078,22210,22211,17553,22213,22214,22215,17607,22217,22218,22219,22220,22221,22222,22223,22224,22225,22226,17636,22228,22229,22230,22231,22232,22233,22234,19586,22236,22237,22238,22239,22240,22241,20142,22243,22244,22245,22246,22247,22248,22249,22250,22251,22252,22253,20692,22255,22256,22257,22258,22259,22260,22261,22262,18502,20631,22265,19165,22267,22268,22269,22270,22271,22272,22273,22274,22275,19278,19305,22278,22279,22280,22281,22282,22283,22284,17998,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,21159,22301,22302,22303,22304,22305,22306,22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,18271,22322,22323,22324,22325,22326,20902,20849,22329,22330,22331,22332,22333,22334,22335,19146,22337,22338,22339,18361,22341,22342,22343,22344,22345,22346,22347,18374,22349,22350,22351,22352,18397,22354,22355,18404,22357,22358,18421,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,22382,22383,18436,22385,22386,22387,22388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,21017,22400,22401,22402,22403,22404,22405,20614,22407,22408,22409,22410,18327,22412,22413,22414,22415,22416,22417,18485,22419,22420,22421,18501,22423,21136,22425,22426,22427,22428,21149,22430,21926,22432,22433,19733,22435,22436,22437,18979,22439,22440,22441,22442,18675,22444,22445,22446,17549,22448,22449,22450,22451,22452,17567,22454,22455,22456,22457,22458,22459,22460,22461,20279,22463,22464,20283,22466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,22478,22479,17698,22481,22482,22483,22484,22485,21326,22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,21676,22499,22500,18234,22502,22503,22504,22505,19089,22507,22508,22509,22510,22511,22512,22513,22514,22515,18296,22517,22518,22519,22520,22521,22522,22523,22524,22525,22526,18270,22528,22529,22530,22531,22532,22533,19733,22535,22536,22537,22538,19125,22540,22541,22542,22543,22544,22545,22546,18463,22548,22549,22550,22551,22552,22553,22554,22555,22556,21650,22558,17993,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,20596,22571,22572,22573,22574,22575,22576,22577,22578,22579,19179,22213,22582,22583,17606,22585,22586,22587,22588,22589,22590,22591,22592,22593,22232,22595,22596,22597,22598,22599,21898,22601,22602,22603,20143,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,20547,22616,22617,22618,22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,21229,22632,22633,22634,19908,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,20593,22647,22648,22649,22650,19756,22652,18318,22654,22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,18024,22666,22667,22668,22669,22670,22671,18463,22673,22674,22675,22676,22677,22678,22679,22680,19613,22682,22683,17997,22685,22686,22687,18738,22689,22690,22691,22692,21809,22694,22695,22696,22697,22698,22699,22700,22701,19025,22703,22704,22705,22706,22707,22708,22709,22710,22711,21173,22713,22714,22715,21770,22717,22718,20958,22720,22721,22722,22723,22724,22609,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,18893,22738,22739,22740,22741,20465,22743,22744,20362,22746,22747,22748,21526,22750,22751,22752,22753,22754,22755,22756,22757,22758,22759,19658,22761,22762,22763,22764,20223,22766,22767,22768,22769,22770,22771,22772,22773,22774,22775,20230,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,18675,22788,22789,22790,20705,22792,22793,22794,22795,21933,22797,22798,22799,22800,22801,22802,22803,22804,22805,22806,22807,20190,22809,22810,22811,22812,22813,22814,22815,22816,22817,19816,22819,22820,22821,22344,22823,22824,22825,22826,18804,22828,22829,22830,22831,18821,22833,22834,22835,22836,22837,22838,22839,18845,22841,22842,22843,22844,22845,19593,22847,22848,22849,22850,22851,21489,22853,22854,22855,22856,22857,22858,22859,22860,22861,22862,22863,22864,22865,22866,18914,22868,22869,22870,22871,22872,18723,22874,22875,22876,22877,22878,22879,18741,22881,22882,22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,18203,22895,22896,22897,22898,22899,22900,22901,22193,22903,22904,22905,22906,22907,22908,22909,22910,22911,19797,22913,22914,22915,22916,22917,17869,22919,22920,22921,22922,22923,19902,22925,22926,22927,22928,22929,22930,22931,18329,22933,19142,22935,22936,19386,22938,22939,22940,22458,22942,22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22587,22955,22956,22957,22958,22959,22960,20520,22962,22963,22964,22965,22966,22967,22968,18411,22970,22971,22972,18879,22974,22975,22976,22977,22978,22979,22980,22981,18890,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,22994,19276,22996,22997,22998,21833,23000,23001,23002,23003,23004,21411,23006,23007,23008,21678,23010,23011,23012,23013,23014,23015,20164,23017,23018,23019,18583,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034,23035,18043,23037,23038,23039,23040,23041,23042,20213,23044,23045,23046,23047,23048,23049,18723,23051,23052,23053,23054,21408,23056,23057,23058,23059,23060,23061,17585,23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,20788,23110,23111,23112,18798,23114,23115,23116,23117,23118,23119,23120,18819,19586,23123,23124,23125,23126,23127,19593,23129,23130,23131,23132,23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,21490,23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,23159,18905,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,18727,23172,23173,23174,23175,23176,23177,23178,23179,23180,20048,23182,23183,23184,23185,22900,23187,23188,23189,23190,17864,23192,23193,23194,23195,23196,23197,23198,21041,23200,23201,23202,23203,23204,23205,23206,19307,23208,23209,23210,23211,21015,23213,23214,23215,23216,23217,18317,23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,23234,23235,23236,18244,23238,23239,23240,23241,23242,17980,23244,23245,23246,23247,23248,23249,20248,23251,23252,23253,20274,23255,21176,18633,23258,23259,23260,17697,23262,23263,20312,23265,23266,23267,19114,23269,23270,20902,22540,23273,23274,23275,23276,23277,19142,23279,23280,19080,23282,23283,23284,20872,23286,23287,23288,23289,23290,23291,23292,23293,21142,23295,23296,23297,23298,23299,23300,23301,23302,19084,23304,23305,23306,20840,23308,22331,23310,23311,23312,23313,23314,23315,23316,23317,20918,19386,23320,23321,23322,23323,22943,23325,23326,23327,23328,23329,23330,23331,20279,23333,23334,23335,23336,18636,23338,23339,23340,23341,23342,23343,23344,23345,20958,23347,23348,23349,23350,23351,23352,20966,23354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,23366,19660,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,19668,23379,23380,23381,21358,23383,23384,23385,23386,23387,23388,23389,23390,23391,18229,18915,23394,23395,23396,23397,23398,18725,23400,23401,23402,23403,23404,23405,23406,23407,19486,23409,23410,23198,23412,23413,23414,18501,22338,23417,23418,18473,22638,23421,23422,23423,23424,23425,23426,22344,23428,23429,23430,23431,19393,23433,23434,23435,23436,23437,23438,17614,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,23450,23451,20530,23453,23454,22370,23456,23457,23458,23459,23460,23461,23462,23463,18452,23465,23466,23467,23468,23469,18477,23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,19908,23482,23483,23484,23485,23486,23487,23488,21230,23490,23491,23492,23493,23494,23495,20993,23497,23498,23499,23500,23501,23502,18983,23504,23505,23506,23507,21647,23509,23510,23511,23512,17884,23514,23515,18024,23517,23518,23519,23520,23521,21809,23523,23524,23525,23526,23527,23528,23529,23530,23531,17544,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,20274,21173,23572,23573,17661,23575,23576,23577,23578,23579,23580,23581,23582,23583,23584,20958,23586,23587,23588,23589,23590,20969,23592,23593,23594,20726,23596,23597,23598,23599,23600,23601,23602,23603,21957,20019,23606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,23618,21976,23620,23621,19276,23623,23624,23625,17869,23627,18241,23629,23630,23631,23632,23633,23634,23635,23636,23637,20224,23639,23640,18905,18926,23643,23644,23645,23646,23647,23648,23649,23650,19367,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,17558,23674,23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,20788,23711,23712,19203,23714,23715,22833,23717,23718,23719,23720,23721,23722,23723,18849,23725,23726,23727,23728,23729,23730,23731,23732,23733,18875,23735,23736,23737,23738,23739,23740,23741,23742,23743,18897,23745,23746,23747,23748,23749,23750,18913,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,23762,18923,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,23774,23652,23776,23777,23778,23779,23780,23781,23782,21676,23784,23785,23786,23787,23788,23789,21252,21963,23792,23793,23794,23795,23796,23797,23798,23799,23800,18502,21810,23803,23804,23805,23806,23807,23808,18326,23810,23811,23812,23813,19142,23815,23816,23817,23818,23819,23820,23821,23822,23823,19026,23825,23826,18375,23828,23829,23830,23831,23832,23833,23834,23835,18390,23837,23838,23839,23840,23841,23842,23843,23844,23845,23846,23847,23848,23849,23850,23851,20811,23853,23854,23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,23870,23871,23872,23873,23874,17701,23876,23877,20312,23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,21712,23891,23892,23893,23894,19670,22638,23897,23898,23899,23900,23901,17869,23903,23904,23905,20627,18465,23908,23909,18024,23911,23912,23913,23914,23915,23916,23917,23918,17843,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,23930,23931,23932,19920,23934,23935,23936,18716,23938,23939,23940,23941,23942,21011,23944,23945,23946,23947,23948,18078,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,22213,23961,19204,23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,21610,23979,23980,23981,23982,23983,23984,23985,23986,19419,23988,23989,23990,23991,20538,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,21913,24006,24007,24008,24009,24010,24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,24110,24111,19082,24113,24114,24115,24116,24117,19091,24119,24120,24121,24122,18295,24124,24125,24126,24127,24128,24129,22996,24131,24132,17887,24134,24135,24136,24137,19674,24139,24140,24141,24142,18063,24144,24145,24146,19788,24148,24149,24150,22876,24152,24153,24154,24155,24156,24157,24158,24159,24160,19479,24162,24163,24164,24165,24166,24167,24168,24169,24170,24171,20768,24173,24174,24175,24176,24177,24178,24179,24180,24181,22703,24183,24184,24185,24186,24187,24188,23434,24190,24191,24192,24193,24194,24195,24196,24197,18812,24199,24200,24201,20529,24203,24204,24205,23456,24207,24208,24209,24210,24211,24212,24213,24214,24215,20966,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,20726,24231,24232,24233,24234,22503,20013,24237,24238,24239,24240,24241,24242,22160,24244,19114,24246,24247,24248,19639,24250,24251,24252,24253,24254,21664,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,24266,20736,24268,24269,19623,24271,24272,24273,17979,24275,24276,24277,24278,24279,18077,24281,24282,24283,24284,24285,21263,24287,24288,24289,24290,24291,24292,24293,24294,24295,22025,24297,24298,24299,18123,24301,24302,24303,24304,24305,24306,24307,24308,24309,22236,24311,24312,24313,24314,24315,20535,24317,24318,24319,24320,24321,24322,24323,24324,24325,24326,24327,19078,24329,24330,24331,24332,24333,24334,18917,24336,24337,24338,24339,24340,24341,24342,18493,24344,24345,24346,24347,24348,24349,24350,24351,24352,24353,24354,19139,22322,24357,24358,24359,24360,24361,24252,24363,24364,24365,24366,24367,23653,24369,24370,24371,24372,24373,24374,24375,24376,24377,24378,24379,19910,24381,24382,24383,24384,24385,24386,19897,24388,24389,24390,18284,24392,24393,24394,24395,24396,24397,20189,24399,24400,24401,24402,24403,24404,24405,20247,24407,24408,24409,18362,24411,24412,24413,24414,21263,24416,24417,20502,24419,24420,24421,24422,24423,24424,20519,24426,24427,24428,22357,24430,24431,24432,24433,24434,24435,24436,24437,24438,19251,24440,24441,24442,24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,18436,24454,24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,22683,24471,18004,24473,24474,24475,24476,21528,24478,24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,21707,24490,24491,24492,24493,24494,24495,24496,24497,24498,21977,24500,24501,21722,24503,24504,24505,24506,24507,24508,21141,24510,24511,24512,24513,24514,24515,24516,24517,24518,20210,24520,24521,18234,24523,24524,24525,19924,24527,24528,24529,24530,24531,19307,24533,24534,24535,24536,24537,22819,24539,24540,24541,24542,24543,21462,24545,24546,24547,24548,24549,24550,24551,24552,24553,20524,24555,19054,24557,24558,24559,24560,19593,24562,24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,21491,24574,24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,19514,24587,24588,24589,24590,21130,24592,24593,24594,24595,24596,24597,24598,24599,24600,18687,24602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,21921,24614,24615,24616,24617,24618,24619,24620,24621,24622,19643,24624,24625,24626,24627,24628,24629,21525,24631,24632,24633,24634,24635,24636,24637,24638,24639,23012,24641,24642,24643,21226,24645,24646,24647,21137,24649,24650,24651,24652,24653,24654,24655,21665,24657,24658,24659,24660,24661,19821,24663,24664,24665,18093,24667,24668,24669,24670,24671,24672,24673,24674,20502,24676,24677,24678,24679,24680,24681,24682,24683,24684,18821,24686,24687,24688,24689,19054,24691,24692,24693,24694,24695,24696,18875,24698,24699,24700,24701,24702,24703,24704,24705,24706,22986,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,24719,18270,24721,21934,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24659,24734,24735,24736,24737,24738,24739,22762,24741,24742,24743,24744,24745,24746,24747,24748,17883,24750,24751,24752,24753,24754,17907,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,24770,20902,20211,24773,24774,24775,20042,24777,24778,24779,24780,24781,24782,23006,24784,24785,24786,24787,24788,24789,24790,23063,24792,24793,24794,22344,24796,24797,24798,24799,24800,17594,24802,24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,19411,24814,24815,24816,22236,24818,24819,18427,24821,24822,24823,24824,18439,18501,23803,24828,24829,24830,24831,18688,24833,24834,24835,24836,24837,24838,24839,24840,19142,24842,24843,24844,21645,24846,24847,24848,22294,24850,24851,24852,23912,24854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,24866,24867,24868,19149,24870,21570,24872,24873,24874,18003,24876,24877,24878,24879,24880,24881,24882,24883,19366,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,24793,24900,24901,24902,24903,23825,24905,23115,24907,24908,24909,24910,24911,24912,24913,24914,19411,24916,24917,24918,24919,24920,24921,24922,24818,24924,17689,24926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,24938,24939,24940,24941,19442,24943,24944,24945,24946,24947,19516,24949,24950,24951,24952,18695,24954,24955,24956,24957,24958,24959,24960,24961,24962,24857,24964,24965,24966,20630,24968,24969,24970,24971,18705,24973,24974,24975,24976,19089,24978,24979,24980,24981,24982,24983,24984,24985,24986,24987,24988,24989,20881,24991,24992,24993,24994,24995,24996,23049,22503,24999,23634,25001,23379,25003,25004,25005,25006,25007,18078,25009,25010,25011,25012,25013,25014,19944,25016,25017,25018,25019,25020,25021,25022,25023,25024,22589,25026,25027,25028,25029,25030,25031,22230,25033,25034,25035,19419,25037,25038,25039,25040,25041,25042,25043,25044,21778,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,18439,24247,25059,20007,25061,25062,19329,23627,17843,25066,25067,25068,25069,25070,25071,25072,18446,25074,25075,25076,25077,25078,25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,18713,25092,25093,25094,25095,25096,25097,25098,25099,20744,25101,18441,25103,21810,25105,25106,25107,25108,24604,25110,25111,25112,25113,25114,25115,22420,25117,25118,25119,25120,19026,25122,25123,25124,21173,25126,25127,25128,25129,18633,25131,25132,25133,20972,25135,25136,25137,25138,25139,25140,25141,25142,25143,25144,25145,21346,25147,25148,25149,25150,25151,22504,20167,25154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,21257,25167,25168,25169,25170,25171,25172,25173,25174,18914,25176,25177,25178,25179,25180,25181,25182,19469,25184,25185,25186,25187,18738,25189,25190,18712,25192,21016,25194,22509,25196,25197,25198,25199,25200,25201,25202,25203,18979,25205,25206,25207,25208,25209,25210,20101,25212,25213,23826,25215,25216,20500,25218,25219,25220,25221,23717,25223,25224,25225,18841,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,23131,25238,25239,25240,25241,25242,25243,25244,25245,25246,18890,25248,25249,25250,25251,25252,18705,25254,25255,25256,25257,25258,25259,25260,25261,25262,18580,25264,25265,25266,20080,25268,25269,25270,25271,25272,25273,25274,23161,25276,25277,25278,25279,25280,25281,19467,25283,25284,25285,25286,25287,25288,25289,25290,18745,25292,25293,25294,25295,25296,25297,25298,25299,19776,25301,25302,25303,25304,25305,25306,18913,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,21434,25319,25320,25321,18579,19821,25324,25325,23114,25327,25328,25329,25330,25331,25332,25333,25334,25335,25336,25337,25338,25339,23440,25341,25342,25343,25344,25345,20532,25347,22361,25349,25350,25351,25352,25353,25354,25355,25356,25357,25358,22387,25360,25361,25362,25363,25364,22558,25366,20840,19127,25369,25370,25371,25372,25373,25374,25375,19749,25377,25378,25379,25380,25381,23305,24392,25384,25385,25386,25387,25388,25389,21664,25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,25403,22763,25405,25406,25407,25408,25409,25410,25411,20164,25413,25414,25415,25416,25417,18239,22502,25420,25421,25422,22820,25424,25425,21079,25427,25428,25429,25430,22589,25432,25433,25434,25435,25436,19224,25438,25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,18410,25502,25503,25504,25505,25506,25507,25508,23132,25510,25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,25526,25527,21491,25529,25530,25531,25532,25533,25534,25535,23754,25537,25538,25539,25540,24156,25542,25543,25544,25545,25546,25547,19368,25549,25550,25551,25552,25553,25554,21984,25556,25557,25558,25559,25560,25561,19307,25563,25564,25565,25566,25567,18712,25569,25570,25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,21958,25586,25587,25588,25589,25254,25591,25592,21131,25594,25595,25596,23911,25598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,25610,25611,25612,25613,21136,25615,25616,25617,25618,25619,25620,22706,25622,25623,25624,25625,18372,25627,25628,25629,25630,23838,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,24438,23877,25648,25649,25650,24006,25652,25653,25654,25655,25656,25657,25658,25659,25660,25661,25662,19114,25664,25665,22160,25667,25668,25669,17910,25671,25672,25673,25674,25675,25676,19115,22174,25679,25680,25681,25682,25683,25684,25685,21525,25687,25688,25689,25690,25691,25692,25693,25694,25695,25696,25697,25698,25699,21679,25264,25702,22914,25704,25705,25706,25707,25708,17869,25710,25711,25712,25713,25714,25715,18078,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,22703,25729,25730,25731,25732,25733,25734,25735,25736,25737,18372,25739,25740,25741,25742,25743,25744,25745,25640,25747,25748,25749,25750,25751,25752,25753,25754,24436,25756,25757,25758,17700,25760,25761,25762,25763,25764,20547,25766,25767,25768,25769,25770,25771,19897,25773,22789,25775,25776,25777,20641,25779,25780,20918,19082,25783,25784,19089,25786,25787,25788,25789,22305,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,24775,25802,25803,21355,22151,25806,25807,25808,25809,25810,25811,25812,25813,25814,25815,21872,25817,25818,19821,25820,25821,25822,24290,25824,25825,25826,25827,25828,25829,25830,25831,19964,25833,25834,25835,25836,25837,25838,25839,25840,18849,25842,25843,25844,25845,25846,25847,25848,25849,22605,25851,25852,25853,25854,25855,25856,21031,25858,25859,25860,25861,25862,25863,19517,25865,25866,18520,25868,25869,25870,25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,20594,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,22530,25893,20904,25895,25896,25897,17915,25899,25900,25901,25902,25903,25904,17983,25906,23753,25908,25909,25910,25911,25912,25913,18723,25915,25916,25917,25918,25919,25920,22686,25922,25923,25924,25925,25926,25927,25391,25929,25930,25931,23697,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,24185,25946,25947,25948,25949,25950,25951,19411,25953,25954,25955,25956,25957,25958,24818,25960,18860,25962,25963,25964,25965,25966,25967,25968,25969,25970,25971,25972,19439,25974,25975,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,23465,25987,25988,25989,25990,25991,25992,18463,25994,25995,25601,25997,25998,25999,26000,26001,26002,23803,26004,26005,26006,26007,26008,19155,26010,19760,26012,26013,26014,22517,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,23047,26027,24523,26029,21993,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,19668,26043,26044,26045,21073,26047,26048,26049,17558,26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,18110,26062,26063,26064,26065,26066,26067,18121,26069,26070,26071,26072,26073,26074,26075,26076,26077,26078,22236,26080,26081,26082,20683,26084,26085,26086,26087,20549,26089,21645,26091,26092,26093,26094,26095,26096,26097,18281,26099,26100,26101,26102,26103,26104,26105,18024,26107,26108,26109,19776,26111,26112,26113,26114,26115,26116,26117,26118,26119,18579,26121,26122,26123,26124,21726,26126,26127,26128,21414,26130,26131,26132,26133,26134,26135,26136,23011,26138,26139,26140,26141,26142,26143,21689,26145,26146,26147,26148,26149,25570,26151,26152,26153,26154,26155,20010,26157,25009,26159,26160,26161,26162,19948,21880,26165,26166,26167,26168,26169,26170,26171,26172,26173,21891,26175,26176,22236,26178,26179,26180,26181,26182,20140,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,22617,26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,18501,20875,26207,26208,19888,26210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,18270,26223,26224,17979,26226,26227,17913,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,22436,26242,26243,26244,20210,26246,26247,26248,26249,26250,26251,26252,26253,23400,26255,26256,26257,26258,20048,26260,26261,26262,26263,26264,17600,26266,26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,22345,26290,23435,26292,26293,26294,26295,18399,26297,26298,26299,26300,26301,25761,26303,26304,26305,26306,26307,26308,26309,18663,26311,26312,26313,19113,26315,26316,26317,26318,26319,26320,25004,24237,26323,26324,26325,26326,26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,26342,21976,26344,21921,26346,26347,26348,26349,26350,26351,20902,26353,23311,26355,26356,26357,26358,26359,21812,26361,26362,26363,22322,26365,26366,26367,26368,26369,26370,18001,26372,26373,26374,26375,26376,26377,26378,26379,26380,26381,26382,24660,26384,26385,26386,26387,26388,26389,20485,26391,24674,20500,26394,26395,26396,26397,26398,26399,26400,24686,26402,26403,26404,26405,26406,26407,26408,26409,23126,26411,26412,24208,26414,26415,26416,26417,26418,24008,26420,26421,26422,26423,26424,26425,19876,26427,26428,26429,26430,26431,17979,26433,26434,26435,26436,26437,18535,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,22436,26451,19113,26453,26454,26455,26456,26457,26458,26459,25683,26461,25687,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,26474,26475,26476,26477,26478,26479,21983,26481,26482,26483,26484,26485,23170,20872,26488,26489,26490,26491,21669,26493,26494,26495,26496,26497,18086,26499,26500,20499,26502,26503,26504,26505,26506,26507,26508,26509,26510,26511,22834,26513,26514,19586,26516,26517,26518,26519,26520,26521,26522,26523,19428,26525,26526,26527,26528,26529,26530,26531,25976,26533,26534,26535,26536,26537,26538,18452,26540,26541,26542,26543,26544,24523,26546,26547,25807,26549,26550,26551,26552,26553,26554,18066,20355,21396,26558,26559,26560,26561,26562,26563,23653,26565,26566,26567,26568,26569,26570,26571,26572,21676,26574,26575,26576,26577,26578,26579,26580,26581,26582,26583,18579,26585,26586,26587,26588,20079,26590,26591,26592,26593,26594,26595,26596,26597,26598,21987,26600,21259,26602,26603,26604,26605,21081,26607,26608,26609,26610,26611,26612,26613,26614,22587,26616,26617,26618,22229,26620,26621,26622,26623,26624,26625,21473,26627,26628,26629,20685,26631,26632,22618,26634,26635,26636,26637,26638,26639,26640,18501,20871,26643,26644,26645,22267,26647,26648,26649,26650,19635,26227,26653,26654,26655,26656,26657,26658,20231,26660,26661,17981,26663,19346,26665,26666,26667,19465,26669,26670,26671,26672,26673,26674,18740,26676,26677,26678,18053,26680,26681,26682,26683,26684,26685,26686,26687,26688,19028,26690,26691,26692,26693,26694,25628,26696,26697,26698,26699,26700,26701,26702,26703,26704,26705,26706,26707,17626,26709,26710,26711,20282,26713,26714,26715,26716,26717,26718,26719,18135,26721,26722,26723,26724,26725,26726,26727,26728,26729,26730,21907,26732,26733,26734,26735,26736,26737,26738,20692,26740,26741,26742,26743,26744,20574,26746,26747,26748,26749,24979,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,26762,25883,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,26774,26775,22683,26777,26778,19736,20847,26781,26782,26783,26784,26785,26786,26787,26788,26789,18318,26791,26792,26793,19111,18925,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,24373,26808,26809,26810,26811,26812,26813,23689,26815,26816,26817,26818,26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,26843,22345,26845,26846,26847,26848,26849,26850,24803,26852,26853,26854,26855,26856,26857,26858,26859,26860,19407,26862,26863,26864,26865,26866,26867,18411,26869,17700,26871,26872,26873,26874,26875,26876,18433,26878,26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,19153,26890,26891,26892,17981,26894,18019,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,19732,26911,26912,26913,26914,26915,26916,23269,26918,26919,26920,20358,26922,26923,26924,26925,26926,26927,26928,26929,26930,25549,26932,26933,26934,26935,26936,26937,26938,26939,19998,26941,26942,18905,26944,26945,26946,26947,20993,26949,26950,26951,26952,20642,26954,26955,26956,26957,26958,26959,26960,19178,26962,26963,26964,26965,18361,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,23438,18396,26979,26980,26981,18410,26983,26984,26985,26986,26987,17701,26989,26990,26991,26992,24008,26994,26995,26996,26997,26998,26999,19081,27001,27002,27003,27004,27005,27006,27007,19688,27009,27010,27011,22329,27013,27014,27015,27016,27017,27018,27019,27020,26792,21647,27023,27024,19760,27026,27027,27028,27029,27030,27031,18543,27033,27034,27035,27036,27037,27038,27039,27040,27041,27042,27043,23625,21870,27046,27047,27048,27049,27050,27051,27052,27053,20338,27055,27056,27057,27058,27059,27060,22768,27062,21259,27064,27065,24289,27067,22024,27069,27070,27071,27072,27073,18123,27075,27076,27077,23125,22249,27080,27081,27082,27083,27084,27085,27086,20694,27088,27089,27090,27091,27092,27093,27094,21647,27096,27097,27098,27099,20707,18736,27102,26116,27104,27105,27106,27107,19307,27109,27110,27111,27112,27113,19795,27115,27116,27117,27118,27119,22193,19876,27122,22160,27124,27125,27126,27127,18507,27129,27130,27131,27132,27133,27134,27135,27136,27137,20596,27139,27140,27141,27142,18078,27144,27145,27146,27147,19188,27149,21457,27151,27152,27153,27154,27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,21601,27166,27167,27168,27169,27170,27171,27172,27173,27174,27175,24440,27177,27178,27179,27180,27181,19865,27183,27184,27185,19876,27187,27188,27189,27190,27191,24723,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,24259,27204,27205,27206,27207,21851,27209,27210,27211,27212,25061,27214,27215,18505,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,21354,27243,27244,27245,18707,27247,27248,27249,19142,27251,18688,27253,27254,27255,27256,27257,19139,20787,27260,27261,27262,17623,27264,27265,27266,19964,27268,27269,27270,27271,27272,27273,27274,17679,27276,27277,22244,27279,27280,27281,27282,27283,27284,21635,27286,27287,27288,27289,27290,27291,27292,26347,27294,27295,27296,27297,27298,27299,18481,27301,27302,27303,27304,19373,27306,23925,27308,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,18913,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,23500,27334,27335,27336,27337,27338,27339,27340,27341,17976,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,20842,23269,27370,26922,27372,27373,27374,27375,27376,27377,27378,18031,27380,27381,27382,27383,27384,27385,27386,19182,27388,27389,27390,27391,27392,27393,27394,19562,27396,18804,27398,27399,27400,27401,27402,27403,22833,27405,27406,27407,19593,27409,27410,27411,27412,27413,27414,27415,21487,27417,27418,27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,19919,27431,27432,18491,27434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,18736,27446,27447,27448,27449,27450,27451,27452,27453,27454,23904,27456,27457,27458,27459,27460,23170,18713,27463,27464,27465,27466,27467,27468,23192,27470,27471,27472,26093,27474,27011,18538,27477,27478,27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,27494,27495,27496,27497,27498,20902,20923,27501,21262,27503,27504,27505,27506,18112,27508,27509,27510,27511,26070,27513,27514,27515,27516,24312,27518,20535,27520,27521,27522,27523,27524,24455,27526,27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,18673,20362,27541,27542,27543,19006,27545,27546,19146,27548,27549,19157,19091,27552,24991,27554,27555,27556,27557,27558,27559,27560,27561,27562,27563,17988,27565,17880,27567,24761,27569,27570,27571,27572,27573,27574,27575,27576,27577,27011,27579,18080,27581,27582,27583,20274,22024,27586,27587,27588,27589,27590,27591,21770,27593,27594,27595,27596,27597,27598,27599,26722,27601,27602,27603,27604,27605,27606,27607,27608,20146,27610,27611,27612,27613,27614,27615,27616,19489,27618,27619,27620,27621,27622,23198,21433,27625,27626,27627,27628,27629,22203,27631,27632,27633,27634,27635,27636,27637,27638,20850,27640,27641,27642,22998,24777,27645,27646,18934,27648,26273,27650,27651,27652,27653,27654,27655,27656,27657,24185,27659,23434,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,25638,27672,27673,27674,27675,17661,27677,27678,27679,27680,27681,27682,27683,27684,27685,27686,27687,27688,17698,27690,27691,27692,27693,27694,27695,27696,22121,27698,27699,27700,27701,27702,23927,27704,27705,27706,27707,23753,27709,27710,27711,27712,27713,27714,25918,18740,27717,27718,27719,27720,27721,27722,27723,23925,27725,27726,27727,27728,27729,27730,24973,27732,26951,27734,27735,27736,27737,27738,19305,27740,27741,27742,27743,26454,27745,27746,27747,27748,27749,20024,27751,20331,27753,27754,27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,18066,25011,25019,27769,27770,27771,27772,27773,27774,27775,17632,27777,27778,27779,27780,27781,27782,27783,20529,27785,27786,27787,27788,19063,27790,27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27526,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,27818,27819,27820,27821,24390,27823,26373,27825,27826,27827,27828,27829,27830,27831,18025,27833,27834,27835,27836,27837,27838,27839,27840,21676,27842,27843,27844,27845,27846,27847,27848,27849,27850,27851,20077,27853,27854,27855,27856,18452,27858,27859,27860,27861,27862,27863,27864,27865,19733,27867,27868,27869,27870,27498,27872,27873,27874,27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,24408,27934,27935,27067,27509,27938,27939,27940,18123,27942,27943,27944,27945,27946,27947,27948,18848,27950,27951,27952,27953,27954,27955,27956,18875,27958,27959,27960,27961,27962,24576,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,27974,25908,27976,27977,27978,27979,27980,27981,27982,19468,27984,27985,27986,27987,27988,19481,27990,27991,27992,27993,27994,27995,27996,23924,27998,27999,28000,28001,28002,21136,28004,28005,28006,28007,28008,28009,28010,28011,21141,28013,28014,28015,28016,28017,28018,27745,28020,28021,28022,25170,28024,28025,28026,28027,24238,28029,28030,28031,28032,28033,28034,28035,28036,28037,28038,28039,20736,28041,20478,28043,28044,28045,28046,28047,19948,28049,28050,28051,28052,28053,17602,28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,28082,28083,28084,28085,28086,28087,27166,28089,28090,28091,18876,28093,28094,28095,28096,28097,18895,28099,28100,28101,28102,28103,28104,28105,28106,28107,28108,28109,25179,28111,28112,28113,28114,19525,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,18737,28127,28128,28129,28130,28131,24969,28133,28134,28135,28136,27006,22177,18742,28140,28141,28142,28143,28144,28145,28146,28147,28148,18712,28150,28151,28152,28153,28154,28155,28156,28157,19156,25384,28160,28161,28162,24259,28164,28165,28166,28167,28168,17874,28170,28171,28172,28173,28174,28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,20100,28188,28189,28190,22013,28192,18109,28194,28195,28196,28197,28198,28199,21887,28201,28202,28203,28204,28205,28206,28207,24924,20683,28210,28211,28212,28213,26200,28215,28216,28217,28218,28219,26890,28221,19760,28223,28224,28225,28226,24478,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,28238,23785,28240,28241,18579,28243,28244,28245,28246,28247,28248,28249,28250,28251,28252,23286,28254,28255,28256,28257,28258,28259,28260,28261,28262,22301,28264,28265,28266,28267,28268,28269,23598,28271,28272,28273,28274,23466,28276,28277,28278,28279,28280,28281,22513,28283,28284,28285,28286,28287,28288,28289,28290,24257,28292,28293,28294,28295,28296,28297,28298,28299,17600,28301,28302,28303,28304,28305,28306,28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,27260,28342,28343,24293,28345,28346,28347,28348,28349,28350,28351,28352,21453,28354,28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,28367,20519,28369,28370,28371,28372,28373,28374,18836,28376,18427,28378,28379,28380,28381,28382,28383,22389,28385,28386,28387,28388,28389,28390,18272,28392,28393,24978,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,28406,28407,28408,18295,28410,28411,28412,28413,28414,28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,22896,28431,28432,28433,28434,28435,28436,28437,19917,28439,21512,28441,28442,28443,28444,28445,25600,28447,28448,28449,28450,28451,28452,28453,18961,23269,28456,28457,21503,28459,28460,28461,28462,28463,28464,28465,17882,28467,28468,28469,28470,28471,28472,28473,28474,18241,28476,28477,28478,28479,22502,28481,19936,28483,28484,28485,28486,28487,18371,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,28502,17623,28504,28505,28506,25833,28508,28509,28510,28511,28512,28513,24315,27793,28516,28517,28518,28519,28520,28521,28522,22988,28524,28525,28526,28527,28528,18241,28530,28531,28532,28533,19117,24645,28536,28537,24649,28539,28540,28541,28542,28543,28544,28545,18296,28547,28548,28549,28550,28551,28552,28553,28554,26115,28556,28557,28558,20707,28560,28561,28562,28563,28564,28565,28566,19373,28568,28569,19142,28571,28572,28573,28574,28575,28189,28577,28578,18094,28580,28581,18805,28583,28584,28585,28586,18396,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,28598,20283,28600,26722,28602,28603,28604,28605,28606,28607,27520,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,24708,28622,28623,28624,28625,28626,28627,28628,25254,28630,28631,28632,28633,28634,28635,20916,28637,20845,28639,28640,28641,28642,28643,28644,28645,19733,28647,28648,28649,22870,28651,28652,28653,28654,28655,20613,28657,28658,28659,21435,28661,28662,28663,28664,28665,28666,23627,21016,28669,18264,25673,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,24282,28691,28692,28693,28694,28695,28696,28697,28698,28699,18362,28701,28702,28703,28704,28705,28706,19215,28708,28709,28710,22232,28712,28713,28714,28715,28716,28717,28718,28719,28720,21896,28722,28723,28724,19980,27795,28727,28728,28729,28730,28731,19072,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,25256,28744,28745,28746,28747,28748,28749,28750,28751,25563,28753,28754,28755,28756,28757,28758,28759,28760,19091,28762,28763,28764,28765,26467,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28779,27869,18244,28782,28783,28784,28785,28786,28787,21155,28789,28790,28791,28792,21355,28794,25571,28796,28797,28798,28799,28800,28801,28802,28803,26212,28805,28806,28807,28808,28809,28810,28303,28812,28813,28703,28815,28816,28817,26053,20502,28820,28821,28822,28823,28824,28825,28826,28827,28828,23718,28830,28831,28832,22239,28834,24006,28836,28837,28838,24491,28840,28841,28842,27471,28844,22640,24602,28847,28848,28849,28850,28851,28852,28853,19121,28855,28856,28857,19342,28859,18463,28861,28862,28863,28864,28865,28847,28867,28868,28869,28870,28871,28872,28873,28874,28875,28876,22549,28878,28879,28880,28881,28882,28883,28884,24615,28886,28887,28888,21930,28890,28891,28892,28893,28894,28895,28896,28897,28292,28899,28900,28901,28902,28903,23253,24412,28906,28907,28908,28909,28910,25740,28912,28913,28914,28915,28916,28917,28918,20277,28920,28921,28922,28923,28924,28925,19966,28927,28928,28929,28930,28931,28932,28933,28934,23123,28936,28937,28938,28939,28940,28941,28942,28943,19061,28945,28946,28947,28948,28949,28950,28951,28952,19268,28954,28955,28956,26903,28958,28959,28960,28961,28962,28963,28964,28965,28966,28967,20093,28969,28970,23925,28972,28973,28974,28975,20869,17997,28978,28979,28980,18739,28982,28983,28984,28985,28986,28987,28988,28989,28990,28991,17843,28993,28994,28995,28996,20705,28998,28999,29000,29001,29002,29003,18489,29005,29006,29007,29008,29009,29010,22667,29012,29013,29014,29015,29016,29017,29018,29019,29020,22163,29022,29023,26962,29025,29026,29027,19198,23849,29030,29031,29032,19964,29034,29035,29036,29037,29038,29039,29040,18411,29042,23735,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,29054,19441,29056,29057,29058,29059,29060,29061,17850,29063,29064,29065,19876,29067,29068,29069,21394,29071,29072,29073,29074,29075,29076,29077,29078,29079,29080,27990,29082,29083,29084,29085,18677,29087,25103,19336,29090,29091,29092,18713,29094,29095,29096,29097,29098,29099,29100,19312,29102,29103,29104,29105,23047,25704,29108,19500,29110,29111,29112,29113,29114,29115,29116,27146,18363,29119,29120,18110,29122,29123,29124,29125,29126,29127,29128,29129,23980,29131,19593,29133,29134,29135,29136,29137,23148,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,25257,18310,29151,19164,29153,29154,29155,24500,25254,29158,29159,26896,29161,29162,29163,29164,29165,19335,29167,29168,29169,29170,29171,23304,29110,29174,29175,29176,29177,29178,29179,29180,21137,29182,29183,29184,19888,29186,29187,29188,20247,29190,29191,29192,23429,23834,29195,25127,29197,26075,29199,29200,29201,29202,20283,29204,29205,29206,29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,18136,29220,29221,29222,22605,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,23921,29235,29236,29237,29238,29239,29240,29241,18452,29243,29244,29245,29246,20873,29248,29249,29250,29251,29252,29253,26770,29255,22743,29257,29258,24473,29260,29261,29262,21526,29264,29265,29266,29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,25303,29278,29279,18502,18001,29282,29283,29284,29285,21738,29287,26278,29289,28701,29291,29292,29293,29294,29295,27504,21463,29298,19038,29300,29301,29302,29303,19591,29305,29306,29307,19719,29309,29310,19987,29312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,19298,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29343,19081,29345,29346,29347,29348,29349,29350,29351,19281,29353,29354,29355,21409,29357,29358,29359,29360,29361,29362,29363,29364,29365,18694,29367,29368,29369,29370,29371,29372,25783,29374,29375,29376,29377,29378,29379,23400,29381,29382,29383,29384,29385,29386,29387,21022,19995,29390,26797,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,24855,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,29414,29415,29416,18960,26604,29419,19027,29421,29422,29423,29424,29425,29426,17567,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,29498,22024,29500,29501,29502,29503,25438,29505,29506,29507,29508,29509,29510,29511,29512,24430,29514,29515,29516,29517,29518,20958,29520,29521,29522,29523,25852,29525,29526,29527,29528,29529,29530,29531,29532,29533,29534,20691,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29548,29549,27980,29551,29552,29553,20624,29555,29556,29557,29558,29559,29560,21010,29562,29563,29564,29565,29566,29567,29568,29569,29570,29571,19122,19788,29574,19469,29576,29577,29578,29579,29580,29581,29582,29583,29584,29585,29586,19480,29588,29589,29590,29591,29592,29593,29594,29595,23476,29597,29598,29599,29600,29601,19276,29603,29604,29605,19144,29607,29608,29609,20847,29611,29612,29613,29614,29615,29616,29617,29618,24500,18078,29621,29622,29623,25628,29625,29626,29627,29500,29629,29630,19845,29632,29633,29634,29635,29636,17691,29638,29639,29226,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,23747,28631,29653,29654,29655,29656,25062,29658,29659,29660,29661,17998,29663,21239,29665,29666,29667,29668,29669,22788,29671,29672,19880,25413,29675,29676,22509,29678,29679,29680,29681,29682,29683,29684,29685,28128,29687,29688,29689,29690,29691,29692,29693,29694,22446,29696,29697,29698,29699,29700,29701,19776,29703,29704,29705,29706,29707,29708,29709,29710,29711,21569,29713,29714,18705,29716,29717,29718,29719,29720,23402,29722,29723,29724,29725,29726,29727,29728,29729,25775,20247,29732,24413,29734,29735,29736,29737,21452,29739,22833,29741,29742,26713,29744,29745,29746,29747,24311,29749,29750,29751,29752,29753,23739,29755,29756,29757,29758,22389,26577,29761,29762,29763,29764,29765,29766,18271,29768,29769,29770,29771,29772,29773,29774,29775,29776,21375,29778,20164,29780,29781,29782,18449,29784,29785,29786,29787,29788,19690,19683,29791,29792,26894,29794,29795,23524,29797,29798,29799,29800,29801,29802,19126,29804,29805,29806,18319,29808,29809,29810,19182,29812,29813,22016,29815,29816,17602,29818,29819,29820,29821,29822,19050,29824,29825,29826,29827,29828,29829,29830,22850,29832,29833,29834,29835,29836,29837,29838,29839,29840,23147,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,25257,29855,29856,29857,29858,29859,29860,19166,29862,29863,29864,29865,29866,29867,29868,24276,20030,29871,29872,29873,18995,29875,29876,29877,29878,29879,29880,29881,29882,19320,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,18950,29896,29897,29898,18452,29900,29901,21976,21963,29904,29905,29906,26603,29908,20500,29910,29911,29912,29913,29914,29915,29916,18819,29918,29919,29920,29921,29922,29923,29924,29925,19591,29927,29928,20824,29930,29931,29932,29933,29934,29935,29936,29937,28789,29939,18067,19679,29942,29943,29944,29945,29946,29947,29948,29949,29950,17883,29952,29953,29954,18917,29956,24955,29958,29959,29960,29961,29962,29963,29404,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,22673,29978,29979,29980,19277,29982,29381,29984,29985,29986,27718,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,30002,30003,18972,30005,30006,30007,30008,30009,22823,17577,29503,30013,21095,30015,30016,30017,30018,30019,21898,30021,30022,30023,24317,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,30035,27527,30037,30038,30039,30040,24357,30042,30043,30044,30045,30046,30047,19354,30049,30050,30051,27014,30053,30054,30055,30056,30057,30058,30059,30060,23305,28891,30063,30064,24400,30066,30067,30068,30069,30070,30071,18207,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,30143,18579,30145,30146,30147,19795,30149,30150,30151,30152,30153,23950,30155,30156,30157,30158,30159,19190,30161,30162,30163,30164,30165,30166,30167,30168,30169,30170,20503,30172,30173,30174,30175,30176,30177,30178,19038,30180,25233,18416,30183,30184,18439,30186,22423,20230,30189,30190,30191,30192,30193,30194,30195,30196,30197,30198,21380,30200,30201,18913,30203,27437,30205,30206,30207,30208,30209,24856,30211,30212,30213,30214,30215,30216,30217,30218,30219,18722,30221,30222,30223,30224,30225,30226,30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,30242,30243,19757,30245,30246,30247,30248,21933,30250,30251,24888,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,23066,22706,30268,19393,30270,30271,30272,30273,30274,30275,30276,30277,30278,30279,30280,25642,30282,30283,30284,20282,30286,30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,29520,30298,30299,24217,30301,30302,30303,30304,30305,30306,30307,30308,30309,18439,30311,25258,30313,30314,30315,30316,19137,30318,24596,30320,30321,18501,30323,21931,30325,30326,30327,30328,30329,18293,30331,30332,30333,30334,30335,30336,30337,21848,30339,30340,30341,30342,30343,30344,30345,30346,20072,30348,30349,30350,21722,30352,30353,30354,30355,30356,30357,30358,30359,18579,30361,30362,30363,30364,30365,30366,28044,30368,30161,30370,30371,20502,30373,30374,30375,30376,30377,30378,30379,24686,30381,30382,30383,30384,30385,28381,30387,30388,30389,30390,30311,30323,27640,30394,30395,20842,24246,30398,30399,30400,18723,30402,30403,30404,30405,30406,30407,30408,30409,20370,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,29236,30422,30423,30424,30425,30426,20576,30428,27027,30430,30431,30432,24256,30434,30435,30436,30437,30438,30439,30440,30441,30442,26823,30444,30445,30446,30447,30448,30449,18361,30451,19389,30453,30454,30455,30456,30457,25639,30459,28369,30461,30462,30463,30464,30465,30466,18849,30468,30469,30470,30471,30472,30473,30474,30475,30476,21479,30478,30479,30480,30481,30482,30483,21488,30485,30486,30487,30488,30489,30490,30491,30492,30493,18463,30495,30496,30497,30211,30499,30500,30501,30502,30503,30504,30505,30506,18712,18705,30509,30510,30511,30512,30513,30514,28401,30516,30517,27035,30519,23047,19929,30522,19321,30524,30525,30526,30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,21987,30587,19179,30589,30590,30591,30592,19942,30594,30595,30596,30597,30598,30599,30600,30601,21463,30603,30604,30605,30606,30607,30608,30609,30610,30611,22962,30613,30614,30615,30616,30617,29825,30619,30620,23130,30622,30623,30624,19600,30626,30627,30628,30629,30630,30631,21228,30633,30634,30635,30636,30637,30638,30639,22694,30641,30642,30643,22933,30645,30646,19732,30648,30649,30650,30651,30652,18905,30654,30655,30656,30657,30658,30659,30660,30661,30662,30663,30664,22695,30666,30667,30668,30669,30670,30671,30672,30673,27642,30675,30676,30677,30678,30679,30680,30681,23308,27328,30684,30685,30686,30687,30688,25995,30690,30691,30692,30693,30694,30695,30696,30697,20848,30699,30700,30701,30702,30703,30704,30705,30499,30707,30708,30709,30710,30711,30712,30713,24381,30715,30716,30717,30718,22703,30720,30721,30722,30723,30724,30725,26700,30727,30728,30729,30730,30731,30732,30733,22468,30735,30736,30737,30738,30739,30740,30741,30742,19985,30744,21676,30746,30747,30748,30749,25571,30751,30752,30753,30754,30755,18502,30645,30758,30759,26251,30761,30762,30763,30764,30765,30766,30767,25595,30769,30770,30771,30772,30773,25998,30775,30776,30777,30778,30779,30780,30781,30782,30783,26363,30785,30786,30723,30788,30789,30790,22943,30792,30793,17623,30795,30796,29034,30798,30799,30800,30801,30802,30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,27081,30814,20551,30816,30817,19879,20359,30820,30821,30822,30823,30824,30825,30826,21409,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,29238,30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,24980,30850,30851,30852,30853,30854,30855,30856,30857,30858,25797,30860,30861,30862,30863,30864,30865,30866,18467,30868,30869,30870,30871,30872,25257,30874,30875,30876,30877,30878,17885,30880,30881,30882,30883,30884,30885,30886,30887,27013,30889,30890,30891,30892,30893,30894,30895,23111,29501,27942,30899,30900,18410,30902,30903,30904,30905,30906,30907,19062,30909,30910,30911,30912,30913,30914,30915,18890,30917,30918,30919,30920,29982,30922,30923,24152,30925,30926,30927,30928,30929,20370,30931,30932,30933,30934,30935,30936,30937,30938,30939,30940,23925,30942,30943,30944,18705,30946,30947,30948,30949,30950,30951,30952,30953,19089,30955,30956,30957,30958,22312,30960,30961,30962,20986,30964,30965,30966,20077,30968,30969,30970,30971,28243,30973,30974,30975,30976,30977,30978,21259,30980,30981,30982,19188,30984,28354,30986,30987,30988,30989,30990,30991,30992,30993,30994,30461,30996,30997,30998,30999,31000,31001,31002,18841,31004,31005,31006,31007,31008,17688,31010,31011,31012,30311,24848,27011,31016,31017,31018,20230,31020,31021,31022,31023,31024,31025,31026,31027,28469,31029,31030,31031,31032,31033,31034,18912,31036,31037,31038,31039,31040,31041,31042,31043,31044,30884,31046,29015,31048,31049,31050,31051,31052,31053,31054,23623,31056,31057,31058,30407,31060,31061,31062,31063,25550,31065,17595,31067,31068,31069,31070,31071,18363,31073,31074,31075,31076,19573,31078,31079,31080,31081,31082,31083,31084,31085,23839,31087,31088,31089,31090,31091,31092,31093,31094,31095,30735,31097,31098,31099,31100,31101,31102,31103,31104,20143,31106,31107,31108,29063,22904,31111,31112,31113,18716,31115,31116,31117,31118,31119,31120,19308,31122,31123,31124,28221,31126,31127,31128,19736,31130,20234,31132,31133,31134,31135,31136,17982,18915,31139,31140,31141,31142,31143,31144,22337,31146,31147,31148,21022,23531,25215,31152,31153,31154,31155,31156,20274,31158,22024,31160,31161,31162,31163,31164,31165,18121,31167,31168,31169,31170,20673,31172,31173,31174,21779,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,31190,31191,18890,31193,31194,31195,31196,31197,31198,31199,31200,31201,29982,31203,31204,18726,31206,31207,31208,31209,31210,26896,31212,31213,31214,22446,31216,31217,26918,18723,31220,31221,31222,31223,19367,31225,31226,31227,31228,31229,29704,31231,31232,31233,31234,19921,31236,31237,31238,31239,31240,31241,31242,31243,18968,31245,31246,31247,31248,31249,20594,31251,31252,31253,31254,31255,31256,31257,31258,30980,19411,31261,31262,31263,27786,31265,31266,25761,31268,31269,31270,20968,31272,31273,31274,31275,31276,31277,31278,23925,31280,31281,31282,30510,31284,31285,31286,27193,31288,31289,31290,25294,23474,31293,31294,31295,28999,31297,31298,31299,31300,31301,31302,31303,31304,29722,31306,31307,31308,31309,30214,31311,31312,31313,31314,31315,31316,18463,31318,31319,31320,31321,31322,23269,18726,31325,31326,31327,31328,31329,31330,18736,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,18311,22705,31348,31349,17569,31351,31352,31353,31354,31355,29503,19961,31358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,21897,31371,31372,31373,31374,31375,31376,21905,31378,31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,25977,31390,31391,31392,31393,31394,31395,31396,31397,31398,31399,25255,31401,31402,31403,31404,31405,31406,22648,31408,31409,31410,31411,31412,31413,31414,19122,23401,31417,31418,31419,31420,31421,31422,31423,31424,21416,31426,31427,31428,29063,31430,31431,31432,18270,31434,18283,31436,31437,31438,28547,31440,31441,31442,31443,31444,31445,31446,31447,31448,27144,31450,31451,31452,31453,31454,27261,31456,26856,31458,31459,31460,31461,31462,20503,31464,31465,31466,31467,31468,23844,31470,17652,31472,31473,31474,31475,31476,31477,31478,31479,31480,31481,29523,31483,22606,31485,31486,31487,31488,22618,31490,31491,31492,31493,23163,31495,28471,31497,31498,30149,31500,31501,31502,31503,31504,31505,28805,31507,31508,31509,31510,31511,31512,31513,31514,28432,31516,31517,31518,31519,31520,31521,31522,31523,20627,28561,31526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,31538,21525,31540,31541,31542,31543,31544,31545,31546,31547,24970,31549,31550,19276,31552,31553,31554,29556,31556,31557,31558,30645,31560,31561,31562,31563,31564,31565,31566,31567,21824,31569,31570,31571,31572,31573,31574,31575,31576,28189,31578,31579,19189,31581,31582,31583,29442,31585,31586,31587,31588,31589,25639,31591,31592,20283,31594,31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,31607,17684,31609,22605,31611,31612,31613,31614,31615,31616,31617,24455,31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,27243,31630,31631,25094,31633,31634,31635,31636,31637,31638,31639,26766,31641,31642,31643,31644,21107,31646,31647,31648,23168,31650,31651,27552,31653,31654,31655,31656,31657,31658,31659,31660,31440,31662,31663,31664,31665,31666,31667,18205,28277,31670,31671,31672,18002,31674,31675,31676,31677,31678,31679,31680,31681,31682,21735,17637,31685,31686,31687,31688,31689,31690,31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,18366,24291,31704,31705,26403,28723,17700,31709,31710,31711,31712,31713,31714,18657,31716,31717,31718,31719,31720,22762,31722,31723,31724,31725,31726,31727,31728,17866,31730,31731,31732,21135,31734,31735,31736,31737,31738,31739,31740,31741,31742,31743,30332,28432,31746,31747,31748,31749,31750,31751,20747,31753,31754,31755,31756,31757,31758,21935,31760,31761,31762,31763,21731,31765,31766,31767,31768,31769,31770,31771,24344,29604,31774,31775,18696,31777,31778,31779,31780,27222,31782,31783,31784,31785,31786,31787,31788,31789,31790,31791,31792,31793,31794,24256,31796,31797,31798,31799,31800,26281,31802,26846,31804,31805,20272,31807,31808,20661,31810,24428,31812,22365,31814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,31826,25360,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,26366,31846,31847,31848,31849,29780,28796,31852,31853,31854,31855,31856,31857,31858,29110,31860,31861,31862,31863,19897,31865,31866,31867,31868,31869,31870,18233,31872,31873,31874,31875,31876,31877,31878,18586,31880,31881,31882,21923,31884,31885,25414,26590,31888,31889,31890,31891,31892,31893,31894,22193,19178,31897,31898,24412,31900,24297,31902,31903,26072,31905,31906,31907,31908,31909,22970,22974,31912,31913,31914,31915,31916,31917,31918,31919,31920,25529,31922,31923,31924,31925,31926,31927,31928,26655,31930,31931,31932,31933,26031,31935,31936,31937,31938,31939,31940,31941,27190,31943,20735,28796,31946,31947,31948,31949,31950,31951,31952,31953,18750,31955,31956,31957,31958,31959,20024,31961,31962,31963,31964,20577,31966,31967,20225,31969,31970,31971,31972,27756,31974,31975,31976,31977,31978,31979,31980,31981,31982,31983,31984,31985,31986,31987,20100,31989,31990,31991,31992,17590,31994,31995,31996,31997,31998,31999,32000,31595,32002,32003,32004,32005,32006,32007,32008,32009,32010,31108,32012,32013,32014,32015,32016,32017,32018,26119,23192,23498,32022,32023,32024,32025,32026,32027,32028,32029,21008,32031,32032,32033,32034,32035,25893,32037,32038,32039,18601,20335,32042,32043,32044,32045,32046,32047,32048,18045,32050,32051,32052,32053,18330,32055,32056,32057,20103,32059,32060,27503,32062,32063,32064,25432,32066,32067,32068,32069,32070,28089,32072,32073,32074,32075,32076,32077,32078,19593,32080,32081,32082,32083,32084,32085,32086,32087,21495,32089,32090,32091,32092,19149,32094,32095,32096,27254,32098,32099,32100,32101,32102,21230,32104,32105,32106,32107,32108,23192,32110,32111,23497,32113,32114,32115,32116,32117,32118,32119,32120,32121,30363,32123,32124,32125,32126,21572,21257,32129,32130,32131,32132,32133,32134,32135,28786,32137,32138,32139,32140,32141,20350,32143,32144,25009,32146,32147,32148,32149,32150,32151,17557,32153,32154,32155,32156,32157,32158,25026,32160,32161,32162,32163,32164,32165,32166,27166,32168,32169,22848,32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,21493,32182,32183,32184,32185,32186,32187,32188,32189,32190,19145,32192,32193,32194,32195,32196,22415,32198,32199,32200,32201,19746,32203,20705,32205,32206,32207,24155,32209,32210,32211,18933,19298,32214,32215,32216,32217,32218,32219,32220,24848,32222,20470,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,21730,32236,32237,32238,32239,19559,32241,32242,22938,32244,18374,32246,32247,32248,32249,32250,32251,29197,32253,32254,31477,32256,32257,30470,32259,32260,32261,32262,32263,27279,32265,32266,32267,32268,32269,22255,32271,32272,32273,32274,32275,32276,19614,32278,32279,32280,32281,32282,32283,32284,32285,25917,32287,32288,32289,32290,28641,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,18270,32303,32304,32305,26561,32307,32308,32309,19369,32311,32312,32313,32314,32315,32316,32317,32318,32319,19776,32321,32322,32323,32324,32325,32326,32327,32328,18709,32330,32331,26489,32333,32334,32335,32336,32337,32338,32339,32340,20645,32342,32343,32344,32345,32346,32347,32348,32349,30155,32351,32352,32353,25954,32355,32356,32357,32358,32359,32360,20674,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,26990,32374,32375,19726,32377,32378,32379,32380,27747,32382,23381,20014,32385,32386,32387,32388,32389,32390,25421,32392,32393,32394,32395,32396,27861,32398,26433,32400,32401,23633,32403,32404,32405,32406,32407,32408,20744,32410,32411,28221,32413,32414,24752,32416,32417,28031,32419,32420,32421,32422,32423,32424,32425,32426,32427,32428,32429,32430,29782,23251,18093,32434,32435,20502,32437,32438,32439,26513,32441,32442,21476,32444,20814,32446,32447,32448,32449,20535,32451,32452,32453,32454,32455,32456,32457,20691,32459,32460,32461,32462,19282,32464,32465,20189,32467,32468,27846,32470,32471,32472,32473,18579,32475,19796,32477,32478,32479,32480,32481,32482,32483,32484,32485,32486,32487,21647,32489,32490,32491,32492,25171,21361,32495,32496,19627,32498,32499,32500,19180,32502,32503,32504,32505,32506,32507,32155,32509,26616,32511,32512,32513,21608,32515,32516,32517,32518,32519,32520,32521,29834,32523,32524,32525,32526,32527,24577,32529,32530,32531,26791,32533,32534,31050,32536,32537,32538,22445,19118,18726,32542,32543,32544,32545,32546,32547,32548,32549,32550,32551,23182,32553,32554,17899,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,32654,32655,32656,24621,32658,18923,32660,32661,32662,32663,32664,32665,32666,32553,32668,32669,32670,32671,32672,20437,18078,32675,32676,32677,32678,32679,21084,32681,32682,32683,18372,32685,32686,32687,32688,32689,32690,32691,32692,29629,32694,32695,30015,32697,32698,32699,32700,32701,32702,32703,25971,32705,32706,32707,32708,32709,32710,32711,32712,32713,32714,32715,22388,32717,32718,32719,32720,32721,32722,32723,32724,32725,32726,22683,32728,32729,26949,32731,32732,32733,20598,32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,31057,24523,18584,32748,23621,18264,26898,32752,32753,32754,32755,32756,24276,32758,20247,32760,32761,32762,32763,21877,32765,32766,32767,32768,32769,32770,30996,32772,32773,32774,32775,32776,32777,32778,32779,32780,23458,32782,32783,32784,32785,32786,32787,32788,25363,32790,32791,32792,32793,25784,32795,29952,25808,32798,32799,32800,32801,32802,19928,32804,32805,32806,32807,32808,24390,32133,32811,18587,32813,32814,32815,32816,32817,32818,32819,32820,32821,32822,27474,32824,20329,26753,32827,32828,32829,26932,32831,32832,32833,32834,32835,32836,18768,32838,32839,32840,32841,32842,32843,32844,32845,32846,32847,32848,32849,32850,32851,32852,32853,32854,32855,32856,32857,32858,32244,32860,32861,17580,32863,32864,32865,32866,28921,32868,32869,32870,23579,32872,32873,32874,32875,32876,32877,32878,28602,32880,29227,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,23925,32893,32894,32895,32896,32897,19516,32899,32900,32901,32902,32903,24982,32905,32906,32907,32908,32909,32910,26210,32912,32913,32914,32915,32916,32917,32918,22996,32920,29781,19327,32923,32924,32925,32926,32927,25194,32929,32930,20226,32932,32933,32934,26550,32936,28469,32938,32939,32940,32941,32942,19823,32944,32945,32946,32947,21081,32949,32950,32951,27154,32953,32954,30613,32956,32957,32958,32959,19046,32961,32962,32963,32964,32965,32966,32967,32968,32969,32970,30183,32972,32973,32974,32975,32976,32977,32978,32979,32980,32981,32982,22387,32984,32985,32986,32987,32988,32989,32990,25784,32992,32993,22768,24237,32996,32997,32998,32999,33000,33001,33002,33003,33004,25414,20572,33007,33008,33009,33010,19690,33012,20335,33014,33015,33016,33017,33018,33019,33020,33021,33022,33023,33024,33025,33026,25997,33028,33029,33030,33031,33032,33033,18543,33035,33036,33037,33038,33039,33040,33041,33042,33043,18913,33045,33046,18519,31642,33049,33050,33051,33052,33053,21260,33055,33056,31582,33058,33059,33060,24914,18397,33063,33064,33065,33066,33067,33068,33069,31596,33071,33072,33073,33074,20814,33076,33077,33078,33079,19989,33081,29335,33083,33084,33085,21389,33087,21232,33089,33090,33091,33092,33093,33094,18739,33096,33097,33098,33099,33100,33101,23221,33103,33104,33105,33106,33107,33108,33109,33110,33111,33112,33113,33114,33115,33116,33117,33118,33119,33120,33121,33122,33123,33124,33125,33126,33127,33128,33129,33130,33131,33132,33133,33134,33135,33136,33137,33138,33139,33140,33141,33142,33143,33144,33145,33146,33147,33148,33149,33150,33151,33152,33153,33154,33155,33156,33157,33158,33159,33160,33161,33162,33163,33164,33165,33166,33167,33168,33169,33170,33171,21571,18351,33174,33175,33176,33177,33178,33179,33180,33181,33182,33183,33184,33185,33186,30758,33188,18678,33190,33191,20577,33193,33194,33195,21977,18511,33198,33199,33200,33201,33202,33203,33204,33205,25712,33207,33208,29191,33210,33211,25122,29431,33214,33215,33216,33217,33218,33219,33220,33221,31161,33223,33224,33225,29506,33227,33228,33229,24438,22849,33232,33233,33234,33235,33236,33237,33238,33239,33240,19444,33242,33243,18446,26653,33246,24239,33248,33249,33250,33251,33252,33253,33254,33255,33256,33257,23485,33259,33260,33261,32992,33263,33264,26922,33266,33267,33268,33269,33270,33271,33272,33273,33274,26465,33276,33277,33278,33279,33280,33281,33282,33283,33284,33285,33286,33287,33288,33289,20058,33291,33292,33293,33294,33295,21647,33297,33298,33299,33300,22172,33302,33303,33304,33305,19478,33307,33308,33309,33310,33311,33312,33313,17993,33315,33316,33317,22707,33319,33320,20274,18106,33323,33324,33325,23725,33327,33328,33329,33330,33331,33332,33333,33334,33335,31817,33337,33338,33339,33340,33341,33342,20551,33344,33345,33346,33347,33348,33349,33350,33351,33352,33353,33354,33355,33356,33357,33358,24132,33360,31500,33362,33363,33364,18579,33366,33367,33368,33369,21155,33371,33372,19668,33374,33375,33376,23021,33378,33379,33380,33381,33382,33383,33384,33385,33386,33387,33388,33389,33390,21252,22652,33393,21355,21993,33396,33397,33398,33399,33400,33401,33402,29780,25721,33405,33406,33407,33408,19034,33410,19411,33412,33413,33414,33415,33416,22077,20143,33419,33420,33421,33422,33423,33424,33425,33426,32215,33428,33429,33430,33431,21645,33433,33434,33435,33436,28257,33438,33439,33440,33441,33442,33443,33444,33445,33446,26765,33448,33449,33450,33451,33452,20466,33454,33455,20742,31946,33458,33459,33460,33461,33462,32992,21356,21994,33466,33467,33468,33469,33470,21960,29813,33473,22828,33475,33476,19411,33478,33479,33480,33481,33482,23587,22118,33485,31231,33487,33488,19884,33490,33491,33492,33493,33494,33495,33496,33497,26017,33499,33500,21678,33502,33503,33504,33505,33506,33507,33508,33509,33510,33511,22906,33513,33514,33515,27134,33517,33518,33519,33520,18544,33522,33523,33524,33525,33526,33527,33528,33529,33530,33531,19656,33533,33534,33535,33536,33537,33538,33539,33540,33541,19760,33543,33544,21527,33546,33547,33548,33549,33550,33551,33552,33553,33554,17599,33556,21761,32685,33559,33560,33561,33562,33563,33564,33565,33566,17623,33568,33569,33570,33571,33572,33573,19964,33575,33576,33577,19422,33579,19425,33581,33582,33583,33584,33585,33586,33587,33588,33589,33590,33591,26881,33593,33594,33595,33596,33597,33598,33599,33600,22324,33602,30406,33604,33605,33606,33607,33608,33609,20996,33611,33612,33613,33614,33615,33616,31642,33618,33619,33620,19614,33622,33623,33624,33625,33626,33627,33628,33629,33630,19928,33632,18586,33634,33635,33636,33637,33638,33639,33640,33641,33642,33643,33644,33645,33646,33647,33648,33649,27554,33651,33652,33653,33654,21676,33656,33657,33658,33659,33660,33661,33662,30323,27228,33665,33666,33667,33668,33669,28848,33671,33672,33673,33674,33675,33676,33677,33678,25212,33680,33681,19027,33683,33684,33685,33686,15067,33688,33689,33690,33691,33692,33693,33694,33695,33696,33697,33698,33699,33700,33701,33702,33703,33704,33705,33706,33707,33708,33709,33710,33711,33712,33713,33714,33715,33716,33717,33718,33719,33720,33721,33722,33723,33724,33725,33726,33727,33728,33729,33730,33731,33732,33733,33734,33735,33736,33737,33738,33739,33740,33741,33742,33743,33744,33745,33746,33747,33748,33749,33750,33751,33752,33753,33754,33755,33756,33757,33758,33759,33760,33761,33762,33763,33764,33765,33766,33767,33768,33769,33770,33771,33772,33773,33774,33775,33776,33777,33778,33779,33780,33781,33782,33783,33784,33785,33786,33787,33788,33789,33790,33791,33792,33793,33794,33795,33796,33797,33798,33799,33754,33801,33802,33803,33804,33805,33806,33807,33808,33809,33810,33811,33812,33813,33814,33815,33816,33817,33818,33819,33820,33821,33822,33823,33824,33825,33826,33827,33828,33829,33830,33831,33832,33833,33834,33835,33836,33837,33838,33839,33840,33841,33842,33843,33844,33845,33846,33847,33848,33849,33850,33851,33852,33853,33854,33855,33856,33857,33858,33859,33860,33861,33862,33725,33864,33865,33866,33867,33868,33869,33870,33871,33872,33873,33874,33875,33876,33877,33878,33879,33880,33881,33882,33883,33884,33885,33886,33887,33888,33889,33890,33891,33892,33893,33894,33895,33896,33897,33898,33899,33900,33901,33902,33903,33904,33905,33906,33907,33908,33909,33910,33911,33912,33913,33914,33915,33916,33917,33918,33919,33920,33921,33922,33923,33924,33925,33926,33927,33928,33929,33930,33931,33932,33933,33934,33935,33709,33937,33938,33939,33940,33941,33942,33943,33944,33945,33946,33947,33948,33949,33950,33951,33952,33953,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33967,33968,33969,33970,33971,33972,33973,33974,33975,33976,33977,33978,33979,33980,33981,33982,33983,33984,33985,33986,33987,33988,33989,33990,33991,33992,33993,33994,33995,33996,33997,33998,33999,34000,34001,34002,34003,34004,34005,34006,34007,34008,34009,34010,34011,34012,34013,34014,34015,34016,34017,34018,34019,34020,34021,34022,34023,33946,34025,34026,34027,34028,34029,34030,34031,34032,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34044,34045,34046,34047,34048,34049,34050,34051,34052,34053,34054,34055,34056,34057,34058,34059,34060,34061,34062,34063,34064,34065,34066,34067,34068,34069,34070,34071,34072,34073,34074,34075,34076,34077,34078,34079,34080,34081,34082,34083,34084,34085,34086,34087,34088,34089,34090,34091,34092,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34103,34104,34105,34106,34107,34108,34109,34110,34111,34112,34113,34114,34115,34116,34117,34118,34119,34120,34121,34122,34123,34124,34125,34126,34127,34128,34129,34130,34053,34132,34133,34134,34135,34136,34137,34138,34139,34140,34141,34142,34143,34144,34145,34146,34147,34148,34149,34150,34151,34152,34153,34154,34155,34156,34157,34158,34159,34160,34161,34162,34163,34164,34165,34166,34167,34168,34169,34170,34171,34172,34173,34174,34175,34176,34177,34178,34179,34180,34181,34182,34183,34184,34185,34186,34187,33698,34189,34190,34191,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34203,34204,34205,34206,34207,34208,34209,34210,34211,34212,34213,34214,34213,34216,34217,34218,34219,34220,34221,34222,34223,34224,34225,34226,34227,34228,34229,34230,34231,34232,34233,34234,34235,34236,34237,34238,34239,34240,34241,34242,34243,34244,34245,34246,34247,34248,34249,34250,34251,34252,34253,34254,34255,34256,34257,34258,34259,34260,34261,34262,34263,34264,34265,34266,34267,34268,34269,34270,34271,34272,34273,34274,34275,34276,34277,34278,34279,34280,34281,34282,34198,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,34297,34298,34299,34300,34301,34302,34303,34304,34305,34306,34307,34308,34309,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34321,34322,34323,34324,34325,34326,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34343,34344,34345,34346,34347,34193,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34360,34361,34362,34363,34364,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34381,34382,34383,34384,34385,34386,34387,34388,34389,34390,34391,34392,34393,34394,34395,34396,34397,34398,34399,34400,34401,34402,34403,34404,34405,34406,34407,34408,34409,34410,34411,34412,34413,34414,34415,34416,34417,34418,34419,34420,34421,34422,34423,34424,34425,34426,34427,34428,34429,34430,34431,34432,34189,34434,34435,34436,34437,34438,34439,34440,34441,34442,34443,34444,34445,34446,34447,34448,34449,34450,34451,34452,34453,34454,34455,34456,34457,34458,34459,34460,34461,34462,34463,34464,34465,34466,34467,34468,34469,34470,34471,34472,34473,34474,34475,34476,34477,34478,34479,34480,34481,34482,34483,34484,34485,34486,34487,34488,34489,34490,34491,34492,34493,34494,34495,34496,34497,34498,34499,34500,34501,34502,34503,34504,34505,34506,34507,34508,34509,34510,34511,34512,34513,34514,34515,34516,34517,34518,34519,34520,34521,34522,34523,34524,34525,34526,34527,34528,34529,34530,34531,34532,34533,34534,34535,34536,34442,34538,34539,34540,34541,34542,34543,34544,34545,34546,34547,34548,34549,34550,34551,34552,34553,34554,34555,34556,34557,34558,34559,34560,34561,34562,34563,34564,34565,34566,34567,34568,34569,34570,34571,34572,34573,34574,34575,34576,34577,34578,34579,34580,34581,34582,34583,34584,34585,34586,34587,34588,34589,34590,34591,34592,34593,34594,34595,34596,34597,34598,34599,34600,34601,34602,34603,34604,34605,34606,34607,34608,34609,34610,34437,34612,34613,34614,34615,34616,34617,34618,34619,34620,34621,34622,34623,34624,34625,34626,34627,34628,34629,34630,34631,34632,34633,34634,34635,34636,34637,34638,34639,34640,34641,34642,34643,34644,34645,34646,34647,34648,34649,34650,34651,34652,34653,34654,34655,34656,34657,34658,34659,34660,34661,34662,34663,34664,34665,34666,34667,34668,34669,34670,34671,34672,34673,34674,34675,34676,34677,34678,34679,34680,34681,34682,34683,34684,34685,34686,34687,34688,34689,34690,34691,34692,34693,34694,34695,34696,34697,34698,34699,34700,34701,34702,34703,34704,34705,34706,34707,34708,34709,34616,34711,34712,34713,34714,34715,34716,34717,34718,34719,34720,34721,34722,34723,34724,34725,34726,34727,34728,34729,34730,34731,34732,34733,34734,34735,34736,34737,34738,34739,34740,34741,34742,34743,34744,34745,34746,34747,34748,34749,34750,34751,34752,34753,34754,34755,34756,34757,34758,34759,34760,34761,34762,34763,34764,34765,34766,34767,34768,34769,34770,34771,34772,34773,34774,34775,34776,34777,34778,34779,34780,34781,34782,34783,34784,34785,34786,34787,34788,34789,34790,34791,34792,34793,34794,34795,34796,34797,34798,34799,34800,34801,34802,34803,15060,34805,34806,34807,34808,34809,34810,34811,34812,34813,34814,34815,34816,34817,34818,34819,34820,34821,34822,34823,34824,34825,34826,34827,34828,34829,34830,34831,34832,34833,34834,34835,34836,34837,34838,34839,34840,34841,34842,34843,34844,34845,34846,34847,34848,34849,34850,34851,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34866,34867,34868,34869,34870,34871,34872,34873,34874,34875,34876,34877,34878,34879,34880,34881,34882,34883,34884,34885,34886,34887,34888,34889,34890,34891,34892,34893,34894,34895,34896,34897,34898,34899,34900,34901,34902,34903,34904,34905,34906,34907,34908,34909,34910,34911,34912,34913,34914,34915,34916,34917,34918,34919,34920,34921,34922,34923,34827,34925,34926,34927,34928,34929,34930,34931,34932,34933,34934,34935,34936,34937,34938,34939,34940,34941,34942,34943,34944,34945,34946,34947,34948,34949,34950,34951,34952,34953,34954,34955,34956,34957,34958,34959,34960,34961,34962,34963,34964,34965,34966,34967,34968,34969,34970,34971,34972,34973,34974,34975,34976,34977,34978,34979,34980,34981,34982,34983,34984,34985,34986,34987,34988,34989,34990,34991,34992,34993,34994,34995,34996,34997,34998,34999,35000,35001,35002,35003,35004,35005,35006,35007,35008,34816,35010,35011,35012,35013,35014,35015,35016,35017,35018,35019,35020,35021,35022,35023,35024,35025,35026,35027,35028,35029,35030,35031,35032,35033,35034,35035,35036,35037,35038,35039,35040,35041,35042,35043,35044,35045,35046,35047,35048,35049,35050,35051,35052,35053,35054,35055,35056,35057,35058,35059,35060,35061,35062,35063,35064,35065,35066,35067,35068,35069,35070,35071,35072,35073,35074,35075,35076,35077,35078,35079,35080,35081,35082,15055,35084,35085,35086,35087,35088,35089,35090,35091,35092,35093,35094,35095,35096,35097,35098,35099,35100,35101,35102,35103,35104,35105,35106,35107,35108,35109,35110,35111,35112,35113,35114,35115,35116,35117,35118,35119,35120,35121,35122,35123,35124,35125,35126,35127,35128,35129,35130,35131,35132,35133,35134,35135,35136,35137,35138,35139,35140,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35166,35167,35168,35169,35170,35171,35172,35173,35174,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35106,35195,35196,35197,35198,35199,35200,35201,35202,35203,35204,35205,35206,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35265,35266,35267,35268,35269,35270,35271,35272,35273,35274,35275,35276,35277,35278,35279,35280,35281,35282,35283,35284,35285,35095,35287,35288,35289,35290,35291,35292,35293,35294,35295,35296,35297,35298,35299,35300,35301,35302,35303,35304,35305,35306,35307,35308,35309,35310,35311,35312,35313,35314,35315,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35328,35329,35330,35331,35332,35333,35334,35335,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35390,35391,35392,35393,35394,35395,35396,35397,35398,35399,35400,35401,35291,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35449,35450,35451,35452,35453,35454,35455,35456,35457,35458,35459,35460,35461,35462,35463,35464,35465,35466,35467,35468,35469,35470,35471,35472,35473,35474,35475,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35287,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,122,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35591,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35622,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35686,35687,35688,35689,35690,35691,35692,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35592,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35744,35745,35746,35747,35748,35749,35750,35751,35752,35753,35754,35755,35756,35757,35758,35759,35760,35761,35762,35763,35764,35765,35766,35767,35768,35769,35770,35771,35772,35773,35774,35775,35776,35777,35778,35779,35780,35781,35782,35783,117,35785,35786,35787,35788,35789,35790,35791,35792,35793,35794,35795,35796,35797,35798,35799,35800,35801,35802,35803,35804,35805,35806,35807,35808,35809,35810,35811,35812,35813,35814,35815,35816,35817,35818,35819,35820,35821,35822,35823,35824,35825,35826,35827,35828,35829,35830,35831,35832,35833,35834,35835,35836,35837,35838,35839,35840,35841,35842,35843,35844,35845,35846,35847,35848,35849,35850,35851,35852,35853,35854,35855,35856,35857,35858,35859,35860,35861,35862,35863,35864,35865,35866,35867,35868,35869,35870,35871,35872,35873,35874,35875,35876,35877,35878,35879,35880,35881,35882,35883,35884,35885,35886,35887,35888,35889,35890,35891,35892,35893,35894,35895,35896,35897,35898,35899,35900,115,35902,35903,35904,35905,35906,35907,35908,35909,35910,35911,35912,35913,35914,35915,35916,35917,35918,35919,35920,35921,35922,35923,35924,35925,35926,35927,35928,35929,35930,35931,35932,35933,35934,35935,35936,35937,35938,35939,35940,35941,35942,35943,35944,35945,35946,35947,35948,35949,35950,35951,35952,35953,35954,35955,35956,35957,35958,35959,35960,35961,35962,35963,35964,35965,35966,35967,35968,35969,35970,35971,35972,35973,35974,35975,35976,35977,35978,35979,35980,35981,35982,35983,35984,35985,35986,35987,35988,35989,35990,35991,35992,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,6244,36027,36028,36029,36030,36031,36032,36033,36034,224,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36039,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36072,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36125,36126,36127,36128,36104,36130,36131,36132,36133,36134,36135,36136,36137,36138,36139,36140,36141,36142,36143,36144,36145,36146,36147,36148,36149,36150,36151,36152,36153,36154,36155,36156,36157,36158,36138,36160,36161,36162,36163,36164,36165,36166,36167,36168,36169,36170,36171,36172,36173,36174,36175,36176,36177,36178,36179,36180,36181,36182,36183,36184,36185,36186,36187,36188,36189,36190,36191,36192,36193,36194,36093,36196,36197,36198,36199,36200,36201,36202,36203,36204,36205,36206,36207,36208,36209,36210,36211,36212,36213,36214,36204,36216,36217,36218,36219,36220,36221,36222,36223,36224,36225,36226,36227,36228,36229,36230,36231,36232,36233,36234,36235,36236,36237,36238,36239,36240,36241,36242,36243,36244,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36255,36227,36257,36258,36259,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36273,36274,36275,36276,36261,36278,36279,36280,36281,36282,36283,36284,36285,36286,36287,36288,36289,36290,36291,36292,36293,36294,36295,36296,36297,36298,36299,36300,36301,36302,36303,36304,36305,36306,36307,36227,36309,36310,36311,36312,36313,36314,36315,36316,36317,36318,36319,36320,36321,36322,36323,36324,36325,36326,36327,36328,36329,36330,36331,36332,36333,36334,36335,36319,36337,36338,36339,36340,36341,36342,36343,36344,36341,36346,36347,36348,36349,36350,36351,36352,36353,36354,36355,36356,36357,36358,36359,36360,36361,36226,36363,36364,36365,36366,36367,36368,36290,36370,36244,36372,36373,36374,36375,36376,36377,36378,36379,36380,36381,36382,36383,36384,36385,36386,36387,36388,36389,36390,36391,36392,36393,36394,36321,36396,36397,36398,36399,36400,36401,36402,36403,36313,36405,36406,36407,36408,36409,36410,36411,36412,36413,36414,36415,36416,36417,36418,36419,36350,36421,36422,36423,36424,36425,36426,36427,36428,36429,36430,36431,36432,36433,36434,36435,36204,36437,36438,36439,36440,36441,36442,36443,36444,36445,36446,36232,36448,36449,36450,36451,36452,36453,36454,36455,36456,36457,36458,36291,36460,36461,36462,36463,36464,36284,36466,36467,36468,36469,36470,36471,36472,36473,36474,36475,36291,36477,36478,36479,36480,36481,36482,36483,36484,36485,36402,36487,36488,36489,36490,36491,36492,36493,36494,36495,36496,36497,36498,36499,36500,36501,36502,36503,36411,36505,36506,36507,36508,36509,36510,36511,36512,36341,36514,36515,36516,36517,36518,36366,36520,36521,36522,36284,36524,36525,36526,36527,36528,36529,36530,36531,36532,36533,36534,36535,36536,36537,36380,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36312,36550,36551,36552,36553,36554,36555,36556,36557,36558,36559,36560,36561,36562,36563,36564,36565,36566,36567,36497,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,36309,36582,36583,36584,36585,36064,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36606,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36630,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36594,36671,36672,36673,36674,36675,36676,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36680,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36710,36711,36712,36713,36705,36715,36716,36717,36718,36719,36720,36721,36722,36723,36724,36725,36726,36727,36728,36729,36730,36731,36732,36733,36734,36735,36736,36737,36738,36739,36740,36704,36742,36743,36744,36745,36746,36747,36748,36719,36750,36683,36752,36753,36754,36755,36756,36757,36758,36759,36760,36707,36762,36763,36764,36765,36766,36767,36768,36769,36770,36771,36772,36773,36774,36775,36776,36777,36778,36779,36780,36781,36782,36783,36784,36785,36786,36787,36788,36789,36790,36791,36792,36793,36794,36730,36796,36797,36798,36799,36800,36801,36802,36803,36742,36805,36806,36807,36808,36809,36810,36725,36812,36813,36814,36815,36816,36817,36818,36819,36820,36821,36822,36823,36824,36597,36826,36827,36828,36829,36830,36831,36832,36833,36631,36835,36836,36837,36838,36839,36840,36841,36647,36843,36844,36845,36846,36847,36848,36849,36850,36851,36852,36853,36854,36855,36680,36857,36858,36859,36860,36861,36862,36863,36864,36865,36866,36709,36868,36869,36870,36871,36872,36718,36874,36875,36876,36877,36878,36879,36702,36881,36882,36883,36884,36885,36886,36887,36888,36889,36890,36891,36892,36893,36894,36895,36896,36897,36898,36899,36813,36901,36902,36903,36904,36905,36906,36907,36908,36909,36910,36911,36912,36913,36914,36798,36916,36917,36918,36919,36920,36921,36922,36923,36924,36745,36926,36927,36928,36929,36930,36931,36932,36933,36934,36935,36936,36937,36938,36939,36940,36941,36942,36943,36944,36945,36946,36947,36906,36949,36950,36951,36952,36953,36954,36955,36956,36957,36958,36959,36960,36961,36962,36963,36964,36965,36966,36967,36968,36969,36970,36971,36972,36973,36974,36975,36976,36977,36978,36979,36980,36981,36982,36983,36984,36985,36986,36987,36988,36989,36990,36991,36992,36993,36994,36995,36996,36997,36998,36999,37000,37001,36883,37003,37004,37005,37006,37007,37008,37009,37010,37011,37012,37013,37014,37015,37016,36776,37018,37019,37020,37021,37022,36730,37024,37025,37026,37027,37028,37029,37030,37031,37032,37033,37034,37035,37036,36622,37038,37039,37040,37041,37042,37043,37044,37045,37046,37047,37048,37049,37050,37051,37052,37053,37054,37055,37056,37057,37058,37059,37060,37061,37062,37063,36624,37065,37066,37067,37068,37069,37070,37071,37072,37073,37074,37075,37076,37077,37078,37079,37080,37081,36635,37083,37084,37085,37086,37087,37088,37089,37090,37091,37092,37093,37094,37095,37096,37097,37098,37099,37100,36844,37102,37103,37104,37105,37106,37107,37108,37109,37110,37111,36881,37113,37114,37115,37116,37117,37118,37119,37120,37121,37122,37123,37124,37018,37126,37127,37128,37129,37130,36876,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,36806,37144,37145,37146,37147,37148,37149,36954,37151,37152,37153,37154,37155,37156,37157,37158,37159,37160,37006,37162,37163,37164,37165,37166,37167,37168,37169,37024,37171,37172,37173,37174,37175,37176,36805,37178,37179,37180,37181,37182,37183,37184,37185,36833,37187,37188,36839,37190,37191,37192,37193,37194,37195,37196,37197,36849,37199,37200,37201,37202,37203,37204,36651,37206,37207,37208,37209,37210,37211,37212,37213,37214,37215,37216,37217,37218,36805,37220,37221,37222,37159,37224,36703,37226,37227,37228,37229,37230,37231,37232,37233,37234,37235,37236,37237,37238,37239,37240,37241,37242,36742,37244,37245,37246,37247,37248,37249,37250,37251,37252,37253,36949,37255,36697,37257,37258,37259,37260,37261,37262,37263,37264,36869,37266,37267,37268,37269,37270,37271,36796,37273,37274,37275,37276,37277,37278,37279,37280,37281,37282,37283,37284,37285,37286,37287,37288,37289,37290,37291,37251,37293,37294,36705,37296,37297,36601,37299,37300,37301,37302,37303,37304,37305,37306,37307,36840,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37319,37320,37321,37210,37323,37324,37325,37326,37327,37328,37329,37330,36858,37332,37333,37334,37335,37336,37337,37338,36709,37340,36730,37342,37343,37344,36807,37346,37347,37348,37349,37350,37351,37352,37353,37354,37355,37356,37357,37156,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,36719,37370,37371,37372,37373,37374,37375,37376,37377,37378,36710,37380,37134,37382,37383,37384,37385,37386,37387,37388,37389,36888,37391,37392,37393,37394,37395,37396,37156,37398,37399,37400,37401,37402,37403,37275,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,36629,37416,37417,37418,37419,37420,37421,37422,37086,37424,37425,37426,37427,37428,37429,36691,37431,36709,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37296,37444,37445,37446,37447,37448,37449,37351,37451,37452,37453,36902,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,36694,37466,37467,37468,37469,37433,37471,37472,37473,37474,37475,37476,37477,37478,37344,37480,37294,37360,37483,37484,37485,37486,37487,37488,37489,37490,37491,37492,37493,36609,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37094,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37104,37519,37520,37521,36881,37523,37524,37525,37526,37527,37528,37529,37530,36707,37532,37533,37534,37344,37536,37349,37538,37539,37540,37541,37542,37543,37462,36857,37546,37547,37271,36876,37550,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37393,37562,37563,37564,37565,37566,37156,37568,37569,37570,37571,37572,37573,36731,37575,37576,37577,37578,37579,37580,37581,37582,37422,37519,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,36669,36806,37614,37615,37616,36686,37618,37619,37620,37621,37622,37407,37624,37625,37626,36929,37628,37629,37630,37631,37632,37633,36703,37635,37636,36682,37638,37639,37640,37641,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,36705,37653,37654,37655,37656,37657,36916,37659,37660,37039,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37094,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37694,37695,37696,37697,37698,37699,37700,37701,37702,37602,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,36649,37726,37727,37728,37729,37730,37336,37732,37733,37734,37027,37736,37737,37738,37739,37740,37741,37742,37743,36805,37745,37746,37747,37635,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,36684,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37775,37776,37380,37756,37779,37780,37781,37616,37783,36610,37785,37786,37787,37788,37789,37087,37791,36659,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37332,37813,37476,37815,37816,37817,36796,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,36806,37159,37576,37836,37837,37838,37839,37840,37841,37842,37433,37844,37845,37846,37847,36730,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37147,37867,37868,37869,37870,37871,37872,37873,37874,37361,37876,37877,37878,36589,37880,37881,37882,37883,37884,37885,37886,37887,37418,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37715,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,36624,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,36938,37934,37935,37936,37937,37938,37939,37940,37941,37942,37943,36817,37945,37946,37947,37948,37949,37950,37951,37952,37953,37954,37163,37956,37957,37958,37959,37960,37961,37962,37963,37964,37464,37736,37967,37968,37969,37970,37971,36745,37973,37974,37975,37976,37224,36881,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,36877,36624,37992,37993,37994,37995,37996,37997,37998,37999,38000,38001,36633,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,36657,38016,38017,38018,38019,38020,38021,38022,38023,38024,38025,38026,38027,38028,38029,36903,38031,38032,38033,38034,37981,38036,38037,38038,38039,38040,36708,38042,38043,36742,38045,38046,38047,37156,38049,38050,38051,38052,38053,38054,38055,37121,38057,38058,38059,38060,36766,38062,38063,38064,38065,38066,37171,38068,38069,38070,38071,38072,38073,38074,38075,38076,38077,38078,38079,37994,38081,38082,38083,38084,38085,38086,38087,38088,38089,38090,38091,38092,38093,37588,38095,37801,38097,38098,38099,38100,38101,38102,38103,38104,38105,38106,38107,38108,38109,36645,38111,38112,38113,38114,38115,38116,38117,38118,38050,38120,38121,38122,38123,38124,38125,38126,38127,38128,37005,38130,38131,38132,38133,38134,38135,38136,38137,38138,38139,38140,38141,38142,38143,38144,38062,38146,38147,38148,38149,38150,38151,38152,37846,37844,38155,38156,37819,38158,38159,38160,38161,38162,38163,38164,37936,38166,38167,38168,38169,36876,38171,38172,38173,37785,38175,38176,38177,36633,38179,38180,38181,38182,38183,38184,38185,38186,38187,38188,38189,36849,38191,38192,38193,38194,36602,38196,38197,38198,38199,36926,38201,38202,38203,38204,38205,38206,38207,38208,38209,38210,38211,37159,37769,38214,38215,38216,38217,38218,38219,37533,38221,38222,37344,37165,38225,38226,38227,38228,38229,38230,38231,38232,38233,37296,38235,38236,38237,37857,36903,38240,38241,38242,38243,38244,38245,38246,38247,38248,37786,38250,38251,38252,38253,38254,38255,38256,38257,36840,38259,38260,38261,37214,38263,38264,38265,38266,37920,38268,38269,38270,38271,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38140,38283,36765,38285,38286,38287,38288,38289,38290,38291,37344,37614,38294,38295,36705,38297,38298,38215,38300,38301,38302,38303,36705,37576,38306,38307,38308,38309,38167,38311,38312,38313,38254,38315,38316,38317,38318,38319,38320,38321,36632,36669,37642,38325,38326,38327,38328,38287,38069,38331,38332,38333,38334,38335,37485,38337,38338,38339,38340,38341,38342,38343,37336,38345,38346,38347,38348,38349,38350,38351,38352,38069,38354,38355,38356,38357,38358,38359,38360,38361,37349,37156,38364,38365,38366,38367,38368,38369,36060,38371,38372,38373,38374,38375,38376,38377,38378,38379,38380,38381,38382,38383,38384,38385,38386,38387,38388,38389,38390,38391,38392,38393,38394,38395,38396,38397,38398,38399,38400,38401,38402,38403,38404,38405,38406,38407,38408,38409,38410,38411,38412,38413,38414,38415,38416,38417,38418,38419,38420,38421,38422,38423,38424,38425,38426,38427,38428,38429,38430,38431,38432,38433,38434,38435,38436,38437,38438,38439,38440,38441,38442,38443,38444,38445,38446,38447,38448,38449,38450,38451,38452,38453,38454,38455,38456,38457,38458,38459,38460,38461,38462,38463,38464,38465,38466,38467,38380,38469,38470,38471,38472,38473,38474,38475,38476,38477,38478,38479,38480,38481,38482,38483,38484,38485,38486,38487,38488,38489,38490,38491,38492,38493,38494,38495,38496,38497,38498,38499,38500,36057,38502,38503,38504,38505,38506,38507,38508,38509,38510,38511,38512,38513,38514,38515,38516,38513,38518,38519,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38533,38534,38535,38536,38537,38538,38539,38540,38541,38527,38543,38544,38545,38546,38547,38548,38549,38550,38551,38552,38553,38554,38555,38556,38557,38558,38544,38560,38561,38562,38563,38564,38565,38566,38567,38568,38569,38570,38571,38572,38573,38574,38575,38576,38577,38578,38579,38580,38581,38582,38583,38584,38585,38586,38587,38588,38589,38590,38591,38592,38593,38594,38595,38596,38597,38598,38599,38600,38601,38602,38603,38604,38605,38606,38607,38608,38609,38610,38590,38612,38613,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38624,38625,38626,38627,38628,38629,38630,38631,38632,38633,38634,38635,38636,38637,38638,38639,38640,38641,38642,38643,38644,38645,38646,38647,38648,38649,38634,38651,38652,38653,38654,38655,38656,38657,38658,38659,38660,38661,38662,38663,38664,38665,38666,38667,38668,38669,38670,38656,38672,38673,38674,38675,38676,38677,38678,38679,38680,38681,38682,38683,38684,38685,38686,38687,38688,38689,38690,38691,38692,38693,38694,38695,38696,38697,38698,38699,38700,38701,38702,38685,38704,38705,38706,38707,38708,38709,38710,38711,38712,38713,38714,38715,38716,38717,38718,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38631,38733,38734,38735,38736,38737,38738,38739,38740,38741,38742,38743,38744,38745,38746,38747,38748,38749,38750,38751,38752,38753,38754,38755,38756,38757,38758,38759,38760,38761,38762,38763,38764,38765,38741,38767,38768,38769,38770,38771,38772,38773,38774,38775,38776,38777,38778,38779,38780,38781,38782,38783,38784,38785,38786,38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,38777,38798,38799,38800,38801,38802,38803,38804,38805,38806,38807,38808,38809,38810,38811,38812,38813,38814,38815,38816,38817,38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830,38784,38832,38833,38834,38835,38836,38837,38838,38839,38840,38841,38765,38792,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38800,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38812,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38743,38887,38888,38889,38890,38891,38892,38893,38894,38895,38896,38768,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,38908,38909,38800,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930,38931,38932,38933,38815,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38511,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38504,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38578,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38599,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,38655,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,39023,39024,39025,39026,39027,39028,38682,39030,39031,39032,39033,39034,39035,39036,39037,39038,39039,39040,39041,39042,38685,39044,39045,39046,39047,39048,39049,39050,39051,39052,39053,39054,39055,39056,39057,39058,39059,39060,39061,39062,39063,39064,39065,39066,39067,38735,39069,39070,39071,39072,39073,39074,39075,39076,39077,39078,39079,39080,39081,39082,38753,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,38800,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,38808,39115,39116,39117,39118,39119,39120,39121,39122,39123,39124,39125,39126,39127,39128,39129,39130,39131,39132,39133,39134,39135,39136,38740,39138,39139,39140,39141,39142,39143,39144,39145,39146,39147,39148,39098,39150,39151,39152,39153,39154,39155,39156,39157,39158,39120,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39139,39171,39172,39173,39174,39175,39176,39177,39178,39179,39180,39181,39182,39183,39184,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39089,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39102,39209,39210,39211,39212,39213,39214,39215,39216,39217,39218,39219,39220,39120,39222,39223,39224,39225,38586,39227,39228,38962,39230,39231,39232,39233,39234,38544,39236,39237,39238,39239,39240,39241,39242,39243,39244,38595,39246,39247,39248,39249,39250,39251,39252,39253,38626,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,38658,39266,39267,39268,39269,39270,39271,39272,39273,39274,39275,38688,39277,39278,39279,39280,39281,39282,39283,39284,39285,39286,39287,39288,39289,39290,39291,39292,39293,39294,39295,39296,39297,39298,39299,39300,39301,38718,39303,39304,39305,39306,39307,39308,39309,39310,39311,39312,39313,39314,39315,39316,39317,39318,39319,39320,39321,39322,39092,38836,39325,39326,39327,39328,39329,39330,39331,39332,38863,39334,39335,39336,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,38780,39352,39353,39354,39355,39356,39357,39358,39359,39092,39361,38755,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,38809,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,38785,39405,38812,39407,39408,39409,39410,39326,39412,39413,38952,39415,39416,39417,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,38513,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,38975,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,38613,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,38662,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39032,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39045,39512,39513,39514,39515,39516,39517,39518,39519,39520,39521,39522,39182,39524,39525,39526,39527,39528,39529,39530,39531,39532,39533,38753,39535,39536,39537,39538,39539,39540,38927,39542,39543,39544,39545,39546,39547,39548,39549,39550,38812,39552,39553,39554,39555,39556,39557,39558,39559,39560,39561,39562,39563,39564,39565,39566,39567,39176,39569,39570,39571,39572,39573,39574,39575,39576,39577,38772,39579,39580,39581,39582,39583,39584,39585,39586,38929,39588,39589,39590,39591,39592,39593,39594,39595,39596,39597,39598,39599,39600,39601,39602,39391,39604,39605,39606,39607,39608,39609,39610,39611,39612,39613,39614,39615,38771,39617,39618,39544,39620,39621,39622,39623,39624,39625,39626,39627,39628,39629,39630,39631,39632,39633,39634,39635,39555,39637,39638,39639,39640,39641,39642,39643,39644,39645,39646,39647,39648,39419,39650,39651,39652,39653,39654,38964,39656,39657,39658,39659,39660,39661,39662,39663,39664,39665,39666,39237,39668,39669,39670,39671,39672,39673,39674,39675,39676,39677,39678,38602,39680,39681,39682,39683,39684,39685,39686,39687,38626,39689,39690,39691,39692,39693,39694,39695,39696,39697,39698,39699,39700,39701,39702,39703,39489,39705,39706,39707,39708,39709,39284,39711,39712,39713,39714,39715,39716,39717,39718,38721,39720,39721,39722,39723,39209,39725,39726,39727,39728,39729,39730,39731,39732,38773,39734,39735,39736,39737,39738,39571,39740,39741,39742,39743,39744,39745,39585,39747,39748,39749,39750,39751,39752,39753,38928,39755,39756,39757,39758,39759,39760,39761,39762,39763,39120,39765,39766,39767,39768,39769,39770,38926,38887,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,38790,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39119,39798,39799,39800,39801,39802,39803,39804,39805,39806,39807,39808,39809,39405,39415,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,38515,39825,39826,39827,38569,39829,39830,39831,39832,39833,38992,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39019,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,38677,39870,39871,39872,39873,39874,39060,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,38711,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,39900,39901,39902,38747,39904,39905,39906,39907,39908,39909,39910,39911,39912,39097,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39765,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,38735,39953,39954,39955,39956,39092,39958,39932,39960,39961,39962,39963,39964,39965,39939,39967,39968,39969,39970,39971,39926,39973,39974,39975,39976,39977,39978,39979,39980,39981,38743,39983,39984,39985,39986,39987,39988,39989,39990,39991,39927,39993,39994,39995,39996,39997,39998,39999,40000,40001,40002,40003,39120,40005,40006,40007,40008,40009,40010,40011,40012,40013,38838,40015,40016,40017,40018,40019,40020,39426,40022,40023,38515,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,39830,40036,40037,40038,40039,40040,40041,40042,40043,39836,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,39015,40056,40057,40058,40059,40060,40061,40062,40063,40064,40065,40066,40067,40068,40069,40070,40071,40072,40073,38663,40075,40076,40077,40078,40079,40080,40081,40082,40083,40084,40085,40086,40087,40088,40089,40090,40091,38689,40093,40094,40095,40096,40097,40098,40099,40100,40101,40102,40103,40104,40105,40106,39879,40108,40109,40110,40111,40112,38678,40114,40115,40116,40117,40118,40119,38748,40121,39100,40123,40124,40125,40126,40127,40128,40129,40130,40131,40132,40133,40134,40135,40136,40137,39127,40139,40140,40141,40142,40143,40144,40145,39182,40147,40148,40149,40150,40151,40152,40153,38748,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164,39622,40166,40167,40168,40169,40170,39608,40172,39174,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,39196,40253,40254,40255,40256,40257,39098,40259,40260,40261,39767,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,38619,40281,40282,40283,40284,40285,40286,40287,38963,40289,40290,40291,40292,40293,40294,39432,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,39448,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,39467,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,39271,40335,40336,40337,40338,40339,39032,40341,40342,40343,40344,40345,40346,40347,40348,40349,39061,40351,40352,40353,40354,40355,40356,40357,40358,40359,40360,40361,40362,40117,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,39906,40375,40376,40377,40378,40379,39993,40381,40382,40383,40384,40385,40386,40387,40388,40389,39120,40391,40392,40393,38836,40395,40396,40397,40398,40399,38836,40401,40402,40403,39927,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,39765,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40401,40430,40431,40432,40433,39908,40435,40436,40437,40438,39583,40440,40441,40442,40443,40444,40445,40446,40447,40448,39100,40450,40451,40452,40453,40454,38912,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40479,40480,40481,40482,40483,40484,39115,40486,40487,40488,40489,40490,40491,40492,40493,40494,40495,40496,40497,40498,40499,40500,40501,40502,40503,39160,40505,40506,40507,40508,40509,40510,40511,40512,40513,40514,40515,39359,40517,39974,40519,40520,40521,40522,38950,40524,40525,40526,40527,40528,40529,40530,40531,40532,40533,40534,38515,40536,40537,40538,40539,40540,40541,40542,40543,38526,40545,40546,40547,40548,40549,39669,40551,40552,40553,40554,40555,40556,38585,40558,40559,40560,40561,40562,40563,40564,40565,40566,40567,40568,39476,40570,40571,40572,40573,40574,39012,40576,40577,40578,40579,40580,40581,40582,40583,40584,40585,40586,40079,40588,40589,40590,40591,40592,40593,40594,40595,40596,40597,40598,40599,40600,40601,40602,38689,40604,40605,40606,40607,40608,40609,40610,40611,38717,40613,40614,40615,40616,40617,40618,40619,40620,40621,40622,40623,40624,40625,40626,40627,40628,40629,40630,40631,40632,40633,39906,40635,40636,40637,40638,40639,40640,40641,40642,39993,40644,40645,40646,40647,40648,40649,39765,40651,40652,40653,40654,40655,39790,40657,40658,40659,40660,40661,40662,40663,39910,40665,40666,40667,40668,40669,40670,39927,40672,40673,40674,40675,40676,40677,40678,40679,40680,40681,40682,40683,39940,40685,40686,40687,40688,40689,40690,40691,39974,40693,40694,40695,40696,39989,40698,40699,40700,40701,40522,40703,40704,40705,40706,40707,40708,40709,40710,40711,40391,40713,40714,40715,40716,40717,40718,40719,40720,40721,38792,40723,40724,40725,40726,40727,40728,40729,40730,40731,40732,40733,40734,40735,39651,40737,40738,40300,40740,40741,40742,39457,40744,40745,40746,40747,40748,40749,40750,40751,40752,40570,40754,40755,40756,39490,40758,40759,39504,40761,40762,40763,40764,40765,40766,40767,38685,40769,40770,40771,40772,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40784,40785,40786,40787,40788,40789,40790,40791,39182,40793,40794,40795,40796,40797,40798,40124,40800,40801,40802,40803,40804,40805,40806,39938,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,39542,40821,40438,40823,40824,40673,40826,40827,40828,40829,40830,40715,40832,40833,40834,40835,40836,40837,40838,40839,40840,40841,40726,40843,40844,40845,40846,40847,40848,39790,40850,40851,40852,40853,40854,40855,40856,39543,40858,40859,40860,40861,40862,40863,40864,40865,40866,40867,40868,40869,39765,40871,40872,40873,38928,40875,40876,40877,40878,40879,40880,40881,40882,40883,40884,40885,40886,40887,40888,40889,40890,40891,40892,40893,40894,40895,40896,40897,40898,40899,40900,40901,40902,40903,40904,40905,40906,40907,40908,40909,40910,40911,40912,40913,40914,40915,40916,40917,40918,40919,40920,40921,40922,40923,40924,40925,40926,40927,40928,40929,40930,40931,40932,40933,40934,40935,40936,40937,40938,40939,40940,40941,40942,40943,40944,40945,40946,40947,40948,40949,40950,40951,40952,40953,40954,40955,40956,40957,40958,40959,40960,40961,40962,40963,40964,40965,40966,40967,40968,40969,40970,40971,40972,40973,40974,40975,38962,40977,40978,40979,40980,40981,40982,40983,40984,40547,40986,40987,40988,38592,40990,40991,40992,40993,40994,40995,40996,40997,39471,40999,41000,41001,41002,41003,41004,41005,41006,41007,41008,41009,41010,41011,40593,41013,41014,41015,41016,41017,41018,39499,41020,41021,41022,41023,41024,41025,41026,41027,41028,41029,41030,41031,41032,41033,41034,41035,41036,41037,41038,41039,41040,38717,41042,41043,41044,41045,40018,41047,40458,41049,41050,41051,41052,41053,41054,41055,41056,41057,41058,41059,41060,41061,41062,41063,41064,41065,39358,41067,41068,41069,41070,39196,41072,41073,41074,41075,41076,41077,39328,41079,41080,41081,41082,38911,41084,41085,41086,41087,41088,41089,41090,41091,41092,38833,41094,41095,41096,41097,39958,38834,41100,41101,41102,41103,41104,41105,41106,41107,41108,41109,40458,41111,41112,41113,41114,41115,41116,41117,41118,41119,41120,41121,41122,41123,41124,41125,41126,41127,41128,38780,41130,41131,41132,41133,41134,41135,41136,41137,41138,41139,39815,41141,41142,41143,41144,41145,40543,38573,41148,41149,41150,41151,41152,41153,41154,41155,41156,41157,39859,41159,41160,41161,41162,41163,41164,41165,41166,41167,41168,41169,40081,41171,41172,41173,41174,41175,41176,41177,41178,41179,41180,41181,41182,40102,41184,40615,41186,41187,41188,41189,41190,41191,41192,41193,41194,41195,41196,41197,41198,41199,41200,41201,39988,41203,41204,41205,41206,41207,39924,41209,41210,41211,41212,41213,41214,41215,41216,41217,40006,41219,41220,41221,41222,41223,41224,41225,41226,38785,41228,41229,41230,41231,41232,41233,41234,41235,41236,41237,39370,41239,41240,41241,41242,41243,38792,41245,41246,41247,41248,41249,41250,41251,39117,41253,41254,41255,41256,41257,41258,41259,41260,41261,41262,41263,41264,41265,39611,41267,41268,41269,41270,41271,41272,41273,41274,41275,39183,41277,41278,41279,41280,41281,41282,41283,39196,41285,41286,41287,41288,41289,41290,41291,41292,39928,41294,41295,41296,41297,41298,41299,41300,41301,41302,40715,41304,41305,41306,41307,41308,41309,41310,41311,41312,41313,41314,41315,41316,41317,40401,41319,41320,41321,41322,41323,39417,41325,41326,41327,39233,41329,39669,41331,41332,41333,41334,41335,39251,41337,41338,41339,41340,41007,41342,41343,41344,41345,41346,41347,41348,41349,41350,41177,41352,41353,41354,41355,41356,41357,39505,41359,41360,41361,39883,41363,41364,41365,41366,39889,41368,41369,41370,41371,41372,41373,41374,41375,41376,39328,41378,40493,41380,41381,41382,41094,41384,41385,41386,41387,41388,41389,41390,41391,41392,41393,39958,40432,41396,40458,41398,41399,41400,41401,41402,41403,41404,41405,41406,41407,41408,41409,39357,41411,41412,41413,39908,41415,41416,41417,41418,41419,41420,41421,41422,41423,41424,41139,38929,41427,41428,41429,41430,41431,41432,41433,38936,41435,41436,41437,41438,41439,41440,38565,41442,41443,41444,41445,41446,41447,41448,41449,41450,41451,41452,41453,41454,41455,41456,41457,41458,41459,41460,41461,41462,41463,41464,41465,41466,41467,41468,41469,41470,41471,41472,38967,41474,41475,41476,41477,40549,41479,41480,41481,41482,41483,41484,41485,41486,41487,41488,41489,41490,41491,39456,41493,41494,41495,41496,41497,41498,41499,41500,41501,41502,41503,41504,39476,41506,41507,41508,41509,41510,41511,39490,41513,41514,41515,41516,41517,39504,41519,41520,41521,41522,41523,41524,41525,39514,41527,41528,41529,41530,41531,41532,41533,41534,41535,41536,41537,41538,41539,41540,41541,41542,39183,41544,41545,41546,41547,41548,41549,41550,39100,41552,41553,41554,41555,41556,41557,41558,41559,40263,41561,41562,41563,41564,41565,41566,41567,41568,41569,41570,41571,41572,41573,41574,38800,41576,41577,41578,41579,41580,41581,41582,40635,41584,41585,41586,41587,41588,41067,41590,41591,38922,41593,41594,41595,41596,41597,41598,41599,41600,41601,41602,41603,41604,41417,41606,41607,41608,41609,39353,41611,41612,41613,41614,41615,41616,41617,41618,41619,41620,41621,41622,41623,41624,41625,41626,41627,41628,41629,41630,41631,41632,41633,41634,41635,41636,41637,41638,41639,41640,41641,41642,41643,41644,41645,41646,41647,41648,41649,41650,41651,41652,41653,41654,41655,41656,41657,41658,41659,41660,41661,41662,41663,41664,41665,41666,41667,41668,41669,41670,41671,41672,41673,41674,41675,41676,41677,41678,41679,41680,41681,41682,41683,41684,38928,41686,41687,41688,41689,41690,41691,41692,41693,41694,41695,41696,41697,41698,39583,41700,41701,41702,41703,41704,41705,41706,39423,41708,41709,41710,39844,41712,41713,41714,41715,41716,41717,41718,39861,41720,41721,41722,41723,41724,38673,41726,41727,41728,41729,41730,41731,41732,41733,41734,41735,39061,41737,41738,41739,41740,41741,39894,41743,41744,41745,41746,41747,41748,41749,41750,41751,41752,41753,41754,40666,41756,41757,41758,41759,40407,41761,41762,41763,41764,41765,41766,41767,41768,39765,41770,41771,41772,41773,41774,41775,41776,41777,41778,41779,41780,41781,41782,41783,39915,41785,41786,41787,41788,41789,41790,41791,41792,41793,41794,41759,41762,41797,41798,41799,41800,41801,41802,41770,41804,41805,41806,41807,41808,41809,41810,41811,38916,41813,41814,41815,41816,39989,41818,41819,41820,41821,39975,41823,41824,41825,41826,41827,41828,41829,40391,41831,41832,41833,41834,41835,41836,41837,41838,41839,39419,41841,41842,41843,41844,41845,41846,41847,39435,41849,41850,41851,41852,41853,41854,39474,41856,38658,41858,41859,41860,41861,41862,40346,41864,41865,41866,41867,41868,41869,39061,41871,41872,41873,41874,41875,41876,41877,41878,41879,41880,41881,41882,41883,41884,41885,41886,41887,41888,41889,41745,41891,41892,41893,41894,41895,41896,41897,41898,41899,41900,41901,41902,41903,39910,41905,41906,41907,41908,41909,40440,41911,41912,41913,41914,41915,41916,41917,39098,41919,41920,41921,41922,41923,41924,41925,41926,39637,41928,41929,41930,41931,41932,41933,41934,41935,39182,41937,41938,41939,40155,41941,41942,41943,41944,41945,39621,41947,41948,41949,41950,41951,41952,41953,39609,41955,41956,41957,41958,39172,41960,41961,41962,41963,41964,41965,41966,41967,41968,41969,41970,41971,41972,40259,41974,41975,41976,41977,41978,41979,41980,40507,41982,41983,41984,41985,41986,41987,41988,41989,41990,41991,38564,41993,41994,41995,41996,41997,39230,41999,42000,42001,42002,42003,42004,42005,42006,42007,40552,42009,42010,42011,42012,42013,42014,42015,42016,39251,42018,42019,42020,42021,42022,42023,42024,39261,42026,42027,42028,42029,42030,42031,42032,42033,42034,42035,42036,39271,42038,42039,42040,39290,42042,42043,42044,42045,42046,42047,42048,42049,42050,42051,42052,39306,42054,42055,42056,42057,42058,42059,42060,42061,39089,42063,42064,42065,42066,42067,42068,42069,42070,42071,38836,42073,42074,42075,42076,42077,42078,40491,42080,42081,42082,42083,42084,38841,42086,41072,42088,42089,42090,39326,42092,42093,42094,42095,42096,38857,42098,39358,42100,42101,42102,42103,40435,42105,42106,42107,42108,42109,39357,42111,42112,42113,42114,38928,42116,42117,42118,42119,42120,42121,42122,42123,42124,42125,38814,42127,42128,42129,42130,42131,42132,42133,40281,42135,42136,42137,42138,42139,42140,42141,42142,42143,42144,42145,42146,39815,42148,42149,42150,42151,42152,40026,42154,42155,42156,42157,42158,42159,42160,42161,42162,42163,42164,42165,40314,42167,42168,42169,42170,42171,42172,42173,42174,38604,42176,42177,42178,42179,42180,42038,42182,42183,42184,42185,39489,42187,42188,42189,42190,42191,42192,42193,42194,42195,42196,42197,39289,42199,42200,42201,42202,42203,42204,42205,42206,42207,42208,42209,42210,41871,42212,42213,42214,42215,42216,42217,42218,42219,42220,42221,42222,42223,42224,42225,38718,42227,42228,42229,42230,42231,42232,42233,39990,42235,39396,42237,42238,39183,42240,42241,42242,38768,42244,42245,39543,42247,42248,42249,42250,42251,42252,42253,42254,39607,42256,42257,42258,42259,42260,42261,42262,42263,39524,42265,42266,42267,42268,42269,42270,42271,42065,42273,42274,42275,42276,42277,42278,39100,42280,42281,42282,42283,42284,42285,42286,42287,42288,42289,39940,42291,42292,42293,42294,42295,42296,42297,42298,42299,42300,42301,42302,42093,42304,40524,42306,42307,42308,42309,42310,42311,38546,42313,42314,42315,42316,42317,42318,42319,42320,42321,42322,42323,42324,38608,42326,42327,42328,42329,42330,38634,42332,42333,42334,42335,42336,42337,42338,42339,42340,42341,42342,42343,42344,42345,42346,42347,39490,42349,42350,42351,42352,42353,42354,42355,42356,38691,42358,42359,42360,42361,42362,42363,42364,42365,42366,42367,42368,38723,42370,38756,42372,42373,42374,42375,42376,42377,42378,42379,42380,42381,42382,42383,42384,40731,42386,42387,42388,42389,42390,42391,42392,42393,42394,42395,42396,42397,39799,42399,42400,42401,42402,42403,42404,42405,42406,42407,42408,42409,42410,42411,42412,42413,39328,42415,42416,42417,38755,42419,42420,42421,42422,42423,42424,42425,42426,42427,42428,42429,42430,42431,42432,42433,42434,42435,42436,42437,42438,42439,42440,42441,42442,42443,42444,42445,42446,42447,42448,42449,42450,42451,42452,42453,42454,42455,42456,42457,42458,42459,42460,42461,42462,42463,42464,42465,42466,42467,42468,42469,42470,42471,42472,42473,42474,42475,42476,42477,42478,42479,42480,42481,42482,42483,42484,42485,42486,42487,42488,42489,42490,42491,42492,42493,42494,42495,42496,42497,42498,42499,38796,39389,42502,42503,42504,42505,42506,42507,42508,42509,38838,42511,42512,42513,42514,42515,39196,42517,42518,42519,42520,42521,42513,42523,42524,42525,42526,42527,40460,42529,42530,42531,42532,42533,42534,42535,42536,42537,42538,42539,42540,42541,42542,39420,42544,42545,42546,39813,42548,42549,42550,42551,42552,42553,42554,42555,41150,42557,42558,42559,42337,42561,42562,42563,42564,42565,42566,42567,39706,42569,42570,42571,42572,42573,42574,39713,42576,42577,42578,42579,42580,42581,42582,42583,42584,42585,42586,38724,42588,42589,42590,42591,42592,42593,42594,42595,42596,41240,42598,42599,42600,42601,42602,42603,42604,42387,42606,42607,42608,42609,42610,42611,42612,42613,42614,42615,40005,42617,42618,42619,42620,42621,42622,39988,42624,42625,42626,42627,38785,42629,42630,42631,42632,42633,42634,42635,42636,42637,42638,42639,42640,39120,42642,42643,42644,39371,42646,42647,38853,39804,42650,42651,42652,39328,42654,42655,42656,42657,39421,42659,42660,42661,42662,42663,42664,42665,40296,42667,42668,42669,42670,42671,42672,42673,42674,42675,42676,40314,42678,42679,42680,42681,42682,42683,39476,42685,42686,42687,42688,42689,42690,42691,42692,42693,42694,39271,42696,42697,42698,42699,42700,39501,42702,42703,42704,42705,42706,42707,39515,42709,42710,42711,42712,42713,42714,42715,42716,42717,39172,42719,42720,42721,42722,42723,42724,42725,42726,39089,42728,42729,40128,42731,42732,40811,42734,42735,42736,42737,42738,42739,42740,42741,41816,42743,42744,42745,42746,42747,40665,42749,42750,42751,42752,42753,42754,39993,42756,42757,42758,42759,42760,42761,42762,42763,42764,42765,42766,42767,40833,42769,42770,42771,42772,42773,42774,42775,42776,42777,42778,42602,42780,42781,42782,42073,42784,42785,42786,42787,42788,39921,42790,42791,42792,42793,42794,42795,42796,42797,42798,42799,42800,42801,42802,42803,42804,42805,42806,42807,42808,42809,42810,42811,42812,42813,42814,42815,42816,42817,42818,42819,42820,42821,42822,42823,42824,42825,42826,40263,42828,42829,42830,38615,42832,40980,42834,42835,42836,42837,38541,40559,42840,42841,42842,42843,42844,42845,42846,42847,42848,42849,42850,41004,42852,42853,42854,42855,42856,42857,42858,42859,42860,42861,42862,42863,40091,41020,42866,41372,42868,42869,42870,42871,42872,42873,39988,42875,42876,42877,42878,41429,42880,42881,42882,42883,42884,42885,42886,42887,42888,42889,42890,39583,42892,42893,42894,40378,42896,42897,39357,42899,42900,42901,42902,41593,42904,42905,42906,42907,42908,42909,42910,42911,42912,42913,42914,42915,42916,39906,42918,42919,42920,42921,42922,38834,42924,42925,42926,42927,42928,39919,42930,42931,42932,42933,42934,42935,42936,41775,42938,42939,42940,42941,42942,42943,38778,42945,42946,42947,42948,42949,42950,42951,42952,42953,42148,42955,42956,42957,42958,42959,42960,42961,42155,38975,42964,42965,42966,42967,42968,42969,42970,42971,42972,42973,42176,42975,42976,41006,42978,42979,42980,42981,42982,42983,42984,42985,42986,42987,42988,42989,42990,42991,42705,42993,39877,42995,42996,42997,42998,42999,43000,39305,43002,43003,43004,43005,43006,43007,43008,43009,41909,39092,43012,40383,43014,43015,43016,43017,43018,43019,41219,43021,43022,43023,43024,43025,43026,43027,43028,43029,43030,43031,43032,43033,43034,42112,43036,43037,42235,43039,43040,42372,40383,43043,43044,43045,43046,39343,43048,43049,43050,43051,43052,43053,43054,40832,43056,43057,43058,43059,43060,43061,43062,42073,43064,43065,43066,43067,39328,43069,43070,43071,43072,40458,43074,43075,43076,43077,43078,43079,43080,43081,43082,43083,43084,43085,38937,43087,43088,43089,43090,43091,43092,43093,43094,43095,41996,43097,43098,43099,43100,43101,43102,43103,43104,43105,43106,43107,43108,43109,43110,43111,43112,43113,43114,43115,43116,43117,43118,43119,43120,43121,43122,43123,43124,43125,43126,43127,43128,43129,43130,43131,43132,43133,43134,43135,43136,43137,43138,43139,43140,43141,43142,43143,43144,41999,43146,43147,41481,43149,42680,43151,43152,40323,43154,43155,43156,43157,43158,43159,43160,43161,43162,43163,43164,43165,43166,43167,40064,43169,43170,43171,43172,43173,38689,43175,43176,43177,43178,43179,38718,43181,43182,43183,43184,43185,43186,43187,43188,43189,43190,43191,43192,41074,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,41070,39592,43208,43209,43210,43211,43212,43213,43214,43215,43216,39123,43218,43219,43220,43221,43222,43223,43224,43225,43226,43227,43228,43229,40858,43231,43232,43233,43234,43235,43236,43237,43238,42876,40846,43241,43242,43243,43244,43245,39804,43247,43248,43249,43250,43251,43252,43253,43254,43255,43256,42075,43258,39908,43260,43261,43262,43263,43264,43265,42728,43267,43268,43269,43270,43271,43272,43273,43015,43275,43276,39120,43278,43279,43280,43281,43282,43283,38780,43285,43286,43287,42956,43289,43290,43291,43292,43293,43294,43295,40980,43297,43298,43299,43300,43301,38532,43303,43304,40990,43306,43307,43308,43309,43310,43311,43312,43313,43314,43315,43316,42984,43318,43319,43320,43321,43322,43323,43324,39489,43326,43327,43328,43329,43330,43331,43332,43333,41871,43335,43336,43337,43338,43339,43340,43341,38717,43343,43344,43345,43346,43347,43348,43349,43350,43351,43352,43353,43354,43355,43356,43268,43358,43359,43360,43361,43362,41411,43364,43365,39151,43367,43368,43369,43370,43371,43372,43373,43374,43375,43376,43377,43378,43379,40264,43381,43382,43383,43384,43385,43386,43387,43388,43389,40846,43391,43392,43393,43394,43395,43396,43397,43398,43399,43400,43401,39071,43403,43404,43405,43406,43407,43408,43409,43410,43411,43412,39089,43414,43415,43416,43417,43418,43419,42793,43421,43422,43423,43424,40266,43426,43427,38735,43429,43430,43431,43432,43433,43434,43435,43436,43437,43438,43439,43440,43441,43442,43443,43444,43445,43446,40377,43448,43449,43450,39993,43452,41776,43454,43455,43456,43457,43458,43459,43460,43461,39974,43463,43464,43465,43466,43467,43468,43469,43470,43471,43472,43289,43474,43475,43476,43477,43478,43479,43480,40298,43482,43483,43484,43485,43486,43487,43488,43152,39474,43491,43492,43493,43494,43495,43496,43497,43498,39274,43500,41520,43502,43503,43504,43505,39516,43507,43508,43509,43510,43511,43512,42875,43514,43515,43516,43464,43518,43519,43520,43521,43522,43523,43524,43525,41833,43527,43528,43529,43530,43531,43532,43533,43534,43535,43536,43537,40121,41411,43540,43541,43542,38929,43544,43545,43546,43547,39608,43549,43550,43551,43552,43553,39528,43555,43556,43557,43558,43559,43560,43561,39196,43563,43564,43565,43566,43567,43568,43569,43570,39102,43572,43573,43574,43575,43576,40809,43578,43579,43580,43581,43582,43583,43584,43585,39096,43587,43588,43589,43590,43591,43592,43593,43594,43595,43596,43597,43598,43599,43600,43601,39815,43603,43604,43605,43606,43607,43608,38514,43610,43611,43612,40312,43614,43615,43616,40327,43618,43619,43620,41858,43622,43623,43624,43625,43626,43627,43628,43629,43630,39034,43632,43633,43634,43635,43636,39065,43638,43639,43640,43641,39892,43643,43644,43645,43646,43647,43648,43649,43650,39366,43652,43653,43654,43655,43656,43657,43658,43659,43660,43661,43662,43287,43664,43665,43666,43667,41599,43669,43670,43671,40437,38834,43674,43675,43676,43677,43678,42531,43680,43681,43682,43683,43684,43685,43686,43687,43540,43689,43690,41759,41412,43693,43694,38914,43696,43697,43698,43699,43700,43701,43702,43703,43704,41130,43706,43707,43708,43709,43710,43711,43712,43713,43714,39815,43716,43717,43718,43719,43720,43721,39825,43723,43724,43725,43726,39000,43728,43729,43730,43731,43732,43733,43734,43735,39860,43737,43738,43739,43740,43741,43742,43743,43744,43745,43746,39872,43748,43749,43750,39877,43752,43753,43754,43755,43756,43757,43758,43759,43760,43761,43762,43763,39893,43765,43766,43767,43768,43769,43770,43771,43772,43773,43774,43775,43776,43777,41606,43779,43780,43781,43782,43783,40382,43785,41777,43787,43788,43789,43790,43791,43792,43793,43794,43391,43796,43797,40376,43799,43800,43801,43802,39993,41833,43805,43806,43807,43808,43809,43810,43811,43812,43813,40731,43815,43816,43817,43818,43819,43820,40159,43822,43823,43824,38844,43826,43827,43828,43829,43830,43831,43832,43833,43834,43835,43836,39801,43838,43839,43840,43841,43842,43843,39413,43845,43846,43847,42307,43849,43850,38514,43852,43853,42168,43855,43856,43857,43858,40327,43860,43861,43862,43863,43864,43865,43866,43867,39271,43869,43870,43871,40593,43873,43874,43875,43876,43877,43878,43879,40342,43881,43882,43883,43884,43885,43886,43887,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,42200,43902,43903,43904,43905,43906,39514,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919,43920,43921,43922,42721,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,40015,43938,43939,43940,43941,43942,43943,43944,43945,43946,40016,43948,43949,43950,43951,43952,40644,43954,43955,43956,43957,43958,40005,43960,43961,43962,43963,43964,42114,43966,41962,40674,43969,43970,43971,43972,43973,43974,43975,43976,42404,43978,43979,43980,43981,39181,43983,43984,43985,43986,43987,43988,43989,43990,43991,39370,43993,43994,43995,43996,43997,43998,43942,44000,38920,44002,44003,44004,44005,44006,44007,44008,42132,44010,44011,44012,38579,44014,44015,44016,44017,44018,38963,44020,44021,44022,44023,44024,44025,44026,40304,44028,39479,44030,44031,44032,44033,39267,44035,44036,44037,44038,39062,44040,44041,44042,44043,44044,44045,44046,44047,44048,44049,40117,44051,39908,44053,44054,44055,44056,44057,44058,44059,44060,41295,44062,44063,44064,44065,44066,44067,42292,44069,44070,44071,44072,44073,44074,44075,44076,44077,44078,44079,39621,44081,44082,44083,44084,44085,44086,40666,44088,44089,44090,44091,40828,44093,44094,44095,43454,44097,44098,44099,44100,44101,44102,43598,44104,44105,44106,44107,44108,39984,44110,39973,44112,44113,44114,44115,41221,44117,44118,44119,44120,44121,44122,44123,44124,44125,44126,44127,42076,44129,42956,44131,44132,44133,44134,44135,44136,44137,44138,38964,44140,38586,44142,44143,44144,44145,44146,44147,44148,44149,44150,44151,42857,44153,44154,44155,44156,44157,44158,44159,44160,44161,44162,44163,38663,44165,39504,44167,44168,44169,44170,44171,41528,44173,44174,44175,44176,44177,44178,44179,44180,44181,44182,44183,44184,44185,39186,44187,44188,44189,44190,44191,44192,44193,44194,44195,39151,44197,44198,44199,44200,44201,44202,44203,44204,44205,44206,44207,44208,44209,44210,40507,44212,44213,44214,44215,44216,44217,44218,44219,44220,39183,44222,44223,44224,44225,44226,43995,44228,44229,44230,41920,42259,44233,44234,41964,44236,44237,44238,44239,44240,44241,44242,39151,44244,44245,44246,44247,44248,40506,44250,44251,44252,44253,44254,44255,44256,44257,44258,44259,44260,44261,44262,44263,44264,44265,44266,44267,44268,43144,44270,44271,44272,44273,44274,44275,44276,44277,44278,44279,44280,44281,44282,44283,44284,44285,44286,44287,44288,44289,44290,44291,44292,44293,44294,44295,44296,44297,44298,44299,44300,44301,44302,44303,44304,44305,44306,44307,44308,44309,44310,44311,44312,44313,44314,44315,44316,44317,44318,44319,44320,44321,44322,44323,44022,44325,38533,44327,44328,44329,44330,44331,43315,44333,44334,44335,44336,44337,44338,42985,44340,44341,44342,44343,44344,44345,44346,44347,40593,44349,44350,44351,44352,44353,44354,41025,44356,44357,44358,44359,44360,44361,44362,44363,44364,44365,44366,44367,44368,44369,44370,44371,44372,44373,44374,44375,38716,44377,44378,44379,44380,44381,40377,44383,44384,44385,44386,44387,44388,44389,44390,39580,44392,44393,44394,44395,44396,44397,44398,44399,44400,44401,44402,44403,44404,38800,44406,44407,44408,40506,44410,44411,44412,44413,44414,44415,44416,44417,43927,44419,44420,44421,44422,44423,44424,44425,44426,44427,39196,44429,44430,44431,44432,44433,42790,44435,44436,44437,44438,44439,44440,44441,44442,44443,40810,44445,44446,44447,43231,44449,44450,44451,44452,44453,44454,44455,42876,44457,44458,44459,40658,44461,44462,44463,44464,44465,44466,40125,44468,44469,44470,44471,44472,44473,39124,44475,44476,44477,44478,44479,44480,44481,44482,44483,44484,44485,44486,44487,44488,38586,44490,44491,44492,44493,44494,44495,44496,44497,44498,44499,44500,44501,44502,44503,44504,44505,44506,44507,44508,44509,44510,44511,44512,39230,44514,44515,44516,44517,43313,44519,44520,44521,44522,44523,44524,44525,44526,44357,44528,44529,44530,44531,44532,44533,44534,44535,44536,44537,41370,44539,44540,44541,44542,44543,44544,44545,43039,41131,44548,44549,44550,44551,44552,38929,44554,44555,44556,44557,44558,44559,44560,44561,39581,44563,44564,44565,44566,39988,44568,44569,44570,44571,44572,44573,44574,44575,44576,44577,38780,44579,44580,42117,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44592,44593,44594,44392,44596,44597,38887,44599,44600,41139,39993,44603,44604,44605,44606,44607,44608,44609,44610,44611,43056,44613,44614,44615,44616,44617,44618,44619,43605,44621,42156,44623,44624,44625,44626,44627,38976,44629,44630,44631,39846,44633,44634,44635,44636,38636,44638,44639,44640,44641,44642,42183,44361,44645,44646,44647,44648,44649,44650,44651,44652,44653,44654,44655,44656,44657,44658,44659,44660,44661,44662,44663,44664,39514,44666,44667,44668,44669,44670,44671,44672,44673,44674,44675,44676,44677,44678,43436,44680,44681,44682,44683,44684,44685,44686,44687,39090,44689,44690,44691,44692,40672,44694,44695,44696,44697,44698,44699,41774,44701,44702,44703,44704,39790,44706,44707,44708,44709,44710,44711,39988,44713,44714,44715,44716,44717,44718,44719,44720,38800,44722,44723,44724,44725,44726,38929,44728,44729,44730,44731,44732,44733,44734,44735,44736,44737,39120,44739,44740,44741,44742,44743,44744,44745,44746,44747,44748,44749,43995,44751,44752,44753,44754,44755,44756,42399,44758,44759,44760,44761,44762,44763,44764,44765,44766,42661,44768,44769,44770,44771,42156,44773,44774,44775,44776,44777,44778,44779,44780,38998,44782,44783,44784,44785,44786,43743,44788,44789,39871,44791,44792,44793,44794,44795,39879,44797,44798,44799,44800,44801,44802,44803,41743,44805,44806,44807,44808,44809,44810,44811,44812,44813,44814,41417,44816,40382,44818,44819,44820,44821,44822,44823,43455,44825,44826,44827,44828,44829,44830,44831,41790,44833,44834,43260,44836,44837,44838,44839,42758,44841,44842,44843,44844,44845,41775,44847,44848,44849,44850,44851,44852,44853,38800,44855,44856,44857,44858,44859,38896,40856,44862,44863,44864,44865,44866,41225,44868,44869,44870,38956,44872,39437,44874,44875,44876,42678,44878,44879,44880,44881,43491,44883,44884,44885,44886,44887,44888,44889,44890,39271,44892,44893,44894,44895,40346,44897,44898,44899,44900,42711,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,43184,44913,44914,44915,44916,44917,44918,44919,44920,44921,44922,42067,44924,39370,44926,44927,44928,44929,44930,44931,44932,44933,40382,44935,44936,44937,44938,44939,44940,44941,44942,44943,40005,44945,44946,44947,38814,44949,44950,44951,44952,44953,44954,44955,44956,44957,44958,44959,44960,39743,44962,44963,44964,44965,44966,38772,44968,44969,41949,44971,44972,38876,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44984,38756,44986,44987,44988,41920,44990,44991,44992,44993,41928,44995,44996,44997,44998,38522,45000,45001,45002,45003,45004,45005,45006,45007,45008,45009,45010,45011,45012,45013,45014,45015,44022,45017,45018,45019,45020,45021,41332,45023,45024,45025,45026,45027,45028,39252,45030,45031,45032,39258,45034,45035,45036,45037,45038,45039,45040,45041,45042,45043,40336,45045,45046,45047,45048,42042,45050,45051,45052,45053,45054,45055,45056,45057,45058,38718,45060,45061,45062,45063,45064,45065,45066,45067,39092,39358,45070,43078,45072,45073,45074,41906,45076,45077,41386,45079,45080,45081,45082,45083,45084,41114,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45096,45097,45098,45099,45100,45101,45102,39357,45104,45105,45106,45107,42900,45109,41688,45111,45112,45113,45114,45115,45116,45117,45118,45119,40738,45121,45122,40542,45124,45125,45126,45127,40045,45129,45130,45131,45132,45133,45134,45135,45136,45137,39861,45139,40081,45141,45142,45143,45144,45145,45146,45147,45148,45149,45150,45151,45152,45153,45154,45155,45156,40094,45158,45159,45160,45161,45162,45163,45164,45165,45166,43347,45168,45169,45170,45171,45172,39172,45174,45175,45176,45177,45178,45179,45180,45181,45182,45183,44714,45185,45186,45187,44583,45189,45190,45191,45192,45193,45194,45195,45196,45197,45198,45199,38773,45201,45202,45203,45204,45205,45206,45207,45208,45209,45210,45211,45212,45213,45214,41416,45216,45217,45218,45219,45220,43542,43669,45223,45224,45225,45226,45227,45228,41137,45230,45231,45232,41204,45234,42892,45236,45237,45238,45239,45240,45241,38928,45243,45244,45245,45246,45247,45248,45249,43088,45251,45252,45253,45254,45255,45256,45257,45258,45259,45260,39814,45262,45263,45264,45265,45266,45267,45268,45269,45270,45271,45272,45017,45274,45275,45276,45277,42324,45279,45280,45281,45282,38602,45284,45285,45286,45287,45288,45289,45290,45291,39258,45293,45294,45295,45296,45297,45298,45299,45300,45301,42697,45303,45304,45305,39294,45307,45308,45309,45310,45311,45312,45313,42054,45315,45316,45317,45318,45319,45320,45321,45322,45323,45324,41072,45326,45327,45328,45329,45330,45331,45332,40401,45334,45335,45336,45337,41113,45339,45340,43262,45342,45343,41412,41689,45346,45347,45348,45349,45350,45351,45352,45353,45354,45355,45356,39581,45358,45359,45360,39370,45362,45363,45364,39151,45366,45367,45368,45369,45370,45371,45372,45373,45374,45375,45376,45377,43218,45379,45380,45381,45382,45383,45384,45385,45386,45387,45388,44495,45390,45391,45392,38962,45394,45395,45396,45397,45398,45399,45400,45401,45402,45403,40990,45405,45406,45407,45408,45409,45410,45411,41350,39015,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,39892,45431,45432,45433,45434,45435,45436,45437,45438,45439,45440,45441,45442,39989,45444,45445,41430,45447,45448,45449,45450,45451,45452,41701,45454,45455,45456,45219,41411,45459,45460,45461,45462,44729,45464,45465,45466,45467,45468,45469,39581,45471,45472,43415,45474,45475,45476,45477,45478,45479,44228,45481,45482,39927,45484,45485,45486,45487,45488,45489,45490,45491,45492,44847,45494,45495,45496,45497,45498,45499,45500,43816,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,39815,45515,45516,45517,45518,45286,45520,45521,45035,45523,45524,45525,45526,45527,45528,45529,45530,45531,45532,45533,45534,43503,45536,39062,45538,45539,45540,45541,45542,45543,45544,45545,45546,45547,38720,45549,45550,45551,45552,45553,45554,45555,45556,45557,45558,44751,45560,45561,45562,45563,45564,45565,45566,41053,45568,45569,45570,45571,45572,45573,45574,45575,45576,45577,45578,45579,43260,45581,45582,45583,45584,45585,45586,43690,45588,45589,45590,44558,45592,45593,45594,45595,45596,45597,38874,45599,45600,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,39574,45613,45614,45615,39091,45617,43969,45619,45620,45621,45622,45623,45624,43458,45626,45627,45628,45629,45630,45631,43393,45633,45634,45635,45636,45637,45638,40975,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45656,45657,45658,45659,45660,45661,40980,45663,45664,38521,45666,45667,45668,45669,45670,45671,45672,38985,42177,45675,45676,45677,45678,45294,45680,45681,45682,45683,45684,45685,45686,45687,45688,43630,42205,45691,45692,45693,45694,45695,45696,38717,45698,45699,45700,45701,45702,45703,45704,45705,45706,45707,45708,45709,45710,45711,45712,45713,39089,45715,45716,45717,45718,45719,45720,41100,45722,45723,45724,42530,45726,45727,45728,45729,45730,45731,45732,45733,45734,45735,45736,45737,43364,45739,45740,45741,39085,45743,45744,45745,45746,45747,41102,45749,45750,40470,45105,45753,45754,45755,45756,43260,45758,45759,45760,45754,45762,45111,45764,45765,45766,45767,45768,45769,45770,45771,45772,45773,45774,45775,44394,45777,45778,45779,45780,45781,42662,45783,45784,40290,45786,45787,45788,38549,45790,45791,45792,45793,45794,45795,38604,45797,45798,45799,45800,45801,45802,39690,45804,45805,45806,45807,45808,45809,45810,45811,45812,45813,39486,45815,45816,39293,45818,45819,45820,45821,45822,45823,42059,45825,45826,45827,45828,41072,45830,45831,42657,39345,45834,45835,45836,45837,45838,41068,45840,45841,40435,45843,45844,45845,45846,45847,41094,45849,45850,38928,45852,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,38904,45867,45868,45869,45870,45871,45872,43822,45874,45875,45876,45877,45878,45879,44129,40486,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45908,45909,45910,45911,45912,45913,45914,45915,45916,45917,45918,45919,45920,45921,45922,45923,45924,45925,45926,45927,45928,45929,45930,45931,45932,45933,45934,45935,45936,45937,45938,45939,45940,45941,45942,45943,45944,45945,45946,45947,45948,45949,45950,45951,45952,45953,45954,45955,45956,45957,45958,45959,45960,45961,45962,45963,45964,45965,45966,45967,45968,45969,45970,45971,45972,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45984,45985,45986,45987,45988,45989,45990,45991,45992,45993,45994,45995,45996,45997,45998,42515,42551,46001,46002,42157,42969,46005,46006,46007,38593,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,39020,46021,46022,46023,46024,46025,46026,46027,46028,46029,46030,46031,46032,46033,46034,46035,46036,46037,46038,46039,46040,46041,46042,46043,46044,46045,46046,46047,46048,46049,46050,46051,46052,46053,46054,46055,46056,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46076,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46096,46097,46098,46099,40094,46101,46102,46103,46104,46105,46106,46107,46108,46109,40615,46111,46112,46113,46114,46115,46116,46117,46118,46119,42876,41823,46122,46123,46124,46125,46126,44760,46128,46129,46130,46131,41412,46133,46134,38741,46136,46137,46138,46139,46140,44582,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,42502,46153,46154,46155,46156,46157,46158,43394,46160,46161,46162,46163,41139,43372,46166,46167,46168,46169,46170,46171,46172,46173,46174,39123,46176,46177,46178,46179,46180,46181,46182,46183,46184,46185,46186,46187,46188,46189,46190,46191,46192,42135,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46208,46209,44021,46211,46212,46213,46214,46215,46216,40549,46218,46219,46220,46221,46222,46223,46224,46225,40755,46227,46228,46229,45815,46231,46232,46233,46234,42704,46236,46237,46238,46239,46240,46241,46242,44905,46244,46245,46246,46247,46248,46249,39143,46251,46252,46253,43569,46255,44062,46257,46258,46259,46260,46261,46262,46263,40808,46265,46266,46267,46268,46269,46270,46271,46272,46273,46274,46275,46276,46277,46278,40821,46280,46281,46282,46283,40665,46285,46286,46287,46288,46289,40384,46291,46292,46293,46294,46295,46296,46297,46298,44202,46300,46301,46302,46303,46304,46305,46306,39337,46308,46309,46310,46311,46312,46313,46314,46315,41615,42920,46318,46319,46320,44730,46322,46323,46324,46325,46326,46327,46328,46329,46330,39736,46332,46333,41841,46335,46336,46337,46338,46339,38969,46341,42010,46343,46344,41340,42986,46347,46348,46349,46350,46351,46352,41352,46354,46355,46356,46357,39509,42714,46360,46361,46362,46363,42720,46365,46366,46367,46368,46369,44714,46371,46372,46373,46374,43014,46376,46377,46378,46379,46380,46381,46382,46383,46384,46385,46386,46387,46388,43528,46390,43659,46392,46393,46394,42785,46396,46397,46398,46399,46400,40458,46402,46403,46404,46405,46406,46407,46408,46409,46410,38757,46412,46413,46259,46415,46416,46417,46418,46419,40686,46421,46422,46423,46424,46425,46426,46427,46428,46429,46430,46431,46432,39813,46434,42157,46436,46437,46438,38975,46440,46441,46442,46443,42179,42337,46446,46447,44895,46449,42200,46451,46452,46453,46454,46455,46456,46457,46458,38717,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,39172,46476,46477,46478,46479,38756,46481,46482,46483,40803,46485,46486,46487,46488,46489,46490,46491,44760,46493,46494,46495,46496,46497,46498,46499,46500,46501,46502,46503,46504,46505,46506,46507,46508,46509,46510,41222,46512,46513,46514,46515,46516,46517,46518,46519,46520,39357,46522,46523,46524,46525,46526,46527,40635,46529,46530,46531,46532,46533,43012,44818,46536,46537,46538,46539,41305,46541,46542,46543,46544,46545,38853,40401,46548,46549,46550,46551,40461,46553,46554,46555,46556,46557,46558,46559,43711,46561,46562,46563,46564,46565,46566,46567,38948,46569,46570,46571,46572,46573,46574,46575,46576,40290,46578,46579,46580,46581,46582,38541,39449,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,39476,46601,46602,46603,46604,46605,46606,46607,41352,46609,46610,46611,38691,46613,46614,46615,46616,46617,46618,46619,46620,46621,46622,45316,46624,46625,46626,46627,46628,46629,46630,46631,46632,46633,46634,46635,46636,40669,46638,40121,45485,46641,46642,46643,46644,39553,46646,46647,46648,46649,46650,39182,46652,46653,46654,46655,43417,46657,46658,46659,46660,46661,40732,46663,46664,46665,46666,46667,42503,46669,46670,46671,46672,46673,46674,43985,46676,46677,46678,39988,46680,46681,46682,46683,46684,46685,46554,46687,46688,46689,46690,46691,46692,46693,46694,46695,46696,46697,42629,46699,46700,39815,46702,46703,46704,46705,46706,46707,46708,38514,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,39251,46723,46724,46725,46726,46727,39836,46729,39022,46731,46732,46733,46734,46735,46736,46737,46738,42044,46740,46741,46742,46743,46744,46745,46746,46747,46748,46749,46750,46751,46752,46753,46754,46755,46756,38713,46758,46759,42058,46761,46762,46763,46764,46765,46766,46767,46768,39906,46770,39912,46772,46773,38794,45886,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46804,46805,39906,46807,46808,46809,46810,46811,46812,46813,39627,40506,46816,46817,46818,46819,46820,46821,46822,46823,46824,39070,46826,46827,46828,46829,46830,46831,46832,46833,46834,46835,46836,46837,43516,40486,46840,46841,42901,46843,46844,41710,46846,46847,39658,46849,46850,46851,40987,46853,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,42176,46873,46874,46875,46876,46877,45806,46879,46880,46881,46882,46883,46884,46885,46886,46887,46888,46889,46890,46891,45815,46893,46894,46895,46896,42042,46898,46899,46900,46901,46902,46903,46904,46905,46906,39306,46908,46909,46910,46911,46912,46913,46914,46915,46916,46917,46918,46919,46920,46921,46922,39361,42523,46925,45726,46927,46928,46929,46930,46931,46932,46933,46934,46935,46936,46937,46938,46939,46940,46941,46813,39591,46944,46945,46946,44261,46948,46949,46950,46951,46952,46953,43430,46955,46956,46957,46958,46959,46960,41207,43242,46963,46964,46965,46966,39554,46968,46969,46970,46971,46972,46973,46974,46975,46976,46977,46978,46979,46980,46981,46982,46523,46984,46985,41709,46987,46988,46989,38551,46991,46992,46993,46994,46995,46996,46997,46998,46999,47000,47001,38601,47003,47004,47005,47006,47007,47008,47009,39258,47011,47012,47013,47014,47015,47016,47017,47018,47019,47020,47021,47022,47023,47024,47025,47026,45806,47028,47029,47030,47031,47032,47033,47034,47035,47036,47037,44349,47039,47040,47041,47042,47043,44649,47045,47046,46460,47048,47049,47050,47051,47052,47053,47054,47055,47056,43260,47058,47059,47060,43364,45854,47063,47064,47065,47066,39581,41819,47069,38929,47071,47072,47073,45601,39187,47076,47077,40666,47079,47080,47081,47082,45488,47084,47085,47086,40652,47088,47089,47090,47091,38793,47093,39426,47095,47096,40302,47098,47099,47100,47101,47102,47103,47104,47105,47106,40312,47108,47109,47110,47111,47112,46011,47114,47115,47116,47117,47118,47119,47120,39017,47122,47123,47124,47125,47126,47127,47128,41354,47130,47131,47132,47133,47134,47135,40094,47137,47138,47139,47140,47141,47142,47143,47144,47145,47146,47147,47148,47149,43345,47151,47152,47153,47154,47155,47156,47157,47158,47159,41239,47161,47162,47163,47164,47165,47166,47167,47168,47169,47170,46804,47172,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,47190,47191,47192,47193,47194,47195,47196,47197,42625,47199,47200,46530,47202,47203,47204,47205,47206,47207,42101,47209,47210,45854,47212,47213,47214,47215,47216,47217,47218,47219,47220,47221,47222,46666,47224,38928,47226,47227,40378,40016,47230,47231,47232,47233,47063,47235,47236,47237,47238,47239,47240,44701,47242,47243,47244,47245,47246,47247,47248,47249,47250,47251,47252,47253,47254,44097,47256,47257,47258,47259,47260,38773,47262,47263,47264,47265,39651,47267,47268,43297,47270,47271,47272,47273,41483,47275,47276,47277,47278,47279,47280,47281,47282,47283,47284,41500,47286,47287,47288,47289,47290,47291,47292,47293,47294,40570,47296,47297,47298,47299,47300,42698,47302,47303,47304,40346,47306,47307,47308,47309,47310,39061,47312,47313,47314,47315,47316,47317,47318,47319,47320,46831,47322,47323,47324,47325,43416,47327,47328,47329,40672,47331,47332,47333,47334,47335,40808,47337,47338,47339,44833,47341,47342,47343,47344,47345,47346,41907,47348,47349,47350,47351,47352,47353,39993,47355,47356,47357,47088,47359,47360,47361,47362,47363,47364,47365,42784,47367,47368,47369,47370,38840,47372,41113,47374,39818,47376,44021,42318,47379,47380,47381,47382,38604,39260,47385,47386,47387,47388,47389,47390,47391,47392,47393,47394,42182,47396,47397,42042,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,45698,47413,47414,47415,47416,47417,47418,47419,47420,47421,47422,47423,47424,45475,47426,47427,47428,47429,47430,47431,47432,40517,47434,47435,43704,47437,42920,47439,47440,47441,47442,47443,45464,47445,47446,47447,47448,47449,47450,47451,47452,47453,47454,41267,47456,47457,47458,43984,47460,47461,47462,47463,47464,47465,47466,47467,47468,47469,43260,47471,47472,47473,47474,45219,44114,47477,47478,47479,47480,47481,47482,47483,47484,47485,47486,47487,42769,43817,47490,47491,47492,47493,47494,47495,47496,39424,47498,41480,41500,47501,47502,47503,40999,47505,47506,47507,47508,47509,47510,43327,47512,47513,47514,47515,47516,41525,47518,44666,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47532,40176,47534,47535,47536,47537,47538,47539,47540,47541,47542,42244,47544,47545,47546,47547,47548,47549,47550,41920,47552,47553,47554,47555,47556,47557,47558,39555,47560,47561,47562,47563,47564,47565,47566,47567,47568,43436,47570,47571,47427,47573,47574,47575,40676,47577,47578,47579,47580,47581,47582,47583,47584,39967,47586,47587,47588,47589,39977,47591,47592,47593,47594,47595,39988,47597,47598,47599,47600,47601,45634,47603,47604,47605,47606,47607,47608,47609,39120,47611,39413,47613,47614,47615,43289,47617,47618,47619,47620,47621,42163,47623,47624,42970,47626,47627,47628,38999,47630,47631,47632,47633,47634,47635,47636,41160,47638,47639,47640,47641,47642,47643,46614,47645,47646,47647,47648,47649,47650,47651,47652,47653,38721,47655,47656,47657,47658,47659,47660,47661,47662,47663,39405,43049,47666,47667,47668,47669,43365,47671,41606,47673,47674,47675,44579,47677,47678,39993,47680,47681,47682,47683,47684,47685,47686,47687,44618,47689,47690,47691,47692,42388,47694,47695,47696,47697,43994,47699,47700,47701,47702,47703,40488,47705,47706,43951,39815,47709,38515,47711,47712,42969,47714,47715,47716,47717,39005,47719,47720,47721,47722,40066,47724,47725,47726,47513,39290,47729,47730,47731,47732,47733,47734,47735,47736,47737,47738,47739,39303,47741,47742,47743,47744,42273,47746,47747,47748,47749,47750,45334,40458,47753,47754,47755,47756,39358,47758,47759,41586,40405,47762,47763,47764,47765,47766,47767,47768,47769,47770,47771,40127,47773,47774,47775,47776,47777,47778,44212,47780,47781,47782,47783,47784,47785,47786,47787,47788,47789,47790,47791,38925,47793,47794,47795,47796,47797,47798,47799,47800,47801,47802,44751,47804,47805,47806,47807,47808,47809,44580,41921,47812,47813,47814,47815,43280,47817,40015,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,46699,47830,39813,47832,47833,47834,39669,47836,47837,47838,47839,47840,47841,47842,47843,41338,47845,47846,44167,47848,47849,47850,44906,47852,47853,46958,47855,47856,47857,47858,47859,40823,39995,47862,47863,47864,47865,47866,47867,47868,47869,41117,47871,47872,47873,47874,47875,47876,47877,47878,47879,41400,47881,47882,47883,47884,47471,47886,47887,42900,47889,47890,47891,47445,47893,47894,47895,47896,47897,47898,38812,47900,47901,47902,47903,47904,47905,40176,47907,47908,39361,41295,47911,47912,47913,47914,47915,47916,47917,47918,47919,39944,47921,47922,46124,47924,47925,47926,45517,47928,47929,47930,47284,43497,47933,38658,47935,47936,47937,47938,47939,47940,42215,47942,47943,47944,47945,44806,47947,47948,47949,47950,47951,47952,47953,47954,47955,47956,47957,47958,47959,47960,47961,39905,47963,47964,47965,47966,47967,47968,47969,47591,47971,47972,47973,47974,47975,47976,47977,47978,47979,47980,42644,47982,47161,47984,47985,47986,47987,47988,47989,46310,47991,47992,47993,45070,40666,47996,47997,47998,44730,48000,48001,48002,48003,48004,44995,48006,48007,48008,48009,48010,48011,48012,48013,48014,48015,38579,48017,48018,48019,48020,48021,45396,48023,48024,48025,48026,48027,48028,48029,45405,48031,48032,48033,48034,48035,48036,48037,48038,48039,42858,48041,48042,48043,48044,48045,43329,48047,48048,48049,48050,44171,41528,48053,48054,48055,48056,48057,38721,48059,48060,48061,48062,48063,48064,48065,43064,48067,48068,48069,48070,48071,48072,46840,48074,48075,48076,46925,48078,48079,48080,43067,39343,48083,48084,48085,48086,47210,40435,48089,48090,48091,48092,48093,48094,48095,48096,41682,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48120,48121,48122,48123,48124,48125,48126,48127,39545,48129,48130,48131,48132,48133,41435,48135,48136,48137,48138,48139,48140,48141,48142,48143,45004,48145,48146,48147,48148,48149,48150,48151,48152,48153,48154,48155,48156,48157,48158,48159,48160,48161,48162,48163,48164,48165,48166,48167,48168,48169,48170,48171,48172,48173,48174,48175,39233,48177,48178,48179,42011,48181,48182,48183,48184,48185,39251,48187,48188,48189,48190,48191,38618,48193,48194,48195,48196,48197,48198,48199,48200,48201,48202,48203,40079,48205,48206,48207,48208,48209,48210,48211,48212,48213,48214,48215,48216,48217,48218,48219,48220,48221,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,44652,48249,48250,48251,48252,44378,48254,48255,48256,48257,48258,48259,48260,48261,48262,48263,48264,48265,48266,48267,48268,42875,48270,48271,48272,48273,45203,48275,48276,39622,48278,48279,48280,48281,48282,48283,48284,48285,48286,39639,48288,48289,48290,48291,48292,41278,48294,48295,48296,48297,48298,48299,47773,48301,48302,48303,48304,48305,48306,48307,48308,48309,42828,48311,48312,48313,40860,48315,48316,48317,48318,38743,48320,48321,48322,48323,43394,48325,48326,48327,48328,48329,48330,48331,46130,48333,48334,48335,43951,44771,42179,48339,48340,42853,48342,48343,48344,48345,48346,48347,48348,48349,48350,48351,41871,48353,48354,48355,48356,48357,48358,48359,48360,48361,39074,48363,48364,48365,48366,48367,48368,48369,48370,48371,48372,48373,48374,48375,48376,48377,39908,48379,48380,48381,48382,48383,48384,48385,48386,42758,48388,48389,48390,48391,48392,44475,48394,46663,48396,48397,48398,48399,43039,47971,48402,48403,48404,48405,48406,48407,48408,48083,48410,48411,48412,48413,48414,48415,48416,39179,48418,48419,48420,48421,39373,48423,48424,48425,48426,48427,48428,48429,48430,47232,48432,38929,48434,48435,45383,48437,48438,48439,48440,48441,48442,48131,48444,48445,48446,48447,42309,48449,41150,48451,48452,42176,48454,48455,48456,48457,47030,48459,48460,48461,48462,48463,45815,48465,48466,48467,42045,48469,48470,48471,48472,48473,48474,47416,48476,48477,48478,48479,48480,48481,48482,48483,48484,48485,48486,48487,48488,40437,46133,47213,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,38768,41205,48506,48507,42892,48509,48510,48511,48512,48513,40821,48515,48516,48517,48518,48519,48520,48521,48522,48523,48524,48525,46153,48527,48528,48529,48530,48531,48532,48533,48534,41546,48536,48537,48538,48539,48540,47081,48542,39994,48544,48545,48546,48547,48548,43805,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48560,48561,48562,44254,48564,48565,48566,48567,38579,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,39232,48592,48593,48594,48595,45405,48597,48598,48599,48600,48601,48602,48603,48604,48605,48606,48607,40781,48609,48610,48611,48612,48613,48614,48615,48616,48617,48618,48619,39138,48621,48622,48623,48624,48625,48626,48627,48628,48629,48630,48631,38898,48633,43367,48635,48636,48637,48638,48639,48640,48641,48642,48643,48644,39391,48646,48647,48648,48649,48650,48651,48652,48653,48654,48655,48656,48657,48658,48659,48660,48661,48662,48663,48664,48665,48666,48667,48668,48669,48670,48671,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,44189,44469,48686,48687,48688,48689,48690,48691,48692,48693,40263,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,43231,48706,48707,48708,48709,48710,48711,43516,47604,48714,48715,48716,44945,48718,48719,48720,48721,48722,39815,48724,39433,48726,48727,48728,48729,48730,48731,48732,48733,48734,48735,40314,48737,48738,48739,48740,48741,48742,48743,43618,48745,48746,48747,38678,48749,41871,48751,48752,48753,48754,48755,45433,48757,48758,48759,48760,48761,48762,48763,48764,48765,48766,48767,48768,48769,45444,48771,48772,40846,48774,48775,48776,43021,48778,48779,48780,48781,48782,48783,48784,48785,48786,48787,48788,48789,48790,48791,40458,48793,48794,48795,48796,48797,48798,43036,46281,48801,48802,43927,48804,48805,47887,40644,48808,48809,48810,48811,41777,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,40657,48824,48825,40737,48827,48828,48829,48830,48731,48832,48833,48834,48738,48836,48837,48838,48839,48840,48841,39844,48843,48844,48845,48846,48847,42333,48849,48850,48851,48852,48853,48854,48855,48856,48857,48858,48859,40337,48861,48862,41026,48254,48865,48866,48867,48868,48869,48870,48871,48872,48873,48874,48875,48876,44457,48878,48879,40644,48881,43530,48883,48884,48885,48886,48887,48888,48889,48890,48891,48892,45445,48894,38773,48896,39589,48898,48899,48900,48901,48902,48903,48904,48905,48906,42258,48908,48909,48910,48911,48912,48913,48914,48915,41278,48917,48918,48919,48920,48921,48922,48923,48924,48925,48926,39993,48928,48929,48930,48931,48932,48933,48934,44097,48936,48937,48938,48939,48940,48941,48942,39791,48944,48945,48946,48947,39651,48949,48950,48951,43612,42969,48954,48955,48956,48957,48958,38994,48960,48961,48962,48963,48964,48965,48966,48967,39861,48969,48970,48971,48972,48973,48974,48975,48976,48977,48978,48979,48980,42358,48982,43183,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,39331,48999,45570,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,45230,46684,49014,41606,49016,49017,49018,49019,45634,49021,49022,49023,49024,49025,44708,49027,49028,49029,49030,49031,49032,44762,49034,49035,49036,49037,49038,38834,49040,49041,49042,49043,49044,49045,38747,49047,49048,49049,49050,49051,49052,49053,49054,49055,49056,49057,38902,41555,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,40714,49071,49072,49073,49074,49075,48950,49077,49078,49079,41481,49081,49082,49083,49084,49085,49086,49087,49088,42840,49090,42691,49092,39872,49094,49095,49096,49097,49098,49099,49100,49101,49102,40095,49104,49105,49106,49107,46112,49109,49110,49111,49112,49113,49114,49115,43515,49117,49118,40732,49120,43279,49122,49123,49124,49125,49126,43065,49128,42598,49130,49131,49132,40498,49134,49135,49136,43675,49138,49139,49140,49141,38749,49143,43037,45464,49146,49147,49148,49149,49150,49151,49152,49153,49154,47904,49156,49157,49158,49159,49160,49161,49162,49163,41474,49165,49166,49167,49168,49169,49170,41174,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,42866,48611,49184,49185,49186,49187,49188,49189,49190,49191,40794,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,39151,49204,49205,49206,49207,41114,49209,49210,49211,49212,49213,49214,49215,45462,41687,49218,49219,49220,38773,44245,49223,49224,49225,49226,49227,49228,39391,49230,49231,41996,49233,49234,40290,49236,49237,49238,49239,49240,49241,47837,49243,49244,49245,49246,49247,49248,39253,49250,42027,49252,49253,49254,44365,46462,49257,49258,49259,49260,49261,49262,49263,49264,40666,49266,49267,49268,49269,49270,43541,43074,49273,49274,49275,49276,49277,49278,49279,49280,41608,49282,41130,49284,49285,42116,49287,49288,49289,49290,49291,47549,49293,49294,49295,42932,49297,49298,49299,49300,49301,49302,49303,49304,49305,49306,49307,49308,49309,49310,49311,49312,49313,49314,49315,49316,49317,49318,49319,49320,49321,49322,49323,49324,49325,49326,49327,49328,49329,49330,49331,49332,49333,49334,49335,49336,49337,49338,49339,49340,49341,49342,49343,49344,39939,49346,49347,49348,49349,49350,49351,49352,49353,49354,49355,39977,49357,39657,49359,49360,49361,46866,49363,49364,49365,39478,49367,49368,49369,49370,49371,41015,49373,49374,49375,40346,49377,49378,49379,49380,49381,49382,42215,49384,49385,49386,49387,49388,49389,49390,49391,49392,48054,49394,49395,49396,49397,49398,49399,41533,49401,49402,49403,49404,49405,49406,49407,49408,49409,49410,49411,48760,49413,49414,49415,49416,49417,49418,49419,49420,43951,41690,49423,49424,49425,49426,49427,49428,40440,49430,49431,44574,48896,39622,49435,49436,49437,49438,49439,39608,49441,49442,49443,49444,49445,49446,49447,49448,49449,49450,49451,49452,49453,49454,49455,49456,49457,39527,49459,49460,49461,49462,40437,49464,49465,49466,47863,49468,49469,49470,49471,49472,49473,40420,49475,49476,49477,49478,49479,49480,49481,49482,40845,49484,49485,49486,49487,49488,47267,39435,49491,49492,49493,49494,49495,46006,49497,49498,49499,49500,39000,49502,44788,49504,40588,40606,49507,49508,49509,49510,49511,49512,48759,49514,49515,49516,49517,49518,49519,49520,49521,49522,43039,40846,49525,49526,49527,49528,49529,49530,49531,44119,49533,49534,49535,49536,49537,49538,49539,46308,49541,49542,49543,49544,49545,49546,49547,49548,49549,49550,49551,49552,49553,49554,49555,45070,49557,38748,49559,49560,49561,49562,49563,49564,49565,49566,49567,43209,49569,49570,49571,49572,49573,49574,38814,48154,49577,49578,49579,49580,49581,49582,49583,49584,43298,49586,49587,42009,49589,49590,49591,42840,49593,49594,49595,49596,49597,45797,49599,49600,49601,49602,49603,49604,45294,49606,49607,49608,49609,49610,49611,49612,49613,42038,49615,49616,49617,49618,42207,49620,49621,49622,49623,45701,49625,49626,49627,49628,49629,49630,49631,49632,49633,46524,49635,49636,49637,49638,49639,47871,49641,49642,49643,49644,49645,49646,45231,42105,49649,49650,42900,42914,49653,49654,49655,47069,38902,49658,49659,49660,49661,48636,49663,49664,49665,49666,39552,49668,49669,49670,49671,41993,40981,49674,49675,38531,49677,49678,49679,49680,49681,49682,49683,49684,49685,49686,49687,49688,49689,49690,49691,49692,49693,49694,49695,49696,49697,49698,49699,49700,49701,49702,49703,49704,49705,49706,49707,49708,49709,49710,49711,49712,49713,49714,49715,49716,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,49734,49735,49736,49737,49738,49739,49740,49741,49742,49743,49744,49745,49746,49747,49748,49749,49750,49751,49752,40990,49754,49755,49756,49757,49758,49759,49760,49761,49762,49763,49764,49765,49766,49767,49768,49769,49770,49771,49772,49773,49774,49775,49776,49777,49778,49779,49780,49781,49782,49783,49784,49785,49786,49787,49788,49789,49790,49791,49792,49793,49794,49795,41006,49797,49798,49799,49800,49801,49802,49803,49804,49805,49806,49807,49808,49809,49810,49811,49812,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,49823,49824,49825,49826,49827,49828,49829,49830,49831,49832,49833,49834,49835,49836,49837,49838,49839,49840,49841,49842,49843,49844,49845,41352,49847,49848,49849,49850,49851,49852,49853,49854,49855,42869,49857,49858,49859,49860,49861,49862,49863,49864,49865,38743,49867,49868,49869,49870,38906,49872,49873,48635,49875,49876,49877,49878,49879,49880,49881,49882,49883,49884,49885,49886,39393,49888,49889,43929,49891,49892,49893,49894,49895,49896,38753,49898,49899,49900,43422,49902,49903,49904,49905,49906,49907,49908,39939,49910,49911,49912,49913,49914,49915,49916,49917,49918,49919,49920,49921,49922,49923,49924,49925,49926,40846,49928,49929,49930,49931,49932,49933,49934,47161,49936,49937,49938,49939,49940,49941,39328,49943,49944,49945,49946,49947,41400,49949,49950,49951,49952,49953,49954,49955,49956,46310,49958,49959,49960,49961,49962,49963,49964,49430,49966,49967,49968,49969,41708,49971,43297,49973,49974,49975,49976,38549,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49989,49990,49991,49992,49993,49994,49995,49996,38602,49998,39260,50000,50001,50002,43870,50004,50005,47400,50007,50008,50009,50010,50011,50012,50013,50014,42057,50016,50017,50018,50019,50020,50021,45327,50023,50024,50025,38834,50027,50028,50029,50030,50031,50032,40467,50034,50035,50036,50037,50038,50039,50040,50041,50042,43036,50044,50045,50046,40121,49557,50049,40458,50051,50052,50053,47968,50055,50056,42894,50058,50059,50060,50061,50062,48129,50064,45765,50066,50067,50068,50069,50070,50071,39358,50073,50074,50075,39437,50077,50078,50079,50080,50081,50082,50083,50084,39435,50086,43619,50088,49096,50090,50091,50092,50093,50094,50095,50096,50097,43754,50099,50100,50101,46113,50103,50104,50105,50106,50107,50108,50109,50110,50111,50112,42877,50114,50115,50116,50117,43816,44764,50120,50121,50122,50123,50124,50125,46551,42093,50128,49543,50130,50131,50132,50133,50134,50135,50136,50137,50138,49444,50140,50141,50142,50143,50144,50145,50146,50147,50148,50149,50150,50151,50152,50153,50154,50155,50156,50157,50158,50159,46680,50161,50162,50163,50164,50165,39581,50167,50168,50169,50170,38915,48136,50173,50174,50175,45010,46849,50178,50179,42314,50181,50182,50183,50184,50185,47007,50187,50188,50189,50190,50191,45041,50193,50004,43902,50196,50197,50198,50199,50200,50201,50202,50203,45701,50205,50206,50207,50208,50209,50210,50211,50212,39361,46526,50215,43697,50217,50218,39912,50220,42112,50222,44582,50224,38900,50226,39108,50228,50229,50230,50231,50232,50233,47586,50235,50236,44085,50238,50239,50240,39233,50242,50243,40562,50245,50246,50247,42857,50249,50250,50251,50252,43329,50254,50255,50256,50257,43505,50259,49396,50261,50262,50263,50264,50265,50266,47462,50268,50269,50270,50271,40800,50273,50274,41561,50276,50277,50278,50279,50280,38800,50282,50283,50284,50285,50286,50287,38765,44246,50290,50291,48530,50293,50294,50295,50296,50297,50298,50299,50300,50301,50302,41278,50304,50305,50306,50307,50308,50309,50310,47427,50312,50313,43969,50315,50316,50317,50318,50319,50320,50321,50322,50323,50324,50325,50277,50327,42143,50329,50330,50331,50332,50333,50334,50335,50336,50337,50338,50339,50340,40978,50342,50343,49686,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,44334,50357,50358,38614,50360,50361,50362,50363,50364,50365,50366,50367,50368,50369,50370,50371,50372,50373,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,50400,50401,50402,50403,50404,50405,50406,50407,50408,50409,50410,50411,50412,50413,50414,50415,50416,50417,50418,50419,50420,50421,50422,50423,50424,50425,50426,50427,50428,50429,50430,50431,50432,50433,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50444,50445,41020,50447,50448,50449,50450,50451,50452,50453,50454,50455,45701,50457,50458,50459,50460,50461,50462,50463,39958,50027,50466,50467,50468,50469,42537,50471,50472,50473,41907,46134,50476,45768,50478,50479,50480,50481,50482,50483,50484,42875,50486,50487,50488,50489,43994,50491,50492,50493,49223,50495,50496,50497,50498,50499,50500,50501,50502,50503,40506,50505,50506,50507,50508,44497,50510,50511,50512,50513,50514,50515,50516,50517,50518,50519,50520,50521,42000,50523,40765,41530,50526,50527,50528,50529,50530,50531,43986,50533,50534,50535,50536,47746,50538,47681,50540,50541,50542,50543,50544,41219,50546,50547,50548,50549,48090,50551,50552,39090,50554,50555,50556,50557,39594,50559,50560,50561,50562,50563,50564,50565,41773,50567,50568,50569,50570,50571,50572,50573,50574,50575,50576,50577,50578,50579,44965,50581,50582,42102,49138,50585,50586,50587,39596,50589,50590,39765,42955,50593,50594,50595,50596,50597,48950,50599,50600,50601,50602,50603,50604,47714,50606,50607,50608,50609,48187,50611,50612,50613,50614,41348,49381,39055,50618,50619,50620,50621,50622,50623,50624,50625,46831,50627,50628,50629,50630,50631,50632,40666,50634,50635,50636,47862,50638,50639,50640,50641,50642,50643,50644,50645,50646,50647,42770,50649,50650,50651,50652,50653,50654,50655,50656,39369,50658,50659,50660,50661,48083,50663,50664,50665,41070,43265,50668,50669,50670,50671,40444,50673,50674,47814,50676,41983,50678,50679,50680,50681,44504,50683,50684,50685,50686,50687,50688,50689,50690,38963,50692,49364,50694,50695,50696,50697,39454,50699,50700,50701,50702,50703,50704,50705,49367,50707,50708,50709,50710,50711,50712,44892,50714,50715,50716,40346,50718,50719,50720,50721,50722,40099,50724,50725,50726,44673,50728,50729,50730,50731,50732,41966,50734,50735,50736,50737,50738,38758,50740,50741,49060,50743,50744,50745,50746,50747,50748,50749,50750,50751,40505,50753,50754,50755,50756,50757,50758,50759,50760,50761,39140,50763,50764,50765,50766,50767,39093,41764,50770,50771,50772,50773,50774,50775,47338,50777,50778,50779,50780,50781,50782,50783,50784,50785,50786,50787,50788,50789,50790,50791,39926,42130,50794,50795,40016,50797,39814,50799,50800,50801,44641,50803,50804,50805,50806,50807,50808,50809,50810,39492,50812,50813,39291,50815,50816,50817,50818,42055,50820,50821,50822,50823,50824,50825,39092,38783,50828,41595,50830,50831,50832,50833,50834,50835,50836,50837,50838,50839,50840,50841,50842,50843,50844,50845,39581,50847,50848,48624,50850,50851,50852,50853,50854,38753,50856,50857,50858,40261,50860,50861,50862,50863,39123,50865,50866,50867,46829,50869,50870,50871,50872,50873,50874,47598,50876,50877,39343,50879,50880,50881,50882,50883,50884,41130,50886,50887,50888,39815,50890,38504,50892,40552,50894,50895,50896,50897,50898,50899,39672,50901,50902,50903,50904,50905,50906,50907,50908,50909,50910,38985,42179,45806,50914,50915,50916,50917,50918,50919,50920,50921,50922,50923,50924,38661,50926,47402,50928,50929,50930,50931,50932,50933,50934,50935,50936,50937,50938,50939,46909,50941,50942,50943,50944,50945,50946,50947,50948,50949,50950,50951,50952,50953,43268,50955,50956,50957,50958,50959,50960,50961,40401,50963,50964,50965,50966,50967,50968,41049,50970,50971,50972,50973,50974,50975,50976,50977,43694,50979,43414,50981,50982,50983,50984,50985,42102,42915,50988,50989,50990,50991,50992,42627,46413,39100,50996,50997,50998,50999,51000,51001,51002,51003,51004,48438,51006,46200,51008,51009,51010,42000,51012,51013,51014,51015,51016,51017,51018,46225,40327,51021,51022,51023,51024,39860,51026,51027,51028,51029,51030,51031,51032,51033,51034,51035,51036,42570,51038,51039,51040,51041,51042,51043,47045,51045,51046,51047,51048,51049,51050,51051,51052,51053,45549,51055,51056,51057,51058,51059,51060,51061,51062,51063,51064,51065,51066,51067,51068,44224,51070,51071,51072,51073,51074,39993,51076,51077,51078,51079,51080,51081,51082,51083,51084,51085,51086,42644,51088,42102,41965,51091,51092,51093,51094,51095,51096,43564,51098,51099,51100,43520,51102,51103,51104,51105,51106,50973,51108,51109,51110,51111,51112,51113,51114,51115,51116,51117,39572,51119,51120,51121,51122,51123,40442,51125,51126,51127,51128,51129,38930,51131,51132,51133,51133,41222,51136,51137,51138,51139,38583,46578,51142,40025,41496,51145,51146,51147,51148,51149,51150,51151,51152,51153,51154,51155,51156,47297,51158,51159,51160,51161,51162,44893,51164,51165,51166,43900,51168,51169,51170,51171,51172,45539,51174,51175,51176,43439,51178,51179,51180,51181,39093,40407,51184,51185,51186,51187,51188,51189,51190,41774,51192,51193,51194,51195,51196,51197,51198,51199,51200,51201,51202,51203,51204,51205,43242,51207,51208,51209,44714,51211,51212,46699,51214,51215,51216,51217,51218,51219,51220,42644,50956,51223,51224,51225,51226,40517,51228,51229,45346,51231,51232,51233,51234,51235,39581,51237,51238,51239,39652,51241,51242,51243,38964,51245,51246,51247,51248,51249,49365,50704,51252,46601,51254,51255,51256,51257,51258,39487,51260,51261,51262,51263,51264,51265,39033,51267,51268,51269,51270,51271,51272,51273,51274,51275,51276,51277,48354,51279,51280,51281,51282,51283,41747,51285,51286,51287,51288,51289,51290,41818,51292,51293,51294,49527,51296,51297,51298,51299,39801,51301,51302,51303,51304,51305,51306,51307,40016,51309,51310,51311,51312,51313,41074,51315,51316,51317,51318,51319,51320,41100,51322,51323,51324,51325,51326,51327,42910,51329,51330,51331,51332,51333,51334,51335,51336,51337,51338,51339,46545,51341,51342,51343,51344,51345,51346,51347,51348,48509,51350,51351,51352,38894,40126,51355,51356,51357,51358,51359,51360,51361,51362,51363,51364,51365,51366,51367,51368,43579,51370,51371,51372,51373,51374,51375,51376,51377,51378,41708,51380,42672,51382,51383,38606,51385,51386,39696,51388,51389,51390,51391,51392,51393,51394,51395,51396,48862,51398,41031,51400,51401,51402,51403,51404,41044,51406,51229,43699,51409,51410,51411,51412,51413,51414,46532,51416,38928,51418,51419,51420,39610,51422,51423,51424,51425,51426,51427,51428,51429,39743,51431,40405,51433,51434,51435,51436,51437,51438,51439,41773,51441,51442,51443,51444,51445,51446,51447,51448,51449,40843,51451,51452,51453,51454,51455,51456,51457,51458,51459,40738,51461,47280,51463,39474,51465,51466,51467,51468,51469,42996,51471,51472,51473,51474,51475,41369,51477,51478,51479,51480,51481,51482,51483,46138,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,39408,51497,51498,51499,42902,51501,46958,51503,51504,51505,51506,51507,51508,51509,51510,51511,45746,51513,51514,51515,43540,41686,51518,51519,51520,51521,51522,51523,51524,39209,51526,51527,51528,39160,51530,51531,51532,51533,51534,44496,51536,51537,51538,51539,51540,51541,51542,51543,51544,51545,51546,51547,39230,51549,50251,39271,51552,51553,51554,51555,51556,51557,41738,51559,44807,51561,51562,51563,51564,51565,51566,51567,51568,51569,51570,51571,51572,51573,51574,39906,51576,51577,51578,51579,51580,51581,51582,49945,51584,41920,51586,51587,51588,51589,51590,51591,51592,51593,51594,41770,51596,51597,51598,51599,51600,51601,51602,51603,51604,51605,51606,45502,51608,51609,51610,51611,51612,40137,51614,46553,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,42293,51629,51630,51631,51632,51633,51634,51635,51636,39413,51638,47471,51640,51641,51642,51643,44928,51645,51646,51647,51648,51649,51650,51651,51652,50273,51654,51655,51656,51657,51658,51659,41771,51661,51662,51663,51664,51665,51666,51667,51668,51669,51670,45517,51672,51673,51674,51675,51676,51677,51678,51679,51680,51681,44780,51386,51684,51685,51686,45294,51688,51689,51690,51691,51692,51693,51694,47045,51696,51697,51698,51699,51700,51701,51702,51703,48256,51705,51706,51707,51708,51709,51710,51711,51712,51713,51714,51715,42875,51717,51718,51719,51720,51721,39196,51723,51724,51725,51726,51727,41914,51729,51730,48278,51732,51733,51734,51735,51736,51737,51738,38936,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,51750,51751,50853,51753,51754,39747,51756,51757,51758,41922,51760,51761,51762,51763,43549,51765,51766,51767,51768,51769,51770,39526,51772,51773,51774,51775,51776,51777,39089,51779,51780,51781,41761,51783,51784,51785,51786,51787,51788,51789,51790,51791,51792,39939,51794,51795,51796,51797,51798,51799,51800,43594,51802,51803,51804,51805,51806,51807,44514,51809,51810,46859,51812,51813,51814,51815,51816,51817,51818,51819,38582,51821,51822,50252,43329,51825,51826,51827,51828,51829,39502,51831,51832,51833,39516,51835,51836,51837,51838,51839,43984,51841,51842,51843,51844,39089,51846,51847,51848,51849,51850,51851,41294,51853,51854,51855,51856,51857,51858,51859,51860,51861,40689,51863,51864,51865,43399,51867,51868,45444,51870,42606,51872,51873,51874,51875,44759,51877,51878,51879,51880,51881,51882,51883,51884,51885,51886,40016,51888,51889,44731,51891,51892,51893,51894,51895,51896,51897,51898,51899,51900,51901,38816,51903,51904,51905,51906,51907,51908,51909,51910,51911,51912,51913,38564,51915,51916,51917,51918,51919,51920,51921,51922,51923,51924,51925,51926,51927,51928,51929,51930,51931,51932,51933,51934,51935,51936,51937,51938,51939,51940,51941,51942,51943,51944,51945,49973,51947,51948,51949,51950,50812,44897,51953,51954,51955,51956,50200,51958,51959,51960,51961,51962,51963,51964,46463,51966,51967,51968,51969,51970,51971,51972,51973,51974,46958,51976,51977,50492,51979,51980,51981,51982,42932,51984,51985,45496,51987,51988,51989,51990,51991,51992,42076,39196,51995,51996,51997,51998,41068,44584,52001,52002,39524,52004,52005,52006,52007,52008,52009,47996,40658,52012,52013,52014,48778,52016,52017,52018,52019,52020,52021,40517,45263,52024,52025,52026,40543,39453,46602,52030,52031,52032,39706,52034,52035,52036,43754,52038,52039,52040,52041,52042,52043,52044,52045,52046,49413,52048,47699,52050,52051,52052,51616,52054,52055,52056,52057,52058,52059,52060,52061,52062,52063,52064,52065,40688,52067,52068,52069,48071,52071,52072,52073,45326,52075,52076,52077,50027,52079,52080,52081,52082,52083,39605,52085,52086,47338,52088,52089,52090,43835,50029,52093,52094,43701,52096,52097,52098,52099,52100,50800,52102,52103,52104,45263,52106,52107,52108,52109,52110,43146,52112,52113,40312,52115,52116,52117,52118,52119,52120,52121,39844,52123,52124,52125,48970,52127,52128,52129,52130,52131,42187,52133,52134,52135,52136,52137,39282,52139,52140,52141,52142,52143,43184,52145,52146,52147,52148,52149,52150,52151,52152,52153,52154,52155,42598,52157,52158,52159,52160,52161,52162,52163,52164,52165,52166,52167,52168,42073,52170,52171,52172,52173,48411,52175,52176,52177,52178,52179,52180,41069,39357,52183,52184,52185,52186,52187,52188,42912,52190,52191,52192,52193,52194,52195,52196,52197,52198,52199,52200,39200,52202,52203,52204,52205,52206,52207,51785,52209,52210,52211,42938,52213,52214,52215,52216,52217,52218,52219,52220,52221,52222,52223,52224,52225,52226,42608,52228,52229,52230,52231,52232,44768,52234,39437,52236,52237,52238,52239,52240,52241,46006,52243,52244,52245,52246,39004,52248,52249,44641,52251,52252,52253,39492,52255,42042,52257,52258,52259,52260,52261,52262,52263,52264,52265,46761,52267,52268,52269,52270,52271,52272,52273,52274,41074,52276,52277,52278,52279,45750,52281,52282,44004,52284,52285,52286,52287,52288,52289,52290,45237,52292,40700,40860,52295,52296,52297,52298,52299,52300,52301,52302,52303,42257,52305,52306,52307,52308,52309,52310,52311,52312,52313,52314,52315,52316,47462,52318,52319,52320,52321,52322,52323,52324,52325,52326,52327,52328,43263,52330,52331,43590,52333,52334,52335,52336,52337,52338,52339,44246,52341,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,38930,52359,52360,39737,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,48155,52373,52374,52375,52376,52377,52378,52379,52380,52381,52382,52383,52384,52385,52386,52387,52388,52389,52390,52391,52392,52393,52394,52395,52396,52397,52398,52399,52400,52401,52402,52403,51247,52405,52406,40552,52408,52409,52410,52411,52412,52413,52414,39247,52416,52417,52418,52419,52420,52421,52422,52423,41007,52425,52426,52427,52428,52429,52430,52431,52432,52433,52434,52435,40081,52437,52438,40762,52440,52441,52442,52443,40776,52445,52446,52447,52448,52449,52450,52451,52452,39569,52454,52455,52456,52457,52458,52459,52460,52461,52462,52463,46412,52465,41554,52467,52468,52469,52470,52471,45379,52473,52474,52475,52476,52477,52478,52479,52480,52481,46959,39993,52484,52485,41777,52487,52488,52489,52490,46965,52492,47699,52494,52495,52496,52497,52498,52499,52500,39327,52502,52503,52504,52505,52506,52507,52508,45573,52510,52511,52512,52513,52514,52515,42960,52517,52518,38504,52520,52521,52522,52523,38549,52525,52526,52527,52528,52529,39252,52531,52532,52533,47013,52535,52536,52537,52538,52539,52540,51698,52542,52543,52544,52545,52546,52547,48867,52549,52550,52551,52552,48272,39583,52555,52556,52557,52558,52559,52560,52561,50996,52563,52564,46177,52566,52567,52568,52569,52570,52571,52572,52573,52574,39927,52576,52577,52578,52579,52580,52581,52582,52583,52584,52585,52586,52587,52588,52589,52590,52591,52592,52593,52594,52595,52596,52597,52598,52599,52600,52601,52602,52603,52604,52605,52606,52607,52608,52609,52610,52611,52612,52613,52614,52615,52616,52617,52618,52619,52620,52621,52622,52623,41587,52625,40845,52627,52628,52629,52630,52631,52632,52633,52634,39116,52636,52637,52638,52639,52640,52641,44117,52643,52644,52645,52646,52647,52648,52649,52650,52651,52652,43677,52654,52655,45844,52657,44730,52659,52660,52661,52662,52663,52664,52665,52666,41708,52668,52669,52670,40978,52672,52673,52674,52675,52676,49245,52678,52679,52680,39249,52682,52683,52684,52685,52686,44341,52688,52689,52690,52691,41352,52693,52694,52695,52696,52697,52698,38712,52700,52701,52702,52703,52704,52705,52706,52707,52708,52709,52710,52711,48272,39098,52714,52715,52716,52717,40809,52719,52720,52721,52722,52723,52724,52725,52726,52727,52728,52729,52730,52731,39927,52733,43262,52735,47973,52737,52738,52739,52740,41834,52742,43541,52744,52745,43464,52747,52748,52749,52750,52751,52752,47072,52754,52755,52756,52757,52758,42294,52760,52761,52762,52763,43071,52765,51009,52767,52768,52769,52770,42663,52772,52773,49491,52775,52776,52777,52778,52779,52780,38595,52782,52783,46883,52785,52786,52787,52788,52789,52790,52791,52792,52793,52794,52795,52796,46101,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,47152,52810,52811,48079,41117,52814,52815,52816,52817,52818,52819,52820,52821,52822,45205,52748,52825,52826,52827,52828,42106,52830,52659,52832,52833,52834,52835,52836,44238,52838,52839,43414,52841,52842,52843,52844,52845,47863,52847,52848,52849,52850,52851,52852,52853,52854,52855,52856,40426,52858,52859,38851,45516,52862,52863,48727,49998,52866,39260,52868,52869,41016,52871,52872,52873,52874,52875,52876,52877,52878,52700,52880,52881,52882,46478,52884,44564,52886,52887,50501,52889,52890,52891,52892,52893,52894,52895,52896,52897,48682,52899,52900,52901,52902,52903,52904,52905,52906,52907,52908,52909,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,52923,52924,52925,52926,52927,52928,52929,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,43927,52942,52943,52944,39091,52946,48809,52948,52949,41773,52951,52952,52953,52954,38834,52956,52957,52958,52959,52960,40458,52962,52963,52964,52965,39816,52967,52968,52969,52970,52971,52523,52973,38554,52975,52976,52977,52978,52979,52980,52981,52982,48187,52984,52985,52986,50365,52988,52989,40590,52991,52992,52993,52994,52995,52996,52441,52998,52999,53000,53001,48055,53003,53004,53005,53006,53007,53008,53009,53010,53011,53012,46831,53014,53015,53016,53017,53018,53019,53020,47886,53022,40123,53024,53025,53026,53027,53028,40505,53030,53031,53032,53033,53034,53035,43433,53037,53038,53039,47427,53041,53042,44818,53044,53045,53046,53047,53048,53049,53050,53051,53052,53053,49912,53055,53056,53057,46963,53059,53060,47370,53062,46840,53064,53065,53066,53067,53068,53069,53070,53071,53072,45082,53074,53075,53076,53077,41142,53079,53080,53081,53082,53083,53084,45797,53086,53087,53088,45806,53090,53091,53092,53093,53094,53095,39266,53097,53098,53099,53100,38687,53102,53103,53104,53105,53106,53107,53108,53109,53110,53111,53112,41043,53114,45846,42113,53117,53118,53119,44584,53121,53122,53123,53124,53125,53126,46333,44110,53129,53130,53131,53132,53133,53134,39373,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,39211,53147,53148,53149,53150,53151,53152,53153,53154,53155,44475,53157,53158,53159,53160,53161,38734,46969,53164,53165,53166,53167,53168,53169,53170,53171,53172,53173,53174,53175,53176,53177,47434,51380,53180,40036,53182,53183,53184,53087,49607,53187,53188,53189,53190,53191,53192,53193,53194,51696,53196,53197,53198,53199,49106,53201,53202,45433,53204,53205,53206,53207,53208,53209,53210,53211,50877,42403,53214,53215,53216,53217,53218,53219,53220,53221,50966,41053,53224,53225,53226,53227,53228,53229,53230,53231,53232,41069,48542,53235,44090,53237,43422,53239,53240,53241,53242,53243,53244,46425,53246,45724,53248,39652,53250,53251,53252,40547,53254,53255,53256,53257,53258,53259,53260,53261,53262,42976,53264,53265,45806,53267,53268,53269,53270,53271,53272,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,47039,53285,53286,53287,53288,53289,53290,53291,53292,53293,39502,53295,53296,53297,53298,53299,53300,53301,50624,53303,53304,53305,53306,53307,41744,53309,53310,53311,53312,53313,53314,53315,53316,53317,53318,53319,53320,53321,53322,48072,52833,41931,53326,53327,53328,53329,39074,53331,53332,53333,53334,50220,53336,47972,53338,53339,53340,43032,53342,53343,53344,41320,53346,40121,41920,53349,40506,53351,53352,53353,53354,53355,53356,46209,53358,53359,53360,53361,53362,53363,53364,42150,53366,53367,40543,49689,53370,53371,53372,53373,53374,53375,45405,53377,53378,53379,53380,53381,41521,53383,53384,53385,53386,53387,53388,53389,48055,53391,53392,53393,53394,53395,53396,53397,53398,53399,53400,53401,53402,44224,53404,53405,39103,53407,53408,53409,53410,53411,53412,53413,53414,53415,53416,53417,50866,53419,53420,53421,53017,53423,53424,53425,53426,53427,53428,39927,53430,53431,53432,53433,53434,53435,53436,53437,39765,53439,53440,53441,53442,53443,53444,53445,53446,53447,42381,41320,53450,46688,53452,53453,53454,53455,53456,53457,53458,40533,53460,53461,40537,53463,40040,53465,38604,53467,53468,53469,53470,53471,45035,53473,53474,53475,53476,53477,53478,41031,53480,53481,53482,53483,53484,53485,53486,51967,53488,53489,53490,53491,53492,53493,41609,39543,53496,53497,41929,53499,53500,53501,53502,53503,53504,48621,53506,53507,53508,53509,53510,53511,53512,53513,53514,53515,53516,43012,47863,53519,53520,53521,53522,53523,53524,53525,53526,53527,40834,53529,53530,53531,53532,43360,53534,53535,53536,45741,47972,53539,53540,53541,53542,53543,53544,53545,42644,53547,42078,51681,46715,53551,53552,42969,53554,53555,53556,53557,53558,50803,53560,53561,53562,53563,53564,53565,53566,51260,53568,53569,53570,53571,53572,42042,53574,53575,42056,53577,53578,53579,53580,53581,53582,53583,53584,53585,53586,43012,50074,53589,42914,53591,53592,53593,48896,46371,53596,53597,53598,53599,43367,53601,53602,53603,48528,53605,53606,53607,43926,53609,53610,53611,53612,53613,53614,40846,53616,53617,53618,39800,53620,53621,53622,53623,53624,53625,53626,53627,53628,53629,53630,40016,53632,53633,53634,53635,49077,40025,53638,38982,53640,44638,53642,53643,53644,53645,42570,53647,53648,53649,53650,53651,42044,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,39305,53664,53665,53666,53667,53668,53669,53670,53671,53672,53673,53674,52744,46142,53677,53678,53679,53680,53681,53682,53683,53684,53685,38741,53687,53688,53689,53690,44237,53692,53693,53694,39372,53696,53697,40128,53699,53700,53701,53702,53703,53704,41111,53706,53707,53708,53709,53710,53711,53712,53713,53714,53715,53716,53717,53718,53719,53720,53721,52059,53723,53724,38812,53726,53727,53728,53729,53730,53731,53732,53733,43983,53735,53736,53737,53738,47203,53740,53741,47604,53743,53744,53745,53746,44120,53748,53749,53750,53751,53752,38836,53754,53755,53756,53757,53758,53759,53760,53761,39815,53763,53764,38513,53766,53767,53768,53769,53770,53771,39013,53773,53774,53775,53776,53777,53778,53779,53780,41514,47045,53783,53784,45549,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,49867,53800,53801,53802,47963,53804,53805,41591,48075,53808,39738,52334,53811,53812,53813,53814,53815,49047,53817,42932,53819,53820,53821,53822,53823,53824,51193,53826,53827,53828,53829,53830,53831,53832,47614,53834,53835,53836,43564,43592,53839,53840,53841,53842,49034,53844,53845,53846,53847,53848,53849,53850,53851,42100,53853,45267,53855,38964,53857,53858,46589,53860,53861,46601,53863,53864,42038,53866,43752,53868,53869,53870,53871,53872,53873,53874,40615,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53888,45876,53890,53891,53892,39342,53894,53895,53896,53897,53898,53899,53900,41773,53902,53903,53904,53905,53906,53907,53908,40730,39983,53911,53912,53913,40732,53915,53916,53917,53918,53919,53920,53921,49534,53923,53924,53925,53926,53927,42785,53929,39589,53931,43094,44015,53934,49360,53936,53937,41482,53939,53940,53941,53942,53943,53944,53945,53946,42170,53948,53949,53950,53951,40327,53953,53954,53955,53956,45418,53958,53959,53960,53961,53962,53963,53964,53965,53966,53967,40091,46615,53970,53971,53972,53973,53974,43185,53976,53977,53978,53979,53980,53981,53982,53983,53984,53985,53986,53987,52173,53989,41400,53991,53992,53993,53994,53995,53996,53997,53998,53999,54000,46133,49269,39590,54004,54005,54006,54007,54008,54009,54010,54011,54012,54013,52306,54015,54016,54017,54018,54019,54020,54021,43925,54023,54024,54025,54026,54027,45186,54029,53916,54031,54032,54033,54034,54035,54036,54037,39800,54039,54040,54041,54042,54043,54044,53346,54046,54047,47709,54049,53470,54051,54052,47017,54054,54055,54056,54057,54058,54059,54060,54061,40593,54063,54064,54065,54066,54067,54068,54069,54070,40786,54072,54073,54074,54075,54076,54077,54078,54079,54080,54081,54082,46111,54084,54085,54086,54087,41545,54089,54090,54091,54092,42106,54094,54095,54096,54097,54098,47863,54100,54101,54102,54103,54104,54105,47243,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,53633,54118,47573,44200,54121,54122,54123,39162,54125,54126,54127,45337,39908,54130,54131,54132,54133,54134,54135,44930,54137,54138,54139,52470,54141,54142,54143,54144,54145,54146,54147,52473,54149,54150,54151,54152,54153,54154,54155,54156,54157,53359,54159,42000,40302,54162,54163,54164,54165,54166,54167,54168,48739,38999,54171,54172,54173,54174,54175,39863,54177,54178,54179,54180,54181,54182,54183,54184,54185,54186,42189,47731,54189,54190,54191,54192,54193,54194,54195,45549,54197,54198,54199,43414,54201,54202,44548,54204,54205,51900,41435,54208,54209,54210,54211,54212,44224,54214,54215,54216,54217,54218,54219,49907,54221,54222,54223,54224,54225,40688,54227,54228,54229,54230,54231,54232,54233,40846,54235,54236,54237,54238,52157,54240,54241,54242,54243,54244,45337,42533,54247,54248,54249,54250,54251,54252,46332,54254,54255,54256,54257,54258,54259,54260,54261,54262,54263,38574,54265,54266,54267,54268,54269,54270,54271,54272,54273,54274,54275,54276,54277,54278,54279,54280,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,54295,54296,54297,54298,54299,54300,54301,54302,44020,54304,54305,50704,54307,54308,54309,54310,54311,54312,54313,46606,54315,54316,41013,54318,54319,54320,54321,54322,54322,52440,54325,54326,54327,54328,54329,54330,43345,54332,54333,54334,54335,54336,54337,54338,54339,54340,54341,54342,54343,54344,54337,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,54356,39581,54358,54359,54360,40402,54362,54363,54364,54365,53218,38938,54368,54369,54370,54371,54372,54373,54374,54375,54376,54377,54378,54379,51103,45760,54382,52171,54384,51901,44251,54387,54388,54389,54390,54391,54392,54393,54394,54395,52335,54397,54398,54399,54400,54401,52158,54403,54404,54405,54406,54407,42512,54409,54410,54411,45111,54413,54414,54415,54416,54417,54418,54419,54420,38770,54422,54423,38511,54425,54426,54427,54428,54429,54430,54431,54432,54433,54434,54435,47271,54437,54438,54439,54440,46854,54442,39473,54444,54445,43630,38673,54448,54449,54450,54451,54452,54453,54454,54455,54456,54457,54458,54459,43176,54461,54462,54463,54464,54465,54466,54467,54468,47154,54470,54471,54472,54473,54474,54475,54476,50128,54478,54479,41400,54481,54482,54483,54484,54485,54486,54487,54488,54489,54490,54491,41139,48894,54494,40441,54496,54497,54498,54499,54500,50861,54502,39765,54504,54505,54506,54507,54508,54509,54510,51322,54512,54513,54514,54515,54516,49867,54518,54519,39993,54521,54522,54523,54524,51088,45336,48168,54528,54529,54530,54531,54532,47709,54534,54535,54536,54537,54538,54539,41332,54541,54542,54543,54544,54545,54546,54547,54548,43309,54550,54551,54552,44897,54554,54555,54556,50620,54558,54559,54560,54561,54562,54563,54564,54565,54566,46958,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,50313,54584,54585,46378,44702,54588,54589,54590,54591,54592,54593,54594,54595,54596,54597,38844,54599,54600,48320,46310,54603,54604,54605,54606,54607,54608,54609,54610,54611,54612,54613,54614,54615,54616,46524,54618,54619,54620,44090,54622,48516,54624,54625,54626,54627,54628,54629,54630,39552,54632,54633,54634,54635,51542,54637,54638,54639,54640,54641,54642,54643,54644,54645,54646,54647,54648,54649,44515,54651,38581,54653,54654,54655,54656,54657,54658,54659,54660,54661,54662,49368,54664,54665,54666,54667,51552,54669,54670,54671,54672,54673,54674,41031,54676,54677,54678,54679,54680,54681,54682,54683,48255,54685,41969,54687,54688,54689,54690,40124,54692,54693,52719,54695,54696,54697,54698,54699,54700,54701,54702,54236,54704,54705,54706,54707,54708,54709,48771,54711,45504,54713,54714,54715,54716,54717,54718,44759,54720,54721,54722,54723,54724,54725,54726,54727,54728,54729,54730,52187,54732,46807,54734,54735,54736,54737,54738,54739,42244,54741,42390,54743,54744,54745,54746,39595,54748,54749,54750,41993,54752,54753,54754,40981,54756,54757,54758,54759,46864,54761,54762,54763,54764,54765,54766,54767,54768,54769,54770,54771,54772,54773,54774,54775,54776,54777,54778,54779,54780,54781,51152,54783,54784,54785,54786,54787,42688,54789,54790,54791,48861,39877,54794,54795,54796,54797,41743,54799,54800,54801,54802,54803,43801,38792,54806,52643,54808,54809,54810,54811,54812,54813,52173,42094,54816,49003,54818,54819,54820,54821,54822,54823,54824,54825,40636,54827,54828,54829,54830,54831,54832,39370,54834,54835,54836,39211,54838,54839,54840,54841,54842,54843,39765,54845,54846,54847,54848,54849,54850,54851,54852,54853,54854,54855,54856,52750,54858,54859,54860,39232,54862,54863,54864,46854,54866,54867,51021,54869,54870,54871,54872,45423,54874,54875,42362,54877,54878,54879,54880,38718,54882,49223,54884,54885,54886,54887,54888,54889,54890,54891,46177,54893,54894,54895,54896,54897,45326,54899,54900,54901,54902,54903,54904,54905,54906,39927,54908,54909,54910,54911,43231,54913,54914,54915,54916,54917,54918,54919,54920,54921,52359,54923,54924,54925,44566,39141,54928,54929,54930,54931,54932,54933,54934,54935,54936,54937,54938,54939,54940,54941,54942,54943,54944,54945,54946,54947,54948,54949,54950,54951,54952,54953,54954,54955,54956,54957,54958,54959,54960,54961,54962,54963,54964,54965,54966,54967,54968,54969,54970,54971,54972,54973,54974,54975,54976,54977,54978,54979,54980,54981,54982,54983,54984,54985,54986,54987,54988,54989,54990,54991,54992,54993,54994,54995,54996,54997,52157,54999,55000,55001,45206,55003,55004,55005,55006,41974,55008,55009,55010,55011,55012,43219,55014,55015,55016,55017,55018,55019,55020,55021,55022,55023,47796,55025,42661,55027,55028,55029,38515,55031,55032,45290,39256,55035,55036,55037,55038,55039,55040,55041,47039,55043,55044,55045,55046,55047,55048,55049,54072,55051,55052,55053,49193,55055,55056,55057,55058,55059,39917,55061,55062,50278,55064,55065,55066,55067,55068,55069,42950,55071,55072,55073,55074,44573,55076,38853,54041,55079,55080,55081,55082,55083,40019,45844,55086,48281,55088,55089,55090,55091,55092,55093,46968,45391,55096,55097,44514,55099,55100,53860,55102,55103,55104,55105,55106,52030,55108,55109,55110,55111,55112,42039,55114,49095,55116,55117,55118,55119,55120,47645,55122,55123,55124,55125,55126,55127,55128,55129,55130,55131,55132,54197,55134,55135,55136,55137,55138,55139,39958,52833,55142,55143,55144,55145,55146,55147,55148,53531,55150,55151,55152,55153,55154,55155,55156,55157,44410,55159,55160,55161,55162,48367,55164,55165,55166,55167,55168,55169,55170,55171,55172,46657,55174,40645,55176,55177,55178,55179,55180,47359,55182,55183,55184,38756,55186,55187,55188,55189,54046,40464,55192,55193,39815,55195,55196,38513,52410,55199,55200,55201,54550,55203,55204,55205,55206,55207,55208,55209,55210,55211,55212,53295,55214,55215,55216,55217,55218,39514,55220,55221,55222,55223,55224,55225,55226,55227,50767,55229,55230,55231,43415,55233,55234,55235,55236,55237,39995,55239,55240,55241,55242,41304,55244,55245,55246,55247,46413,55249,39327,55251,55252,55253,55254,55255,55256,41116,55258,55259,38896,51995,55262,55263,55264,55265,55266,48389,55268,55269,55270,55271,55272,55273,55274,51441,55276,39815,55278,55279,55280,55281,39437,55283,55284,42970,55286,55287,55288,42342,55290,55291,55292,55293,55294,55295,44892,55297,55298,55299,50197,55301,55302,55303,55304,55305,55306,51966,55308,55309,55310,55311,55312,55313,55314,55315,40617,55317,55318,55319,55320,55321,55322,55323,55324,55325,55326,55327,55328,48758,55330,55331,55332,55333,55334,55335,55336,55337,55338,55339,55340,48507,55342,55343,55344,47700,55346,55347,55348,41553,55350,55351,40509,55353,55354,55355,55356,55357,55358,55359,55360,39143,55362,55363,55364,55365,55366,55367,55368,55369,55370,55371,55372,55373,55374,55375,55376,52848,55378,55379,55380,55381,55382,55383,55384,51661,55386,55387,55388,55389,55390,55391,55392,54512,55394,55395,55396,55397,49277,44768,55400,55401,46578,55403,55404,47837,55406,55407,55408,55409,55410,55411,52782,45155,55414,55415,55416,55417,55418,55419,55420,55421,55422,55423,55424,55425,55426,55427,55428,55429,55430,55431,55432,55433,55434,55435,55436,55437,55438,55439,55440,55441,55442,55443,55444,55445,55446,55447,55448,55449,55450,55451,55452,55453,55454,55455,55456,55457,55458,55459,55460,55461,55462,55463,55464,55465,55466,55467,55468,55469,52441,55471,55472,55473,47400,55475,55476,55477,55478,55479,55480,55481,55482,46462,55484,55485,55486,44421,55488,55489,55490,55491,55492,55493,55494,39370,55496,55497,38928,55499,55500,55501,55502,55503,55504,52754,55506,55507,55508,44392,55510,55511,55512,55513,51103,55515,50486,55517,55518,52080,55520,55521,55522,55523,55524,49146,55526,55527,55528,55529,47900,55531,42086,55533,39986,55535,48091,47592,55538,55539,55540,55541,55542,55543,55544,52018,55546,38834,55548,55549,41841,55551,55552,55553,55554,40980,55556,55557,55558,40750,55560,55561,55562,43861,55564,55565,55566,55567,40062,55569,55570,55571,55572,55573,55574,54452,55576,55577,55578,55579,47138,55581,55582,55583,55584,55585,55586,55587,55588,55589,39892,55591,55592,55593,44458,38935,55596,55597,41094,55599,43012,45741,41429,55603,55604,55605,55606,55607,39581,55609,55610,39958,43043,55613,55614,55615,55616,55617,47088,55619,55620,55621,45516,55623,55624,55625,52238,55627,55628,55629,55630,46443,46879,55633,55634,55635,55636,55637,55638,55639,55640,55641,55642,42040,53105,55645,55646,55647,55648,55649,55650,55651,41045,45846,39591,55655,55656,55657,55658,55659,55660,55661,55662,55663,55664,55665,55666,55667,43087,55669,55670,55671,55672,55673,55674,55675,55676,43927,55678,55679,43015,55681,55682,55683,55684,55685,44616,55687,55688,55689,55690,55691,43267,44549,55694,44730,55696,55697,51903,55699,55700,55701,55702,55703,55704,55705,55706,55707,55708,55709,55710,55711,55712,55713,55714,55715,55716,55717,43540,55719,45516,55721,55722,55723,55724,55725,55726,55727,47003,55729,48197,55731,55732,55733,55734,54063,55736,55737,55738,55739,55740,55741,55742,44670,55744,55745,55746,55747,55748,55749,55750,55751,55752,55753,48917,55755,55756,55757,55758,46255,55760,51086,40872,55763,55764,55765,55766,55767,55768,55769,43394,55771,55772,55773,55774,55775,54494,38844,55778,55779,44763,55781,55782,55783,55784,42926,55786,45845,48275,55789,55790,55791,55792,55793,55794,55795,46166,55797,55798,55799,41982,55801,55802,55803,55804,55805,55806,55807,50330,55809,46579,55811,55812,55813,55814,36053,55816,55817,55818,55819,55820,55821,55822,55823,55824,55825,55826,55827,55828,55829,55830,55831,55832,55833,55834,55835,55836,55837,55838,55839,55840,55841,55842,55843,55844,55845,55846,55847,55848,55849,55850,55851,55852,55853,55854,55855,55856,55857,55858,55859,55860,55861,55862,55863,55864,55865,55866,55867,55868,55869,55870,55871,55872,55873,55874,55875,55876,55877,55878,55879,55880,55881,55882,55883,55884,55885,55886,55887,55888,55889,55890,55891,55892,55893,55894,55895,55896,55897,55898,55899,55900,55901,55902,55903,55904,55905,55906,55907,55908,55909,55910,55911,55912,55913,55914,55915,55916,55917,55918,55919,55920,55921,55922,55923,55924,55925,55926,55927,55928,55929,55930,55931,55932,55933,55934,55935,55858,55937,55938,55939,55940,55941,55942,55943,55944,55945,55946,55947,55948,55949,55950,55951,55952,55953,55954,55955,55956,55957,55958,55959,55960,55961,55962,55963,55964,55965,55966,55967,55968,55969,55970,55971,55972,55973,55974,55975,55976,55977,55978,55979,55980,55981,55982,55983,55984,55985,55986,55987,55988,55989,55990,55991,55992,55993,55994,55995,55996,55997,55998,55999,56000,56001,56002,56003,56004,56005,56006,56007,56008,56009,56010,56011,56012,56013,56014,56015,56016,56017,56018,56019,56020,56021,56022,56023,56024,56025,56026,56027,56028,55960,56030,56031,56032,56033,56034,56035,56036,56037,56038,56039,56040,56041,56042,56043,56044,56045,56046,56047,56048,56049,56050,56051,56052,55853,56054,56055,56056,56057,56058,56059,56060,56061,56062,56063,56064,56065,56066,56067,56068,56069,56070,56071,56072,56073,56074,56075,56076,56077,56078,56079,56080,56081,56082,56083,56084,56085,56086,56087,56088,56089,56090,56091,56092,56093,56094,56095,56096,56097,56098,56099,56100,56101,56102,56103,56104,56105,56106,56107,56108,56109,56110,56111,56112,56113,56114,56115,56116,56117,56118,56119,56120,56121,56122,56123,56124,56125,56126,56127,56128,56129,56130,56131,56132,56133,56134,56135,56136,56137,56138,56139,56140,56128,56142,56143,56144,56145,56146,56147,56148,56149,56082,56151,56152,56153,56154,56155,56156,56157,56158,56159,56160,56161,56162,56163,56164,56165,56166,56167,56168,56169,56170,56171,56172,56173,56174,56175,56176,56177,56178,56179,56180,56181,56182,56183,56184,56185,56186,56187,56188,56189,56190,56191,56192,56193,56194,56195,56196,56197,56198,56199,56200,56201,56202,56155,56204,56205,56206,56207,56208,56209,56210,56211,56212,56213,56214,56215,56216,56217,56218,56219,56220,56221,56222,56223,56224,56225,56226,56227,56228,56229,56230,56231,56232,56233,56234,56235,56236,56237,56238,56239,56240,56241,56242,56243,56244,56245,56246,56247,56248,56249,56250,56251,56252,56253,56254,56151,56256,56257,56258,56259,56260,56261,56262,56263,56264,56265,56266,56267,56268,56269,56270,56271,56272,56273,56274,56275,56276,56277,56278,56279,56280,56281,56282,56283,56284,56285,56286,56287,56288,56289,56290,56291,56292,56293,56294,56295,56296,56297,56298,56299,56300,56301,56302,56303,56304,56305,56306,56307,56308,56309,56310,56259,56312,56313,56314,56315,56316,56317,56318,56319,56320,56321,56322,56323,56324,56325,56326,56327,56328,56329,56330,56331,56332,56333,56334,56335,56336,56337,56338,56339,56340,56341,56342,56343,56344,56345,56058,56347,56348,56349,56350,56351,56352,56353,56354,56355,56356,56357,56358,56359,56360,56361,56362,56363,56364,56365,56366,56367,56368,56369,56370,56371,56372,56373,56374,56375,56376,56377,56378,56379,56380,56381,56382,56383,56384,56385,56386,56387,56388,56389,56390,56391,56392,56393,56394,56395,56396,56397,56398,56399,56400,56401,56402,56403,56404,56405,56406,56407,56408,56409,56410,56411,56412,56413,56414,56415,56416,56417,56418,56419,56420,56421,56422,56423,56424,56425,56426,56427,56428,56429,56430,56431,56432,56433,56434,56435,56436,56437,56438,56439,56440,56441,56442,56443,56444,56445,56446,56447,56448,56449,56450,56391,56452,56453,56454,56455,56456,56457,56458,56459,56460,56461,56462,56463,56464,56465,56466,56467,56468,56469,56470,56471,56472,56473,56474,56475,56476,56477,56478,56479,56480,56481,56482,56483,56484,56485,56486,56487,56488,56489,56490,56491,56492,56493,56494,56495,56496,56497,56498,56499,56500,56501,56502,56503,56504,56505,56506,56507,56508,56471,56510,56511,56512,56513,56514,56515,56375,56517,56518,56519,56520,56521,56522,56523,56524,56525,56526,56527,56528,56529,56530,56531,56532,56533,56534,56535,56536,56537,56538,56539,56540,56541,56542,56543,56544,56545,56546,56547,56548,56549,56550,56551,56552,56553,56554,56555,56556,56557,56558,56559,56560,56561,56562,56563,56564,56565,56566,56567,56568,56569,56570,56571,56572,56573,56574,56575,56576,56577,56370,56579,56580,56581,56582,56583,56584,56585,56586,56587,56588,56589,56590,56591,56592,56593,56594,56595,56596,56597,56598,56599,56600,56601,56602,56603,56604,56605,56606,56607,56608,56609,56610,56611,56612,56613,56614,56615,56616,56617,56618,56619,56620,56621,56622,56623,56624,56625,56626,56627,56628,56629,55837,56631,56632,56633,56634,56635,56636,56637,56638,56639,56640,56641,56642,56643,56644,56645,56646,56647,56648,56649,56650,56651,56652,56653,56654,56655,56656,56657,56658,56659,56660,56661,56662,56663,56664,56665,56666,56667,56668,56669,56670,56671,56672,56673,56674,56675,56676,56677,56678,56679,56680,56681,56682,56683,56684,56685,56686,56687,56688,56689,56690,56691,56692,56693,56694,56695,56696,56697,56698,56699,56700,56701,56702,56703,56704,56705,56706,56707,56708,56709,56710,56711,56712,56713,56714,56715,56716,56717,56718,56719,56720,56721,56722,56723,56724,56725,56726,56727,56728,56729,56730,56731,56732,56733,56645,56735,56736,56737,56738,56739,56740,56741,56742,56743,56744,56745,56746,56747,56748,56749,56750,56751,56752,56753,56754,56755,56756,56757,56758,56759,56760,56761,56762,56763,56764,56765,56766,56767,56768,56769,56770,56771,56772,56773,56774,56775,56776,56777,56778,56779,56780,56781,56782,56783,56784,56785,56786,56787,56788,56789,56790,56791,56792,56793,56794,56795,56796,56797,56798,56799,56800,56801,56802,56803,56804,56805,56806,56807,56808,56809,56810,56811,56812,56640,56814,56815,56816,56817,56818,56819,56820,56821,56822,56823,56824,56825,56826,56827,56828,56829,56830,56831,56832,56833,56834,56835,56836,56837,56838,56839,56840,56841,56842,56843,56844,56845,56846,56847,56848,56849,56850,56851,56852,56853,56854,56855,56856,56857,56858,56859,56860,56861,56862,56863,56864,56865,56866,56867,56868,56869,56870,56871,56872,56873,56874,56875,56876,56877,56878,56879,56880,56881,56882,56883,56884,56885,56886,56847,56888,56889,56890,56891,56892,56893,56894,56895,56896,56897,56898,56899,56900,56901,56902,56903,56904,56905,56906,56907,56908,56909,56910,56911,56912,56913,56914,56915,56916,56917,56918,56919,56920,56921,56922,56923,56924,56925,56926,56927,56928,56929,56930,56931,56932,56933,55826,56935,56936,56937,56938,56939,56940,56941,56942,56943,56944,56945,56946,56947,56948,56949,56950,56951,56952,56953,56954,56955,56956,56957,56958,56959,56960,56961,56962,56963,56964,56965,56966,56967,56968,56969,56970,56971,56972,56973,56974,56975,56976,56977,56978,56979,56980,56981,56982,56983,56984,56985,56986,56987,56988,56989,56990,56991,56992,56993,56994,56995,56996,56997,56998,56999,57000,57001,57002,57003,57004,57005,57006,57007,57008,57009,57010,57011,57012,57013,57014,57015,57016,57017,57018,57019,57020,57021,57022,57023,57024,57025,57026,57027,57028,57029,57030,57031,57032,57033,57034,57035,57036,57037,57038,57039,57040,56968,57042,57043,57044,57045,57046,57047,57048,57049,57050,57051,57052,57053,57054,57055,57056,57057,57058,57059,57060,57061,57062,57063,57064,57065,57066,57067,57068,57069,57070,57071,57072,57073,57074,57075,57076,57077,57078,57079,57080,57081,57082,56939,57084,57085,57086,57087,57088,57089,57090,57091,57092,57093,57094,57095,57096,57097,57098,57099,57100,57101,57102,57103,57104,57105,57106,57107,57108,57109,57110,57111,57112,57113,57114,57115,57116,57117,57118,57119,57120,57121,57122,57123,57124,57125,57126,57127,57128,57129,57130,57131,57132,57133,57134,57135,57136,57137,57138,57139,57140,57141,57142,57143,57144,57145,57146,57147,57148,57149,57150,57151,57152,57153,57154,57155,57156,57157,57158,57159,57160,57161,57162,57163,57164,57165,57166,57167,57168,57169,57170,57171,57172,57173,57174,57088,57176,57177,57178,57179,57180,57181,57182,57183,57184,57185,57186,57187,57188,57189,57190,57191,57192,57193,57194,57195,57196,57197,57198,57199,57200,57201,57202,57203,57204,57205,57206,57207,57208,57209,57210,57211,57212,57213,57214,57215,57216,57217,57218,57219,57220,57221,57222,57223,57224,57225,57226,57227,57228,57229,57230,57231,57232,57233,57234,57235,57236,57237,57238,57239,57240,57241,57242,57243,57244,57245,56935,57247,57248,57249,57250,57251,57252,57253,57254,57255,57256,57257,57258,57259,57260,57261,57262,57263,57264,57265,57266,57267,57268,57269,57270,57271,57272,57273,57274,57275,57276,57277,57278,57279,57280,57281,57282,57283,57284,57285,57286,57287,57288,57289,57290,57291,57292,57293,57294,57295,57296,57297,57298,57299,57300,57301,57302,57303,57304,57305,57306,57307,57308,57309,57310,57311,57312,57313,57314,57315,57316,57317,57318,57255,57320,57321,57322,57323,57324,57325,57326,57327,57328,57329,57330,57331,57332,57333,57334,57335,57336,57337,57338,57339,57340,57341,57342,57343,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57250,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57396,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,57532,57533,57534,57535,57536,57537,57538,57539,57540,122,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57553,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57658,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,35796,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,35914,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,14012,58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,3814,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58024,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58056,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58091,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58085,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58045,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,58190,58191,58192,58193,58194,58195,58196,58197,58198,58171,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58212,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58200,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58248,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,58284,58285,58286,58287,58288,58244,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58169,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58200,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58212,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58275,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58246,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58294,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58200,58434,58435,58326,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58354,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,58472,58473,58474,58475,58476,58477,58478,58342,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58370,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58294,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58238,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58180,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58220,58557,58558,58559,58560,58561,58562,58563,58564,58565,58566,58567,58568,58569,58570,58382,58572,58573,58574,58575,58576,58577,58578,58278,58580,58581,58582,58583,58584,58585,58393,58587,58588,58589,58590,58237,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,14132,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58627,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58657,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,14130,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58734,58755,58756,58757,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58757,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58756,58792,58793,58794,58795,58796,58797,58798,58799,58782,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58757,58813,58814,58792,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58804,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,58853,58854,58855,58856,58857,58858,58717,58860,58861,58862,58863,58864,58865,58866,58867,58822,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58847,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58630,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58674,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58687,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,58950,58951,58952,58953,58954,58725,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58763,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58775,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58737,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,58804,59010,59011,58787,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,58824,59029,59030,59031,59032,58847,59034,59035,59036,59037,58987,59039,59040,59041,59042,59043,59044,59045,59046,59047,59048,59049,59050,58776,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,58816,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,58836,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,58641,59094,59095,59096,58940,59098,59099,59100,59101,59102,59103,58735,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,58759,59128,59129,59130,59131,59132,59133,59134,59135,59136,58757,59138,59139,58794,59141,59142,59143,59144,59145,58805,59147,59148,59149,59150,59151,59152,58730,59154,59136,59156,59157,58757,59159,59160,59161,59162,59163,59164,59165,59166,59167,58798,59169,58806,59171,59172,59173,59174,59175,59176,59177,59178,58630,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,58658,59196,59197,59198,59199,59200,59201,59202,59203,59204,58928,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,58725,59220,59221,59222,59223,59224,59129,59226,58776,59228,58796,58847,59231,59232,59233,59234,59235,59236,59237,59238,59013,59240,59241,59242,59243,59244,59245,59246,59247,59248,59249,59250,59251,59252,59253,58881,59255,59256,59257,59258,59259,59084,59261,59262,59263,59264,59265,59266,58741,59268,59269,59270,59271,58787,59273,59274,59275,59276,59277,59278,59279,59280,59281,59282,59283,59284,58651,59286,59287,59288,59289,59290,59291,59292,59293,59294,59295,59296,59297,59298,59299,59300,59301,59302,59303,58692,59305,59306,59307,59308,59309,59310,58689,59312,59313,59314,59315,59316,59317,59318,59319,59320,58792,59322,59323,59324,59325,59326,58889,59328,59329,59330,59331,59332,59333,59334,59335,58734,59337,59338,59339,59340,59341,59342,59343,59344,59345,59346,58755,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,59362,59363,59364,59365,59366,59367,59368,59369,59370,59371,59372,59373,59374,59375,59376,59377,59378,59379,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,59408,59409,59410,59411,59412,59413,59414,59415,59416,59417,59418,59419,59420,59421,59422,59423,59424,59425,59426,59427,59428,59429,59430,59431,58847,59433,59434,59435,59436,59437,59438,58741,59440,59441,59442,59443,59444,59445,59446,59447,59448,58972,59450,59451,59452,59453,59454,59455,59456,59457,59458,59459,59460,59461,59462,59463,59464,59465,59466,59467,59468,59469,59470,59471,58790,59473,58794,59475,58757,59477,59478,59479,59480,59481,59482,59483,59484,59485,59486,59487,59488,59489,59490,59491,59492,59493,59349,59495,59496,59497,59498,59499,59500,59501,59502,59503,59504,59505,59506,58639,59508,59509,59510,59511,59512,59513,58677,59515,59516,59517,59518,59519,59520,59521,59522,59523,59524,59525,59526,59441,59528,59529,59530,59531,59532,59533,59534,59470,59536,59537,59538,59539,59540,59541,59542,59543,59544,59545,59546,59547,59548,59549,59550,59551,59552,59553,58790,59555,58793,59557,59558,59559,59560,59561,59562,59563,59564,59565,59566,59567,59568,59569,58844,59571,59572,59573,59574,59575,59576,59577,59578,59579,59580,58735,59582,59583,59584,59585,59586,59587,59588,59589,59590,59591,59592,59593,59594,59595,59596,59597,59598,58759,59600,59601,59602,59603,59604,58790,59606,58792,59608,59609,59610,59611,59612,59613,59614,59615,59616,59617,59034,59619,59620,59621,58911,59623,59624,59625,58949,59627,59628,59629,58725,59631,59632,59633,59634,59635,59636,59637,59638,59639,59640,59641,59642,59501,59644,59645,59646,59019,59648,59649,59650,58819,59652,59653,59654,59089,59656,59221,59658,59659,59601,59052,59662,59663,59664,59665,59666,59667,59668,59669,59670,59671,59672,59673,59000,59675,59676,59677,59678,59679,59680,59681,59682,59683,59684,59685,59686,59687,59688,58807,59690,59691,59692,59014,59694,59695,59696,59697,59698,59699,59700,59701,59702,59703,59704,59705,59706,59707,59708,59709,59296,59711,59712,59713,59714,59715,59716,59717,58660,59719,59720,59721,59722,59723,59724,59725,59726,59727,59728,59729,59730,58690,59732,59733,59734,59735,59736,59737,59738,59739,59740,59741,59742,59743,59744,59745,59746,59747,59748,59749,59750,59751,59752,59753,59754,59755,59756,59757,59758,59759,59760,59761,59762,59763,59764,59765,59766,59767,59768,59769,59770,59771,59772,59773,59774,59775,59142,59777,59778,59779,59780,59781,59036,58755,59784,59785,59786,59787,59788,59789,59790,59791,59792,59793,59794,59795,59796,59797,59798,58881,59800,59801,59802,59803,59804,59805,59806,59807,59041,59809,59810,59811,59812,59813,59814,59815,59816,59817,59818,59819,59443,59821,59822,59823,59824,59825,59826,59827,59130,59829,59830,59831,59832,59833,59834,59017,59836,59837,59838,59839,59840,59841,59842,59843,59844,59845,59846,59847,59848,59849,59850,59142,59852,59853,59056,59855,59856,59857,59858,59859,59860,59861,59862,59863,59864,59865,59866,59867,58643,59869,59870,59871,59872,58649,59874,59875,59876,59877,59878,59879,59880,59881,59882,59883,59884,59885,59886,59887,59888,59889,59890,58674,59892,59893,59894,59895,59896,59897,59898,59899,59900,59901,58934,59903,59904,59905,59906,59907,59908,59909,59910,59911,59912,59913,59914,59658,59916,59917,59918,59919,59667,59921,59922,59923,59924,59675,59926,59927,59928,59929,59930,59931,59932,59933,59934,59935,59936,59937,58832,59939,59940,59941,59942,59943,59944,59013,59946,59947,59948,59949,59950,59951,59952,59800,59954,59955,59956,59957,59329,59959,59444,59961,59962,59963,59964,59965,58801,59967,59968,59969,59970,59971,59972,59973,59974,59975,59836,59977,59978,59979,59980,59981,59982,59983,59984,59985,58651,59987,59988,59989,59990,59991,59992,59993,59994,59995,59996,59997,59998,59999,60000,60001,58936,60003,60004,60005,60006,60007,60008,60009,60010,60011,60012,59779,60014,60015,60016,60017,60018,60019,60020,60021,58729,60023,60024,60025,60026,60027,59129,60029,59505,60031,60032,60033,60034,60035,60036,60037,60038,60039,60040,58796,60042,59632,60044,60045,60046,60047,60048,60049,60050,60051,59478,60053,60054,59241,60056,60057,60058,60059,60060,59875,60062,60063,60064,60065,60066,60067,60068,60069,60070,60071,60072,60073,60074,60075,58677,60077,60078,60079,60080,60081,60082,60083,60084,60085,60086,60087,60088,60089,60090,60091,60092,60093,60094,58704,60096,60097,60098,60099,60100,60101,60102,60103,60104,60105,60106,60107,60108,60109,60110,60111,60112,60113,60114,59682,60116,60117,60118,60119,60120,60121,60122,60123,60124,59013,60126,60127,60128,60129,60130,60131,60132,60133,60134,60135,58818,60137,60138,60139,60140,60141,60142,60143,59232,60145,60146,60147,60148,60149,60150,60151,60152,60153,60154,60155,59584,60157,60158,60159,60160,60161,60162,60163,60164,60165,60166,60167,60168,60169,60170,60171,60172,58787,60174,60175,60176,60177,60178,60179,60180,60181,60182,60183,60184,59029,60186,60187,60188,60189,60190,58888,60192,60193,14350,60195,60196,60197,59991,60199,60200,60201,60202,60203,60204,60205,60206,60207,60208,59200,60210,60211,60212,60213,60214,60215,60216,60217,60218,59521,60220,60221,60222,60223,60224,60225,60226,60227,60228,60229,60230,60231,60232,60233,60234,60235,60236,60237,60238,58704,60240,60241,60242,60243,60244,60245,60246,60247,60248,60249,59269,60251,60252,60253,60254,60255,60256,60257,60258,60259,59601,60261,60262,60263,59166,60265,60015,60267,60268,60269,60270,60271,60272,60273,60274,59178,60047,60277,58766,60279,60280,60281,60282,60283,60284,60285,60126,60287,59323,60289,59621,60291,60176,60293,60294,59879,60296,60297,60298,60299,60300,60301,60302,60303,60304,60305,60306,60307,60308,60309,60231,60311,60312,60313,60314,58685,60316,60317,60318,60319,60320,60321,59916,60323,59129,60325,60326,60327,60328,60329,60330,60331,60332,59261,60334,60335,60336,60337,60338,60339,60340,60341,60342,60343,60344,60345,59221,60347,60348,60349,60350,60351,60352,60353,60354,58869,60356,58802,60358,60359,60360,60361,60362,60363,60364,60365,60366,60367,60368,60369,60370,60371,58718,60373,60374,60375,60376,60377,59800,60379,60380,60381,60382,60383,60384,60385,60386,59690,59221,60389,60390,59834,58892,60393,60394,60395,60396,58656,60398,60399,60400,60401,60402,60403,60404,60405,60406,60407,60408,60409,60410,60411,60412,60413,60414,58714,59316,60417,60418,60419,60420,60421,58997,60423,60424,60425,60426,60427,60428,60429,60430,60431,60432,60433,60434,60435,60436,60437,60438,60439,59013,60441,60442,60443,60444,60445,60446,60447,60448,60449,60450,60451,60452,59323,60454,60455,59329,60457,60458,60459,60460,60461,60462,60463,60464,60465,58861,60467,60468,60469,60326,60471,60472,58814,60424,60475,60476,60477,60478,60479,60480,60481,60482,60483,60484,59473,59291,60487,60488,60489,60490,60491,59722,60493,60494,60495,60496,60497,60498,60499,60500,60501,60502,58690,60504,60505,58651,60507,60508,60509,60510,60511,60512,60513,60514,60515,60516,60517,60518,60519,60520,60521,60522,60523,60524,60525,60526,60527,58741,60529,60530,60531,60532,60533,60534,60535,60536,59157,59855,60539,60540,59169,59125,60543,60544,60545,60546,60547,59160,60549,60550,60551,60552,59779,60554,60555,60556,60557,60558,60559,60560,60561,60562,59176,60564,60565,60566,60567,59184,58662,60570,60571,60572,60573,60574,60575,60576,59658,60578,60579,59273,60581,60582,60583,58794,60457,60586,60587,60588,59919,60590,60591,60592,60593,60594,60595,60596,60597,59157,58986,60600,60601,60602,60434,60604,59696,60606,60607,60608,60609,60610,60611,60612,60613,60614,60615,60616,60617,60618,60619,60620,59990,60622,60623,60624,59778,60626,60627,60628,60047,60630,60631,60632,60633,60634,60635,60636,60637,60638,60639,60640,60053,60642,60643,60644,60645,60646,60647,59020,60649,60137,60651,59434,60653,59919,60655,60656,60657,60658,60659,60660,60661,59606,3809,60664,60665,60666,60667,60668,60669,60670,60671,60672,60673,60674,60675,60676,60677,60678,60679,60680,60681,60682,60683,60684,60685,60686,60687,60688,60689,60690,60691,60692,60693,60694,60695,60696,60697,60698,60699,60700,60701,60702,60703,60704,60705,60706,60707,60708,60709,60710,60711,60712,60713,60714,60715,60716,60717,60718,60719,60720,60721,60722,60723,60724,60725,60726,60727,60728,60729,60730,60731,60732,60733,60734,60735,60736,60737,60738,60739,60740,60741,60742,60743,60744,60745,60746,3809,60748,60749,60750,60751,60752,60753,60754,4420,60756,60757,60758,60759,60760,60761,60762,60763,60764,60765,60766,60767,60768,60769,60770,60771,60772,60773,60774,60775,60776,60777,60778,60779,60780,60781,60782,60783,60769,60785,60786,60787,60788,60789,60790,60791,60792,60793,60794,60795,60796,60797,60798,60799,60800,60801,60802,60803,60804,60805,60806,60807,60808,60809,60810,60811,60812,60813,60814,60815,60816,60817,60818,60805,60820,60821,60822,60823,60824,60825,60826,60827,60828,60829,60830,60831,60832,60833,60834,60835,60836,60837,60838,60839,60840,60841,60842,60843,60844,60845,60846,60847,60848,60849,60850,60831,60852,60853,60854,60855,60856,60857,60858,60859,60860,60861,60862,60863,60864,60865,60866,60867,60868,60869,60870,60871,60872,60873,60874,60866,60876,60877,60878,60879,60880,60881,60882,60883,60884,60885,60886,60887,60888,60889,60890,60891,60892,60893,60894,60895,60896,60897,60898,60899,60900,60901,60889,60903,60904,60905,60906,60907,60908,60909,60910,60911,60912,60913,60914,60915,60916,60917,60918,60919,60920,60921,60922,60923,60924,60925,60926,60927,60928,60929,60930,60931,60932,60933,60934,60935,60936,60937,60938,60913,60940,60941,60942,60943,60944,60945,60946,60947,60948,60949,60950,60951,60952,60953,60954,60955,60956,60957,60958,60959,60960,60961,60962,60963,60964,60965,60966,60967,60968,60969,60970,60971,60972,60973,60942,60975,60976,60977,60978,60979,60980,60981,60982,60983,60984,60985,60986,60987,60988,60880,60990,60991,60992,60993,60994,60995,60996,60997,60998,60999,61000,61001,61002,61003,61004,61005,61006,61007,61008,61009,61010,61011,61012,61013,61014,61015,60997,61017,61018,61019,61020,61021,61022,61023,61024,61025,61026,61027,61028,61029,61030,61031,61032,61033,61034,61035,61036,61037,61038,61039,61040,61041,61017,61043,61044,61045,61046,61047,61048,61049,61050,61051,61052,61053,61054,61055,61056,61057,61058,61059,61060,61061,61062,61063,61064,61065,61066,61067,61068,61069,61070,61071,61072,61073,61074,61075,61076,61077,61078,61079,61080,61081,61056,61083,61084,61085,61086,61087,61088,61089,61090,61091,61092,61093,61094,61095,61096,61097,61098,61099,61100,61101,61102,61103,61104,61105,61106,61107,61108,61109,61110,61111,61053,61113,61114,61115,61116,61117,61118,61119,61120,61121,61122,61123,61124,61125,61126,61127,61128,61129,61019,61131,61132,61133,61134,61135,61136,61137,61138,61139,61140,61125,61142,61143,61144,61145,61146,61147,61148,61149,61150,61151,61152,61153,61095,61155,61156,61157,61158,61159,61160,61161,61162,61163,61164,61165,61166,61167,61168,61169,61119,61171,61172,61173,61174,61175,61176,61177,61178,61179,61180,61181,61182,61029,61184,61185,61186,61187,61188,61189,61190,61191,61192,61193,61194,61115,61196,61197,61198,61199,61200,61201,61202,61203,61204,61205,61059,61207,61208,61209,61210,61211,61212,61213,61214,61215,61216,61217,61096,61219,61220,61221,61222,61223,61096,61225,61226,61227,61228,61229,61126,61231,61232,61233,61234,61235,61236,61237,61238,61239,61240,61241,60757,61243,61244,61245,61246,61247,61248,61249,61250,61251,61252,61253,61254,61255,61256,61257,61258,61259,61260,61261,61262,60768,61264,61265,61266,61267,61268,61269,61270,61271,61272,61273,61274,60822,61276,61277,61278,61279,61280,61281,61282,61283,61284,61285,61286,61287,61288,61289,61290,61291,61292,61293,61294,61295,61296,61297,61298,61299,61300,61301,61302,61303,61304,61305,61306,61307,61308,61309,61310,61311,61312,61313,61314,61315,61316,61317,61318,61319,61320,61321,61322,61323,61324,61325,61326,61327,61328,61329,61330,61331,61332,61333,61334,61335,60853,61337,61338,61339,61340,61341,61342,61343,61344,61345,61346,61347,61348,61349,60883,61351,61352,61353,61354,61355,61356,61357,61358,61359,61360,61361,61362,61363,61364,60891,61366,61367,61368,61369,61370,61371,61372,61373,61374,61375,61376,61377,61378,61379,61380,61381,61382,61383,61384,61385,61386,61387,61369,61389,61390,61391,60960,61393,61394,61395,61396,61397,61398,61399,60942,61401,61402,61403,61404,61405,61406,61407,61408,61409,61410,61411,61412,61413,61414,61415,61416,61417,61418,61419,61420,61421,61422,61423,61424,61425,61426,61427,61428,61005,61430,61431,61432,61433,61434,61435,61436,61437,61438,61439,61440,61441,61442,61443,61444,61445,61446,61023,61448,61449,61450,61451,61452,61453,61454,61455,61456,61457,61458,61459,61460,61143,61462,61463,61464,61465,61466,61467,61468,61469,61470,61471,61472,61473,61156,61475,61476,61477,61478,61479,61480,61481,61482,61483,61484,61485,61172,61487,61488,61489,61490,61189,61492,61493,61494,61495,61496,61056,61498,61499,61500,61501,61502,61503,61504,61505,61506,61507,61508,61509,61510,61511,61512,61513,61514,61515,61516,61517,61518,61519,61520,61521,61522,61523,61090,61525,61526,61527,61528,61529,61530,61531,61532,61533,61534,61535,61536,61537,61538,61539,61540,61541,61542,61543,61544,61545,61546,61547,61548,61434,61550,61551,61450,61553,61554,61555,61556,61557,61468,61559,61560,61561,61562,61563,61564,61565,61566,61567,61092,61569,61570,61571,61572,61573,61574,61575,61576,61115,61578,61579,61580,61581,61582,61583,61584,61585,61586,61587,61588,61589,61251,61591,61592,61593,61594,61595,61596,61597,60759,61599,61600,61601,60786,61603,61604,61605,61606,61607,61608,61609,61610,61611,61612,61613,61614,61615,61616,61617,60808,61619,61620,61621,61622,61623,61624,61625,61626,61627,61628,61629,61630,60833,61632,61633,61634,61635,61636,61637,61638,61639,61640,61641,61642,61343,61644,61645,61646,61647,61648,61649,61650,61651,61652,61653,61654,61655,61656,61657,61658,61659,61660,61661,61662,61391,61664,61665,61666,61667,61668,61669,60916,61671,61672,61673,61674,61675,61676,61677,61678,61679,61680,60942,61682,61683,61684,61685,61686,61687,61688,61689,61690,61691,61692,61693,61694,61695,61696,61697,61698,61699,61700,61701,61702,61703,61704,61136,61706,61707,61708,61709,61041,61207,61712,61713,61714,61715,61716,61717,61718,61719,61720,61721,61722,61723,61724,61725,61726,61727,61728,61729,61730,61731,61096,61733,61734,61735,61736,61737,61738,61739,61740,61741,61742,61512,61744,61745,61746,61747,61748,61749,61750,61751,61752,61753,61754,61452,61756,61757,61758,61759,61760,61761,61762,61763,61764,61765,61058,61767,61768,61769,61770,61771,61772,61773,61774,61775,61776,61777,61096,61779,61780,61781,61782,61783,61784,61785,61786,61787,61788,61789,61790,61791,61792,61793,61794,61175,61796,61797,61798,61799,61800,61492,61802,61803,61514,61805,61806,61807,61808,61809,61810,61811,61812,61813,61814,61815,61816,61525,61818,61819,61820,61821,61822,61823,61824,61825,61826,61827,61828,61829,61830,61831,61832,61833,60827,61835,61836,61837,61838,61839,61840,61841,61842,61843,61844,61845,61846,61847,61848,61849,61850,61851,61852,61853,61600,61855,61856,61857,61858,61859,61860,61861,61862,61863,61864,61865,61866,61867,60796,61869,61870,61871,61872,61873,61874,61875,61876,61877,61878,60843,61880,61881,61882,61883,61884,61337,61886,61887,61888,61889,61890,61891,61892,61893,61894,61895,61896,61375,61898,61899,61900,61901,61902,61903,61904,61905,61906,61907,61908,61909,61676,61911,61912,61913,61914,61915,60976,61917,61918,61919,61920,61921,61922,61923,61924,61925,61926,61927,61928,61929,61930,61931,61932,61933,61934,61935,61936,61937,61938,61939,61940,61941,61942,61943,60909,61945,61946,61947,61948,61949,61450,61951,61952,61953,61954,61955,61465,61957,61958,61959,61960,61961,61962,61963,61964,61965,61966,61967,61157,61969,61970,61971,61972,61973,61176,61975,61976,61977,61978,61979,61189,61981,61982,61983,61984,61985,61986,61987,61988,61583,61990,61991,61992,61516,61994,61995,61996,61997,61535,61999,62000,62001,62002,62003,62004,62005,62006,62007,61001,62009,62010,62011,62012,62013,62014,62015,62016,62017,62018,62019,61019,62021,62022,62023,62024,62025,62026,62027,62028,62029,62030,61796,62032,62033,62034,62035,62036,61499,62038,62039,62040,62041,62042,62043,62044,62045,62046,62047,62048,62049,62050,62051,61097,62053,62054,62055,62056,62057,62058,61796,62060,62061,62062,62063,4415,62065,62066,62067,62068,62069,62070,62071,62072,60783,60826,62075,62076,62077,62078,62079,62080,62081,62082,62083,61655,62085,62086,62087,61665,62089,62090,62091,62092,62093,60916,62095,62096,62097,62098,62099,62100,62101,61933,62103,62104,62105,62106,62107,62108,62109,62110,62111,62112,62113,62114,62115,62116,61947,62118,62119,61758,62121,62122,62123,62124,62125,62126,61775,62128,62129,62130,62131,62132,62133,62134,61779,62136,62137,62138,62139,62140,62141,62142,62143,61153,61031,62146,62147,62148,62149,62150,62151,62152,62153,62154,62155,62156,62157,62158,62159,62160,61120,62162,61056,62164,62165,62166,62167,62168,62169,62170,62171,62172,62173,62174,62175,62176,62177,62178,62179,62180,62181,62182,62183,62184,62185,62186,62187,62188,62189,62190,61583,62192,62193,62194,62195,62196,61021,62198,62199,62200,61041,61715,62203,62204,62205,62206,62207,62208,62209,62210,62211,61100,62213,62214,62215,62216,62217,62218,61559,62220,62221,62222,62223,62224,62225,62226,62227,62228,62229,62230,62231,62066,62233,62234,62235,62236,62237,62238,60786,62240,62241,62242,62243,62244,62245,62246,62247,62248,62249,61632,62251,62252,62253,62254,62255,62256,62257,62258,62259,62260,62261,62262,62263,62264,61649,62266,62267,62268,62269,62270,62271,62272,62273,62274,62275,62276,62277,60917,62279,62280,62281,61926,62283,62284,62285,62286,62287,62288,62289,60992,62291,62292,62293,62294,62295,62296,62297,62298,62299,62300,62301,62302,62303,62304,62305,62306,62307,62308,61452,62310,62311,62312,62313,61530,62315,62316,62192,62318,62319,62320,62321,62310,62323,62324,62325,62326,62327,62328,62329,61806,62331,62332,62333,62334,62335,62336,62337,62338,62339,61096,62341,62342,62343,62344,62345,62346,62347,62296,62349,62350,62351,61802,62353,61073,62355,62356,62357,62358,62359,62360,62361,62362,62363,62364,62365,61097,62367,62368,62369,62370,62371,62372,62373,62374,62375,62376,62377,62378,62379,62380,4420,62382,62383,62384,62385,62386,62387,62388,62389,62390,62391,62392,62393,62394,62395,62396,62397,62398,62399,62400,62401,62402,62403,62404,62405,62406,62407,62408,60840,62410,62411,62412,62413,62414,62415,62416,62417,62418,62419,62420,62421,62422,62423,62424,62425,62426,62427,62428,62429,62430,62431,62432,62433,62415,62435,62436,62437,62438,62439,62440,62441,60945,62443,62444,62445,62446,62104,62448,62449,62450,62451,62452,62453,62454,60979,62456,62457,62458,62459,62460,62461,62462,62463,62464,62465,62466,61001,62468,62469,62470,62471,62472,62473,62474,62475,62476,62477,62478,62479,62480,62481,62482,61452,62484,62485,62486,62487,62488,61958,62490,62491,62492,62493,62494,61509,62496,62497,62498,62499,62500,61044,62502,62503,62504,62505,62506,62507,62508,62509,62510,62511,62512,62513,62514,61435,62516,62517,62518,62519,62520,62521,62522,61029,62524,62525,62526,62527,62528,62529,62530,62531,62532,62533,62534,62535,62536,62355,62538,62539,62540,62541,62542,62543,62370,62545,62546,62547,62548,62549,62550,62551,62552,61990,62554,62555,62556,62557,61515,62559,62560,62561,62562,62563,62564,62565,62566,62567,62568,61049,62570,62571,62572,62573,62574,60769,62576,62577,62578,62579,62580,62581,62582,62583,61867,60838,62586,62587,60858,62589,62590,62591,62592,62593,62594,62595,62596,62597,61382,62599,62600,62601,62602,62603,62604,62605,60920,62607,62608,62609,62610,62611,62612,62613,62614,62615,62616,60979,62618,62619,62620,62621,62622,62623,62624,61551,62626,62627,62628,62629,62630,62631,62632,62633,62634,62635,62636,62637,62638,61803,62359,62641,62642,62643,62644,62645,62646,62647,62648,62649,62650,62651,61783,62653,62654,62655,62656,62657,62658,62659,62660,61175,62662,62663,62664,62665,62666,62667,62668,62192,62670,62671,62672,61808,62674,62675,62676,62677,62678,62679,62680,62038,62682,61205,62518,62685,62686,62687,62688,62689,62690,62691,62692,61456,62694,62695,62696,61961,62698,62699,62700,62701,62702,62703,62704,62705,62706,61229,62708,62709,62710,61173,62712,62713,62714,62715,62716,62717,61591,62719,62720,62721,62722,62723,62724,62725,62726,61264,62728,62729,62730,62731,62732,62733,62734,62735,62736,62737,62738,62739,62740,62741,62742,62743,61622,62745,62746,62747,62748,62749,62750,62751,62752,62753,62754,62755,62756,62757,62758,62759,62760,62761,62762,61339,62764,62765,62766,62767,62768,62769,62770,62771,62772,60953,62774,62775,62776,62777,62778,62779,62780,62781,62782,62783,61694,62785,62786,62787,62788,62789,62790,62791,62792,62793,62794,62795,62796,62797,62798,62799,62800,62801,62802,62803,62804,62805,62806,62807,62808,62809,62810,62811,62812,61189,62814,62815,62816,62817,62818,62819,62820,62821,62822,62823,61487,62825,62826,62827,62828,62829,61515,62831,62832,62833,61136,62835,62836,62837,62838,62506,62840,61713,62842,62843,62844,62845,62846,62847,62848,62849,62850,62851,62852,62853,61734,62855,62856,62857,62858,62859,62860,62861,62862,62863,62864,62865,62866,62867,62868,62869,62870,61069,62872,62873,62874,62875,62876,61024,62878,62879,62880,62881,62882,62883,62884,62885,62886,62887,62888,62889,61177,62891,62892,62893,62894,62040,62896,62897,62898,62899,62900,62901,62902,62903,62904,62905,62906,62907,62908,61049,62910,61592,62912,62913,62914,62915,62916,62917,62918,62919,60759,62921,62922,62923,62924,62925,62926,62927,62928,62929,62930,62931,60808,62933,62934,62935,62936,62937,62938,62939,62940,62941,62942,62417,62944,62945,62946,62947,62948,62949,62950,62951,62952,62953,60866,62955,62956,62957,62958,62959,62960,62961,62962,62963,62964,62965,62966,62967,62968,62969,62970,62971,62972,62973,60891,62975,62976,60928,62978,62979,62980,62981,62982,62983,62984,62985,62986,62987,62988,62989,62990,62991,62992,62993,62994,62995,62996,62997,62998,62999,63000,61689,63002,63003,63004,63005,63006,63007,63008,63009,63010,62472,63012,63013,63014,63015,61073,63017,63018,63019,63020,62373,63022,63023,63024,63025,63026,63027,63028,63029,62015,63031,63032,63033,63034,63035,63036,63037,63038,63039,61024,63041,62359,63043,63044,63045,62369,63047,63048,63049,63050,63051,63052,63053,63054,63055,63056,63057,63058,63059,63060,62555,63062,63063,63064,63065,63066,61516,63068,63069,63070,63071,63072,63073,63074,63075,63076,63077,63078,63079,63080,62508,63082,60764,63084,63085,63086,63087,61855,63089,63090,63091,63092,63093,63094,63095,63096,62959,63098,63099,63100,63101,63102,63103,63104,63105,63106,63107,63108,60929,63110,63111,61699,63113,63114,63115,63116,63117,63118,63119,61136,63121,63122,63123,63124,63125,63126,61048,63128,63129,63130,63131,63132,63133,63134,63135,61713,63137,63138,63139,63140,63141,62855,63143,63144,63145,63146,63147,63148,63149,63150,63151,61072,63153,63154,63155,63156,63157,63158,63159,63160,63161,63162,61951,63164,63165,61143,63167,63168,63169,63170,63171,63172,61477,63174,63175,63176,63177,63178,63179,63180,63181,63182,63183,63184,63185,63186,63187,63188,63189,61173,63191,63192,63193,63194,63195,63196,62484,63198,63199,63200,63201,63202,62153,63204,63205,63206,63207,63208,63209,61065,63211,63212,63213,63214,63215,63216,63217,63218,63219,61097,63221,63222,63223,63224,63225,63226,63227,63228,63172,63230,63231,63232,63233,63234,63235,63236,63237,63238,63239,63240,63241,63242,63243,63244,63245,63246,63247,63248,63249,63250,63251,63252,63253,63254,63255,63256,63257,63258,63259,63260,63261,63262,63263,63264,63265,63266,63267,63268,63269,63270,63271,63272,63273,63274,63275,63276,63277,63278,63279,63280,63281,63282,63283,63284,63285,63286,63287,63288,63289,63290,63291,63292,63293,63294,63295,63296,63297,63298,63299,63300,63301,63302,63303,63304,63305,63306,63307,63308,63309,63310,63311,63312,63313,63314,63315,63316,63317,63318,63319,63320,63321,63322,63323,63324,63325,63326,63327,63328,63329,63330,63331,62066,63333,63334,63335,63336,63337,63338,60786,63340,63341,63342,62087,63344,61391,63346,63347,63348,63349,61390,63351,63352,63353,60958,63355,63356,63357,63358,63359,63360,63361,63362,63363,63364,62785,63366,63367,63368,63369,63370,63371,63372,63373,63374,63375,63376,63377,63378,63007,63380,63381,63382,63383,63384,63385,63386,63387,63388,63389,63390,63391,62554,63393,63394,63395,62664,63397,63398,63399,63400,63401,63402,62355,63404,63405,63406,63407,63408,63409,63410,63411,63412,63413,61516,63415,63416,63417,63418,63419,63420,63421,63422,63423,63424,63425,63426,63129,63428,63429,63430,63431,61145,63433,63434,63435,61118,63437,63438,61516,63440,63441,63442,63443,63444,63445,63446,62343,63448,63449,63450,63451,63452,63453,63454,63455,63456,63457,63458,63459,63460,63461,63462,63463,63464,63465,63466,63467,63468,62310,63470,63471,61235,63473,61096,63475,63476,63477,63478,63479,63480,63481,63482,63483,63484,63485,63486,63487,61176,63489,63490,63491,63492,61251,63494,63495,63496,63497,63498,63499,63500,62924,63502,63503,63504,63505,63506,63507,63508,63509,63510,63511,63512,63513,62938,63515,63516,63517,63518,63519,63520,63521,62953,60883,63524,63525,63526,63527,63528,63529,63530,63531,63532,63533,63534,63535,63536,63537,60891,63539,63540,63541,63542,63543,63544,63545,63546,63547,63548,63549,60926,63551,63552,63553,63554,63555,63556,63557,63558,63559,63560,63561,63562,62785,63564,63565,63566,63567,63568,63569,63570,63571,63572,61454,63574,63575,63576,63577,63578,63428,63580,63581,63582,63583,63584,63585,63586,61207,63588,63589,63590,63591,63592,63593,63594,63595,62341,63597,63598,63599,63600,63601,63602,63603,63604,63605,63606,63607,63608,61061,63610,63611,63612,63613,63614,63615,63616,63617,63618,63619,61449,63621,63622,63623,63624,63625,63626,63627,63628,63629,63630,63631,63632,61143,63634,63635,63636,63637,61477,63639,63640,63641,63642,63643,63644,63645,63646,63647,63648,63649,63650,63651,63652,63653,63654,63655,63656,63657,61173,63659,63660,63661,63662,62484,63664,63665,63666,63667,63668,61044,63670,63671,63672,63673,63139,63675,63676,63677,63678,63679,63680,63681,63682,63683,63684,63685,62855,63687,63688,63689,63690,63691,63692,63693,63694,61120,63696,63697,63698,63699,63700,63701,63702,63703,63704,63705,63706,63707,63708,63709,63710,63711,63336,63713,63714,63715,62243,63717,63718,63719,63720,63721,63722,63723,63724,63725,63726,61634,63728,63729,63730,61655,63732,63733,63734,63735,63736,63737,63738,63739,63740,63741,62089,63743,63744,63745,63746,63747,63748,63749,62095,63751,63752,63753,63754,63755,61933,63757,63758,63759,63760,63761,63762,63380,63764,63765,63766,63767,63768,63769,63770,63771,63772,63773,63774,63775,63776,63369,63778,63779,63780,63781,63782,63783,63784,63785,63786,63665,63788,62152,63790,63791,63792,63793,63794,63795,63796,61718,63798,63799,63800,63801,63802,63803,63804,63805,63806,63807,62855,63809,63810,63811,61806,63813,63814,63815,63816,63817,63818,61456,63820,63821,63822,63823,63824,63825,61466,63827,63828,63829,63830,63831,63832,63482,63834,63835,63836,63837,63838,63839,63840,61173,63842,63843,63844,63845,63846,61454,63848,63849,63850,63851,63852,63853,63854,63855,63017,63857,63858,63859,63860,63861,63862,63863,63864,63223,63866,63867,63868,63869,63870,63871,63872,63873,63874,63333,63876,63877,63878,63879,63718,63881,63882,63883,63884,63885,63886,62258,63888,61676,63890,63891,63892,63893,63894,63895,63896,61932,63898,63899,63900,63901,63902,63903,63904,63905,63906,63907,63908,63909,63910,63911,63912,63913,63914,60909,63916,63917,63918,63822,63920,61559,63922,63923,63924,63925,63478,63927,63928,63929,63930,63931,63932,63933,61176,63935,63936,61983,63938,63939,63940,63941,63942,63943,63944,63945,61990,63947,63417,63949,63950,63951,63952,63953,63954,63955,63956,63957,61541,63959,63960,61550,63962,63963,63964,63965,63966,63967,61136,63969,63970,63971,63972,63973,63974,61150,61530,63977,63978,63979,63980,63981,63982,63983,63984,63985,63986,63987,63988,63989,63990,63991,63992,63993,63994,63995,63996,63997,63998,63999,64000,64001,64002,64003,64004,64005,64006,64007,64008,64009,64010,64011,64012,64013,64014,64015,64016,64017,64018,64019,64020,64021,64022,64023,64024,64025,64026,64027,64028,64029,64030,64031,64032,64033,64034,64035,64036,64037,64038,64039,64040,64041,64042,64043,64044,64045,64046,64047,64048,64049,64050,64051,64052,64053,64054,64055,64056,64057,64058,64059,64060,64061,64062,64063,64064,64065,64066,64067,64068,64069,64070,64071,64072,64073,64074,64075,64076,64077,64078,64079,64080,64081,64082,61583,64084,64085,64086,64087,61243,64089,64090,64091,64092,64093,64094,64095,64096,63506,64098,64099,64100,64101,64102,64103,64104,64105,64106,64107,61624,64109,64110,64111,64112,64113,64114,64115,64116,62417,64118,64119,64120,64121,60888,64123,64124,64125,64126,64127,64128,64129,64130,64131,64132,64133,64134,64135,64136,64137,64138,64139,64126,64141,64142,64143,64144,64145,64146,64147,64148,64149,64150,64151,64152,64153,61665,64155,64156,64157,64158,64159,63356,64161,64162,64163,64164,64165,62785,64167,64168,64169,64170,64171,64172,64173,64174,64175,64176,64177,64178,64179,64180,61803,61583,64183,64184,64185,64186,64187,64188,62559,64190,64191,64192,64193,64194,64195,62508,64197,64198,64199,64200,63012,64202,64203,64204,64205,64206,64207,64208,64209,61075,64211,64212,64213,64214,64215,64216,63222,64218,64219,64220,64221,64222,64223,64224,64225,64226,64227,64228,64229,64230,64231,61562,64233,64234,64235,64236,64237,64238,61032,64240,64241,64242,64243,64244,62318,62832,64247,64248,64249,64250,64251,64252,64253,64254,64255,64256,63133,64258,64259,64260,60764,64262,64263,64264,64265,64266,64267,64268,64269,64270,64271,64272,64273,64274,64275,64276,64277,64278,64279,64280,64281,64282,64283,64284,64285,61855,64287,60818,60845,64290,64291,64292,64293,64294,64295,64296,64297,60870,64299,64300,64301,64302,64303,64304,64305,64306,64307,64308,64309,61419,64311,64312,64313,61435,64315,64316,64317,64318,64319,64320,64321,64322,62698,64324,64325,64326,61087,64328,63664,64330,64331,64332,62121,64334,64335,64336,64337,62040,64339,64340,64341,64342,64343,64344,64345,64346,64347,64348,64349,64350,63696,64352,64353,61435,64355,64356,64357,64358,64359,64360,64361,64362,64363,64364,64365,64366,64367,61131,64369,64370,62033,62899,64373,64374,64375,64376,64377,64378,64379,61820,64381,64382,64383,64384,64385,64386,64387,64388,64389,64390,63267,64392,61774,64394,64395,64396,64397,64398,64399,64400,61591,64402,64403,64404,64405,64406,61859,64408,64409,64410,64411,64412,64413,64414,64415,64416,63719,64418,64419,64420,64421,64422,64423,64424,64425,61644,64427,63544,64429,64430,64431,64432,64433,60908,64435,64436,64437,64438,64439,64440,64441,64442,64443,64444,62443,64446,64447,64448,64449,64450,64451,64452,64453,64454,63005,64456,64457,64458,64459,64460,64461,64462,64463,64464,64465,64466,62153,64468,64469,64470,61120,64472,64473,64474,64475,64476,62183,64478,64479,64480,64481,64482,64483,64484,64485,64486,64487,64488,64489,64184,64491,64492,64493,64337,64495,61207,64497,64498,64499,64500,64501,64502,64503,64504,64505,64506,64507,61534,64509,64510,64511,64512,64513,64514,64515,64516,64517,64518,64519,64520,64521,64522,61001,64524,64525,64526,64527,64528,64529,64530,64531,64532,64533,61138,61505,64536,64537,64538,61976,62914,64541,64542,64543,64544,64545,64546,60764,64548,64549,64550,64551,64552,64553,64554,64555,64109,64557,64558,64559,64560,64561,64562,62425,64564,64565,64566,64567,64568,64569,64570,64571,64572,64573,64133,64575,64576,64432,63556,64579,64580,61696,64582,64583,64584,64585,64586,62835,64588,64589,64590,62878,64592,64593,64594,64595,64596,63676,64598,64599,64600,64601,64602,64603,61097,64605,64606,64607,64608,63473,64610,64611,64612,64613,64614,64615,61708,64617,61175,64619,64620,64621,64622,64623,64624,64625,62042,64627,64628,64629,64630,64631,64632,64633,64634,64635,62474,64637,64638,64639,64640,64641,62121,64643,64644,64645,64646,61566,64648,64649,64650,62846,64652,64653,64654,64655,64656,64657,62855,64659,64660,64661,64662,64663,64664,64665,61116,62068,64668,61610,64670,64671,64672,64673,64674,64675,64676,60836,64678,64679,64680,64681,64682,64683,64684,64685,64686,64687,64688,62267,64690,64691,64692,64693,64694,64695,64696,64697,64698,64699,64700,64701,64702,64703,64704,64705,62611,64707,64708,64709,64710,64711,64712,62283,64714,64715,64716,64717,64718,64719,64720,60992,64722,64723,64724,64725,64726,64727,64728,64729,64730,64731,64732,64733,64734,64735,64736,64737,64738,61952,64740,64741,61961,64743,64744,64745,64746,64747,64748,64749,64750,64751,64752,63477,64754,64755,64756,64757,64758,64759,64760,64761,64762,64763,64764,64765,64766,64767,62663,64769,64770,64771,64772,62713,64774,64775,64776,64777,62496,64779,64780,64781,64782,64783,64784,64785,64786,64787,64788,62910,64202,64791,61024,64793,64395,64795,64796,64797,64798,64799,64800,64801,61096,64803,64804,64805,64806,62033,64092,64809,64810,62752,64812,64813,64814,64815,64816,64817,64818,64819,64820,64821,64822,64823,64824,64825,64826,64827,61346,64829,64830,64831,64150,64833,64834,64835,64836,64837,64838,64839,64840,64841,64842,64843,61665,64845,64846,64847,64848,64849,64850,64851,63358,64853,64854,64855,64856,64857,64858,64859,64860,64861,64862,64863,62786,64865,64866,64867,64868,64869,64870,64871,64872,64873,64874,64875,64876,61981,64878,64879,64880,61990,64882,64883,64884,63416,64886,64887,64888,64889,64890,64891,64892,64893,64894,64895,64896,64382,64898,64899,64900,64901,64902,64903,64904,64905,64906,64907,64908,64909,64910,64911,64912,62011,64914,64915,64916,64917,61803,64919,63044,64921,64922,64923,64924,64925,62137,64927,64928,64929,64930,64931,64932,64933,64934,64935,64936,64937,64938,64509,64940,64941,64942,64943,64944,64945,64946,64947,62296,64949,64950,64951,62668,64953,64954,62498,64956,64957,64958,64959,64960,64961,64962,64963,64964,64965,63581,64967,64968,64969,64970,61515,64972,64973,64974,64975,64976,61600,64978,64979,64980,64981,64982,64983,64984,64985,62765,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64124,64999,65000,65001,65002,65003,65004,65005,65006,65007,65008,65009,65010,65011,63544,65013,65014,65015,60979,65017,65018,65019,65020,61009,65022,65023,65024,65025,65026,65027,61073,65029,65030,62371,65032,65033,65034,65035,65036,65037,65038,65039,65040,65041,65042,65043,65044,65045,61799,65047,65048,62192,65050,65051,65052,61515,65054,65055,65056,65057,65058,65059,65060,65061,65062,65063,65064,63130,65066,65023,65068,65069,65070,65071,65072,65073,65074,65075,65076,65077,65078,65079,65080,65081,65082,65083,65084,65085,65086,65087,65088,65089,65090,65091,65092,65093,65094,65095,65096,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65107,65108,65109,65110,65111,65112,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65127,65128,65129,65130,65131,65132,65133,65134,65135,65136,65137,65138,65139,65140,65141,65142,65143,65144,65145,65146,65147,65148,65149,65150,65151,65152,65153,65154,65155,65156,65157,65158,65159,65160,65161,65162,65163,65164,65165,65166,65167,65168,65169,65170,65171,65172,65173,65174,65175,63849,65177,62701,65179,65180,65181,65182,65183,65184,65185,64898,65187,65188,65189,65190,65191,65192,65193,65194,65195,65196,65197,65198,65199,65200,61585,65202,65203,65204,65205,65206,64095,65208,62730,65210,65211,65212,65213,65214,65215,62770,65217,65218,65219,65220,64126,65222,65223,65224,65225,65226,65227,65228,65229,65230,65231,65232,65233,65234,65235,65236,65237,65238,65239,62444,65241,65242,62448,65244,65245,65246,65247,65248,65249,64315,65251,65252,65253,65254,65255,65256,65257,64337,62670,65260,65261,65262,64498,65264,65265,65266,65267,65268,65269,64220,65271,65272,65273,65274,65275,65276,65277,65278,62665,65280,65281,65282,65283,61136,65285,65286,65287,65288,65289,65290,65291,61803,65293,63428,65295,65296,65297,65298,65299,62843,65301,65302,65303,65304,65305,61102,65307,65308,65309,65310,65311,64234,65313,65314,65315,65316,65317,65318,65319,61583,65321,65322,65323,65324,65325,64886,65327,65328,65329,65330,60801,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,64983,61607,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,62258,65374,65375,65376,65377,65378,61668,65380,61676,65382,65383,65384,62449,65386,65387,65388,65389,65390,63005,65392,65393,65394,65395,65396,65397,65398,65399,65400,65401,62835,65403,65404,61159,65406,65407,65408,65409,65410,65411,65412,65413,65414,65415,61175,65417,65418,65419,65420,65421,65422,65423,63939,65425,65426,64498,65428,65429,65430,65431,65432,65433,65434,64659,65436,65437,65438,65439,65440,65441,62230,65443,62154,65445,65446,65447,65448,65449,65450,65451,65452,61583,65454,65455,65456,65457,65458,65459,65460,65461,65462,64247,65464,65465,65466,65467,65468,65469,65470,63132,65472,65473,65474,65475,65476,65477,64276,65479,65480,65481,65482,65483,65484,65485,65486,65487,64683,65489,65490,65491,65492,65493,65494,65495,65496,61644,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,61907,65510,65511,65512,62609,65514,65515,65516,62286,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,65536,64458,65538,65539,65540,65541,65542,65543,65544,65545,65546,65547,65548,65549,65550,65551,65552,61553,65554,65555,65556,65557,65558,65559,65560,65561,65562,65563,65564,65565,61153,62185,65568,65569,65570,65571,61091,65573,65574,65575,65576,65577,65578,65579,65580,65581,65582,65583,65584,65585,65586,64491,65588,65589,62696,65591,65592,61210,65594,65595,65596,65597,65598,65599,65600,65601,65602,65603,65604,65605,61528,65607,65608,65609,65610,65611,65612,65613,65614,65615,65616,65617,62292,65619,65620,65621,65622,65623,65624,65625,65626,65627,65628,65629,61173,65631,65632,65633,65634,65635,65636,65637,63416,65359,65640,65641,64291,65643,65644,65645,65646,64300,65648,65649,62611,65651,65652,65653,65654,65655,65656,61419,65658,65659,65660,65661,65662,65663,65664,65665,65666,64355,65668,65669,65670,65671,65672,62355,65674,65675,65676,65677,65678,65679,65680,65681,63022,65683,65684,65685,65686,65687,65688,65689,65690,65282,65692,62896,65694,65695,65696,65697,65698,60998,65700,65701,65702,65703,65704,65705,65706,65707,62310,65709,65710,65711,65712,64610,65714,65715,65716,65717,65718,65719,65720,65721,63480,65723,65724,65725,65726,65727,65728,65729,63491,62913,65732,65733,65734,65735,65736,65737,65738,62729,65740,65741,65742,65743,65744,65745,65746,65747,65748,65749,65750,65751,65752,65753,65754,65755,65756,65757,65758,65759,62769,65761,65762,65763,65764,65765,63355,65767,65768,65769,65770,65771,65772,65773,64868,65775,65776,65777,65778,65779,65780,65781,65782,65783,65784,65785,62516,65787,65788,65789,65790,65791,65792,65793,65794,63791,65796,65797,65798,65799,62668,65801,64482,63041,61205,61519,65806,65807,65808,65809,65810,65811,65812,65813,65814,61435,65816,65817,65818,65819,61452,65821,65822,65823,65824,65825,65826,62699,63927,65829,65830,65831,65832,65833,65834,65835,65836,65837,62893,61248,65840,65841,65842,65843,65844,65845,65846,65847,64815,65849,65850,65851,65852,65853,61346,65855,65856,65857,65858,65859,65860,62777,65862,65863,65864,65865,65866,65867,65868,65869,65870,65871,65872,65873,65874,65875,65876,65877,65878,65879,65880,65881,65882,65883,65884,65885,65886,65887,65888,65889,65890,65891,65892,65893,65894,65895,65896,65897,65898,65899,65900,65901,65902,65903,65904,65905,65906,65907,65908,65909,62788,65911,65912,65913,65914,65915,65916,65917,65918,65919,65920,65921,61982,65923,65924,65925,65926,65927,65928,65589,61517,65931,65932,65933,65934,65935,65936,65937,64899,65939,65940,65941,65942,65943,60999,65945,65946,65947,65948,65949,65950,65951,65952,63156,65954,65955,65956,65957,65958,65959,65960,65961,64805,62323,65964,65965,65966,65967,63582,65969,65970,65971,65972,65973,65974,65975,65976,65723,65978,65979,65980,65981,65982,64221,65984,65985,65986,65987,65988,60859,65990,65991,65992,65993,65994,61247,65996,65997,62242,65999,66000,66001,66002,66003,66004,66005,66006,66007,66008,66009,66010,64558,66012,66013,66014,66015,66016,66017,66018,66019,60872,66021,66022,66023,66024,66025,66026,66027,61909,63751,66030,66031,66032,66033,66034,66035,66036,66037,63356,66039,66040,66041,66042,66043,66044,62108,66046,66047,66048,66049,66050,66051,66052,62785,66054,66055,66056,66057,66058,66059,66060,66061,66062,66063,63938,66065,66066,66067,66068,66069,66070,66071,62153,66073,66074,66075,66076,63017,66078,66079,66080,66081,66082,64219,66084,66085,66086,66087,66088,66089,66090,66091,66092,66093,66094,63433,66096,66097,66098,66099,66100,62886,66102,66103,61122,66105,62176,66107,66108,66109,66110,66111,66112,66113,66114,66115,66116,66117,66118,66119,66120,66121,66122,66123,66124,66125,66126,66127,64086,66129,62835,66131,66132,63858,66134,66135,66136,66137,66138,66139,66140,66141,66142,66143,65985,66145,66146,66147,66148,66149,66150,66151,62700,66153,66154,66155,66156,63333,66158,66159,66160,66161,65749,66163,66164,66165,66166,66167,62770,66169,66170,65228,66172,66173,66174,66175,66176,66177,66178,65770,65775,66181,66182,66183,66184,66185,66186,66187,66188,66189,66190,66191,66192,66193,66194,66195,66196,61189,66198,66199,66200,66201,66202,61583,66204,66205,66206,66207,66208,64886,66210,66211,66212,66213,62516,66215,66216,66217,66218,66219,66220,66221,66222,62355,66224,66225,66226,66227,66228,66229,66230,66231,66232,66233,66234,66235,66236,61097,66238,66239,66240,66241,66242,66243,66244,61189,66246,66247,66248,66249,66250,66251,61209,66253,66254,66255,66256,66257,66258,66259,66260,66261,66262,66263,66264,66265,66266,66267,66268,66269,66270,64659,66272,66273,66274,66275,66276,66277,66278,66279,63923,66281,66282,66283,66284,66285,63336,66287,66288,66289,66290,61612,66292,66293,66294,66295,66296,65853,66298,66299,66300,66301,66302,66303,66304,66305,66306,66307,66298,66309,66310,66311,66312,66313,66314,66315,62960,66317,66318,66319,66320,66321,66322,66323,66324,66325,66326,66327,66328,66329,66330,66331,66332,66333,66334,63114,66336,66337,66338,66339,66340,66341,66342,66343,61557,66345,65474,66347,66348,66349,66350,66351,66352,63589,66354,66355,66356,66357,66358,66359,66360,62347,66362,66363,66364,66365,66366,66367,66368,66369,66370,62678,66372,66373,62487,66375,62224,66377,66378,63929,66380,66381,64771,65970,66384,66385,63681,66387,66388,66389,66390,66391,66273,66393,66394,66395,66396,63613,66398,66399,66400,63335,66402,66403,66404,62243,66406,66407,66408,66409,61655,66411,66412,66413,66414,66415,66416,63544,66418,66419,66420,66421,66422,60909,66424,64447,66426,66427,66428,66429,66430,66431,66432,66433,66434,66435,62785,66437,66438,66439,66440,66441,66442,66443,66444,66445,66446,66447,66448,66449,64468,66451,66452,66453,66454,66455,66456,66457,65418,66459,66460,66461,66462,66463,66464,66465,66466,66467,62498,66469,66470,66471,66472,66473,66474,66475,66476,63130,66478,66479,66480,62688,66482,66483,61981,66485,66486,66487,66488,66489,66490,66491,66492,63043,66494,66495,66496,66497,66498,66499,66500,66501,61782,66503,66504,66505,66506,66507,62121,66509,66510,66511,66512,62153,66514,66515,66516,66517,66518,66519,61716,66521,66522,66523,66524,66525,66526,61527,66528,66529,66530,66531,66532,66533,66534,66535,66536,62572,66538,66539,65350,66541,66542,66543,66544,66545,66546,66547,66548,66549,66550,66551,66552,66553,66554,66555,66556,64290,66558,66559,66560,66561,60872,66563,66564,66565,66566,66567,66568,66569,66570,66571,60938,61690,66574,66575,66576,66577,66578,66579,66580,66581,66582,66583,66584,66585,61137,66587,62149,66589,66590,66591,66592,66593,61714,66595,66596,66597,66598,66599,66600,66601,66602,66603,61096,66605,66606,61113,66608,66609,66610,66611,66612,66613,66614,66615,66616,66617,66618,63122,66620,65575,66622,66623,66624,66625,66626,66627,66628,66629,66630,66631,66632,66633,66634,66635,66636,62318,66638,61450,66640,61067,66642,66643,66644,66645,66646,66647,66648,66649,66650,66651,63223,66653,66654,66655,66656,66657,66658,66659,61962,66661,66662,66663,66664,66665,66666,66667,66668,62258,66670,66671,66672,66673,66674,66675,66676,63344,63346,66679,66680,66681,66682,66037,65768,66685,66686,66687,66688,66689,66690,66691,65777,66693,66694,66695,66696,66697,66698,66699,61139,66701,65293,61059,66704,63478,66706,66707,66708,66709,66710,66711,66712,66713,64727,66715,66716,66717,66718,66719,66720,63623,66722,66723,66724,66109,66726,66727,66728,66729,66730,66731,61197,66733,66734,66735,66736,66737,61551,66739,66740,66741,66742,66743,66744,66745,61125,66747,66748,66749,66750,66751,66752,66753,66754,66755,66756,66757,66758,66759,66760,66761,66762,66763,66764,66765,66766,66767,66768,63476,66770,66771,66772,66773,66774,66775,66776,66777,66778,66779,63492,63497,66782,60766,66784,61625,66786,60883,66788,66789,63544,66791,66792,66793,66794,61703,66796,66797,66798,66799,66800,66801,66802,66803,63971,66805,66806,66807,62504,66809,66810,66811,66812,62843,66814,66272,66816,66817,66818,66819,66820,66821,61070,66823,66824,66825,66826,66827,63623,66829,66830,66831,66832,66833,65607,66835,66836,66837,66838,66839,66840,66841,66842,65052,62021,66845,66846,66847,66848,66849,66850,66225,66852,66853,66854,66855,66856,66857,66858,66859,66860,66861,62368,66863,66864,66865,66866,66867,66868,66869,66870,66871,66872,63876,66874,66875,66876,60773,66878,66879,66880,66881,66882,66883,66884,66885,66886,66887,66888,66889,66890,66891,66892,66893,66894,66895,66896,66897,66898,66899,66412,66901,66902,66903,66904,66905,64429,66907,66908,66424,66426,66911,66912,66913,66914,66915,66916,66917,66440,66919,66920,66921,66922,66923,66924,66925,66926,66927,62156,66929,66930,66931,66932,66933,66934,66935,66936,66937,62061,66939,66940,66941,66942,64342,66944,66945,66946,66947,66948,66949,66950,66951,66952,66953,66954,63971,66956,66957,61048,66959,63801,66961,66962,66963,66964,66965,66966,66967,66968,61807,66970,66971,66972,66973,66974,66975,66976,62899,66978,66979,66980,66981,66982,66983,61003,66985,66986,66987,66988,66989,66990,66991,66992,66993,66994,66995,66996,66997,66998,66999,67000,67001,67002,67003,67004,67005,67006,67007,67008,67009,67010,67011,67012,67013,67014,67015,67016,67017,67018,67019,61455,67021,67022,67023,67024,63168,67026,67027,67028,63477,67030,67031,67032,67033,67034,61253,67036,67037,67038,67039,67040,67041,62753,67043,67044,67045,67046,67047,67048,67049,67050,67051,61346,67053,67054,67055,67056,67057,67058,67059,67060,67061,61900,67063,67064,67065,67066,67067,67068,62445,67070,67071,67072,67073,67074,67075,67076,62786,67078,67079,67080,67081,67082,67083,67084,63844,67086,67087,65466,67089,67090,67091,67092,67093,67094,63428,67096,67097,67098,64202,67100,67101,67102,67103,67104,67105,61713,67107,67108,67109,67110,67111,67112,67113,67114,67115,67116,61100,67118,67119,67120,67121,67122,67123,67124,67125,67126,67127,67128,67129,61236,67131,67132,67133,67134,67135,67136,67137,61032,67139,67140,67141,67142,67143,67144,67145,62319,67147,67148,64190,67150,67151,67152,67153,67154,67155,67156,67157,67158,67159,67160,67161,67162,67163,65341,67165,67166,67167,67168,67169,67170,67171,67172,67173,67174,67175,67176,67177,67178,67179,67180,67181,61880,67183,67184,67185,67186,67187,67188,60854,67190,67191,67192,67193,67194,67195,67196,67197,67198,67199,67200,67201,67202,67203,61899,67205,67206,67207,67208,67209,67210,67211,67212,67213,67214,67215,67216,67217,67218,67219,67220,64710,67222,67223,67224,61932,67226,67227,67228,67229,67230,67231,67232,67233,67234,65624,67236,67237,67238,67239,67240,62121,67242,67243,67244,66281,67246,67247,61157,67249,67250,67251,67252,67253,67254,67255,67256,67257,67258,61586,67260,67261,67262,62128,67264,67265,67266,67267,67268,67269,67270,65669,67272,67273,67274,66246,67276,67277,67278,67279,67280,67281,67282,62356,67284,67285,67286,67287,62545,67289,67290,67291,67292,67293,67294,67295,67296,61516,67298,67299,67300,67301,67302,61820,67304,67305,67306,67307,67308,67309,67310,67311,67312,67165,67314,67315,67316,67317,67318,67319,67320,67321,67322,67323,67324,67325,67326,67327,67328,61870,67330,67331,67332,67333,67334,65490,67336,66022,67338,67339,67340,67341,67213,67343,67344,67345,67346,67347,67348,67349,67350,67351,67352,61676,67354,67355,67356,63759,67358,67359,62785,67361,67362,67363,67364,67365,67366,67367,67368,67369,67370,67371,67372,67373,67374,67375,67376,67377,67378,61981,67380,67381,67382,67383,67384,67385,63476,67387,67388,67389,67390,67391,67392,67393,67394,61991,67396,62313,67398,64499,67400,67401,67402,67403,67404,67405,67406,67407,67408,67409,67410,67411,67412,65612,67414,67415,67416,61808,67418,67419,67420,67421,61976,67423,67424,67425,67426,67427,67428,65694,67430,67431,67432,67433,67434,61199,67436,67437,67438,67439,67440,67441,67442,67443,64277,67445,67446,67447,67448,67449,67450,67451,67452,67453,67454,67455,67456,67457,67458,67459,67460,67461,67462,67463,67464,67465,67466,67467,67468,67469,67470,67471,61867,65490,67474,67475,67476,67477,65502,67479,67480,67481,67482,67483,67484,62611,67486,67487,67488,67489,67490,67491,67492,67493,67494,67495,67229,67497,67498,67499,67500,67501,67502,62296,67504,67505,67506,67507,67508,63201,63433,67511,67512,61075,67514,67515,67516,67517,67518,67519,63866,67521,67522,67523,67524,67525,67526,67527,67528,67529,62157,67531,67532,67533,67534,67535,67536,67537,67538,61796,67540,67541,67542,67543,67544,62181,67546,67547,67548,67549,67550,67551,67552,64087,67554,62835,67556,67557,67558,67559,61076,67561,67562,67563,67564,67565,67566,67567,67568,67569,67570,67571,63866,67573,67574,67575,67576,61559,67578,67579,67580,67581,67582,62066,61604,67585,67586,67587,67588,67589,67590,67591,67592,67593,67594,67595,61642,63732,67598,67599,67600,67601,67602,67603,67604,61391,67606,67607,67608,67609,67610,66037,66911,67613,67614,67615,67616,67617,63002,67619,67620,67621,67622,67623,67624,65446,67626,67627,67628,67629,67630,67631,67632,67633,67634,67635,61176,67637,67638,67639,67640,67641,62902,67643,67644,67645,67646,67647,67648,61132,67650,67651,67652,67653,67654,67655,67656,66642,67658,67659,67660,67661,67662,67663,67664,67665,67666,67667,67668,67669,66084,67671,67672,67673,67674,67675,67676,67677,67678,64491,67680,67681,67420,67683,67684,62346,67686,67687,67688,67689,67690,67691,67692,67693,62333,67695,67696,67697,67698,67699,67700,66158,67702,67703,67704,62240,67706,67707,67708,67709,67710,61655,67712,67713,67714,67715,67716,67717,63544,67719,67720,67721,67722,67723,67724,60904,67726,67727,67728,67729,67730,67731,67732,67733,62445,67735,67736,67737,67738,67739,67740,67741,67742,67743,67744,67745,67623,67747,67748,67749,67750,67751,67752,67753,67754,62296,67756,67757,67758,67759,67760,67761,64588,67763,67764,65188,67766,67767,67768,67769,67770,67771,67772,67773,61487,67775,67776,67777,67778,67779,67780,67781,67782,67783,67784,62487,62540,67787,67788,67789,67790,67791,67792,67793,67794,65032,67796,67797,67798,67799,67800,67801,67802,67803,61515,67805,67806,67807,67808,67809,67810,67811,67812,65187,67814,67815,67816,67817,67818,67819,67820,67821,67822,67823,67824,67825,67826,67827,67828,60859,67830,67831,67832,67833,67834,67835,67836,67837,61607,61632,67840,67841,67842,67843,67844,67845,67846,67847,67848,67849,67850,67851,67852,67853,67854,67855,67856,67857,67858,67859,67860,67861,67862,67863,67864,67865,67866,67867,67868,67869,67870,67871,61370,67873,60916,67875,67876,67877,67878,61933,67880,67881,67882,67883,67884,67885,67886,67887,67888,67889,67890,67891,67892,67893,63764,67895,67896,67897,61137,67899,67900,67901,67902,67903,67904,67905,62162,62040,67908,67909,67910,67911,67912,63849,67914,67915,67916,63130,67918,67919,67920,67921,67922,67923,61716,67925,67926,67927,67928,67929,61104,67931,67932,61240,67934,61991,67936,67937,67938,61520,67940,67941,67942,67943,67944,67945,64898,67947,67948,67949,67950,67951,67952,67953,67954,67955,67956,67957,67958,67959,67960,61841,67962,67963,67964,67965,67966,67967,67968,67969,67970,67971,67972,67973,67974,67975,67976,67977,67978,67979,67980,67981,63333,67983,61607,67985,67986,67987,67988,67989,67990,67991,67992,67993,67994,67995,67996,62254,67998,67999,68000,68001,68002,68003,68004,68005,68006,68007,68008,68009,68010,68011,68012,68013,63344,64131,68016,68017,68018,68019,68020,68021,68022,68023,68024,68025,68026,68027,64833,68029,68030,68031,68032,68033,61899,68035,68036,60920,68038,68039,68040,68041,68042,68043,68044,68045,68046,68047,62105,68049,68050,68051,68052,68053,68054,68055,68056,68057,68058,68059,68060,68061,68062,68063,63382,68065,68066,68067,68068,68069,68070,68071,68072,68073,68074,68075,68076,61192,68078,68079,68080,68081,63418,68083,68084,68085,68086,68087,68088,63867,68090,68091,68092,68093,68094,63155,68096,68097,68098,68099,68100,68101,68102,68103,68104,68105,68106,66451,68108,68109,68110,68111,68112,68113,68114,68115,62033,68117,67300,68119,68120,68121,68122,64727,68124,65418,68126,68127,68128,68129,68130,64786,68132,68133,65476,68135,65348,68137,68138,68139,68140,68141,68142,68143,68144,68145,68146,68147,68148,68149,68150,68151,68152,68153,68154,68155,68156,68157,61857,68159,68160,61878,64684,68163,68164,68165,61676,68167,68168,68169,68170,68171,68172,68173,63900,68175,68176,68177,68178,68179,68180,68181,68182,68183,68184,68185,68186,61949,61450,68189,68190,63178,68192,68193,68194,68195,68196,68197,68198,61579,68200,68201,68202,68203,68204,68205,68206,68207,68208,68209,68210,68211,68212,68213,68214,68215,68216,68217,68218,68219,68220,68221,68222,68223,68224,68225,68226,68227,68228,68229,68230,66131,68232,68233,66225,68235,68236,68237,68238,68239,68240,68241,68242,68243,68244,68245,61097,68247,68248,68249,68250,68251,68252,68253,68254,68255,68256,62665,68258,68259,68260,61451,68262,68263,66812,65301,68266,68267,68268,68269,67574,68271,68272,68273,68274,68275,68276,62699,68278,68279,68280,68281,68282,68283,68284,63154,68286,68287,68288,68289,68290,68291,68292,68293,68294,68295,68296,62068,68298,60822,68300,68301,68302,68303,67054,68305,68306,68307,68308,68309,68310,67212,68312,68313,67739,68315,68316,68317,68318,68319,68320,68321,66437,68323,68324,68325,68326,61031,68328,68329,67638,68331,64627,68333,68334,68335,68336,61136,68338,68339,68340,61032,68342,68343,62203,68345,68346,61733,68348,68349,68350,65716,63791,68353,68354,68355,62318,68357,68358,68359,65054,68361,68362,68363,68364,68365,68366,68367,68368,68369,68370,68371,61049,68373,68374,60820,68376,68377,68378,64985,68164,61931,68382,68383,68384,68385,68386,68387,68388,68389,68390,68391,63005,68393,68394,68395,68396,68397,68398,68399,63947,68401,68402,63418,68404,68405,68406,68407,68408,64900,68410,68411,68412,68413,68414,62013,68416,68417,68418,68419,68420,68421,68422,68423,66768,68425,68426,68427,68428,68429,68430,68431,68432,68433,68434,68435,68436,68437,68438,68439,68440,68441,68442,68443,68444,68445,68446,68447,68448,68449,68450,68451,68452,68453,68454,68455,68456,68457,68458,68459,68460,68461,68462,68463,68464,68465,68466,68467,68468,68469,68470,68471,68472,68473,68474,68475,68476,68477,68478,68479,68480,68481,68482,68483,68484,68485,68486,68487,68488,68489,68490,68491,68492,68493,68494,68495,68496,68497,68498,68499,68500,68501,68502,68503,68504,68505,68506,68507,68508,68509,68510,68511,68512,68513,68514,68515,68516,68517,68518,68519,68520,68521,68522,68523,68524,68525,68526,68527,68528,68529,63174,68531,68532,68533,68534,68535,68536,68537,68538,68539,68540,68541,68542,68543,68544,68204,68546,68547,62324,68549,68550,68551,68552,64751,68554,67561,68556,68557,68558,68559,68560,67574,68562,68563,68564,68565,68566,68567,68568,68569,68570,68571,62066,68573,68574,68575,60775,68577,68578,68579,68580,68581,61335,68583,68584,68585,68586,68587,68588,68589,68590,68591,68592,68593,68594,68595,68596,68597,68598,68599,68600,68601,68602,68603,68305,68605,68606,68607,65863,68609,68610,68611,68612,68613,68614,62789,68616,68617,68618,68619,68620,68621,68622,68623,68624,68625,68626,62192,68628,68629,68630,63072,68632,61001,68634,68635,68636,68637,68638,68639,68640,68641,68642,65718,68644,68645,68646,68647,68648,63475,68650,68651,68652,68653,68654,68655,68656,68657,68658,68659,66460,68661,68662,68663,62488,61147,61530,68667,68668,68669,68670,68671,68672,68673,68674,68675,68676,68677,68678,68679,61255,68681,68682,68683,68684,61859,61609,68687,68688,68689,68690,68691,64686,68693,68694,67192,68696,68697,68698,68699,63544,68701,68702,68703,68704,68705,68706,62445,68708,68709,68710,68711,68712,64171,68714,68715,68716,68717,68718,68719,68720,68721,68722,68723,61757,68725,68726,68727,67279,68729,68730,68731,68235,68733,68734,68735,68736,68737,68738,68739,68740,68741,68742,66944,68744,68745,68746,68747,68748,68749,68750,68751,68752,68753,62516,68755,68756,68757,68758,65956,68760,68761,68762,68763,68764,68765,68766,68767,63479,68769,68770,68771,68772,68773,68774,67796,68776,68777,68778,68779,68780,68781,65033,68783,68784,68785,68786,68787,68788,68789,68790,68791,68792,61585,68794,68795,68796,68797,68798,68799,61707,68801,68802,68803,68804,68805,62361,68807,68808,68809,68810,64927,68812,68813,68814,68815,68816,68817,68818,68819,68820,68821,63335,68823,68824,68825,60771,62415,68828,68829,68830,68831,68832,68833,68834,68835,68836,68837,68838,68839,68840,68841,64833,68843,68844,68845,68846,68847,68848,68849,68850,68851,64159,68853,63556,68855,68856,68857,68858,68859,68860,63368,68862,68863,68864,68865,68866,68867,68868,68869,68870,64506,68872,68873,61825,68875,68876,68877,68878,68879,68880,68881,60992,68883,61553,68885,68886,68887,68888,68889,68890,66632,68892,66638,67557,68895,68896,66235,68898,68899,68900,62367,68902,68903,68904,68905,68906,68907,68908,68909,68910,68911,68912,62912,68914,68915,68916,68917,62762,65763,65228,68921,68922,68923,68924,68925,68926,61665,68928,68929,68930,68931,68932,68933,64854,68935,68936,68937,68938,68939,68940,68941,68942,64167,68944,68945,68946,68947,68948,68949,68950,68951,62310,68953,68954,68955,68956,64968,68958,68959,61714,68961,68962,68963,68964,63222,68966,68967,68968,68969,68970,68971,63194,68973,68974,68975,68976,68977,68978,68979,68980,64610,68982,68983,68984,68985,68986,64799,68988,68989,66624,68991,68992,68993,68994,68995,68996,61503,68998,68999,69000,69001,69002,69003,69004,69005,69006,69007,63583,69009,69010,69011,66644,69013,69014,69015,69016,69017,69018,69019,69020,69021,69022,69023,69024,68090,69026,69027,69028,69029,69030,69031,69032,69033,62233,69035,69036,69037,69038,60806,69040,69041,69042,69043,69044,69045,69046,69047,69048,69049,69050,69051,69052,67054,69054,69055,69056,69057,69058,69059,69060,69061,69062,63356,69064,69065,69066,69067,69068,69069,69070,69071,69072,69073,69074,69075,69076,69077,62786,69079,69080,69081,69082,69083,69084,69085,69086,69087,69088,69089,61189,69091,69092,69093,69094,69095,69096,69097,63814,69099,69100,69101,61823,69103,69104,69105,69106,69107,69108,69109,69110,69111,69112,69113,62297,69115,69116,69117,69118,69119,69120,69121,69122,69123,69124,69125,64337,68280,69128,69129,69130,69131,69132,69133,69134,69135,61477,69137,69138,69139,69140,69141,69142,69143,69144,65051,65403,69147,69148,69149,69150,69151,62540,69153,69154,69155,69156,69157,69158,69159,69160,69161,69162,69163,69164,69165,69166,62374,69168,69169,69170,69171,69172,69173,69174,69175,61591,69177,69178,69179,69180,69181,65853,69183,69184,69185,69186,65761,69188,69189,65226,69191,69192,69193,69194,69195,69196,69197,69198,67873,69065,69201,69202,69203,69204,69080,69206,69207,63198,69209,69210,63428,69212,69213,69214,69215,66814,69217,69218,69219,69220,69221,69222,69223,69224,69225,69226,68532,69228,69229,69230,69231,69232,69233,69234,69235,69236,69237,69238,69239,64754,69241,69242,69243,69244,69245,69246,69247,69248,69249,69250,69251,63012,69253,69254,69255,69256,69257,69258,63858,69260,69261,69262,69263,69264,65984,69266,69267,69268,69269,69270,69271,69272,69273,69274,63444,69276,69277,69278,69279,69280,69105,69282,69283,69284,69285,69286,67977,69288,69289,69290,69291,61856,69293,69294,69295,69296,69297,69298,69299,69300,64683,69302,69303,69304,64431,67354,69307,69308,69309,69310,61928,69312,69313,69314,69315,69316,69317,63380,69319,69320,69321,69322,69323,69324,63971,69326,69327,63429,62645,69330,63481,69332,69333,69334,69335,69336,69337,61436,69339,69340,69341,69342,69343,69344,69345,61073,69347,69348,69349,69350,69351,69352,68531,69354,69355,69356,69357,69358,62311,69360,69361,69362,69363,69364,62174,69366,69367,69368,69369,69370,69371,69372,69373,69374,69375,69376,69377,69378,69379,69380,69381,69382,69383,69384,69385,69386,69387,69388,69389,69390,69391,69392,69393,69394,69395,69396,69397,69398,69399,69400,69401,69402,69403,69404,69405,69406,69407,69408,69409,69410,69411,69412,64085,69414,69415,69416,69417,61591,69419,69420,69421,64416,67330,69424,60843,69426,69427,61645,67354,69430,69431,69432,69433,62106,69435,69436,69437,69438,69439,63380,69441,69442,69443,69444,69445,69446,69447,69448,69449,69450,69451,61982,69453,69454,69455,69456,63041,64746,69459,69460,69461,69462,69463,61229,69465,69466,69467,69468,68127,69470,69100,69472,69473,69474,61535,69476,69477,69478,69479,69480,69481,69482,69483,69484,69485,64727,69487,69488,69489,69490,69491,69492,62030,62062,62040,69496,69497,69498,69499,69500,69501,69502,69503,69504,69505,69506,69507,69508,61245,69510,69511,69512,69513,69514,69515,69516,69517,69518,60843,69520,69521,69522,67194,69524,69525,69526,62095,69528,69529,69530,69531,61932,69533,69534,65541,69536,69537,69538,69539,69540,69541,61136,69543,69544,69545,69546,69547,61175,69549,69550,69551,69552,69553,69554,69555,69556,69557,69558,68333,69560,69561,69562,69563,69564,61709,69566,69567,69568,69569,69570,69571,66134,69573,69574,69575,69576,69577,69578,69579,68783,69581,69582,69583,69584,69585,69586,65925,69588,69589,69590,69591,69592,69593,66254,69595,69596,69597,69598,69599,64660,69601,69602,69603,69604,69605,69606,67132,69608,69609,69610,69611,69612,69035,69614,69615,69616,69617,66407,69619,66901,69621,69622,69623,69624,69625,69626,63545,69628,69629,69630,69631,61378,69633,69634,69635,69636,69637,69638,69639,69640,69641,65242,69643,69644,69645,69646,69647,69648,69649,69650,69651,69652,69653,63898,69655,69656,69657,69658,69659,69660,69661,62293,69663,69664,69665,69666,69667,69668,69669,69670,66451,69672,69673,64771,69675,64627,69677,69678,69679,69680,69681,69682,69683,68885,69685,69686,69687,69688,69689,69690,63428,69692,69693,61719,69695,69696,69697,69698,69699,61101,69701,69702,69703,69704,69705,69706,69707,69708,69709,61559,69711,69712,69713,69714,69414,69716,69717,67941,69719,69720,69721,69722,69723,69724,61823,69726,69727,69728,69729,69730,69731,69732,65991,69734,69735,69736,69737,69738,69739,69740,69741,69742,69743,69744,69745,69746,69747,69748,61878,64683,69751,69752,69753,69754,69755,61665,69757,69758,69759,69760,69761,69762,69763,68386,69765,69766,69767,69768,69769,69770,69771,69772,64458,69774,69775,69776,69777,69778,69779,69780,69781,69782,69783,69784,69785,69786,68109,69788,69789,69790,69791,62665,69793,69794,69795,69796,69797,62899,69799,69800,69801,69802,69803,69804,69805,69806,69807,69808,69809,69810,69811,69812,69813,69814,63580,69816,64358,69818,69819,69820,62819,61073,69823,69824,69825,62654,69827,69828,69829,69830,69831,69832,69833,69834,69835,69795,69837,69838,69839,69840,64337,67144,69843,69844,69845,69846,63859,69848,69849,69850,69851,69852,69853,69854,69855,69856,63027,69858,69859,69860,69861,69862,61591,69864,69865,69866,69867,69868,65748,69870,69871,69872,69873,69874,69875,69876,69877,69878,69879,69880,62262,69882,69883,69884,68834,69886,69887,69888,69889,68845,69891,69892,69893,64159,69895,69896,69897,60947,69899,69900,69901,69902,69903,69904,69905,69906,69907,69908,69909,69910,69911,69912,68946,69914,69915,69916,69917,69918,69919,69920,69921,69922,69923,69924,69925,61495,67787,69928,69929,69930,69931,66863,69933,69934,69935,69936,62155,69938,69939,69940,69941,69576,69943,69944,69945,69946,62857,69948,69949,69950,69951,69952,69953,69954,69955,69956,69957,69958,69959,66722,69961,69962,61803,69964,62335,69966,69967,69968,69969,69970,61501,69972,69973,69974,69975,69976,69977,69978,66478,69980,69981,60852,64985,62750,69985,69986,69987,69988,69989,69990,69991,64829,69993,69994,69995,69996,69997,69998,61666,70000,70001,70002,70003,70004,70005,63361,69919,70008,70009,70010,61450,70012,70013,70014,70015,70016,70017,70018,70019,62504,70021,70022,70023,70024,61720,70026,70027,70028,70029,70030,70031,70032,67573,70034,70035,70036,70037,70038,70039,70040,70041,67396,65597,70044,62347,70046,70047,70048,70049,70050,70051,66617,70053,70054,70055,70056,70057,64085,65932,70060,70061,63174,70063,70064,70065,70066,70067,70068,70069,69104,70071,70072,70073,70074,70075,70076,61805,70078,70079,70080,70081,70082,70083,70084,70085,70086,67592,68003,70089,70090,70091,70092,70093,70094,70095,70096,70097,61649,70099,70100,70101,70102,70103,70104,70105,62089,70107,70108,70109,70110,70111,64447,70113,70114,70115,70116,70117,70118,65540,70120,70121,70122,70123,70124,70125,70126,70127,70128,70129,61017,70131,70132,70133,70134,70135,70136,70137,70138,70139,70140,70141,70142,70143,70144,70145,70146,70147,62062,64627,70150,61450,70152,70153,70154,70155,69009,70157,70158,70159,70160,70161,70162,61715,70164,70165,70166,70167,70168,67521,70170,70171,70172,70173,70174,61962,70176,61196,70178,70179,70180,70181,70182,70183,70184,70185,62331,70187,70188,70189,70190,70191,70192,70193,70194,69106,70196,70197,68374,70199,70200,70201,70202,70203,70204,70205,61607,70207,70208,70209,70210,70211,70212,70213,70214,70215,70216,70217,70218,70219,70220,70221,70222,70223,65374,70225,70226,63743,70228,70229,70230,64446,70232,70233,70234,67363,70236,70237,70238,70239,70240,70241,70242,65594,70244,70245,70246,70247,70248,70249,70250,70251,63449,70253,70254,70255,70256,70257,70258,70259,70260,70261,70262,70263,70264,70265,70266,70267,70268,61770,66701,70271,69561,70273,70274,70275,70276,70277,70278,70279,70280,70281,70282,70283,70284,70285,70286,70287,70288,64202,70290,66249,70292,70293,70294,70295,70296,65926,70298,70299,70300,70301,70302,70303,70304,70305,70306,70307,61029,68097,70310,70311,70312,70313,70314,69830,70316,69549,70318,70319,70320,70321,70322,70323,70324,70325,61591,70327,70328,70329,70330,70331,70332,62753,70334,70335,70336,70337,65765,63357,70340,70341,70342,64866,70344,70345,70346,70347,70348,70349,70350,61210,70352,70353,70354,69728,70356,70357,70358,70359,70360,61515,70362,70363,61456,70365,70366,70367,70368,66107,70370,70371,70372,70373,70374,70375,70376,70377,70378,61115,70380,70381,70382,70383,66512,68280,70386,70387,70388,69354,70390,70391,70392,70393,70394,70395,62671,70397,70398,64092,70400,70401,70402,70403,70404,62736,70406,70407,70408,70409,70410,70411,70412,70413,63515,70415,70416,70417,70418,70419,70420,70421,70422,62959,70424,70425,70426,70427,70428,70429,70430,70431,70432,70433,70434,70435,70436,62612,70438,70439,70440,62619,70442,70443,70444,70445,70446,70447,70448,70449,70450,70451,70452,70453,70454,70455,70456,62118,70458,70459,70460,70461,70462,70463,70464,70465,70466,70467,61137,70469,70470,70471,61994,70473,70474,70475,70476,70477,67147,61233,70480,70481,70482,68108,70484,70485,70486,70487,70488,70489,61520,70491,70492,70493,70494,70495,70496,70497,70498,70499,70500,70501,70502,70503,70504,70505,70506,70507,66981,70509,70510,70511,70512,70513,70514,70515,70516,70517,70518,70519,70520,62902,70522,70523,70524,70525,70526,70527,70528,70529,70530,70531,70532,62033,70534,61803,70536,61073,70538,70539,70540,70541,70542,70543,70544,64803,70546,70547,70548,70549,62892,70551,70552,70553,69865,70555,70556,70557,70558,70559,70560,61856,60849,70563,70564,70565,68696,70567,70568,70569,70570,70571,70572,70573,70574,70575,70576,70577,70578,70579,70580,70581,70582,70583,70584,70585,70586,70587,70588,70589,70590,70591,70592,70593,70594,70595,70596,70597,70598,70599,70600,70601,70602,70603,70604,70605,70606,70607,70608,70609,70610,70611,70612,70613,70614,70615,70616,70617,70618,70619,70620,70621,70622,70623,70624,70625,70626,70627,70628,70629,70630,70631,70632,70633,70634,70635,70636,70637,70638,70639,70640,70641,70642,70643,70644,70645,70646,70647,70648,70649,70650,70651,70652,70653,70654,70655,70656,70657,70658,70659,70660,70661,70662,70663,70664,70665,70666,70667,70668,61676,70670,70671,70672,70673,70674,70675,67226,70677,70678,70679,69118,70681,70682,70683,70684,70685,68890,70687,70688,61824,70690,70691,70692,63947,61757,70695,70696,70697,64654,70699,70700,70701,70702,66272,70704,70705,66377,70707,70708,70709,61578,64976,70712,70713,70714,70715,70716,70717,61821,70719,67697,70721,70722,70723,70724,68573,70726,70727,70728,70729,70730,70731,70732,70733,70734,62245,70736,70737,67212,70739,70740,70741,70742,70743,70744,70745,70746,70747,70748,70749,70750,63355,70752,70753,70754,70755,70756,70757,70758,70759,70760,70761,70762,70763,70764,70765,70766,70767,70768,70347,70770,70771,70772,70773,70774,61452,70776,70777,70778,70779,70780,70781,70782,70783,64599,70785,70786,70787,70788,70789,70790,70791,70792,70793,61100,70795,70796,70797,70798,70799,70800,70801,70802,70803,70804,70805,64732,70807,70808,70809,70810,70811,70812,68726,70814,70815,61044,70817,70818,70819,70820,67659,70822,70823,70824,70825,70826,70827,70828,70829,70830,70831,70832,70833,70834,70835,70836,70837,70838,70839,70840,70841,70842,70843,70844,70845,70846,70847,70848,70849,70850,70851,70852,70853,70854,70855,70856,70857,70858,70859,70860,70861,70862,70863,70864,70865,70866,70867,70868,70869,70870,70871,70872,70873,70874,70875,70876,70877,70878,70879,70880,70881,70882,70883,70884,70885,70886,70887,70888,70889,70890,70891,70892,70893,70894,70895,70896,70897,70898,70899,70900,70901,70902,70903,70904,70905,70906,70907,70908,70909,70910,70911,70912,70913,70914,70915,70916,70917,70918,70919,70920,70921,70922,69702,70924,70925,70926,70927,70928,70929,70930,70931,70932,61963,70934,70935,70936,70937,70938,70939,70940,70941,67680,70943,70944,70945,70946,61519,70948,70949,70950,70951,70952,70953,70954,70955,64898,70957,70958,70959,70960,70961,70962,70963,70964,70965,70966,69291,64679,70969,70970,70971,70972,70973,70974,70975,70976,70977,70978,65380,67885,70981,70982,70983,70984,70985,70986,70987,70988,70989,68066,70991,70992,70993,70994,70995,70996,70469,70998,70999,62182,71001,71002,71003,70380,71005,71006,61450,71008,71009,71010,70140,71012,66647,71014,71015,71016,71017,71018,71019,71020,64218,71022,71023,71024,71025,71026,71027,71028,71029,71030,67380,71032,71033,71034,67442,71036,66357,71038,71039,71040,67524,71042,71043,69128,71045,71046,71047,62235,71049,69879,71051,64558,71053,71054,71055,62595,71057,71058,61909,69432,67883,71062,71063,71064,71065,71066,71067,71068,71069,65539,71071,71072,71073,63206,71075,71076,71077,71078,71079,71080,71081,64953,66966,71084,71085,71086,69245,71088,62670,71090,65710,61209,71093,71094,71095,71096,71097,71098,64509,71100,71101,71102,71103,71104,71105,64723,71107,71108,71109,71110,71111,71112,71113,71114,71115,71116,71117,71118,71119,71120,71121,71122,62663,71124,71125,71126,71127,71128,64628,71130,71131,71132,71133,65733,71135,71136,71137,71138,71139,60845,71141,71142,71143,71144,71145,71146,62590,71148,71149,71150,71151,71152,71153,71154,71155,71156,71157,71158,71159,71160,67352,71162,62609,71164,71165,71166,71167,71168,67497,71170,71171,71172,71173,71174,62119,69209,71177,71178,71179,71180,71181,71182,71183,69354,71185,71186,71187,71188,71189,71190,71191,71192,71193,71194,61488,71196,71197,71198,69092,65429,71201,65612,71203,71204,71205,71206,71207,71208,71209,65624,71211,71212,61976,62898,71215,71216,71217,71218,69693,71220,71221,71222,60791,71224,71225,71226,71227,71228,71229,71230,71231,71232,71233,71234,71235,71236,71237,71238,71239,71240,71241,71242,71243,71244,71245,71246,71247,71248,71249,71250,71251,71252,71253,71254,71255,71256,71257,71258,71259,71260,71261,71262,71263,71264,71265,71266,71267,71268,71269,71270,71271,71272,71273,71274,71275,71276,71277,71278,71279,71280,71281,71282,71283,71284,71285,71286,71287,71288,71289,71290,71291,71292,71293,71294,71295,61882,71297,71298,71299,71300,71301,71302,64699,71304,71305,71306,71307,71308,71309,62600,71311,71312,71313,71314,71315,71316,71317,71318,71319,71320,62443,71322,71323,71324,71325,68862,71327,71328,71329,71330,71331,71332,71333,71334,71335,71336,69915,71338,71339,71340,71341,71342,71343,71344,71345,71346,71347,64867,71349,71350,71351,71352,71353,71354,71355,66992,71357,71358,71359,71360,71361,71362,71363,71364,71365,71366,71367,71368,71369,71370,71371,71372,71373,71374,71375,71376,71377,71378,71379,71380,71381,71382,71383,71384,71385,71386,71387,71388,71389,71390,71391,71392,71393,71394,71395,71396,71397,71398,71399,71400,71401,71402,71403,71404,71405,71406,71407,71408,71409,71410,71411,71412,67899,71414,71415,70553,71417,65430,71419,71420,71421,71422,71423,65437,71425,71426,71427,71428,61057,71430,71431,71432,71433,71434,71435,71436,71437,71438,71439,71440,63154,71442,71443,71444,71445,71446,71447,71180,71449,61800,62042,71452,71453,71454,71455,71456,71457,71458,71459,71460,71461,71462,71463,71464,64208,71466,63973,71468,71469,65569,71471,71472,71473,71474,62724,71476,71477,70970,71479,71480,71481,71482,71483,71484,71485,61666,71487,71488,71489,71490,66912,71492,71493,71494,71495,67623,71497,71498,71499,71500,71501,71502,71503,71504,71505,71506,71507,71508,71509,71510,71511,71512,71513,71514,71515,71516,71517,71518,71519,71520,71521,71522,71523,71524,71525,71526,71527,71528,71529,71530,71531,71532,71533,71534,71535,71536,71537,71538,71539,71540,71541,71542,71543,71544,71545,71546,71547,71548,71549,71550,71551,71552,71553,71554,71555,71556,71557,71558,71559,71560,71561,71562,71563,71564,71565,71566,71567,71568,71569,71570,71571,71572,71573,71574,71575,71576,71577,71578,71579,71580,71581,71582,71583,71584,71585,71586,71587,71588,71589,71590,71591,71592,71593,71594,71595,71596,71597,71598,71599,71600,62154,71602,71603,71604,71605,71606,71607,62555,64888,71610,71611,71612,71613,71614,71615,71616,71617,71618,71619,64901,71621,71622,71623,71624,71625,71626,71627,71628,71629,71630,71631,64727,71633,71634,71635,71636,71637,71638,71639,71640,61452,71642,71643,71644,71645,71646,71647,71648,61962,71650,71651,71652,71653,61533,71655,71656,71657,62194,71659,69547,66246,71662,71663,61775,71665,71666,71667,66706,71669,71670,71671,71672,71673,71674,71675,71676,71677,71678,71679,71680,71681,71682,71683,61173,71685,71686,71687,64543,71689,71690,71691,71692,60764,71694,62938,71696,71697,71698,60870,71700,71701,71702,71703,71704,71705,71706,71707,68845,71709,71710,71711,71712,71713,60892,71715,71716,71717,65767,71719,71720,71721,71722,71723,65913,71725,71726,71727,71728,71729,71730,71731,65925,71733,71734,71735,71736,70187,71738,71739,71740,71741,71742,71743,71744,64900,71746,71747,71748,71749,71750,71751,71752,71753,71754,62016,71756,71757,71758,71759,71760,71761,71762,71763,61235,71765,71766,71767,71768,71769,71770,71771,71670,71773,67423,71775,71776,62484,71778,71779,71780,71781,71782,65029,71784,71785,71786,71787,71788,71789,71790,71791,62369,71793,71794,71795,71796,71797,71798,71799,71800,71801,71802,66159,71804,71805,71806,71807,71808,71809,71810,71811,67051,71813,71814,71815,71816,65761,71818,71819,71820,64144,71822,71823,71824,71825,71826,71827,70110,60942,71830,71831,62785,71833,71834,71835,71836,64336,71838,63132,71840,61713,71842,61097,71844,71845,71846,71847,71848,63634,71850,66451,71852,71853,71854,71855,71856,71857,71858,71126,64376,71861,71862,71863,71864,61011,71866,71867,71868,71869,63623,71871,71872,71873,71874,71875,71876,71877,71878,67549,71880,71881,71882,71883,71884,71885,71886,63428,71888,71889,71890,71891,71892,71893,68287,71895,71896,71897,71898,71899,71900,71901,71902,68145,71904,71905,71906,71907,71908,71909,71910,71911,71912,71913,71914,71915,71916,71917,71918,61591,71920,71921,71922,71923,71924,66406,71926,71927,71928,71929,71930,71931,67054,71933,71934,71935,71936,71937,66792,71939,71940,71941,68935,71943,71944,71945,71946,71947,71948,71949,71950,71951,71952,71953,71835,65969,71956,70787,71958,69701,71960,71961,71962,71963,71964,71965,71966,71967,61964,71969,71970,71971,71972,64617,71974,71975,71976,71977,62061,64627,71980,71981,71982,71983,71984,71985,71986,71987,71988,71989,71990,71991,65712,71993,66662,71995,71996,71997,71998,71999,72000,72001,61969,72003,72004,72005,72006,72007,72008,72009,68127,69868,72012,62729,72014,72015,72016,72017,72018,72019,72020,72021,72022,72023,72024,72025,72026,72027,72028,72029,72030,72031,72032,72033,72034,72035,72036,72037,72038,72039,72040,64558,72042,72043,72044,61352,72046,72047,72048,72049,72050,72051,72052,63542,72054,72055,72056,72057,72058,72059,72060,72061,72062,72063,61413,72065,72066,72067,72068,72069,72070,72071,72072,64357,72074,72075,72076,69611,63835,72079,72080,72081,67776,63678,61733,72085,72086,72087,72088,72089,72090,66661,72092,72093,72094,72095,62153,72097,72098,72099,72100,67109,72102,72103,68961,72105,72106,72107,72108,61990,72110,72111,72112,72113,63923,72115,72116,69866,72118,72119,72120,72121,72122,63505,72124,72125,64688,68606,72128,62611,72130,72131,72132,72133,72134,72135,72136,72137,72138,60979,72140,72141,72142,72143,72144,64917,72146,72147,72148,72149,67244,72151,61823,72153,72154,72155,72156,72157,62555,70158,72160,72161,72162,66524,72164,72165,70795,72167,72168,72169,72170,72171,72172,63636,72174,65594,72176,72177,72178,69104,72180,72181,72182,72183,72184,72185,72186,72187,72188,72189,72190,72191,61749,72193,72194,72195,72196,62070,72198,72199,72200,69183,72202,72203,72204,72205,72206,72207,72208,72209,72210,72211,72212,69188,65228,72215,72216,72217,72218,72219,62089,72221,72222,72223,72224,72225,60944,72227,72228,72229,72230,72231,72232,72233,72234,72235,72236,72237,72238,72239,71835,72241,61708,72243,72244,62125,62061,64248,72248,72249,72250,72251,72252,70023,72254,61435,72256,72257,72258,72259,72260,72261,72262,72263,61802,72265,64750,68532,72268,65610,72270,72271,72272,72273,72274,72275,72276,72277,72278,72279,72280,72281,72282,72283,72284,72285,63195,61131,72288,72289,72290,72291,72292,72293,72294,72295,62642,72297,72298,72299,72300,72301,72302,72303,69934,72305,72306,72307,72308,61591,72310,72311,72312,72313,62734,72315,61625,72317,72318,72319,72320,72321,63099,72323,72324,72325,72326,72327,72328,72329,72330,72331,72332,72333,72334,62612,72336,72337,72338,72339,72340,72341,60982,72343,72344,72345,72346,72347,72348,72349,72350,72351,72352,72353,72354,72355,72356,72357,72358,72359,72360,62519,72362,72363,72364,72365,72366,72367,72368,61803,61056,72371,64805,68331,65293,61209,72376,72377,72378,72379,72380,72381,72382,72383,72384,72385,72386,62346,72388,72389,72390,72391,72392,72393,72394,72395,72396,72397,72398,61770,72400,72401,72402,72403,72404,72405,72406,72407,72408,72409,72410,68343,70497,72413,72414,70071,72416,72417,72418,72419,72420,72421,72422,72423,61056,72425,72426,72427,72428,72429,72430,72431,72432,72433,72434,72435,72436,72437,72438,72439,72440,72441,72442,72443,72444,72445,72446,72447,72448,72449,72450,72451,72452,72453,72454,72455,72456,72457,72458,72459,72460,72461,72462,72463,72464,72465,72466,72467,72468,72469,72470,72471,72472,72473,72474,72475,72476,72477,72478,72479,72480,72481,72482,72483,72484,72485,72486,72487,72488,72489,72490,72491,72492,72493,72494,72495,62245,72497,72498,72499,72500,72501,71933,72503,72504,72505,72506,63356,72508,72509,72510,72511,72512,72513,72514,72515,72516,71338,72518,72519,72520,72521,72522,72523,72524,72525,72526,72527,72528,61456,72530,72531,72532,72533,62508,72535,72536,72537,66135,72539,72540,72541,72542,62371,72544,72545,72546,72547,72548,72549,72550,64493,63154,72553,72554,72555,64341,72557,72558,72559,72560,62474,72562,72563,72564,72565,67900,72567,72568,69796,71980,72571,72572,72573,72574,72575,72576,72577,72578,72579,72580,72581,72582,72583,72584,69177,72586,72587,72588,72589,72590,72591,60759,72593,72594,72595,72596,60845,72598,72599,72600,72601,72602,72603,72604,71150,72606,72607,72608,72609,72610,61900,72612,72613,62609,72615,72616,72617,72618,72619,62105,72621,72622,72623,65538,72625,72626,72627,72628,72629,72630,72631,72632,72633,72634,72635,69544,72637,72638,64766,72640,72641,72642,72643,61782,72645,72646,72647,72648,72649,64953,72651,61454,72653,62358,72655,72656,72657,72658,72659,72660,72661,72662,72663,72664,62182,72666,72667,72668,72669,72670,72671,72672,72673,61044,72675,72676,64724,72678,72679,72680,72681,72682,72683,72684,65447,72686,72687,72688,72689,72690,63616,72692,72693,72694,67030,72696,67261,72698,61591,72700,72701,72702,72703,72704,72705,72706,72707,72708,72709,61632,72711,72712,72713,72714,64156,72716,72717,64437,72719,72720,72721,72722,72723,62443,72725,72726,72727,72728,72729,72730,72731,65912,72733,72734,72735,72736,72737,72738,62817,72740,72741,72742,72743,72744,72745,72746,72747,72748,65433,72750,66238,72752,72753,72754,72755,72756,72757,72758,72759,72760,71840,72762,72763,72764,72765,72766,62296,72768,70697,72770,66622,72772,72773,72774,72775,62554,61191,72778,72779,72780,72781,72782,61236,72784,72785,72786,72787,72788,72789,72790,63835,72792,72793,72794,72795,72796,72797,72798,72799,69470,72801,72802,70328,69878,71053,72806,72807,72808,72809,72810,62424,72812,72813,72814,72815,72816,61355,72818,72819,72820,65015,72822,64456,72824,72825,72826,72827,69545,62357,72830,72831,72832,72833,72834,64927,64953,61191,72838,72839,72840,72841,72842,61208,72844,72845,72846,62341,72848,72849,72850,72851,61126,62331,72854,72855,72856,72857,72858,72859,72860,72861,72862,72863,61821,72865,72866,72867,71898,72869,72870,72871,72872,69037,72874,72875,72876,72877,62243,72879,72880,72881,72882,72883,72884,72885,60818,62752,72888,72889,72890,72891,72892,72893,66170,71710,72896,72897,72898,72899,72900,66419,72065,72903,72904,72905,72906,72907,72908,72909,72910,72911,72912,72913,62626,72915,72916,72917,72918,72919,72920,72921,72922,72923,72924,71607,72926,72927,72928,62883,72930,72931,72932,72933,72934,72935,72936,72937,72938,62844,72940,72941,72942,72943,72944,72945,72946,72947,72948,72949,72950,72951,72952,72953,63689,72955,72956,72957,72958,72959,66661,72961,72962,68108,72964,72965,72966,72967,64770,72969,72970,72971,62043,72973,72974,72975,72976,72977,72978,72979,72980,71009,72982,72983,72984,72985,72986,72987,70375,72989,72990,69716,72992,69865,72994,72995,72996,72997,72998,72999,73000,73001,64985,68833,73004,73005,73006,73007,73008,73009,73010,73011,64575,73013,73014,73015,73016,73017,73018,73019,73020,63545,73022,73023,73024,73025,66574,73027,73028,73029,73030,73031,73032,73033,73034,73035,73036,73037,73038,73039,73040,73041,73042,73043,73044,73045,73046,73047,73048,73049,73050,73051,73052,73053,73054,73055,73056,73057,73058,73059,73060,73061,73062,73063,73064,73065,73066,73067,73068,73069,73070,73071,73072,73073,73074,73075,73076,73077,73078,73079,73080,73081,73082,73083,73084,73085,73086,73087,73088,73089,73090,73091,73092,73093,72562,73095,73096,68290,73098,73099,72645,73101,73102,63492,61803,61208,73106,73107,73108,73109,73110,63144,73112,61147,73114,73115,73116,73117,65029,73119,73120,73121,73122,62368,73124,73125,73126,73127,73128,73129,73130,73131,73132,73133,62665,73135,73136,73137,69419,73139,73140,73141,62730,73143,73144,73145,73146,73147,73148,73149,73150,73151,73152,64558,73154,73155,73156,73157,73158,73159,73160,73161,73162,63100,73164,73165,73166,73167,73168,73169,73170,73171,73172,73173,73174,73175,72132,73177,73178,73179,73180,73181,66432,73183,73184,73185,73186,73187,64456,73189,73190,73191,73192,61138,73194,61234,61780,73197,73198,73199,73200,62665,73202,73203,73204,73205,66198,73207,73208,73209,73210,73211,73212,73213,73214,70825,73216,73217,72005,73219,73220,73221,73222,73223,69717,66645,73226,73227,73228,73229,73230,73231,73232,73233,68813,73235,73236,73237,73238,73239,73240,67637,73242,73243,73244,73245,73246,73247,72586,73249,73250,73251,73252,73253,72880,73255,73256,73257,73258,73259,60827,73261,73262,73263,73264,73265,73266,73267,73268,73269,73270,73271,73272,65855,73274,73275,71701,73277,73278,73279,73280,73281,73282,61381,73284,73285,73286,73287,73288,73289,73290,73291,61676,73293,73294,73295,73296,73297,73298,73299,69658,73301,73302,73303,73304,73305,63621,73307,73308,73309,73310,64478,73312,72637,73314,68733,73316,73317,73318,73319,73320,73321,62055,73323,73324,73325,73326,73327,73328,73329,70322,73331,73332,69094,73334,73335,66516,73337,73338,73339,73340,73341,71785,73343,73344,73345,73346,73347,73348,73349,73350,62368,73352,73353,73354,73355,73356,73357,73358,73359,73360,73204,61250,73363,73364,73365,73366,62734,73368,73369,62942,62410,73372,73004,73374,73375,73376,73377,62959,73379,73380,73381,73382,73383,73384,73385,73386,73387,73388,73389,73390,73391,73392,62612,73394,73395,73396,73397,73398,62619,73400,73401,73402,73403,73404,73405,73406,73407,73408,61438,73410,73411,73412,73413,73414,73415,73416,61981,73418,73419,73420,73421,73422,73423,73424,73425,73426,73427,64613,73429,73430,73431,64806,61800,73434,70179,73436,73437,64974,73439,73440,73441,73442,73443,61540,73445,73446,73447,67757,73449,73450,73451,73452,73453,73454,66737,61811,73457,64381,73459,73460,73461,73462,73463,73464,73465,73466,73467,73468,62875,73470,73471,73472,73473,62236,66890,73476,73477,73478,73479,73480,73481,73482,73483,69990,73485,73486,73487,73488,73489,73490,73491,73492,73493,73494,61345,73496,73497,73498,73499,73500,73501,73502,73503,64848,73505,69906,73507,68862,73509,73510,73511,73512,73513,73514,73515,63970,73517,73518,73519,73343,73521,73522,73523,67796,73525,73526,73527,73528,73529,73530,73531,73114,73533,67396,71740,73536,73537,62345,73539,73540,73541,71443,73543,73544,73545,73546,64498,73548,73549,73550,68812,73552,73553,73554,73555,73556,73557,73558,73559,73560,73561,73562,61101,73564,73565,73566,73567,73568,73569,73570,73571,73572,62068,66169,73575,73576,64150,73578,73579,73580,73581,73582,73583,73584,73585,64158,73587,73588,62986,73590,73591,73592,73593,73594,73595,73596,73509,73598,73599,73600,73601,73602,73603,73604,62694,73337,73607,66134,73609,73610,73611,73612,73613,73614,69029,73616,73617,61798,73619,61209,73621,73622,73623,73624,73625,65608,73627,73628,73629,73630,73631,66827,62334,73634,69282,73636,73637,73638,73639,73640,73641,65993,73643,73644,73645,73646,73647,73648,73649,73650,73651,73652,73653,73654,73655,73656,73657,73658,73659,67586,73661,73662,73663,73664,73665,73666,73667,71937,73669,63355,73671,73672,66181,73674,73675,73676,73677,73678,73679,73680,73681,73682,66249,73684,73685,73686,73687,64498,73689,73690,73691,73692,73693,72388,73695,73696,73697,73698,73699,73700,73701,73702,71765,73704,73705,73706,73707,73708,69973,73710,73711,73712,73713,73714,73715,73716,73717,73718,73719,73720,73721,69213,73723,73410,73725,73726,73727,66592,73729,73730,73731,73732,73733,73734,73735,71075,73737,73738,73739,73740,73741,73742,73743,62557,63949,73746,73747,73748,73749,73750,73751,73752,73753,62574,66971,73756,73757,73758,62066,73760,72035,73762,68163,73764,73765,73766,73767,73768,71701,73770,73771,73772,73773,73774,73775,62774,73777,73778,73779,73780,73781,65776,73783,73784,73785,73786,71075,73788,73789,73790,73791,73792,73793,73794,61516,73796,73797,73798,73799,73800,73801,73802,73803,73804,63222,73806,73807,73808,73809,73810,73811,73812,73813,73814,73815,73816,73817,73818,73819,73820,73821,62629,73823,73824,73825,73826,73827,73828,73829,61189,73831,73832,73833,73834,73835,73836,73837,73838,61144,73840,73841,73842,73843,73844,73845,73846,66622,73848,73849,73850,73851,73852,73853,73854,65576,73856,61991,73858,67038,73860,64416,64684,73863,73864,73865,70002,73867,64447,73869,73870,73871,73872,73873,73874,73875,73876,73877,73878,66439,73880,73881,73882,73883,73884,63191,73886,73887,73888,73889,73890,73891,72250,73893,73894,62628,73896,73897,73898,73899,73900,73901,73902,73903,73904,73905,73906,65964,73908,66096,73910,70510,73912,73913,70523,73915,73916,73917,73918,73919,73920,73921,73922,68784,73924,73925,73926,73927,73928,73929,73930,73931,61173,73933,73934,73935,73936,73937,73938,70153,62645,73941,73526,73943,73944,73945,73946,73947,73948,62068,68833,73951,73952,73953,73954,73955,73956,73957,64149,73959,73960,73961,73962,73963,73964,73965,73966,73967,73968,73969,67724,73971,61411,73973,73974,73975,73976,73977,73978,73979,73980,73981,73982,73983,73984,73985,73986,73987,73988,73989,73990,73991,73992,73993,73994,73995,73996,73997,73998,73999,74000,74001,74002,74003,74004,74005,74006,74007,74008,74009,74010,74011,62478,74013,74014,74015,68103,74017,74018,64805,61977,74021,74022,74023,61193,74025,74026,65301,74028,74029,74030,74031,74032,74033,74034,68790,74036,74037,74038,62121,74040,74041,74042,74043,74044,67787,74046,74047,74048,74049,74050,74051,74052,74053,74054,74055,74056,63048,74058,74059,74060,74061,74062,74063,67542,74065,74066,61591,74068,60847,74070,74071,74072,74073,74074,74075,60870,74077,74078,68035,74080,74081,74082,67356,74084,74085,74086,71062,74088,74089,74090,74091,74092,74093,74094,74095,74096,65541,74098,74099,74100,74101,74102,62153,74104,74105,74106,74107,73933,74109,74110,74111,74112,67153,74114,74115,74116,74117,74118,74119,67306,74121,74122,74123,74124,65948,74126,74127,74128,74129,74130,74131,74132,74133,74134,74135,74136,74137,74138,74139,74140,74141,74142,74143,74144,74145,74146,74147,74148,74149,74150,74151,74152,74153,74154,74155,74156,74157,74158,74159,74160,74161,74162,74163,74164,74165,74166,74167,74168,74169,74170,74171,62516,74173,74174,74175,74176,74177,70136,74179,74180,74181,74182,61076,74184,74185,74186,74187,74188,74189,74190,74191,74192,74193,63225,74195,74196,74197,74198,74199,74200,74201,74202,74203,74204,74205,74206,74207,74208,61981,74210,74211,74212,74213,74214,74215,74216,74217,63428,74219,74220,74221,74222,74223,74224,74225,66647,74227,74228,74229,74230,70039,74232,74233,74234,74235,74236,69510,74238,74239,73006,74241,74242,74243,74244,74245,74246,74247,73962,74249,74250,74251,74252,74253,74254,74255,74256,63540,74258,60983,74260,74261,74262,61551,74264,74265,74266,74267,74268,74269,74270,74271,74272,74273,74274,68753,74276,62469,74278,74279,74280,74281,74282,62355,74284,62140,74286,74287,74288,74289,71127,63850,74292,74293,74294,74295,62357,74297,74298,74299,74300,74301,74302,74303,62653,74305,74306,74307,65420,74309,74310,71231,69874,74313,74314,74315,74316,74317,69990,74319,74320,74321,74322,74323,74324,74325,74326,61655,74328,74329,74330,74331,74332,66326,74334,74335,60889,74337,74338,74339,74340,74341,74342,74343,74344,74345,74346,74347,74348,74349,74350,74351,62611,74353,74354,74355,74356,74357,63899,74359,74360,74361,74362,74363,72733,74365,74366,74367,74368,74369,74370,74371,74372,74373,74374,74375,68963,74377,74378,74379,74380,74381,74382,74383,66961,74385,74386,74387,74388,74389,74390,74391,61719,74393,74394,74395,74396,74397,74398,74399,74400,74401,74402,64484,74404,74405,74406,74407,61962,74409,74410,74411,74412,74413,74414,66806,74416,74417,74418,67546,74420,74421,74422,74423,74424,71005,74426,74427,62701,74429,65831,74431,74432,74433,74434,74435,74436,61173,74438,74439,74440,74441,74442,74443,61591,64408,74446,74447,74448,74449,74450,74451,74452,74453,74454,69302,74456,74457,74458,62277,71323,74461,74462,74463,74464,74465,74466,74467,74468,74469,74470,69778,74472,74473,74474,74475,69845,74477,61175,74479,74480,74481,74482,74483,74484,68362,74486,74487,74488,74489,74490,74491,74492,74493,74494,74495,74496,63133,74498,74499,74500,74501,74502,74503,74504,74505,66217,74507,74508,74509,74510,74511,74512,65293,64234,74515,74516,74517,74518,74519,74520,61156,74522,74523,74524,74525,74526,74527,74528,74529,74530,74531,66208,74533,74534,62021,74536,74537,74538,74539,74540,74541,74542,74543,74544,74545,74546,74547,65293,71995,74550,74551,74552,74553,74554,74555,70390,74557,74558,74559,74560,74561,74562,62555,68916,74565,74566,69302,74568,74569,62443,74571,74572,74573,74574,74575,74576,66337,74578,74579,74580,74581,74582,74583,74584,74585,74586,68946,74588,74589,74590,74591,74592,74593,74594,68718,74596,74597,61583,74599,74600,74601,74602,74603,74604,74605,67153,74607,74608,74609,74610,74611,74612,74613,74614,74615,74616,63589,74618,74619,74620,62344,74622,74623,74624,74625,74626,74627,74628,67899,66723,74631,74632,74633,74634,61796,74636,74637,74638,74639,74640,73716,74642,74643,74644,74645,74646,63130,74648,74649,67971,74651,74652,74653,74654,74655,74656,62068,74658,74659,74660,74661,74662,74663,74664,74665,74662,74667,74668,74669,74670,74671,61600,74673,74674,74675,62745,74677,62769,74679,74680,74681,74682,74683,64150,74685,74686,74687,74688,74689,74690,74691,74692,74693,74694,74695,74696,74697,72717,74699,62981,74701,74702,74703,74704,74705,74706,72241,65710,74709,66254,74711,74712,74713,74714,74715,72153,74717,74718,74719,74720,74721,74722,74723,74724,74725,74726,74727,74728,74729,61963,69545,69244,74733,74734,74735,74736,74737,74738,74739,74740,74741,65324,66131,74744,74745,61803,72571,74748,74749,74750,74751,74752,74753,74754,74755,74756,74757,64968,74759,65990,74761,74762,74763,74764,74765,74766,74767,74768,74769,74770,74771,63503,74773,74774,74775,72025,74777,72880,74779,74780,74781,74782,74783,74784,74785,74786,61639,74788,61894,74790,74791,74792,74793,74794,67212,74796,74797,74798,74799,74800,74801,74802,60901,67228,74805,74806,74807,74808,74809,74810,74811,74812,74813,61136,74815,74816,74817,74818,74819,70310,74821,74822,74823,74824,74825,74826,74827,74828,63928,74830,74831,74832,74833,74834,65946,74836,74837,74838,74839,74840,74841,74842,74749,74844,74845,74846,74847,74848,74849,74850,74851,74852,72261,74854,74855,62030,70551,74858,61507,74860,74861,74862,74863,74864,60805,74866,74867,74868,74869,74870,74871,74872,74873,74874,74875,74876,74877,74878,74879,74880,74881,74882,74883,71815,74885,60834,74887,74888,74889,74890,74891,74892,74893,74894,74895,74896,74897,74898,74899,74900,74901,74902,64833,74904,74905,74906,74907,66907,74909,63115,74911,74912,74913,74914,74915,74916,61137,74918,74919,74920,74921,62182,74923,74924,74925,74926,74927,63428,74929,74930,74931,74932,61235,74934,74935,74936,65447,74938,74939,74940,74941,74942,74943,74944,74945,74946,62321,73227,61097,74950,74951,74952,74953,74954,72273,74956,74957,74958,61758,74960,74961,74962,61520,74964,74965,74966,74967,74968,74969,74970,74971,74622,74973,74974,74975,74976,74977,74978,74979,74980,74981,74982,74983,70320,74985,74986,65735,74988,61593,74990,74991,74992,62923,67333,74995,71053,74997,74998,74999,75000,70424,75002,75003,75004,75005,75006,75007,75008,75009,75010,62615,73401,75013,75014,75015,75016,75017,75018,75019,75020,75021,75022,75023,62516,75025,75026,75027,75028,75029,75030,75031,75032,75033,75034,75035,61455,75037,75038,75039,75040,75041,75042,75043,75044,75045,75046,62060,75048,75049,75050,75051,75052,75053,62898,75055,75056,75057,75058,75059,75060,75061,66478,75063,67381,75065,75066,75067,75068,63131,75070,75071,75072,75073,75074,75075,63017,75077,75078,75079,75080,75081,75082,62374,75084,75085,75086,75087,61203,75089,75090,75091,75092,67420,75094,75095,66066,75097,75098,75099,75100,75101,75102,75103,75104,63159,75106,75107,75108,75109,75110,72079,75112,75113,75114,62337,75116,75117,75118,63715,69878,75121,75122,75123,75124,72498,75126,75127,75128,75129,75130,75131,75132,75133,66300,75135,62770,75137,75138,75139,72049,75141,75142,75143,75144,75145,75146,75147,75148,75149,75150,61382,75152,75153,75154,75155,75156,75157,69307,75159,75160,66430,75162,67361,75164,75165,75166,75167,71778,75169,75170,75171,75172,75173,68117,75175,75176,65464,75178,75179,62892,63849,75182,64627,75184,75185,75186,75187,75188,75189,75190,75191,62508,75193,75194,75195,75196,75197,75198,71776,74541,75201,75202,72770,61216,75205,75206,75207,75208,75209,69333,75211,75212,75213,75214,75215,75216,65323,75218,72704,75220,75221,75222,61859,75224,75225,75226,60800,75228,75229,75230,75231,75232,75233,75234,75235,64684,75237,75238,75239,64696,75241,75242,75243,75244,75245,75246,74909,72131,75249,75250,75251,75252,61399,75254,75255,75256,65775,75258,75259,75260,75261,75262,75263,75264,75265,75266,61981,75268,67381,75270,75271,75272,75273,75274,75275,64340,75277,75278,75279,75280,75281,62343,75283,75284,75285,75286,75287,75288,75289,75290,75291,69128,75293,62814,75295,75296,75297,75298,72940,62341,75301,75302,75303,75304,75305,75306,75307,75308,75309,75310,75311,75312,75313,68278,75315,75316,75317,63141,75319,75320,75321,75322,75323,75324,75325,75326,75327,75328,75329,75330,75331,75332,75333,61097,75335,75336,75337,75338,75339,75340,75341,75342,75343,75344,75345,67512,66013,75348,75349,75350,64290,75352,75353,75354,75355,64697,75357,75358,75359,67873,60908,75362,75363,75364,75365,75366,62986,75368,75369,75370,75371,75372,75373,75374,75375,75376,60981,75378,75379,75380,75381,71112,75383,75384,75385,75386,75387,75388,75389,63139,75391,75392,75393,75394,75395,75396,75397,75398,70924,75400,75401,75402,75403,75404,75405,75406,73832,75408,75391,75410,75411,75412,75413,61737,75415,75416,75417,75418,61537,75420,75421,75422,75423,75424,75425,75426,75427,75428,75429,75430,61436,75432,75433,75434,75435,75436,64589,75438,75439,75440,65575,75442,75443,75444,75445,75446,68402,61591,75449,75450,75451,75452,75453,62923,75455,75456,75457,75229,75459,75460,75461,75462,75463,64679,75465,75466,75467,61666,75469,75470,75471,75472,75473,74462,75475,75476,75477,75478,75479,75480,75481,75482,70120,75484,75485,75486,75487,75488,75489,70139,75491,68260,64341,75494,75495,75496,75497,75498,63125,75500,73730,75502,75503,69848,75505,75506,75507,64222,75509,75510,75511,75512,75513,75514,62815,75516,75517,75518,75519,75520,75521,75522,75523,75524,62910,63678,75527,75528,75529,75530,75531,75532,75533,75534,63143,75536,75537,75538,75539,75540,62236,75542,61339,75544,75545,75546,64833,75548,75549,75550,75551,75552,75553,75554,75555,75556,75557,75558,63351,75560,75561,75562,75563,60930,75565,75566,75567,75568,75569,61697,75571,75572,75573,75574,75575,75576,69327,75578,75579,74046,75581,75582,75583,75584,75585,75586,75403,75588,75589,75590,75591,70704,75593,75594,75595,75596,75597,75598,69669,75600,75601,75602,62882,75604,75605,75606,75607,75608,75609,75610,74821,75612,75613,75614,75615,75616,75617,75618,75619,75620,75621,75622,62355,75624,75625,75626,75627,75628,75629,75630,70493,75632,62014,75634,75635,75636,61008,75638,75639,75640,75641,75642,75643,75644,75645,75646,75647,75500,75649,61033,75651,75652,75653,75654,75655,61976,62336,75658,75659,75660,74625,75662,75663,75664,75665,75666,75667,62914,75669,75670,75671,75672,74675,75674,75675,66881,75677,75678,75679,75680,75681,75682,75683,75684,75349,75686,75687,67183,75689,75690,75691,75692,75693,75694,75695,75696,66420,75698,75699,62984,75701,75702,75703,61692,75705,75706,75707,75708,75709,75710,75711,75712,75713,75714,75715,75716,69819,75718,75719,75720,75721,75722,75723,75724,61719,75726,75727,75728,75729,75730,75731,75732,75733,75734,75735,63224,75737,75738,75739,75740,75741,75742,75743,62193,75745,75746,63622,75748,75749,75750,75751,71872,75753,75754,75755,75756,75757,75758,64770,63074,75761,75762,75763,75764,75765,75766,61820,75768,75769,75770,75771,75772,75773,75774,75775,75776,67696,75778,75779,75780,75781,75782,75783,63794,75785,75786,75787,75788,65266,75790,75791,68875,75793,75794,75795,75796,75797,75798,75799,75800,62873,75802,75803,75804,66875,75806,69879,64109,75809,75810,75811,75812,75813,75814,75815,75816,60872,75818,75819,75820,75821,67344,75823,75824,75825,75826,75827,75828,69431,67882,75831,75832,75833,75834,75835,63380,75837,75838,75839,75840,75841,75842,65450,75844,75845,61586,75847,75848,75849,63417,75851,75852,75853,75854,75855,73553,75857,75858,75859,75860,75861,75862,75863,75864,75865,75866,75867,69705,75869,75870,75871,75872,75873,75874,75875,61039,75877,75878,75879,62196,63070,75882,75883,75884,75885,75886,75887,75888,64200,75890,75891,75892,75893,74264,75895,75896,75897,75898,66460,75900,75901,75902,72249,75904,75905,75906,75907,75908,75909,60768,75911,75912,75913,75914,75915,75916,75917,75918,75919,75920,75921,75922,75923,75924,75925,75926,75927,75928,75929,75930,75931,75932,75933,75934,75935,75936,62258,75938,75939,75940,75941,75942,75943,75944,75945,61655,64429,75948,75949,75950,65512,70752,75953,75954,75955,65918,75957,75958,75959,75960,65924,75962,75963,75964,75965,75966,75967,75968,75969,61976,75971,61747,75973,75974,75975,75976,75977,75978,62858,75980,74270,75982,61019,75984,75985,75986,75987,67396,75989,75990,62898,75992,75993,67311,75995,75996,75997,75998,75999,67638,76001,76002,76003,74938,76005,76006,76007,76008,76009,76010,76011,76012,66522,76014,76015,76016,76017,76018,76019,62369,76021,76022,76023,76024,76025,76026,76027,76028,76029,76030,76031,64899,76033,76034,76035,76036,76037,76038,76039,76040,76041,76042,66460,76044,76045,76046,76047,76048,65847,76050,76051,76052,76053,74673,76055,76056,76057,72039,76059,73764,76061,76062,64846,76064,76065,76066,76067,76068,76069,76070,67071,76072,76073,76074,76075,76076,76077,76078,76079,76080,76081,76082,76083,76084,76085,76086,64865,76088,76089,76090,76091,76092,76093,76094,67627,76096,76097,76098,76099,76100,76101,76102,67276,76104,76105,76106,76107,76108,76109,61585,76111,76112,76113,76114,66255,76116,76117,76118,76119,76120,76121,76122,76123,76124,76125,76126,63599,76128,65293,73610,76131,76132,76133,74951,76135,76136,76137,68238,76139,76140,68784,76142,76143,76144,66159,76146,76147,76148,76149,75455,76151,76152,76153,76154,76155,76156,73863,76158,76159,64156,76161,76162,76163,76164,76165,76166,76167,64437,76169,76170,76171,76074,76173,76174,76175,67363,76177,76178,76179,76180,76181,76182,76183,76184,76185,76186,76187,62671,63070,76190,76191,76192,76193,76194,76195,61833,76197,62063,63798,76200,76201,76202,76203,76204,76205,76206,76207,76208,61097,76210,76211,76212,76213,69964,66517,76216,76217,76218,76219,76220,74185,76222,76223,76224,76225,64219,76227,76228,76229,76230,76231,76232,76233,76234,76235,76236,69177,76238,76239,76240,76241,64414,76243,76244,76245,60809,76247,76248,76249,76250,76251,76252,76253,76254,65646,65380,76257,76258,64442,76260,76261,76262,76263,76264,76265,65863,76267,76268,66431,76270,76271,76272,69916,76274,76275,76276,76277,76278,76279,76280,76281,73207,76283,76284,76285,76286,61821,76288,76289,76290,75175,61709,62047,69209,76295,76296,68675,76298,76299,76300,76301,65322,76303,76304,76305,62914,76307,76308,76309,76310,75457,76312,76313,76314,76315,76316,76317,76318,76319,73004,76321,76322,76323,76324,76325,62277,69201,76328,76329,76330,76331,76332,74588,76334,76335,76336,62518,76338,76339,76340,76341,76342,63200,76344,76345,63979,76347,76348,76349,76350,76351,76352,76353,76354,76355,76356,76357,76358,76359,76360,76361,76362,76363,76364,76365,76366,76367,76368,76369,76370,76371,76372,76373,76374,76375,76376,76377,76378,76379,76380,76381,76382,76383,76384,76385,76386,76387,76388,76389,76390,76391,76392,76393,76394,76395,76396,76397,76398,76399,76400,76401,76402,76403,76404,76405,76406,76407,76408,76409,76410,76411,76412,76413,76414,76415,76416,76417,76418,76419,76420,76421,76422,76423,76424,66459,76426,76427,76428,76429,76430,76431,76432,76433,61983,76435,76436,76437,67382,76439,76440,76441,76442,76443,76444,76445,76446,76447,76448,62062,76450,76451,74967,76453,76454,61175,76456,76457,76458,71852,76460,76461,76462,62508,62040,76465,76466,76467,76468,76469,76470,76471,76472,76473,76474,76475,76476,76477,69703,76479,76480,76481,76482,76483,76484,76485,76486,76487,76488,76489,75449,76491,76492,76493,76494,76495,72593,76497,76498,76499,76500,76501,76502,62938,76504,76505,76506,76507,76508,62953,73005,76511,76512,76513,76514,76515,76516,76517,76518,61655,74077,76521,76522,76523,76524,61909,62095,76527,76528,76529,76530,76531,76532,76533,68383,76535,76536,76537,76538,76539,76540,76541,76542,76543,76544,76545,76546,76547,68065,76549,76550,76551,76552,76553,76554,72964,76556,76557,76558,76559,76560,76561,76562,76563,76564,68127,76566,76567,66475,76569,76570,76571,76572,76573,76574,76575,76576,76577,76578,76579,76580,76581,76582,76583,76584,76585,76586,76587,76588,76589,76590,76591,76592,76593,76594,76595,76596,76597,76598,76599,76600,76601,76602,76603,76604,76605,76606,76607,76608,76609,76610,76611,76612,76613,65251,76615,76616,76617,76618,67278,76620,76621,61235,76623,76624,76625,76626,62664,76628,76629,76630,76631,76632,76633,76634,63199,76636,76637,76638,72841,76640,76641,62032,76643,76644,76645,68363,76647,76648,76649,76650,76651,76652,76653,76654,76655,76656,76657,61966,76659,76660,76661,76662,76663,66158,76665,76666,76667,76668,65743,76670,76671,76672,76673,76674,76675,76676,76677,63519,76679,60845,76681,76682,76683,76684,76685,76686,60854,76688,64439,76690,76691,76692,76693,76694,76695,63355,76697,76698,76699,76700,76701,76702,76703,76704,76705,62786,76707,76708,76709,76710,76711,76712,76713,61494,76715,76716,76201,76718,76719,76720,76721,76722,62215,76724,76725,76726,74484,76728,76729,67150,76731,76732,76733,76734,76735,76736,76737,76738,76739,74837,76741,76742,76743,76744,76745,76746,76747,76748,76749,76750,76751,76752,76753,76754,76755,76756,76757,76758,76759,76760,76761,76762,72112,73748,76765,76766,76767,76768,76769,76770,76771,76772,76773,76774,72753,76776,76777,76778,76779,76780,76781,76782,76783,60820,76785,76786,76787,76788,76789,76790,76791,76792,76793,76794,76795,76796,76797,64685,76799,76800,64848,76802,76803,76804,76805,67728,76807,76808,76174,76810,76811,76812,76813,76814,70236,76816,76817,76818,76819,76820,76821,76111,76823,76824,76825,62831,76827,76828,76829,76830,76831,76832,76833,63582,76835,76836,76837,74173,69964,62701,76841,76842,76843,76844,76845,76846,76847,76848,76849,61096,76851,76852,76853,76854,76855,76113,76857,65403,76859,75270,76861,76862,76863,76864,76865,63613,76867,61783,76869,76870,61176,76872,76873,76874,76875,65845,76877,76878,76879,76880,76059,76882,76883,76884,62938,76886,76887,76888,76889,76681,76891,76892,76893,76894,76895,60869,76897,76898,76899,76900,76901,76902,76903,76904,76905,76906,76907,76908,61899,76910,76911,76912,76913,61677,76915,76916,68386,76918,76919,76920,76921,76922,76923,76924,67623,76926,68328,76928,76929,74438,76931,76932,76933,76934,76935,76936,61515,76938,76939,76940,76941,66538,76943,76944,76945,76946,76947,76948,76949,76950,76951,76952,64727,76954,76955,76956,76957,74961,76959,76960,76961,76962,62042,76964,76965,76966,76967,76968,76969,76970,76971,66482,76973,70536,70144,76976,76977,76978,61186,76980,76981,76982,76983,76984,76985,76986,76987,76988,76989,75746,76991,64886,76993,76994,76995,76996,76997,76998,76999,77000,77001,77002,61840,77004,77005,77006,61855,77008,77009,60794,77011,77012,77013,77014,77015,77016,77017,77018,77019,77020,62087,77022,63545,77024,77025,77026,63356,77028,77029,77030,77031,77032,77033,77034,77035,75259,77037,77038,77039,77040,77041,77042,77043,61985,74711,77046,77047,77048,77049,77050,77051,77052,77053,75283,77055,77056,77057,77058,77059,77060,77061,77062,77063,77064,77065,77066,77067,77068,74935,77070,77071,77072,77073,66587,77075,77076,77077,62896,77079,77080,77081,77082,77083,77084,77085,73411,77087,77088,77089,68802,77091,64770,62038,77094,77095,77096,61049,77098,77099,77100,77101,77102,77103,60792,77105,64561,77107,77108,77109,77110,77111,61356,77113,77114,77115,77116,77117,77118,77119,67873,71323,77122,77123,77124,77125,77126,77127,77128,77129,77130,77131,77132,61023,77134,77135,77136,77137,77138,77139,77140,72765,77142,77143,77144,77145,71897,61485,77148,77149,66733,77151,77152,75898,77154,77155,69545,77157,77158,73623,77160,77161,77162,77163,77164,77165,77166,77167,77168,77169,77170,66116,77172,77173,77174,77175,77176,77177,77178,77179,77180,77181,77182,66534,77184,77185,77186,69664,77188,77189,77190,71852,77192,77193,77194,77195,77196,77197,69004,77199,72182,77201,77202,77203,77204,77205,77206,77207,77208,77209,77210,71446,77212,77213,62069,69880,66014,77217,77218,77219,77220,77221,77222,71702,77224,77225,77226,77227,77228,77229,77230,77231,61381,77233,77234,77235,77236,77237,62609,77239,77240,77241,77242,77243,77244,77245,77246,77247,77248,67230,77250,77251,77252,77253,77254,65948,77256,77257,77258,77259,77260,77261,77262,77263,72151,66628,77266,77267,77268,77269,65589,77271,74292,76216,77274,73343,77276,77277,77278,77279,77280,77281,77282,69266,77284,77285,77286,77287,77288,70536,62153,63858,77292,77293,77294,77295,77296,77297,77298,62367,77300,77301,77302,77303,77304,77305,61591,77307,77308,77309,77310,77311,77312,77313,77314,77315,77316,69879,64110,77319,77320,77321,77322,77323,77324,76681,77326,77327,77328,77329,76521,77331,77332,77333,77334,77335,77336,61920,77338,77339,77340,77341,77342,77343,77344,77345,63005,68121,77348,76347,77350,77351,63924,77353,77354,77355,77356,77357,64202,77359,77360,77361,77362,77363,77364,77365,75322,77367,77368,77369,77370,77371,77372,77373,77374,77375,77376,77377,77378,77379,77380,77381,64660,77383,77384,77385,77386,77387,77388,77389,77390,77391,77392,77393,77394,77395,61559,77397,77398,77399,70700,77401,77402,77403,77404,77055,77406,77407,77408,77409,77410,61237,77412,77413,77414,77415,77416,77417,77418,77419,62233,77421,77422,77423,77221,77425,76681,77427,77428,77429,77430,61665,77432,77433,77434,77435,77436,77437,77438,60908,67071,77441,77442,77443,77444,77445,77446,77447,77448,68618,77450,77451,77452,77453,77454,77455,76861,77457,77458,77459,77460,77461,77462,70249,77464,77465,61820,77467,77468,63615,77470,77471,61136,77473,77474,77475,72584,77477,62474,77479,77480,77481,77482,77483,77484,77485,77486,77487,77474,77489,77490,77491,77492,77493,75176,62043,77496,77497,77498,77499,77500,77501,77502,77503,77504,77505,71295,77507,77508,77509,77510,77511,77512,77513,77514,77515,77516,77517,77518,77519,77520,77521,77522,77523,65363,77525,77526,77527,77528,71933,77530,77531,77532,69902,77534,71327,77536,77537,77538,77539,67914,77541,62355,77543,77544,77545,77546,63815,77548,77549,77550,66835,77552,77553,77554,77555,77556,77557,77558,77559,66587,77561,77562,77563,72833,77565,77566,62370,77568,77569,77570,77571,77572,77573,61800,68729,77576,77577,75625,77579,77580,77581,77582,77583,61228,77585,77586,77587,77588,61144,77590,77591,77592,77593,77594,77595,62914,77597,77598,61858,77600,60836,77602,77603,77604,77605,61657,74797,77608,77609,77610,77611,77612,77613,77614,72140,77616,77617,77618,77619,77620,77621,77622,77623,77624,77625,77626,77627,77628,65945,77630,77631,77632,77633,63576,77635,77636,64480,77638,77639,77640,77641,77642,77643,77644,77645,62476,77647,77648,77649,67382,77651,77652,77653,72115,77655,69245,77657,77658,77659,65050,77661,77662,77663,62313,69496,77666,77667,77668,77669,77670,77671,77672,63670,77674,77675,77676,77677,77678,77679,66015,77681,77682,77683,77684,62956,77686,77687,77688,77689,77690,77691,77692,77693,77694,77695,77696,77697,77698,77699,77700,77701,61382,77703,77704,77705,77706,77707,77708,77709,77710,77711,77712,61680,68383,77715,77716,77717,64868,77719,77720,77721,77722,77723,77724,77725,77726,77727,77728,77729,77730,77731,77732,77733,77734,77735,77736,77737,77738,77739,77740,66693,77742,77743,77744,77745,77746,77747,77748,77749,77750,65911,77752,77753,77754,77755,77756,77757,76140,77759,77760,77761,77762,62374,77764,77765,77766,77767,77768,77769,77770,77771,77772,77773,77774,77775,62334,77777,77778,77779,77780,77781,77782,77783,77784,77785,64940,77787,77788,77789,77790,77791,77792,77793,77794,71898,77796,75652,72196,77799,77800,61823,77802,77803,77804,77805,77806,77807,77808,77809,77810,61752,77812,60783,61339,77815,77816,73960,77818,77819,77820,77821,77822,77823,77824,77825,60901,65017,77828,77829,77830,77831,77832,77833,77834,64315,77836,77837,77838,77839,77840,77841,73845,61093,77844,77845,77846,77847,77848,77849,77850,77851,77852,77853,69414,77855,61951,68734,77858,77859,77860,77861,77862,77863,68250,77865,77866,77867,77868,77869,77870,77871,77872,62194,75041,77875,77876,77877,62046,77879,77880,77881,77882,77883,77884,77885,77886,77887,77888,77889,77890,66554,77892,77893,77894,77895,77896,77897,77898,70211,77900,77901,77902,77903,77904,77905,77906,77907,67056,77909,77910,77911,77912,77913,77914,67218,77916,77917,77918,77919,63356,77921,66693,77923,77924,77925,77926,77927,77928,64598,77930,62343,77932,77933,77934,77935,77936,77937,77938,74550,77940,77941,71076,77943,77944,77945,74309,64247,77948,77949,77950,77951,77952,74930,77954,71112,77956,77957,77958,77959,77960,63205,65595,77963,77964,77965,77966,77967,77968,70357,77970,77971,77972,77973,66616,77975,77976,77977,67704,77979,77980,77981,77982,73164,77984,74348,64708,77987,77988,77989,77990,61932,77992,77993,77994,77995,77996,77997,77998,77999,78000,78001,78002,78003,78004,78005,78006,78007,61031,78009,78010,78011,78012,78013,78014,78015,78016,78017,78018,78019,78020,78021,78022,78023,78024,78025,78026,78027,78028,78029,78030,78031,78032,78033,78034,78035,78036,78037,78038,78039,78040,78041,78042,78043,78044,78045,78046,78047,78048,78049,78050,78051,78052,78053,78054,78055,78056,78057,78058,78059,78060,78061,78062,78063,78064,78065,78066,78067,78068,78069,78070,78071,78072,78073,78074,78075,78076,78077,78078,78079,78080,78081,78082,78083,78084,78085,78086,78087,78088,78089,62557,61713,78092,78093,78094,78095,62344,78097,78098,78099,78100,78101,78102,78103,78104,78105,78106,78107,78108,78109,73137,78111,64086,64976,78114,78115,78116,78117,71100,78119,78120,78121,78122,61235,78124,78125,78126,78127,78128,78129,78130,78131,74385,78133,78134,78135,78136,78137,78138,63222,78140,78141,78142,69796,61592,78145,78146,78147,72312,78149,78150,76152,78152,78153,78154,78155,78156,78157,77014,60892,78160,78161,78162,78163,78164,78165,78166,78167,78168,78169,60960,78171,78172,78173,78174,78175,74589,78177,78178,78179,78180,78181,78182,78183,78184,78185,63576,77858,78188,78189,78190,78191,77568,78193,78194,78195,63041,71125,78198,68287,78200,78201,78202,78203,78204,78205,78206,78207,75768,78209,78210,78211,78212,78213,78214,78215,75746,63788,78218,61192,78220,78221,78222,78223,77669,78225,78226,78227,78228,78229,78230,78231,78232,78233,78234,78235,78236,66533,78238,78239,78240,71045,69037,78243,76152,78245,78246,78247,78248,78249,78250,78251,78252,66407,78254,78255,78256,78257,78258,78259,78260,78261,78262,78263,62760,78265,68829,78267,78268,78269,78270,78271,78272,78273,78274,78275,78276,78277,63529,78279,78280,78281,73294,78283,78284,78285,78286,78287,72621,78289,78290,78291,78292,63006,78294,78295,78296,67680,70352,78299,78300,78301,78302,78303,61092,66281,78306,78307,78308,78309,78310,63208,78312,78313,65633,78315,64888,78317,78318,78319,78320,78321,64940,78323,78324,78325,78326,71767,78328,78329,78330,78331,76203,78333,78334,78335,78336,78337,63442,78339,78340,69829,78342,78343,78344,78345,61258,78347,61858,78349,72711,78351,78352,61655,78354,78355,78356,78357,78358,78359,66419,65769,78362,78363,78364,78365,78366,78367,78368,78369,78370,76088,78372,78373,64879,78375,78376,78377,74394,78379,78380,78381,78382,78383,78384,78385,72169,78387,78388,78389,78390,78391,78392,78393,78394,78395,78396,78397,78398,65323,68233,78401,78402,78403,77457,78405,72667,78407,78408,78409,78410,78411,78412,78413,78414,71116,78416,78417,64240,66852,78420,78421,78422,78423,78424,78425,61477,78427,78428,78429,78430,78431,78432,78433,78434,78435,78436,78437,61511,78439,78440,78441,78442,78443,62076,78445,78446,78447,78448,78449,78450,78451,78452,78453,73005,78455,78456,78457,78458,78459,78460,64300,78462,78463,78464,78465,78466,78467,78468,77446,65911,78471,78472,78473,78474,69009,78476,78477,78478,78479,61074,78481,78482,78483,78484,78485,69581,78487,78488,78489,78490,78491,78492,78493,78494,72110,78496,78497,61139,64919,62042,78501,78502,78503,78504,78505,78506,78507,78508,78509,78510,78511,78512,78513,78514,78515,78210,78517,78518,78519,78520,78521,73887,78523,78524,78525,78526,61240,78528,78529,78530,64396,78532,78533,66198,78535,78536,73543,78538,78539,78540,78541,78542,63799,78544,78545,78546,78547,71128,77073,78550,4415,78552,78553,78554,78555,78556,65363,78558,78559,78560,78561,78562,78563,78564,78565,61607,78567,78568,78569,78570,78571,78572,78573,78574,78575,60831,78577,74889,78579,78580,78581,78582,78583,60868,78585,78586,78587,78588,78589,78590,78591,63547,70741,78594,78595,78596,78597,78598,78599,78600,78601,67736,78603,78604,78605,78606,78607,78608,78609,78610,76088,78612,78613,62486,69500,78616,78617,78618,78619,78620,78621,78622,78623,78624,78625,78626,78627,78628,78629,63581,78631,78632,67541,78634,67650,67144,66609,78638,78639,78640,78641,78642,78643,74558,78645,78646,78647,78648,78649,78650,63125,64629,78653,61578,78655,61591,78657,75942,78659,78660,78661,78662,78663,78664,62087,78666,63351,78668,78669,78670,78671,78672,78673,78674,78675,60921,78677,72140,78679,78680,78681,78682,78683,78684,78685,78686,78687,78688,78689,78690,78691,74648,78693,78694,66853,78696,78697,78698,78699,78700,78701,78702,78703,78704,78705,61782,78707,78708,78709,78710,78711,78712,78713,78714,78715,78716,69001,78718,78719,78720,78721,61041,62153,78724,78725,78726,78727,78728,78729,78730,78731,78732,63154,78734,78735,78736,78737,78738,78739,68235,78741,78742,78743,78744,78745,78746,78747,66355,78749,78750,78751,78752,78753,74625,78755,78756,72111,65711,62171,78760,78761,78762,78763,78764,78765,78766,78767,73647,78769,78770,78771,78772,78773,78774,78775,78776,78777,78778,78779,78780,64109,78782,78783,78784,78785,78786,78787,76891,78789,78790,78791,78792,78793,78794,68698,78796,78797,78798,60909,78800,78801,78802,78803,78804,78805,78806,76329,78808,65778,78810,78811,78812,78813,78814,78815,78816,78817,61190,78819,78820,78821,78822,77100,78824,78825,78826,78827,78828,78829,78830,61717,78832,78833,78834,78835,78836,78837,78838,78839,78840,78841,78842,78843,78844,61100,78846,78847,78848,78849,78850,78851,78852,78853,78854,72112,61516,78857,78858,78859,78860,78861,61536,78863,78864,78865,78866,78867,78868,61113,78870,65447,78872,75790,66531,78875,78876,78877,67136,78879,78880,62070,78882,64564,78884,78885,78886,78887,78888,78889,78890,78891,63529,78893,78894,78895,75250,78897,78898,78899,71172,78901,78902,78903,78904,62119,74744,78907,78908,64953,78910,78911,78912,62040,78914,78915,78916,68769,78918,78919,78920,78921,62546,78923,78924,78925,78926,78927,78928,78929,78930,78931,78932,78933,78934,78935,78936,78937,78938,61182,78940,77493,68287,78943,78944,78945,78946,78947,61475,78949,78950,78951,78952,78953,78954,78955,78956,78957,67915,62891,78960,78961,78962,78963,78964,64503,78966,78967,78968,78969,78970,78971,78972,78973,78974,70924,78976,78977,78978,78979,78980,78981,78982,78983,74605,74239,78986,78987,78988,78989,78990,78991,78992,76056,64112,78995,78996,78997,78998,78999,64302,79001,79002,79003,79004,67212,79006,79007,79008,79009,79010,79011,79012,79013,79014,79015,61680,79017,67881,79019,79020,79021,79022,79023,69444,79025,79026,79027,79028,68329,79030,65051,63069,79033,79034,79035,68413,79037,79038,79039,79040,61808,79042,79043,79044,79045,79046,79047,79048,79049,65403,62033,74644,79053,79054,79055,79056,79057,79058,79059,79060,79061,79062,79063,72915,79065,79066,79067,79068,79069,79070,79071,61586,79073,79074,76996,79076,79077,79078,79079,73649,79081,79082,62245,79084,79085,79086,79087,74680,79089,79090,79091,68017,79093,79094,79095,79096,79097,79098,79099,79100,79101,79102,73177,79104,79105,79106,79107,79108,77992,79110,79111,79112,79113,79114,79115,79116,70998,63428,79119,79120,79121,79122,79123,63492,62896,79126,79127,79128,79129,79130,79131,79132,61196,79134,62519,79136,79137,79138,79139,62182,79141,79142,79143,79144,79145,79146,79147,70012,79149,79150,78111,79130,79153,79154,79155,67172,79157,79158,79159,79160,79161,79162,79163,79164,79165,79166,79167,79168,79169,79170,79171,79172,79173,79174,79175,73662,79177,79178,79179,79180,61642,68305,79183,79184,79185,79186,66681,79188,79189,77618,79191,79192,79193,79194,79195,79196,79197,79198,79199,79200,69488,79202,79203,79204,75750,62035,79207,79208,77881,79210,79211,79212,79213,79214,79215,79216,79217,79218,79219,79220,79221,79222,79223,79224,79225,79226,79227,64967,79229,79230,79231,79232,62626,79234,79235,79236,79237,70531,62627,79240,79241,79242,74029,79244,79245,79246,79247,79248,79249,79250,79251,79252,79253,79254,79255,68091,79257,79258,79259,79260,79261,79262,79263,67541,79265,79266,79267,79268,79269,72119,79271,79272,79273,62731,79275,79276,79277,79278,79279,79280,79281,79282,79283,79284,79285,79286,79287,79288,75237,79290,79291,79292,66420,63358,79295,79296,79297,79298,79299,79300,63759,79302,79303,79304,79305,74371,66495,79308,79309,79310,79311,79312,79313,79314,79315,73237,79317,69964,74378,79320,61102,79322,79323,79324,79325,77565,76777,79328,71126,79330,79331,62913,79333,79334,79335,79336,65743,79338,66786,79340,79341,64698,79343,79344,79345,79346,79347,79348,79349,62445,79351,79352,79353,79354,79355,79356,79357,79358,79359,79360,79361,79362,79363,67366,79365,79366,79367,79368,79369,79370,79371,79372,79373,61115,79375,79376,79377,79378,61073,79380,79381,73552,79383,79384,79385,79386,79387,79388,79389,79390,79391,79392,77662,79394,65822,79396,79397,61173,79399,61059,79401,66647,79403,79404,79405,79406,79407,79408,79409,79410,79411,79412,79413,79414,79415,79416,79417,74832,79419,79420,62022,79422,79423,79424,79425,79426,69213,79428,79429,74553,79431,72006,79433,79434,79435,79436,79437,61853,66287,79440,79441,71696,79443,79444,60847,79446,79447,79448,79449,61346,79451,79452,79453,79454,79455,62087,64150,79458,79459,79460,79461,79462,79463,79464,63547,79466,79467,62456,79469,79470,79471,79472,79473,79474,79475,79476,79477,79478,79479,79480,79481,79482,79483,79484,79485,79486,62516,79488,61186,79490,79491,79492,65188,79494,79495,79496,79497,79498,79499,79500,79501,79502,78698,79504,79505,79506,73130,79508,71125,79510,79511,79512,63970,79514,79515,79516,64381,79518,79519,79520,79521,70402,79523,79524,74446,79526,79527,79528,79529,79530,71933,79532,79533,79534,79535,79536,79537,61907,60921,79540,79541,79542,79543,63368,79545,79546,79547,79548,79549,74819,61189,67511,61825,74816,79555,79556,68429,78949,61991,63625,79561,79562,79563,79564,79565,79566,79567,68260,79569,73713,79571,79572,68902,79574,79575,77777,79577,79578,60773,79580,79581,79582,79583,79584,79585,79586,79587,79588,79589,79590,79591,79592,79593,79594,62754,79596,79597,79598,79599,62769,79601,79602,79603,79095,79605,79606,79607,79608,79609,79610,78677,60979,79613,79136,79615,79616,79617,79618,79619,79620,61024,79622,79623,79624,65573,79626,79627,79628,79629,79630,79631,79632,67650,79634,79635,79636,79637,79638,79639,79640,67247,79642,68651,79644,79645,79646,64771,62498,79649,79650,79651,79652,79653,79654,79655,79656,79657,79658,79659,62506,67968,79662,79663,79664,79665,79666,79667,79668,79669,79670,79671,79672,79673,79674,79675,79676,79677,79678,63096,74784,79681,79682,79683,79684,79685,64819,79687,79688,79689,79690,79691,65218,79693,79694,64833,79696,79697,79698,79699,79700,78677,77617,79703,79704,79705,79706,79707,79708,79709,79710,79711,79712,60992,79714,79715,79716,79717,79718,79719,63470,79721,73717,79723,79724,77100,79726,79727,64357,79729,79730,79731,79732,79733,79734,79735,67556,67420,79738,79739,79740,79741,79742,78953,79744,79745,79746,79747,61563,79749,79750,79751,79752,79753,79754,79755,61029,79757,79758,79759,79760,79761,79762,79763,79764,79765,79766,79767,61981,79769,79770,79771,79772,79773,79774,79775,73337,79777,79778,79779,79780,79781,79782,79783,63581,79785,79786,79787,79788,66747,62136,79791,79792,79793,79794,79795,79796,61260,79798,61857,79800,68003,79802,79803,79804,79805,79806,77022,69628,79541,79810,71835,66375,79813,72299,73327,79816,79817,79818,79819,79820,79821,61983,79823,79824,79825,79826,79827,61712,79829,79830,69703,79832,79833,79834,79835,79836,79837,79838,79839,79840,79841,79842,73211,79844,79845,79846,79847,66518,79849,79850,65029,79852,79853,79854,79855,79856,79857,79858,79859,62372,79861,79862,79863,79864,79865,79866,61798,79868,79869,69177,79871,65740,79873,79874,79875,62940,79877,79878,74071,79880,79881,79882,79883,79884,79885,61888,79887,79888,79889,79890,79891,60951,79893,79894,79895,79896,79897,75260,79899,79900,79901,79902,79903,79904,79905,79906,79907,79908,70536,76835,79911,79912,79913,79914,79915,79916,79917,79918,79919,67561,79921,79922,79923,79924,79925,79926,79927,79928,62367,73434,69964,78094,79933,61482,79935,79936,65617,79938,79939,79940,79941,79942,70542,79944,79945,79946,79947,68906,79949,79950,79951,79952,64541,79954,76670,79956,62939,79958,79959,79885,79961,64700,79963,79964,79965,79966,79967,79968,79969,79970,76073,79972,79973,79974,79975,79976,79977,79978,67080,79980,79981,79982,79983,79984,79985,73689,79987,79988,69109,79990,79991,61562,79993,79994,79995,79996,79997,79998,62157,80000,80001,80002,80003,80004,80005,62714,80007,80008,76192,80010,80011,80012,80013,80014,62307,80016,70485,80018,80019,70245,80021,68668,80023,80024,80025,80026,67135,80028,62236,80030,62425,80032,80033,80034,80035,63532,80037,80038,77988,63898,80041,77077,74534,61713,80045,80046,80047,80048,80049,80050,80051,80052,70928,80054,80055,80056,80057,63634,80059,64330,80061,80062,63939,80064,80065,80066,80067,80068,80069,80070,70298,80072,80073,80074,80075,80076,80077,80078,74604,63676,80081,80082,80083,69476,80085,80086,80087,80088,80089,80090,80091,80092,80093,80094,80095,80096,80097,80098,80099,80100,80101,80102,80103,80104,80105,67102,80107,80108,80109,80110,80111,70999,80113,71125,80115,63477,80117,80118,80119,80120,62508,80122,80123,80124,80125,80126,61849,80128,80129,80130,80131,72022,80133,62939,80135,80136,64683,80138,80139,80140,80141,80142,61933,80144,80145,80146,65912,80148,80149,80150,80151,80152,80153,80154,77541,80156,66826,80158,80159,80160,80161,73220,80163,80164,80165,70382,65554,80168,78640,66381,74533,64740,80173,80174,72248,80176,80177,80178,80179,80180,80181,80182,80183,80184,80185,80186,80187,80188,80189,63130,80191,60852,80193,80194,80195,80196,80197,80198,80199,80200,80201,80202,80203,80204,80205,80206,77691,80208,80209,80210,80211,80212,80213,80214,80215,80216,80217,62599,80219,80220,80221,80222,80223,80224,80225,61677,80227,80228,80229,80230,67887,80232,80233,80234,63383,80236,80237,80238,80239,80240,74939,80242,80243,80244,80245,80246,80247,80248,80249,63947,80251,80252,80253,72376,80255,80256,80257,80258,80259,80260,80261,80262,80263,77777,80265,80266,80267,80268,80269,80270,80271,80272,80273,80274,80275,72157,80277,80278,80279,80280,66110,80282,80283,80284,80285,80286,80287,80288,80289,73840,80291,62844,80293,80294,80295,80296,80297,80298,80299,80300,80301,80302,78097,80304,80305,80306,80307,80308,80309,80310,80311,61235,80313,80314,80315,80316,62068,80318,66015,80320,80321,80322,80323,62959,80325,80326,80327,80328,80329,80330,80331,80332,80333,71311,80335,80336,80337,80338,80339,80340,67354,80342,80343,61933,80345,80346,80347,80348,80349,80350,66921,80352,80353,80354,80355,80356,61803,62311,80359,80360,80361,80362,62183,80364,80365,80366,80367,80368,80369,80370,80371,80372,80373,64919,79723,80376,67781,80378,66216,80380,80381,80382,80383,80384,63128,67265,80387,80388,80389,80390,80391,77267,80393,80394,80395,80396,80397,80398,71224,80400,80401,80402,35786,80404,80405,80406,80407,80408,80409,80410,80411,80412,80413,80414,80415,80416,80417,80418,80419,80420,80421,80422,80423,80424,80425,80426,80427,80428,80429,80430,80431,80432,80433,80434,80435,80436,80437,80438,80439,80440,80441,80442,80443,80444,80445,80446,80447,80448,80449,80450,80451,80452,80453,80454,80455,80456,80457,80458,80459,80460,80461,80462,80463,80464,80465,80466,80467,80468,80469,80470,80471,80472,80473,80474,80475,80476,80477,80478,80479,80480,80481,80482,80483,80484,80485,80486,80487,80488,80489,80490,80491,80492,80493,80494,80495,80496,80497,80498,80499,80500,80501,80502,80503,80504,80505,80506,80507,80508,80509,80510,80511,80512,80513,80514,80515,80516,80517,80518,80519,80520,80521,80522,80523,80524,80525,80526,80527,80528,80529,80530,80531,80532,80533,80534,80535,80536,80537,80538,80539,80540,80541,80542,80475,80544,80545,80546,80547,80548,80549,80550,80551,80552,80553,80554,80555,80556,80557,80558,80559,80560,80561,80562,80563,80564,80565,80566,80567,80568,80569,80570,80571,80572,80573,80574,80575,80576,80577,80578,80579,80580,80581,80582,80583,80584,80585,80586,80587,80470,80589,80590,80591,80592,80593,80594,80595,80596,80597,80598,80599,80600,80601,80602,80603,80604,80605,80606,80607,80608,80609,80610,80611,80612,80613,80614,80615,80616,80617,80618,80619,80620,80621,80622,80623,80624,80625,80626,80627,80628,80629,80630,80631,80632,80633,80634,80635,80636,80637,80589,80639,80640,80641,80642,80643,80644,80645,80646,80647,80648,80649,80650,80651,80652,80653,80654,80655,80656,80657,80658,80659,80660,80661,80662,80663,80664,80665,80666,80667,80668,80669,80670,80671,80672,80673,80674,80675,80676,80462,80678,80679,80680,80681,80682,80683,80684,80685,80686,80687,80688,80689,80690,80691,80692,80693,80694,80695,80696,80697,80698,80699,80700,80445,80702,80703,80704,80705,80706,80707,80708,80709,80710,80711,80712,80713,80714,80715,80716,80717,80718,80719,80720,80721,80722,80723,80724,80725,80726,80727,80728,80729,80730,80731,80732,80733,80734,80735,80736,80737,80738,80739,80740,80741,80742,80743,80744,80745,80746,80747,80748,80749,80750,80751,80752,80753,80754,80755,80756,80757,80758,80759,80760,80761,80762,80763,80764,80765,80766,80767,80768,80769,80770,80771,80772,80773,80774,80775,80776,80777,80778,80779,80780,80781,80782,80783,80784,80785,80786,80787,80788,80789,80731,80791,80792,80793,80794,80795,80796,80797,80796,80799,80800,80801,80802,80803,80804,80805,80806,80807,80808,80809,80810,80811,80812,80813,80814,80815,80816,80817,80818,80819,80820,80821,80822,80823,80824,80825,80826,80827,80828,80829,80830,80831,80832,80833,80834,80835,80836,80837,80802,80839,80840,80841,80842,80843,80844,80845,80846,80847,80848,80849,80850,80851,80852,80853,80854,80855,80856,80857,80858,80859,80860,80861,80862,80863,80864,80865,80866,80867,80868,80869,80870,80871,80872,80873,80874,80875,80876,80877,80878,80879,80880,80881,80882,80726,80884,80885,80886,80887,80888,80889,80890,80891,80892,80893,80894,80895,80896,80897,80898,80899,80900,80901,80902,80903,80904,80905,80906,80907,80908,80909,80910,80911,80912,80913,80914,80915,80916,80917,80918,80919,80920,80921,80922,80923,80924,80925,80926,80927,80928,80929,80930,80931,80932,80933,80888,80935,80936,80937,80938,80939,80940,80941,80942,80943,80944,80945,80946,80947,80948,80949,80950,80951,80952,80953,80954,80955,80956,80957,80958,80959,80960,80961,80962,80963,80964,80963,80966,80967,80968,80969,80970,80971,80972,80973,80974,80975,80976,80977,80978,80979,80980,80981,80982,80983,80884,80985,80986,80987,80988,80989,80990,80991,80992,80993,80994,80995,80996,80997,80998,80999,81000,81001,81002,81003,81004,81005,81006,81007,81008,81009,81010,81011,81012,81013,81014,81015,81016,81017,81018,81019,81020,81021,81022,81023,81024,81019,81026,81027,81028,81029,81030,81031,81032,81033,81034,81035,81036,81037,81038,81039,81040,80440,81042,81043,81044,81045,81046,81047,81048,81049,81050,81051,81052,81053,81054,81055,81056,81057,81058,81059,81060,81061,81062,81063,81064,81065,81066,81067,81068,81069,81070,81071,81072,81073,81074,81075,81076,81077,81078,81079,81080,81081,81082,81083,81084,81085,81086,81087,81088,81089,81090,81091,81092,81093,81094,81095,81096,81097,81098,81099,81100,81101,81102,81103,81104,81105,81106,81107,81108,81109,81110,81111,81112,81113,81114,81115,81116,81117,81118,81119,81120,81121,81122,81123,81124,81125,81126,81127,81128,81129,81130,81131,81132,81133,81134,81135,81136,81137,81092,81139,81140,81141,81142,81143,81144,81145,81146,81147,81148,81149,81150,81151,81152,81153,81154,81155,81156,81157,81158,81159,81160,81161,81162,81163,81164,81165,81166,81167,81168,81169,81170,81171,81172,81173,81174,81175,81176,81076,81178,81179,81180,81181,81182,81183,81184,81185,81186,81187,81188,81189,81190,81191,81192,81193,81194,81195,81196,81197,81198,81199,81200,81201,81202,81203,81204,81205,81206,81207,81208,81209,81210,81211,81212,81213,81214,81215,81216,81217,81218,81219,81220,81221,81222,81223,81224,81225,81226,81227,81228,81229,81230,81071,81232,81233,81234,81235,81236,81237,81238,81239,81240,81241,81242,81243,81244,81245,81246,81247,81248,81249,81250,81251,81252,81253,81254,81255,81256,81257,81258,81259,81260,81261,81262,81263,81264,81265,81266,81267,81268,81269,81270,81271,81272,81273,81274,81275,81276,81277,81278,81279,81280,81281,81282,81046,81284,81285,81286,81287,81288,81289,81290,81291,81292,81293,81294,81295,81296,81297,81298,81299,81300,81301,81302,81303,81304,81305,81306,81307,81308,81309,81310,81311,81312,81313,81314,81315,81316,81317,81318,81319,81320,81321,81322,81323,81324,81325,81326,81327,81328,81329,81330,81331,81332,81333,81334,81335,81336,81337,81338,81339,81340,81341,81342,81343,81344,81345,81346,81347,81348,81349,81350,81351,81352,81353,81354,81355,81356,80424,81358,81359,81360,81361,81362,81363,81364,81365,81366,81367,81368,81369,81370,81371,81372,81373,81374,81375,81376,81377,81378,81379,81380,81381,81382,81383,81384,81385,81386,81387,81388,81389,81390,81391,81392,81393,81394,81395,81396,81397,81398,81399,81400,81401,81402,81403,81404,81405,81406,81407,81408,81409,81410,81411,81412,81413,81414,81415,81416,81417,81418,81419,81420,81421,81422,81423,81424,81425,81426,81427,81428,81429,81430,81431,81432,81433,81434,81435,81436,81437,81438,81439,81440,81441,81442,81443,81444,81445,81446,81447,81448,81449,81450,81451,81452,81453,81454,81455,81456,81397,81458,81459,81460,81461,81462,81463,81464,81465,81466,81467,81468,81469,81470,81471,81472,81473,81474,81475,81476,81477,81478,81479,81480,81481,81482,81483,81484,81485,81486,81487,81488,81489,81490,81491,81492,81493,81494,81495,81496,81497,81498,81499,81500,81501,81502,81503,81504,81505,81506,81507,81508,81372,81510,81511,81512,81513,81514,81515,81516,81517,81518,81519,81520,81521,81522,81523,81524,81525,81526,81527,81528,81529,81530,81531,81532,81533,81534,81535,81536,81537,81538,81539,81540,81541,81542,81543,81544,81545,81546,81547,81548,81549,81550,81551,81552,81553,81554,81555,81556,81557,81558,81559,81560,81561,81562,81563,81564,81565,81566,81567,81568,81569,81570,81571,81572,81573,81574,81367,81576,81577,81578,81579,81580,81581,81582,81583,81584,81585,81586,81587,81588,81589,81590,81591,81592,81593,81594,81595,81596,81597,81598,81599,81600,81601,81602,81603,81604,81605,81606,81607,81608,81609,81610,81611,81612,81613,81614,81615,81616,81617,81618,81619,81620,81621,81622,81605,81624,81625,81626,81627,81628,81629,81630,81631,81632,81633,81634,81635,81636,81637,81638,81639,81640,81641,81642,81643,81644,81645,81646,81647,81648,81649,81650,81651,81652,81653,81654,81655,81656,81657,81658,81659,81660,81661,81662,81663,81664,81665,81666,81580,81668,81669,81670,81671,81672,81673,81674,81675,81676,81677,81678,81679,81680,81681,81682,81683,81684,81685,81686,81687,81688,81689,81690,81691,81692,81693,81694,81695,81696,81697,81698,81699,81700,81701,81702,81703,81704,81705,81706,81707,81708,81709,81710,81711,81712,81713,81714,81715,81716,81717,81718,81719,81720,81721,81722,81723,81724,81725,81726,81727,81728,81729,81730,81731,81732,81733,81734,81735,81736,81737,81738,81739,81740,81741,81742,81743,80413,81745,81746,81747,81748,81749,81750,81751,81752,81753,81754,81755,81756,81757,81758,81759,81760,81761,81762,81763,81764,81765,81766,81767,81768,81769,81770,81771,81772,81773,81774,81775,81776,81777,81778,81779,81780,81781,81782,81783,81784,81785,81786,81787,81788,81789,81790,81791,81792,81793,81794,81795,81796,81797,81798,81799,81800,81801,81802,81803,81804,81805,81806,81807,81808,81809,81810,81811,81812,81813,81814,81815,81816,81817,81818,81819,81820,81754,81822,81823,81824,81825,81826,81827,81828,81829,81830,81831,81832,81833,81834,81835,81836,81837,81838,81839,81840,81841,81842,81843,81844,81845,81846,81847,81848,81849,81850,81851,81852,81853,81854,81855,81856,81857,81858,81859,81860,81861,81862,81863,81864,81865,81866,81867,81868,81869,81870,81871,81872,81873,81874,81875,81876,81877,81878,81879,81880,81881,81882,81883,81884,81885,81886,81887,81888,81889,81890,81891,81892,81893,81894,81895,81896,81897,81898,81899,81900,81901,81902,81903,81904,81905,81906,81907,81908,81909,81910,81911,81912,81913,81914,81846,81916,81917,81918,81919,81920,81921,81922,81923,81924,81925,81926,81927,81928,81929,81930,81931,81932,81933,81934,81935,81936,81937,81938,81939,81940,81941,81942,81943,81944,81945,81946,81947,81948,81949,81950,81951,81952,81953,81954,81749,81956,81957,81958,81959,81960,81961,81962,81963,81964,81965,81966,81967,81968,81969,81970,81971,81972,81973,81974,81975,81976,81977,81978,81979,81980,81981,81982,81983,81984,81985,81986,81987,81988,81989,81990,81991,81992,81993,81994,81995,81996,81997,81998,81999,82000,82001,82002,82003,82004,82005,82006,82007,82008,82009,82010,82011,82012,82013,82014,82015,82016,82017,82018,82019,82020,82021,82022,82023,82024,82025,82026,82027,82028,82029,82030,82031,82032,82033,82034,82035,82036,82037,82038,82039,82040,82041,82042,82043,82044,82043,82046,82047,82048,82049,82050,82051,82052,82053,81985,82055,82056,82057,82058,82059,82060,82061,82062,82063,82064,82065,82066,82067,82068,82069,82070,82071,82072,82073,82074,82075,82076,82077,82078,82079,82080,82081,82082,82083,82084,82085,82086,82087,82088,82089,82090,82091,82092,82093,82094,82059,82096,82097,82098,82099,82100,82101,82102,82103,82104,82105,82106,82107,82108,82109,82110,82111,82055,82113,82114,82115,82116,82117,82118,82119,82120,82121,82122,82123,82124,82125,82126,82127,82128,82129,82130,82131,82132,82133,82134,82135,82136,82137,82138,82139,82140,82141,82142,82143,82144,82145,82146,82147,82148,82149,82150,82116,82152,82153,82154,82155,82156,82157,82158,82159,82160,82161,82162,82163,82164,82165,82166,82167,82168,82169,82170,82171,82172,82173,82174,82175,82176,82177,82178,82179,82180,82181,82182,82183,82184,82185,82186,82187,82188,82189,82190,82191,82192,82193,82194,82195,81960,82197,82198,82199,82200,82201,82202,82203,82204,82205,82206,82207,82208,82209,82210,82211,82212,82213,82214,82215,82216,82217,82218,82219,82220,82221,82222,82223,82224,82225,82226,82227,82228,82229,82230,82231,82232,82233,82234,82235,82236,82237,82238,82239,82240,82241,82242,82243,82244,82245,82246,82247,82248,82249,82250,82251,82252,82253,82254,82255,82256,82257,82258,82259,82260,82261,82262,82263,82264,82263,82266,82267,82268,82269,82270,82271,82272,82273,82274,82275,82276,82277,82278,82279,82280,82281,82282,82283,82284,82285,82286,82287,82288,82289,82290,82291,82292,82293,82294,82226,82296,82297,82298,82299,82300,82301,82302,82303,82304,82305,82306,82307,82308,82309,82310,82311,82312,82313,82314,82315,82316,82317,82318,82319,82320,82321,82322,82323,82324,82325,82326,82327,82328,82329,82330,82331,82332,82333,82334,82335,82336,82337,82338,82339,82340,82341,82342,82343,82344,82345,82346,82347,82348,82349,82350,81745,82352,82353,82354,82355,82356,82357,82358,82359,82360,82361,82362,82363,82364,82365,82366,82367,82368,82369,82370,82371,82372,82373,82374,82375,82376,82377,82378,82379,82380,82381,82382,82383,82384,82385,82386,82387,82388,82389,82390,82391,82392,82393,82394,82395,82396,82397,82398,82399,82400,82401,82402,82403,82404,82405,82406,82407,82408,82409,82410,82411,82412,82413,82414,82415,82416,82417,82418,82419,82420,82421,82422,82423,82424,82425,82426,82427,82428,82429,82430,82431,82432,82433,82434,82435,82436,82437,82438,82439,82360,82441,82442,82443,82444,82445,82446,82447,82448,82449,82450,82451,82452,82453,82454,82455,82456,82457,82458,82459,82460,82461,82462,82463,82464,82465,82466,82467,82468,82469,82470,82471,82472,82473,82474,82475,82476,82477,82478,82479,82480,82481,82482,82483,82484,82485,82486,82487,82488,82489,82490,82491,82492,82493,82494,82495,82496,82497,82498,82499,82500,82501,82502,82503,82504,82505,82506,82507,82508,82509,82510,82511,82512,82513,82355,82515,82516,82517,82518,82519,82520,82521,82522,82523,82524,82525,82526,82527,82528,82529,82530,82531,82532,82533,82534,82535,82536,82537,82538,82539,82540,82541,82542,82543,82544,82545,82546,82547,82548,82549,82550,82551,82552,82553,82554,82555,82556,82557,82558,82559,82560,82561,82562,82563,82564,82565,82566,35786,82568,82569,82570,82571,82572,82573,82574,82575,82576,82577,82578,82579,82580,82581,82582,82583,82584,82585,82586,82587,82588,82589,82590,82591,82592,82593,82594,82595,82596,82597,82598,82599,82600,82601,82602,82603,82604,82605,82606,82607,82608,82609,82610,82611,82612,82613,82614,82615,82616,82617,82618,82619,82620,82621,82622,82623,82624,82625,82626,82627,82628,82629,82630,82631,82632,82633,82634,82635,35904,82637,82638,82639,82640,82641,82642,82643,82644,82645,82646,82647,82648,82649,82650,82651,82652,82653,82654,82655,82656,82657,82658,82659,82660,82661,82662,82663,82664,82665,82666,82667,82668,82669,82670,82671,82672,82673,82674,82675,82676,82677,82678,82679,82680,82681,82682,82683,82684,82685,82686,82687,82688,82689,82690,82691,82692,82693,82694,82695,82696,82697,82698,82699,82700,82701,82702,82703,82704,82705,82706,82707,82708,82709,82710,82711,82712,82713,82714,82715,82716,82717,82718,82719,82720,82721,82657,82723,82724,82725,82726,82727,82728,82729,82730,82731,82732,82733,82734,82735,82736,82737,82738,82739,82740,82741,82742,82743,82744,82745,82746,82747,82748,82749,82750,82751,82752,82753,82754,82755,82756,82757,82758,82759,82760,82761,82762,82763,82764,82765,82766,82767,82768,82769,82770,82771,82772,82773,82774,82775,82776,82777,82778,82779,82780,82781,82782,82783,82784,82785,82786,82787,82788,82789,82790,82791,82792,82793,82794,82795,82796,82797,82798,82799,82800,82801,82802,82803,82804,82805,82806,82807,82808,82809,82810,82811,82812,82813,82814,82815,82816,82817,82818,82819,82820,82821,82822,82823,82824,82825,82826,82827,82828,82646,82830,82831,82832,82833,82834,82835,82836,82837,82838,82839,82840,82841,82842,82843,82844,82845,82846,82847,82848,82849,82850,82851,82852,82853,82854,82855,82856,82857,82858,82859,82860,82861,82862,82863,82864,82865,82866,82867,82868,82869,82870,82871,82872,82873,82874,82875,82876,82877,82878,82879,82880,82881,82882,82883,82884,82885,82886,82887,82888,82889,82890,82891,82892,82893,82894,82895,82896,82897,82898,82899,82900,82901,82902,82903,82904,82905,82906,82907,82908,82909,82910,82911,82912,82913,82914,82915,82916,82917,82918,82919,82920,82921,82830,82923,82924,82925,82926,82927,82928,82929,82930,82931,82932,82933,82934,82935,82936,82937,82938,82939,82940,82941,82942,82943,82944,82945,82946,82947,82948,82949,82950,82951,82952,82953,82954,82955,82956,82957,82958,82959,82960,82961,82962,82963,82964,82965,82966,82967,82968,82969,82970,82971,82972,82973,82974,82975,82976,82977,82978,82979,82980,82981,82982,82983,82984,82985,82986,82987,82988,82989,82990,82991,82992,82993,744,10475,82996,82997,82998,82999,83000,83001,83002,83003,83004,83005,1106,83007,83008,83009,83010,83011,83012,83013,83014,83015,83016,83017,83018,83019,83020,83021,83022,83023,83024,83025,83026,83027,83028,83029,83030,83031,83032,83017,83034,83035,83036,83037,83038,83039,83040,83041,83042,83043,83044,83045,83046,83047,83048,83049,83050,83051,83052,83053,83054,83055,83056,83057,83058,83059,83060,83061,83062,83063,83064,83065,83066,83067,83045,83069,83070,83071,83072,83073,83074,83075,83076,83077,83078,83079,83080,83081,83082,83083,83084,83085,83086,83087,83088,83089,83090,83091,83092,83093,83070,83095,83096,83097,83098,83099,83100,83101,83102,83103,83104,83105,83106,83107,83108,83109,83110,83111,83112,83113,83114,83115,83116,83117,83118,83119,83120,83121,83122,83123,83124,83125,83126,83127,83128,83129,83130,83131,83132,83133,83134,83135,83136,83121,83138,83139,83140,83141,83142,83143,83144,83145,83146,83147,83148,83149,83150,83151,83152,83153,83154,83155,83143,83157,83158,83159,83160,83161,83162,83163,83164,83165,83166,83167,83168,83169,83170,83171,83172,83173,83174,83175,83176,83177,83178,83179,83180,83181,83182,83183,83184,83185,83186,83187,83188,83189,83164,83191,83192,83193,83194,83195,83196,83197,83198,83199,83200,83201,83202,83203,83204,83205,83206,83207,83208,83209,83210,83211,83212,83213,83214,83215,83216,83217,83218,83219,83220,83221,83212,83223,83224,83225,83226,83227,83228,83229,83230,83231,83232,83112,83234,83235,83236,83237,83238,83239,83240,83241,83242,83243,83244,83245,83246,83247,83248,83249,83250,83251,83252,83253,83250,83255,83256,83257,83258,83242,83260,83261,83262,83263,83264,83265,83266,83267,83268,83269,83270,83271,83272,83273,83274,83275,83276,83277,83278,83279,83280,83281,83282,83283,83284,83285,83286,83287,83270,83289,83290,83291,83292,83293,83294,83295,83296,83297,83298,83299,83300,83301,83302,83303,83304,83305,83306,83307,83308,83309,83310,83311,83312,83313,83261,83315,83316,83317,83318,83319,83320,83321,83322,83323,83324,83325,83326,83327,83236,83329,83330,83331,83332,83333,83334,83335,83336,83337,83338,83339,83244,83341,83342,83343,83344,83345,83346,83347,83348,83349,83350,83351,83352,83353,83354,83355,83356,83277,83358,83359,83360,83361,83362,83363,83364,83365,83366,83367,83368,83369,83370,83371,83372,83373,83374,83375,83291,83377,83378,83379,83380,83381,83382,83383,83384,83385,83386,83387,83388,83389,83390,83391,83392,83393,83394,83395,83396,83397,83273,83399,83400,83401,83402,83403,83404,83405,83406,83407,83408,83244,83410,83411,83412,83413,83414,83415,83416,83417,83418,83419,83347,83421,83422,83423,83424,83280,83426,83427,83428,83429,83430,83431,83432,83293,83434,83435,83436,83437,83438,83439,83440,83441,83442,83443,83444,83445,1049,83447,83448,4232,83450,83451,83452,83453,83454,83455,83456,83457,83458,83459,83460,83461,4232,83463,83464,83465,83466,83467,83468,83469,83470,83471,83472,83473,83474,83475,83476,83477,83478,83479,83480,83481,83482,83483,83484,83485,83486,83487,83488,83489,83490,83491,83492,83493,83494,83495,83496,83497,83498,83499,83500,83501,83502,83481,83504,83505,83506,83507,83508,83509,83510,83511,83512,83513,83514,83515,83516,83517,83518,83519,83520,83521,83522,83523,83524,83525,83526,83527,83528,83529,83530,83531,83517,83533,83534,83535,83536,83537,83538,83539,83540,83541,83542,83543,83544,83545,83546,83547,83548,83549,83550,83551,83552,83553,83554,83555,83556,83557,83558,83559,83560,83561,83562,83563,83564,83565,83566,83567,83568,83569,83570,83571,83572,83573,83574,83575,83576,83577,83578,83579,83580,83581,83582,83583,83558,83585,83586,83587,83588,83589,83590,83591,83592,83593,83594,83595,83596,83597,83598,83585,83600,83601,83602,83603,83604,83605,83606,83607,83608,83609,83610,83611,83612,83613,83614,83615,83616,83617,83618,83619,83620,83621,83622,83623,83624,83625,83626,83627,83628,83629,83630,83631,83632,83633,83634,83635,83610,83637,83638,83639,83640,83641,83642,83643,83644,83645,83646,83647,83648,83649,83650,83651,83652,83653,83654,83655,83656,83657,83658,83659,83660,83661,83662,83663,83664,83665,83666,83667,83550,83669,83670,83671,83672,83673,83674,83675,83676,83677,83678,83679,83680,83681,83682,83683,83684,83685,83686,83687,83688,83689,83690,83691,83692,83693,83694,83695,83696,83697,83698,83699,83700,83676,83702,83703,83704,83705,83706,83707,83708,83709,83710,83711,83712,83713,83714,83715,83716,83717,83718,83719,83720,83721,83722,83702,83724,83725,83726,83727,83728,83729,83730,83731,83732,83733,83734,83735,83736,83737,83738,83739,83740,83741,83742,83743,83744,83745,83746,83747,83748,83749,83750,83751,83752,83753,83754,83755,83756,83757,83758,83759,83734,83761,83762,83763,83764,83765,83766,83767,83768,83769,83770,83771,83772,83773,83774,83775,83776,83777,83778,83737,83780,83781,83782,83783,83784,83785,83786,83787,83788,83789,83704,83791,83792,83793,83794,83795,83796,83797,83798,83799,83714,83801,83802,83803,83804,83805,83806,83807,83808,83809,83810,83811,83812,83763,83814,83815,83816,83817,83818,83819,83820,83821,83822,83823,83824,83825,83826,83827,83828,83829,83772,83831,83832,83833,83834,83835,83836,83837,83838,83741,83840,83841,83842,83843,83844,83845,83846,83847,83848,83796,83850,83851,83852,83853,83854,83708,83856,83857,83858,83859,83860,83861,83862,83863,83864,83865,83763,83867,83868,83869,83870,83871,83872,83873,83874,83875,83876,4251,83878,267,83880,83881,83882,83883,83884,83885,83886,83887,83888,83889,60756,83891,83892,83893,83894,83895,83896,83897,83898,83899,83900,83901,83902,83903,83904,83905,83906,83907,83908,83909,83910,83911,83912,83913,83914,83915,83916,83917,83918,83919,83920,83921,83922,83923,83924,83925,83926,83927,83928,83929,83930,83931,83932,83933,83934,83935,83936,83937,83938,83939,83940,83927,83942,83943,83944,83945,83946,83947,83948,83949,83950,83951,83952,83953,83954,83955,83956,83957,83958,83959,83920,83961,83962,83963,83964,83965,83966,83967,83968,83969,83970,83971,83972,83973,83974,83975,83976,83977,83978,83979,83980,83981,83982,83983,83984,83985,83986,83987,83988,83989,83990,83991,83969,83993,83994,83995,83996,83997,83998,83999,84000,84001,84002,84003,84004,84005,84006,84007,83963,84009,84010,84011,84012,84013,84014,84015,84016,84017,84018,84019,84020,84021,84022,84023,84024,84025,84026,84027,84028,84029,83900,84031,84032,84033,84034,84035,84036,84037,84038,84039,84040,84041,84042,84043,84044,84045,84046,84047,84048,84049,84050,84051,84052,84053,84054,84055,84056,84057,84058,84059,84060,84061,84062,84063,84064,84065,84066,84067,84068,84069,84070,84071,84072,84073,84074,84050,84076,84077,84078,84079,84080,84081,84082,84083,84084,84085,84086,84087,84088,84089,84090,84091,84092,84093,84094,84086,84096,84097,84098,84099,84100,84101,84102,84103,84104,84105,84106,84107,84108,84109,84110,84111,84112,84113,84114,84115,84116,84117,84118,84119,84120,84121,84122,84123,84124,84083,84126,84127,84128,84129,84130,84131,84132,84133,84134,84135,84136,84137,84138,84139,84140,84141,84142,84143,84144,84145,84146,84147,84148,84126,84150,84151,84152,84153,84033,84155,84156,84157,84158,84159,84160,84161,84162,84163,84164,84078,84166,84167,84168,84169,84170,84171,84172,84173,84174,84175,84176,84146,84178,84179,84180,84181,84182,84183,84184,84185,84186,84187,84188,84151,84190,84191,84192,84193,84194,84195,84196,84197,84198,84199,84200,84201,84202,84203,84204,84205,84206,84036,84208,84078,84210,84211,84212,84213,84214,84215,84216,84217,84184,84219,84220,84221,84222,84223,84224,84225,84226,84227,84228,84229,84230,84231,84232,84233,84234,84235,84236,84237,84238,84239,84196,84241,84242,84243,84244,84245,84246,84247,84248,84249,84250,84251,84252,84253,84254,84255,84256,84038,84258,84259,84260,84261,84262,84263,84264,84265,84266,84267,84268,84269,84270,84271,84272,84273,84274,84275,84276,84277,84089,84279,84280,84281,84282,84283,84284,84285,84286,84146,84288,84289,84290,84291,84292,84293,84294,84295,84296,84297,84298,84299,84300,84301,84302,84303,84304,84305,84306,84307,84308,84309,84310,84311,84312,84313,84252,84315,84316,84317,84318,84319,84320,84321,84322,84323,84324,84325,84326,84327,84328,84329,84330,84331,84332,84333,84334,84335,84336,84337,84268,84339,84340,84341,84342,84343,84344,84345,84346,84285,84348,84349,84350,84351,84352,84353,84129,84355,84356,84357,84322,84359,84360,84361,84362,84363,84364,84365,84366,84367,228,84369,84370,84371,84372,84373,84374,84375,84376,84377,84378,84379,84380,84381,84382,84383,84384,84385,84386,84387,280,84389,84390,84391,84392,84393,84394,84395,84396,84397,84398,84399,84400,4,84402,84403,84404,84405,4,84407,84408,84409,84410,84409,84412,84413,84414,84415,84416,84409,84409,84419,84409,84421,84422,84409,84424,84409,84426,84427,84428,84429,84429,84424,84432,84409,84434,84409,84421,84437,84438,84439,84440,84409,84442,84443,84444,84415,84446,84412,84448,84449,84450,84451,84452,84421,84454,84455,84456,84421,84458,84459,84460,84461,84462,84412,84464,84465,84466,84467,84468,84421,84470,84471,84421,84473,84474,84475,84476,84477,84422,84412,84480,84481,84482,84460,84484,84485,84456,84487,84488,84409,84490,84491,84492,84480,84461,84495,84458,84484,84498,84499,84500,84501,84502,84503,84504,84505,84409,84507,84480,84409,84510,84511,84467,84513,84409,84515,84516,84517,84518,84519,84520,84521,84522,84412,84524,84525,84526,84527,84528,84529,84413,84422,84532,84533,84534,84535,84536,84537,84444,84412,84473,84474,84542,84543,84544,84533,84546,84547,84548,84549,84550,84412,84552,84553,84554,84555,84556,84557,84558,84559,84560,84561,84442,84409,84409,84565,84444,84434,84516,84569,84570,84571,84409,84573,84409,84414,84412,84577,84409,84579,84422,84466,84421,84409,84577,84585,84473,84587,84588,84589,84480,84591,84432,84485,84594,84595,84596,84597,84598,84599,84600,84409,84602,84603,84546,84605,84606,84607,84608,84609,84610,84611,84612,84613,84614,84615,84616,84424,84618,84597,84421,84448,84459,84409,84624,84625,84565,84412,84628,84629,84630,84631,84632,84573,84510,84464,84565,84482,84507,84434,84640,84524,84642,84643,84644,84645,84646,84460,84510,84409,84650,84466,84652,84653,84654,84655,84656,84657,84658,84659,84660,84450,84662,84663,84664,84665,84666,84667,84668,84669,84670,84671,84672,84673,84674,84675,84676,84677,84678,84679,84680,84681,84682,84683,84684,84685,84686,84687,84688,84689,84587,84691,84692,84693,84694,84524,84696,84697,84409,84409,84466,84603,84603,84412,84427,84507,84449,84707,84708,84709,84710,84711,84712,84713,84602,84422,84716,84717,84718,84414,84720,84721,84448,84723,84724,84725,84421,84727,84728,84729,84473,84731,84732,84733,84696,84735,84470,84737,84738,84739,84548,84741,84742,84743,84744,84745,84746,84747,84511,84602,84409,84751,84752,84753,84754,84755,84465,84757,84758,84759,84760,84761,84603,84427,84764,84681,84602,84767,84464,84628,84770,84771,84772,84432,84470,84775,84776,84777,84778,84779,84454,84781,84782,84413,84784,84785,84428,84587,84788,84464,84790,84791,84792,84515,84794,84795,84796,84533,84480,84491,84800,84473,84802,84803,84804,84471,84806,84510,84412,84809,84810,84811,84525,84813,84814,84815,84816,84817,84818,84535,84645,84546,84822,84409,84470,84825,84826,84827,84428,84829,84480,84424,84832,84532,84834,84835,84836,84837,84838,84421,84840,84841,84427,84424,84707,84845,84846,84847,84848,84849,84850,84851,84852,84853,84854,84855,84856,84857,84409,84548,84860,84697,84466,84863,84532,84421,84866,84498,84868,84869,84870,84871,84872,84758,84640,84459,84602,84413,84878,84784,84458,84881,84882,84883,84412,84532,84413,84887,84888,84889,84890,84891,84421,84428,84603,84731,84896,84507,84898,84421,84459,84813,84745,84460,84534,84905,84480,84907,84908,84909,84910,84911,84912,84913,84914,84448,84464,84838,84918,84710,84920,84909,84922,84923,84924,84524,84415,84547,84664,84929,84930,84931,84442,84933,84731,84935,84468,84409,84866,84887,84940,84434,84474,84943,84944,84945,84565,84947,84948,84949,84434,84813,84952,84953,84409,84409,84956,84757,84958,84959,84960,84961,84443,84490,84964,84965,84966,84967,84968,84495,84970,84971,84484,84973,84974,84975,84409,84977,84978,84979,84980,84981,84982,84909,84984,84794,84986,84987,84988,84642,84990,84426,84866,84993,84994,84995,84996,84997,84998,84999,85000,85001,84646,84909,85004,85005,85006,84471,85008,85009,85010,85011,85012,85013,85014,84491,84510,84524,85018,85019,85020,84794,85022,85023,84890,85025,84642,85027,85028,85029,85030,85031,84732,84471,85034,84424,85036,84909,85038,85039,85040,84642,85042,84454,85044,85045,85046,85047,85048,85049,84910,85051,85052,84988,85054,84504,85056,85057,84465,84896,85060,85061,85062,84449,85008,85065,84999,85044,85068,85069,85070,84454,85072,85068,85074,85075,84495,84547,84474,85079,85080,85081,84781,85083,85084,84459,85086,85087,85088,85089,84579,85091,84653,85054,85094,84455,85096,85042,84458,85099,84595,84424,84424,84462,84965,85105,85106,85107,84521,85109,85110,85111,84986,85113,84986,84733,84602,84654,85118,85119,84491,85121,84652,85123,85124,85125,84516,84662,84424,84455,85130,84524,84944,85133,85134,85135,84546,84656,85138,85139,85140,85141,85142,85143,84468,85145,85146,84516,85148,85149,85150,84767,84845,84603,84491,85155,85156,85157,84758,85046,85160,85161,85162,84888,85164,85165,85166,85167,85168,85169,84409,85171,84474,85173,85173,84448,84840,85177,85178,85179,85180,84988,84965,85183,85184,85185,84424,85187,85188,84467,85190,84510,84516,85193,85194,85195,85196,85086,85198,85199,85200,85201,85202,85203,85204,85205,85206,85207,85208,85209,84492,84409,84442,84533,84443,84923,85029,84735,84452,85219,85220,84645,85222,85223,85188,85046,85226,85227,84958,85229,85230,85231,85232,85233,85234,84958,85236,85237,85238,85239,85240,84421,85242,84473,85244,85245,85246,85247,85177,84579,85250,85251,85252,85253,84409,84412,85256,85257,84565,84515,84510,85261,85262,84691,85264,84421,84426,84482,85268,85269,84451,85271,84770,85273,85274,85275,85276,85277,85278,85279,84534,85281,84413,85283,85284,84751,84995,85287,85028,85289,84840,85291,84487,85293,84987,85295,85148,85297,85298,84510,84429,85145,84659,84977,85304,85305,84412,84412,85308,85309,85310,85311,84424,85313,85030,84532,85316,85130,84452,84412,85320,85321,84524,85123,85324,85325,85326,85327,85328,84753,85330,84515,84697,84990,85334,85335,84458,85150,85338,85339,85340,85341,85342,85343,85344,85345,85346,85347,84697,85273,85350,85351,85352,84911,85354,84978,85356,85357,85358,85359,85069,84461,85362,84500,84475,85365,85366,84958,84437,85369,85370,85371,85372,84492,84784,85375,85376,85377,84515,84481,85380,84599,85382,85383,85384,84522,85386,85387,85388,85389,85390,85391,84923,85393,85394,85268,85396,84409,84526,84451,85400,85237,85402,85403,85404,85405,85406,85407,85408,84646,85410,84409,84432,84412,85396,84465,84516,85417,84424,85087,85420,85421,85422,85423,85424,85029,85426,85427,84642,85429,85430,85431,84758,84645,85434,85435,85088,85437,85438,85439,85440,85145,85442,84987,85444,84490,85446,85447,85448,84456,84481,85451,84475,85250,84980,85455,84656,84421,85237,85459,85460,85461,85462,84412,84794,84888,85466,84409,85468,85145,85304,85471,85472,85473,85474,85475,84979,85477,85478,85479,85480,85481,84432,84421,85484,85485,85486,85487,85488,85489,84476,84554,85492,84448,84988,85495,85496,85497,85498,84587,85500,85501,84477,85250,84907,85505,85506,85507,85508,85509,85510,84534,85512,85284,85514,85515,85516,84888,85518,85519,85369,84988,85522,85523,85524,85525,84599,84524,85268,85529,85229,85531,85532,85533,85534,84428,85536,85133,84518,84421,84965,85541,85542,85543,85344,85545,84866,84442,85548,85298,85550,85551,85552,85553,84652,84754,85556,84454,84827,85559,85560,84432,84775,84451,85564,84652,84587,85567,85568,85569,85570,85571,84543,85573,85574,85575,85576,85335,85365,85579,85400,85406,85582,85583,85584,85573,84697,84602,85588,85589,85590,85089,84628,85593,85594,85595,85596,85597,85598,84460,85600,85601,85602,85603,84474,85605,85606,85607,84414,85609,85610,85611,84887,85335,84990,85615,85616,84535,85618,84597,85468,85621,84437,85250,85624,85625,85626,84461,85628,85268,84434,85030,85632,85633,84480,85030,85636,85637,85638,84535,84909,84428,85642,85643,85644,85057,85646,85647,85648,85649,84443,85651,85652,85653,85297,85655,84579,84468,85658,84644,85660,85380,84944,85054,85664,85665,85666,84602,84485,85669,85046,85671,85672,85673,84409,85556,85676,84970,85678,85679,85680,84646,85682,85683,85684,84424,84654,85222,84448,85689,84510,84487,85692,85693,85694,84502,84565,84424,85698,85028,85700,84646,85702,85703,84525,85705,84424,84458,84587,85709,85710,85711,84510,85713,85714,85715,84460,85459,85072,85573,85237,85155,84624,85171,85556,84434,84434,85148,85698,85729,85730,84967,85732,84412,84428,84986,84473,85573,85738,85739,84421,84473,84602,85743,84421,84421,84412,84409,84628,85749,85750,85751,85752,85753,85754,85755,85756,85757,85758,85759,85760,85008,85762,85763,85764,84495,85766,85767,85768,84533,85770,85771,84473,84834,84432,85149,85776,85777,85778,85779,85780,85781,85782,84958,84409,84480,84697,84549,85788,85789,85790,84970,85618,85618,85794,85795,85796,84409,84987,85799,84655,85801,84495,85803,85804,84513,85442,84654,84424,85133,85810,85811,84696,84517,85814,85815,85816,85817,85818,85819,85820,85821,85822,85823,85824,85825,84488,84409,84448,85829,85618,85831,85815,85833,85834,85835,85836,85837,85838,85839,85840,85841,84482,84995,85844,85845,85846,85847,85848,84510,84544,85219,84475,85853,85854,85423,85856,84487,85858,85655,85660,85113,85862,84657,84697,84448,84428,85867,84415,85869,85870,85871,84658,84474,85874,84532,84438,85478,85878,84491,85369,85881,85882,85883,85884,85885,85472,85887,84450,85810,85890,85891,85892,85262,84953,85145,85054,85897,85898,84412,84967,85901,85902,85903,85904,84499,85906,85907,84979,85909,85910,85911,85271,85047,85914,85915,84847,85430,85918,84565,84565,84490,84464,84409,84944,85925,85874,85155,85928,85929,85930,85931,85008,85933,85934,85935,85936,85937,85938,85328,85940,84424,84993,85943,85944,85945,85946,85947,85948,85949,84565,84834,85404,85134,85925,85382,84548,84535,85958,85959,85034,85961,85962,85963,85236,84751,85966,85738,85268,85969,85970,85971,85334,85973,84426,85975,85976,85977,85978,84466,85980,85935,85982,84986,85984,85985,85986,85338,85988,85989,85990,85991,85992,85993,85994,85995,85996,85997,85998,85999,84602,86001,86002,84434,84424,85038,86006,86007,86008,86009,84409,84439,84524,84451,85375,86015,86016,86017,84444,84465,86020,86021,86022,85472,86024,86025,84498,85155,85471,86029,86030,86031,86032,84794,86034,86035,86036,84409,85750,86039,86040,86041,86042,86043,86044,85810,84526,84599,84644,86049,84956,85980,86052,84652,85045,86055,86056,86057,86058,85856,86060,86061,86062,86063,85518,86065,86066,86067,86068,86069,86070,85766,86072,86073,86074,84995,84511,85382,84480,85177,86080,84775,86082,86083,86084,86085,86086,86087,85022,84981,86090,86091,86092,86093,84606,85048,84533,84573,84826,84524,84449,85615,86102,86103,86104,84422,84434,85991,86108,86109,84438,86111,86112,86113,86114,85304,86116,84485,84644,86119,85009,86121,86122,84525,85298,86125,84977,85738,86128,86042,86130,86131,85029,85298,84535,85304,86111,86137,86138,86139,86140,86141,84654,84424,84834,84775,86146,86147,86148,85056,84602,86151,84602,85789,86154,86155,86156,86157,86158,86159,86160,86161,86162,86163,86164,84747,86166,86167,86168,84426,86170,86171,84414,84454,84448,84628,86176,86177,84565,86179,84442,86181,86182,86183,84739,84449,84424,86187,86121,86189,86190,86191,86192,86193,84594,84546,85978,86049,84465,84587,86200,86201,86202,84988,85145,86205,86206,86207,84434,84664,86210,86211,86212,86213,84450,86215,85698,84662,86218,84481,85906,86221,86222,86223,86224,86225,86226,86227,86228,86229,86230,85402,84464,86233,84826,84456,86236,85738,86238,86239,86240,84986,85250,86243,86244,86245,85155,85334,85803,86249,86250,86251,84482,84455,86254,84510,85335,86119,84434,84466,84618,85883,86262,86263,86264,86265,86266,86267,86268,86269,85550,85426,86272,86273,86274,84628,86276,86277,86278,84977,84888,84424,85261,86283,86284,86285,85564,84454,85256,86289,86290,86291,86292,86293,85710,85824,84993,85402,85320,86299,86300,86049,85943,86303,86304,85121,84840,84662,84510,85976,84986,86311,84596,86313,86314,86315,84434,84455,84665,84655,84464,86315,86322,86323,84548,86325,84482,86327,86328,86329,86330,85250,84424,84475,84526,86335,86336,85321,86338,86339,86340,85396,86190,86343,86344,86345,86346,86347,84977,84475,85814,86351,86352,86353,86354,86355,86356,86357,84834,86359,86360,86361,84458,84487,84656,84476,86366,84533,85156,86369,86370,86371,84480,84507,84660,85139,86376,85297,86378,84708,84415,85655,86254,85375,86384,84594,86386,84510,85365,86389,86218,86391,85751,86393,86394,86395,86396,86397,86398,86399,86400,86401,86402,86403,84510,84660,86406,86407,86408,86409,86410,86411,84464,84475,85119,84696,84448,85219,86418,86419,86420,85334,86422,86423,86424,85383,86190,84605,86428,84795,86430,84412,86029,86433,86434,86435,85273,86437,86438,86439,86440,85087,84940,86443,85298,85867,84442,86447,86448,84532,85009,86451,84565,85257,86454,86455,86456,86111,86458,86459,84504,84421,84825,84565,84532,84565,84473,84761,86468,86469,86470,86471,86472,85198,84784,84467,86476,84524,85289,85847,86480,86481,86482,86483,86484,86485,86486,84764,85118,86489,86490,86491,86492,86299,85471,86495,86496,85201,84646,85426,86500,85156,85156,86503,84511,84473,84443,84458,84424,85574,86510,86511,86512,84659,86514,85001,86516,86391,84428,86519,86520,86521,84905,85958,86524,86525,86526,85166,86528,86529,86530,86531,84409,86533,84990,84887,86536,85034,86265,86539,86540,85522,86542,86543,86544,86062,84466,86547,84691,84454,84414,85698,84412,86492,86554,86555,85709,84480,86558,86559,86560,84443,86562,84532,84458,85471,85574,86567,84408,86569,86570,86571,86572,86573,84408,86575],"frame":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,23,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,71,73,74,66,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,23,90,91,61,92,93,94,67,68,69,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,99,111,112,99,113,101,114,115,116,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,130,100,122,123,124,125,126,127,128,129,131,132,133,123,134,101,102,103,104,135,136,137,138,139,140,141,142,143,144,125,126,145,146,147,148,149,150,151,152,153,154,135,136,137,138,139,136,137,138,155,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,160,161,101,162,163,164,165,166,167,168,169,170,171,172,173,174,161,101,162,163,164,165,175,176,177,169,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,113,122,123,124,125,126,197,198,199,200,201,202,203,204,205,206,207,208,209,210,128,129,211,212,213,214,215,121,109,110,99,111,112,99,161,216,217,218,219,220,110,99,111,112,99,100,221,222,223,224,101,225,226,120,121,109,110,99,111,112,117,113,227,123,124,125,126,228,229,230,146,231,232,233,190,234,235,201,202,236,204,175,176,177,169,237,238,184,185,186,239,185,186,240,188,189,241,185,242,243,244,175,176,177,169,237,238,184,185,186,241,185,186,239,185,186,190,245,246,247,206,207,208,209,210,128,129,131,248,152,249,250,101,225,226,120,121,109,213,214,215,121,109,110,99,111,112,99,161,101,251,252,253,254,255,216,217,218,219,220,110,99,111,112,117,100,101,225,226,120,121,109,110,99,111,112,99,100,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,258,259,260,261,262,263,264,265,266,267,268,269,270,270,271,270,270,270,270,272,69,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,276,179,147,277,278,279,280,281,281,280,282,283,284,285,286,104,135,136,137,138,287,288,117,100,101,225,226,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,159,128,129,131,290,121,109,110,99,111,112,99,100,101,102,103,291,292,293,294,295,296,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,297,298,299,201,202,256,257,99,111,112,117,113,227,123,124,125,126,228,178,179,300,301,302,303,304,303,304,303,305,303,306,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,205,101,102,103,104,135,136,137,138,139,140,307,308,309,113,101,114,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,231,232,311,181,312,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,313,314,315,316,317,318,319,320,193,194,321,101,114,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,322,323,99,113,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,292,324,253,68,325,326,327,99,111,112,99,161,328,329,101,114,119,120,121,109,110,99,111,112,99,100,101,330,252,253,68,331,161,101,330,332,333,334,335,336,337,44,45,338,258,339,340,341,342,343,344,175,176,177,316,317,345,172,346,319,347,348,349,350,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,127,128,129,211,212,326,327,99,111,112,99,161,328,329,101,114,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,352,353,146,346,319,354,328,329,227,123,124,125,126,145,146,147,355,356,357,358,359,359,360,350,243,244,361,362,101,225,226,120,121,109,363,364,365,366,225,226,120,121,367,368,369,370,371,372,373,374,375,376,377,378,313,314,315,379,169,380,381,227,123,124,125,126,228,178,179,382,355,383,384,385,386,225,226,120,289,109,110,99,111,112,99,201,202,243,244,175,387,206,207,208,388,389,179,390,391,392,328,393,394,395,396,397,398,225,226,120,121,367,368,399,400,179,382,401,383,402,358,360,403,404,405,406,407,408,135,136,137,138,139,409,101,251,332,333,410,335,411,412,413,109,110,99,111,112,117,113,414,415,416,244,175,176,177,169,417,333,334,418,419,101,283,284,420,421,422,423,424,425,426,427,428,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,374,178,179,382,148,429,149,430,431,161,328,393,394,395,396,432,433,434,320,435,99,113,101,102,103,291,297,436,437,438,439,440,441,442,161,101,225,226,120,121,109,110,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,367,368,369,400,179,382,401,443,444,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,400,179,382,148,445,149,150,446,447,447,448,156,157,216,449,439,450,451,452,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,453,319,454,455,455,456,455,455,457,203,204,458,459,169,460,179,147,461,462,463,69,243,244,247,101,464,251,465,295,466,102,103,467,291,297,468,299,243,244,313,314,315,169,237,238,184,185,186,190,469,470,471,326,327,99,111,112,99,161,328,329,101,472,157,473,474,475,179,346,476,477,478,479,480,481,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,482,483,484,485,486,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,492,172,382,148,429,429,445,493,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,390,391,494,495,496,497,498,499,117,201,202,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,445,429,429,445,445,501,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,500,146,147,401,383,502,503,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,276,179,390,391,494,495,505,496,496,295,506,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,352,353,146,147,148,429,445,149,279,280,281,281,280,507,99,113,414,415,487,206,488,489,490,227,123,124,125,508,317,345,509,172,382,510,278,511,446,447,447,512,69,99,113,101,472,157,473,474,475,179,147,513,514,515,516,517,203,204,458,459,169,460,179,147,518,519,520,521,522,523,44,45,524,525,225,226,120,121,367,368,399,400,179,382,401,383,526,527,367,368,399,400,179,346,319,454,455,528,515,516,529,167,168,169,178,179,382,148,445,429,530,393,394,395,396,531,146,147,532,533,534,535,536,537,538,538,537,539,166,167,168,169,460,179,346,540,541,328,329,101,472,157,489,490,216,542,543,544,113,101,225,226,120,121,367,368,399,400,179,382,355,383,526,545,546,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,401,356,402,302,303,305,303,304,303,305,303,305,303,548,549,550,551,197,145,146,147,148,429,429,552,258,259,260,261,262,263,264,553,439,266,267,554,555,547,172,382,401,356,556,557,558,557,559,560,561,178,179,382,510,278,562,280,563,564,565,566,567,568,569,532,514,570,571,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,547,172,382,510,573,574,575,576,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,580,345,172,346,319,347,581,582,127,128,129,211,583,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,547,587,434,347,581,455,348,455,455,455,588,589,590,429,149,591,150,446,592,592,447,447,593,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,460,179,147,597,402,302,303,598,472,157,473,474,475,179,147,513,533,599,228,352,600,172,382,601,602,603,603,602,603,602,603,604,374,352,353,146,147,148,149,562,280,281,280,281,280,281,605,472,157,473,474,475,179,180,606,607,608,609,169,460,179,147,461,445,445,445,445,445,149,150,446,512,549,610,145,146,147,355,383,534,535,611,537,538,538,538,538,537,537,612,613,614,615,616,496,497,498,617,618,361,619,620,169,352,621,146,147,355,383,383,384,558,622,500,146,147,148,429,429,429,429,429,445,445,445,149,623,100,101,624,625,626,627,628,146,147,510,573,629,190,630,300,301,302,303,304,631,632,54,55,633,228,352,600,172,382,401,383,502,634,611,538,537,538,538,537,537,538,635,149,150,446,447,447,592,636,637,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,638,169,639,640,427,428,99,111,112,99,201,202,427,428,99,111,112,117,161,101,225,226,120,121,367,368,399,641,642,434,347,348,643,582,109,110,99,111,112,117,201,202,203,204,584,585,222,223,224,644,222,223,645,646,647,648,649,650,651,603,602,603,602,603,602,603,602,603,602,603,561,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,178,179,382,401,356,502,634,536,538,537,652,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,472,157,473,474,475,179,147,589,653,570,571,117,201,202,203,204,458,459,169,460,179,147,597,556,654,557,558,557,558,557,557,557,558,557,557,557,558,557,558,557,655,225,226,120,121,367,368,399,641,656,657,658,616,497,659,660,113,101,472,157,473,474,475,179,147,532,526,545,661,243,244,166,167,662,169,178,179,382,401,383,402,383,502,634,537,611,537,537,663,664,326,327,99,111,112,99,161,328,393,572,489,665,666,667,668,439,669,179,382,518,384,654,557,557,557,558,557,558,557,557,557,563,225,226,120,121,367,368,399,400,179,147,148,445,670,545,671,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,148,149,591,672,280,281,280,281,280,281,280,673,329,122,123,124,125,491,374,352,353,146,147,148,429,445,149,279,280,281,280,281,280,281,280,281,280,674,205,675,676,677,678,146,147,601,679,225,226,120,121,109,110,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,102,103,104,135,136,137,138,139,140,141,680,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,662,169,178,179,382,148,445,445,445,149,150,446,447,447,681,326,327,99,111,112,99,161,328,329,122,123,124,125,491,145,146,147,148,429,149,511,446,592,682,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,127,128,129,683,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,460,179,147,597,556,654,557,558,557,558,557,557,557,558,557,558,557,558,684,367,368,399,613,685,434,454,686,435,161,101,102,154,135,136,137,138,139,136,137,138,139,140,141,680,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,687,688,495,689,496,690,691,692,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,148,429,429,429,445,445,429,149,591,693,99,113,414,415,694,204,594,595,596,379,169,178,179,346,319,454,455,695,99,113,101,225,226,120,121,367,368,399,400,179,382,510,696,697,698,393,394,395,396,699,172,382,532,700,534,535,536,701,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,702,580,703,704,705,706,707,99,111,112,99,113,227,564,133,123,124,125,508,317,703,146,346,319,454,348,456,455,686,549,708,201,202,326,327,99,201,202,326,327,99,111,112,99,161,328,329,227,123,124,125,491,492,172,382,148,445,429,445,149,150,446,447,592,636,435,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,709,60,61,710,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,148,149,279,280,281,281,281,280,281,711,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,510,712,278,591,150,446,592,512,713,117,201,202,427,428,99,111,112,117,113,101,472,157,473,474,475,179,382,513,526,545,714,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,609,169,178,179,382,401,383,402,302,303,304,303,304,303,304,303,548,331,326,327,99,111,112,99,161,328,329,122,123,124,125,491,145,146,147,148,445,429,429,445,149,150,446,447,447,512,435,225,226,120,121,367,368,399,400,179,382,401,383,514,570,516,715,716,717,718,719,718,720,718,721,718,721,722,403,374,352,353,146,147,355,383,384,654,557,557,557,557,557,558,557,558,692,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,178,179,147,148,149,150,446,447,636,69,99,113,101,225,226,120,121,367,368,399,453,476,477,478,723,724,393,572,489,665,666,667,725,439,266,267,268,726,403,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,727,434,454,728,549,729,472,157,489,665,666,667,730,731,268,732,733,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,352,353,727,434,347,734,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,665,735,489,665,735,216,736,179,147,737,738,739,740,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,352,600,172,382,148,445,429,149,150,446,447,741,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,472,157,473,474,475,179,382,589,670,545,742,117,201,202,203,204,458,459,169,237,743,744,188,189,241,185,186,239,185,186,190,745,746,147,589,747,748,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,154,135,136,137,138,139,136,137,138,139,749,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,628,146,147,510,573,629,190,750,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,429,429,149,591,751,752,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,753,754,113,122,123,124,125,126,127,128,129,211,755,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,756,268,757,758,393,394,395,396,531,146,147,589,590,445,429,149,759,446,447,592,592,447,636,549,760,427,428,99,111,112,99,201,202,427,428,99,111,112,99,258,761,260,261,762,262,263,264,763,764,765,766,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,767,752,117,201,202,326,327,99,111,112,99,161,328,393,394,395,396,531,727,434,347,768,528,571,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,367,368,399,400,179,382,510,696,697,769,770,771,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,147,510,696,772,117,201,202,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,429,429,149,511,446,592,592,447,447,512,69,243,244,313,314,315,169,773,774,47,367,368,399,641,775,203,204,458,459,169,352,776,777,778,779,780,780,781,781,780,781,782,382,510,696,783,570,784,453,476,477,478,785,786,787,243,244,166,167,662,169,460,179,147,597,402,302,303,304,303,304,303,304,303,304,303,788,549,789,393,394,395,396,699,172,382,589,590,429,429,429,429,445,429,149,759,446,447,447,790,662,169,352,791,792,793,794,795,707,99,111,112,99,113,101,162,163,796,489,665,666,667,797,169,352,798,172,382,355,383,383,534,535,537,799,549,800,328,329,101,283,284,285,286,467,104,135,136,137,138,139,140,141,680,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,313,314,315,316,317,345,509,172,382,510,573,629,190,191,802,803,472,157,216,804,805,161,328,329,101,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,127,128,806,807,808,809,810,809,809,809,809,809,811,812,813,814,815,816,817,333,410,335,336,337,818,117,161,328,329,101,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,820,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,355,356,519,821,201,202,427,428,99,111,112,99,161,328,329,101,251,332,333,334,335,336,337,44,45,822,823,117,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,367,368,369,370,824,765,825,99,113,101,114,119,120,121,109,110,99,111,112,99,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,201,202,203,204,175,176,177,169,178,179,231,232,182,834,835,258,761,260,261,836,837,262,263,264,553,439,838,47,99,113,101,330,332,333,334,335,336,337,44,45,524,839,840,809,809,809,809,809,811,812,813,814,815,841,650,603,602,603,602,603,603,602,603,602,603,602,603,602,442,492,172,390,391,494,80,842,258,761,843,225,226,120,121,367,368,399,844,845,541,109,110,99,111,112,99,100,122,123,124,125,126,145,777,846,80,847,500,146,147,510,573,574,234,848,849,236,204,175,176,177,169,237,743,744,188,189,190,850,851,852,853,244,313,314,315,316,317,703,146,147,148,854,629,190,191,855,313,314,315,316,317,345,509,172,382,148,854,856,379,169,857,858,859,860,861,458,459,169,417,333,862,584,863,864,489,665,666,667,730,731,268,865,69,794,795,707,99,111,112,99,201,202,427,428,99,111,112,99,161,328,393,572,216,449,439,838,23,866,99,258,259,867,868,243,244,175,176,177,169,869,687,688,870,251,871,489,665,666,667,797,169,178,179,382,148,854,872,873,490,227,123,124,125,508,317,703,146,147,355,356,874,393,394,395,396,699,172,382,532,700,384,557,507,572,489,665,666,667,797,169,875,146,346,319,876,283,284,420,877,878,879,880,881,882,730,731,883,268,884,885,886,543,544,887,888,439,450,889,890,891,892,893,584,863,864,206,488,489,665,666,667,894,895,289,109,110,99,111,112,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,896,807,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,897,113,152,249,250,101,251,332,333,410,418,255,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,178,179,147,510,278,562,281,280,281,280,281,280,281,898,114,119,120,121,109,808,811,812,899,814,815,900,901,902,303,903,904,127,128,129,905,283,284,285,286,467,104,135,136,137,138,906,393,572,489,665,735,216,907,908,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,909,146,231,232,311,181,233,190,910,192,193,194,195,911,912,913,179,914,225,226,120,121,109,110,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,175,176,177,379,169,857,915,916,917,918,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,159,128,129,819,919,117,161,328,329,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,145,146,231,232,921,922,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,923,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,808,811,812,899,814,924,179,390,391,494,495,925,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,367,368,399,641,657,658,495,691,605,109,110,99,111,112,99,100,122,123,124,125,126,374,229,909,146,231,232,311,181,233,241,185,926,927,201,202,203,204,175,176,177,169,178,179,147,401,383,556,560,442,624,625,928,206,488,216,929,930,931,932,68,69,99,113,101,102,103,467,291,292,324,253,933,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,460,934,935,393,572,206,207,208,388,936,937,938,939,211,940,920,492,509,172,382,510,573,574,941,942,374,943,319,454,348,348,944,350,243,244,166,167,662,169,170,171,587,434,347,348,945,946,947,226,120,121,367,368,399,400,179,180,181,233,239,948,949,950,951,570,952,529,947,226,120,121,367,368,399,400,179,147,355,383,953,156,157,152,954,955,956,253,254,255,489,665,735,216,736,179,180,606,957,426,310,146,147,148,429,429,854,574,958,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,251,252,253,254,960,961,962,963,135,136,137,138,139,964,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,547,587,434,320,193,194,195,965,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,472,157,275,473,474,475,179,231,967,968,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,145,146,147,401,356,969,326,327,99,201,202,203,204,594,595,596,379,169,352,353,146,346,319,347,970,971,367,368,399,641,972,973,613,614,615,495,496,497,659,974,104,135,136,137,138,139,975,500,146,390,391,494,495,976,977,291,297,436,978,145,146,147,148,429,445,445,429,979,310,146,390,391,494,616,690,673,243,244,166,167,638,169,352,600,687,980,981,295,982,115,983,253,254,984,153,103,291,292,324,253,254,985,920,145,146,147,148,854,574,986,987,471,467,988,989,145,146,147,401,383,519,990,991,110,99,111,112,99,100,227,123,124,125,126,228,352,600,172,180,181,233,190,992,993,367,368,399,400,179,382,510,278,994,295,982,995,996,299,211,997,367,368,369,400,179,390,391,494,495,691,918,390,391,494,495,689,690,496,496,496,690,496,496,691,442,139,140,141,680,460,179,147,277,712,712,696,696,696,712,696,696,998,999,435,1000,522,523,1001,1002,1003,1004,1005,333,334,335,336,337,44,45,1006,835,808,810,809,809,809,809,809,809,809,809,809,809,1007,1008,1009,1010,1011,23,258,259,867,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1015,172,382,510,696,712,696,1016,168,169,237,743,744,188,189,190,575,802,1017,156,1018,1019,1020,423,424,1021,1022,1023,1024,161,328,393,394,395,396,265,838,23,401,383,519,990,1025,1026,319,347,455,1027,549,1028,1029,954,955,956,253,254,419,229,1015,1030,1007,1031,333,410,418,1032,369,400,179,231,232,233,190,986,1033,420,801,120,289,367,368,369,1034,80,1035,909,146,147,148,429,429,429,445,445,149,672,1036,1037,1031,333,410,418,23,461,149,562,281,281,280,281,280,281,1038,564,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1039,1040,216,449,439,266,1041,68,331,492,172,346,319,347,581,455,582,113,489,665,735,489,490,216,1042,439,1043,178,179,231,232,233,190,986,1044,1045,178,179,147,401,383,402,383,556,282,1046,1047,1048,1049,1050,1051,467,467,467,995,1052,510,696,712,998,463,835,467,467,104,135,136,137,138,139,140,141,680,197,145,146,147,510,712,696,696,696,278,1053,1054,1055,1056,330,1057,468,29,417,1058,102,1059,1060,1061,80,1062,206,1063,777,778,1064,561,203,204,584,585,222,223,224,221,222,223,645,646,647,1065,1066,1067,147,148,429,854,574,1068,1069,1070,1071,237,743,744,188,189,239,185,186,190,910,192,193,194,1072,1073,977,1074,1075,68,69,1076,726,435,1077,1078,1079,1080,1081,69,156,157,489,665,666,667,1082,774,23,624,625,626,627,628,777,846,616,1083,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,175,176,177,379,1084,439,1085,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,159,128,129,211,290,117,161,328,329,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,132,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,1086,333,410,335,336,337,44,45,524,561,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1087,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,1015,172,180,181,233,190,1088,1089,1090,1091,1090,1092,549,1093,117,100,101,118,119,120,121,1037,1031,333,410,418,23,175,176,177,169,943,319,1094,1010,102,103,467,104,135,140,141,1095,522,523,44,45,524,507,117,113,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,1096,227,123,124,125,126,228,1097,1098,203,204,175,176,177,379,169,1099,859,1100,1101,917,839,920,492,509,172,180,181,233,190,1102,178,179,147,401,356,502,634,538,1103,69,99,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,276,179,390,391,494,616,505,1083,351,237,743,744,188,189,190,910,1104,80,1105,117,201,202,326,327,99,111,112,99,100,273,274,227,123,124,125,126,228,229,1106,172,390,391,23,99,113,101,102,103,467,1107,1108,351,1026,319,347,1109,283,284,420,801,120,289,367,368,369,400,179,346,319,347,1110,367,368,399,641,657,658,616,1111,351,1112,1113,746,117,100,101,118,119,120,121,367,368,369,1114,23,109,110,99,111,112,99,100,122,123,124,125,126,374,1115,561,1116,572,273,1117,1118,1119,1120,1121,1122,1123,1124,1125,379,169,352,798,587,434,320,193,194,1126,594,1127,216,449,439,669,179,147,597,519,1128,1129,283,284,285,286,467,104,135,136,137,138,139,140,141,959,101,947,226,120,121,367,368,369,1130,1131,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,145,727,434,347,1132,69,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,243,244,166,167,638,169,352,1133,799,758,414,415,694,204,594,595,596,379,169,756,268,1134,1135,326,327,99,201,202,243,244,1123,1124,1125,379,169,178,179,180,181,233,190,1136,1137,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,145,727,434,347,455,944,69,947,226,120,121,367,368,399,400,179,231,232,233,241,948,949,1138,325,399,400,179,382,355,383,700,1139,487,101,225,226,120,121,109,110,99,111,112,99,100,152,153,154,135,136,137,138,139,1140,330,252,253,68,426,1141,1142,1143,1144,1145,1146,249,250,101,118,1141,1142,1147,1148,454,455,1149,435,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,1150,492,172,382,510,573,1151,873,156,157,101,283,284,285,286,467,467,1152,1153,374,229,909,146,147,401,383,519,520,521,522,1154,102,103,988,1155,1156,159,128,129,1002,156,157,152,249,1157,1158,396,265,266,1041,1122,1159,1160,1161,193,194,1162,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,231,232,1163,232,233,241,185,926,1164,275,473,474,475,179,147,589,670,698,203,204,458,459,169,237,238,184,185,186,240,188,189,239,185,186,239,1165,1166,156,157,206,207,208,388,1167,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1168,203,204,594,595,596,379,1169,439,266,1041,68,637,118,119,120,121,367,368,369,400,179,147,148,854,629,190,191,192,193,194,1170,102,103,104,135,136,137,138,139,140,141,1171,472,157,275,473,474,475,179,180,606,1172,416,244,1123,1124,1125,316,317,345,509,172,180,181,233,190,986,1044,849,1015,687,688,616,690,1173,662,169,237,743,744,188,189,187,188,189,239,185,186,187,1174,1175,1176,330,252,253,68,435,669,1120,1121,254,985,109,110,99,111,112,99,100,133,123,124,125,126,1177,172,390,391,494,495,1178,100,101,624,625,626,627,1179,1180,1181,1182,454,455,686,758,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,1150,145,146,147,510,573,574,1183,1184,1185,1186,1187,182,606,607,545,1188,1189,240,188,189,187,1174,744,188,189,190,1190,367,368,369,1191,145,146,147,355,356,519,1192,1193,1194,237,743,744,188,189,241,185,186,239,185,186,190,1195,1196,1197,1198,382,589,670,545,1188,1199,666,667,725,439,450,1200,1201,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,159,128,129,130,367,368,369,641,642,434,320,193,194,1202,1203,103,104,135,136,137,138,139,140,141,959,367,368,369,400,179,382,510,696,696,696,696,278,150,446,1204,492,172,382,401,356,556,654,557,558,557,558,561,458,459,169,1115,673,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,367,368,369,400,179,382,148,854,1205,1206,115,1207,1208,1209,1210,23,159,128,129,683,143,144,125,126,145,146,147,148,445,445,445,445,149,672,280,281,280,281,280,281,1211,492,172,382,510,278,430,280,281,280,281,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,373,229,1212,1213,267,554,1214,435,118,119,120,121,367,368,369,641,642,434,347,456,1215,1216,109,110,99,111,112,99,100,158,123,124,125,126,145,1217,346,319,454,348,348,1109,1218,1219,367,368,399,400,179,382,148,1220,602,1221,351,229,1015,587,434,347,348,1149,426,909,146,390,391,494,616,690,505,690,690,1222,777,778,779,780,780,780,780,780,780,781,1223,601,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,1224,510,696,278,511,446,447,447,636,69,252,1225,808,809,809,809,809,811,812,899,814,815,816,1226,1182,454,456,455,686,1227,109,110,99,111,112,99,100,133,123,124,125,126,145,146,231,232,233,187,1174,1228,977,251,332,1229,510,712,696,696,278,150,446,592,447,447,512,426,178,179,147,355,383,357,383,357,383,519,1230,1231,1037,1031,333,1232,335,336,337,1233,1234,102,154,135,136,137,138,139,1235,777,846,495,496,496,1236,1237,1037,1031,333,410,335,411,412,54,55,1238,712,278,562,281,280,281,280,281,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,752,816,1226,1182,454,1239,1240,492,687,688,495,496,505,496,691,622,399,400,179,147,355,443,463,1241,492,172,382,401,383,502,634,537,1242,69,172,382,510,712,712,696,696,278,1243,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,674,665,666,667,725,439,266,267,554,1244,69,492,172,390,391,494,1245,310,146,231,232,1163,232,233,190,1246,1247,987,1248,808,809,809,1007,1249,295,1250,346,319,454,348,455,1251,147,355,356,356,534,535,1103,549,1252,662,169,237,238,184,185,186,240,188,189,240,188,189,240,1174,1253,1254,1255,1256,1257,1258,1259,1260,44,45,46,1261,756,554,270,269,270,270,270,270,271,726,403,131,1262,382,401,356,556,557,558,559,560,605,102,103,104,135,136,137,138,139,140,141,680,1003,1263,1264,253,254,1032,808,811,812,899,814,815,900,901,1265,303,903,303,304,303,304,303,304,303,788,835,680,237,743,744,188,189,190,1266,1267,1268,1269,184,185,186,240,1174,744,188,189,240,1174,1270,492,687,980,981,711,103,104,135,136,137,138,139,140,141,680,778,781,781,781,1271,1272,1273,1274,390,391,494,616,505,691,1275,285,286,1107,299,467,104,135,136,137,138,139,140,141,959,157,216,1042,439,266,267,1276,1277,1278,1279,1280,811,812,899,814,924,179,390,391,494,616,505,690,496,496,496,1281,104,135,136,137,138,139,140,141,680,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1283,276,179,346,319,454,455,1284,147,401,443,1056,147,510,573,629,190,191,1285,1286,602,603,603,602,603,602,603,602,603,603,605,104,135,136,137,1287,139,140,141,680,351,352,353,146,231,232,311,181,233,187,188,507,920,492,1288,1289,1290,1291,1292,641,657,658,495,496,1293,1083,149,150,446,447,447,447,447,447,447,447,512,549,789,756,268,1294,726,69,1295,1296,422,1297,1046,1047,1298,333,334,335,336,337,1299,819,1300,253,68,1301,1302,467,104,135,140,141,1303,403,104,135,136,137,138,139,1304,1305,1306,637,332,333,410,335,411,412,758,346,1307,346,319,347,581,348,455,1215,426,1308,367,368,369,400,179,346,319,347,455,581,455,1309,390,391,494,495,690,1293,1111,148,445,445,445,445,445,149,1310,401,1311,510,712,712,696,696,696,278,430,280,281,280,281,280,281,280,281,280,281,280,281,1211,1171,1312,1156,346,319,347,456,455,455,455,1109,382,1286,602,603,602,603,604,712,712,696,696,696,278,591,150,446,447,447,447,447,447,447,592,512,549,1313,1314,567,1315,69,808,810,811,812,899,814,815,816,1226,1182,454,1316,1317,188,655,727,434,347,581,455,455,455,455,455,455,455,1318,1319,346,319,454,456,348,455,455,455,348,455,455,455,455,455,455,1215,435,1320,291,297,1321,134,216,1042,439,266,267,268,270,1294,1322,1323,1324,333,410,335,411,412,758,1325,1326,1327,1328,333,410,1329,687,688,495,689,496,496,496,496,496,690,496,496,496,690,1330,251,252,253,68,1216,597,519,520,1331,1331,1332,1332,1332,1332,1331,1333,959,1107,1334,1335,1336,1337,1050,977,429,429,149,591,150,446,447,447,447,447,447,447,447,447,447,447,447,636,549,1338,460,179,147,518,519,520,1331,1333,1339,463,758,100,133,123,124,125,126,1340,439,838,23,154,1341,510,696,278,672,280,281,280,281,280,281,281,280,281,280,281,674,352,353,146,390,391,494,616,690,496,1342,673,399,400,179,382,510,696,1343,1141,1142,1147,1148,454,1344,115,1345,333,410,335,336,337,44,45,1346,1347,355,383,384,557,1348,557,558,557,558,442,755,696,712,696,696,696,696,696,696,712,696,998,999,713,961,962,963,135,136,137,1287,139,140,141,680,777,778,1349,1350,310,146,147,355,383,384,558,1351,258,761,260,261,836,837,1352,1120,1121,254,724,148,149,591,672,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,1353,216,804,1354,1355,920,492,509,172,390,391,494,495,496,1111,211,132,1356,1357,299,587,434,454,455,455,970,971,510,712,712,278,150,446,447,447,592,447,447,447,447,447,447,1358,115,1046,1359,1350,460,179,147,277,696,696,696,278,279,561,159,128,129,1360,1361,977,355,356,357,302,303,548,713,252,253,1122,147,601,603,603,1362,99,201,202,243,244,175,176,177,379,169,352,776,146,147,597,519,1192,1363,332,333,334,1364,616,689,496,496,496,496,496,496,690,496,561,401,383,502,1365,252,253,254,255,156,157,216,449,439,266,1366,254,255,311,183,1367,231,232,311,181,1163,232,233,190,850,246,811,812,899,814,924,179,346,319,454,456,455,455,348,455,455,455,455,455,455,348,455,1215,1368,445,149,591,150,446,447,447,447,447,447,447,447,447,447,447,447,448,1369,308,1370,172,382,1286,602,603,602,603,602,603,603,602,603,602,431,400,179,147,510,696,696,712,696,278,672,1371,1372,1373,148,429,429,429,445,445,445,445,445,445,445,445,445,462,999,69,586,1374,222,223,645,646,1375,333,410,1364,105,294,295,982,300,1376,1377,130,1378,1379,1380,1081,664,1026,319,347,581,348,455,455,455,455,686,403,924,1120,1121,68,435,1177,172,382,510,573,574,745,80,1381,1382,1130,1383,1384,1385,1386,1385,1385,1385,1385,295,982,564,216,1042,439,266,267,1387,331,712,712,696,696,696,712,696,696,278,672,280,281,280,295,506,207,208,388,936,937,938,939,1388,203,204,313,314,1389,467,104,135,136,137,138,139,1390,233,190,1068,1069,1391,1260,44,45,1392,1393,370,433,434,347,455,456,455,455,455,455,455,582,355,356,534,535,611,537,537,537,537,537,537,537,537,537,537,537,537,1394,460,179,147,518,534,535,537,1395,549,800,172,382,401,356,402,1396,664,1397,1259,1260,44,45,1398,54,55,1399,1400,439,266,267,554,270,269,270,270,270,272,835,520,1332,1332,1332,1401,1402,150,446,447,447,447,447,447,447,512,69,547,172,390,391,494,616,505,1403,712,573,629,1404,1194,237,743,744,188,189,190,575,1405,1031,333,410,418,23,1406,557,557,558,557,558,557,558,557,557,558,557,558,557,558,557,558,557,558,557,655,382,355,383,357,383,1407,146,147,355,383,519,990,1408,382,148,854,629,190,245,1409,1044,849,1410,347,456,455,686,69,1411,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,1086,333,1232,418,255,1046,1047,1048,1336,1414,1050,1050,692,1002,401,383,519,520,1401,1402,393,394,395,396,397,23,178,179,300,301,1396,637,233,190,910,1415,1416,465,295,1250,147,510,278,591,150,446,447,636,403,69,1417,1418,23,709,60,61,1419,93,94,1420,1421,435,276,179,346,319,347,686,435,355,383,534,535,536,538,537,537,537,537,537,537,537,1422,640,297,1423,1424,905,262,263,264,265,266,267,554,1294,270,270,270,270,270,270,270,270,270,272,426,567,568,1425,1426,1427,322,1428,1429,1430,1431,1432,1178,756,554,1433,140,141,959,131,1434,211,1219,1424,687,980,779,1223,276,179,346,319,347,455,455,348,695,1435,1436,1437,1438,1439,69,492,172,382,355,383,519,520,1332,1332,1332,1332,1440,696,696,696,712,696,696,696,696,696,696,712,696,696,696,696,278,150,1441,1442,696,278,759,446,447,447,447,447,447,447,636,426,1037,1031,333,1232,335,336,337,44,45,1443,135,136,137,138,139,140,141,680,1444,148,429,445,445,445,445,445,445,445,445,149,150,446,447,447,636,435,352,791,172,147,401,356,402,383,519,990,1445,399,1446,1447,23,355,383,384,558,557,1348,557,558,557,558,557,558,557,558,557,557,1222,826,1282,829,830,831,832,832,832,832,1448,1413,696,696,696,278,430,280,281,280,281,280,281,280,281,280,281,280,281,281,280,295,982,467,104,135,136,137,138,139,140,141,1449,1450,1451,390,391,494,616,496,690,1452,355,383,357,302,303,304,303,304,303,304,303,304,303,304,303,305,303,304,303,304,303,1453,1454,463,1455,712,696,696,696,696,696,696,712,278,150,446,447,636,664,680,1456,101,251,332,333,410,335,411,412,69,347,456,455,455,348,455,455,455,348,1457,808,1458,1459,255,278,150,446,447,447,447,592,447,636,435,237,238,184,185,186,240,188,189,190,245,1409,1460,1177,172,180,181,1163,232,233,190,630,777,846,616,689,1461,1414,1050,1050,442,375,1462,1463,1464,1464,1464,1465,1466,1467,1467,1468,426,401,383,402,302,1469,1470,211,820,456,455,1215,549,610,777,778,1064,780,781,780,780,780,780,780,780,780,1223,357,302,303,304,303,304,303,304,303,305,303,304,303,304,303,788,403,712,696,696,696,278,150,446,447,447,592,447,447,1471,292,324,253,68,350,616,496,689,295,982,382,355,383,534,535,537,1472,549,1338,278,759,446,592,592,447,447,447,592,636,549,1338,934,1473,1474,1475,1476,154,135,136,137,138,139,136,137,138,139,1304,1477,1049,1414,1050,1050,1050,1050,1478,1479,1480,1281,346,1481,356,556,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1482,369,1435,1483,1484,905,315,316,317,345,172,346,319,1094,23,401,383,556,558,557,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,782,355,383,357,302,303,304,303,304,303,305,303,1485,1059,1361,295,466,178,179,382,1486,758,1487,268,269,270,270,271,270,270,270,270,270,270,271,270,270,270,270,270,1488,820,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,1489,1490,23,379,169,460,179,147,518,384,1348,557,752,367,368,369,641,642,1491,23,509,172,382,401,356,502,634,537,1492,554,269,270,270,272,758,1368,1493,1494,1074,1323,251,1073,386,180,181,233,190,1495,80,1496,1497,233,190,234,1498,1499,1500,453,319,347,1501,1502,780,1064,839,696,696,696,712,696,696,696,696,696,696,712,696,278,1503,815,900,901,1265,303,903,303,305,303,304,303,304,303,304,303,305,303,304,303,304,303,304,303,304,303,1504,370,371,1505,495,496,496,976,1178,1506,561,510,696,696,278,150,446,447,447,447,592,447,447,447,447,512,69,940,1507,563,1356,1508,1037,1031,333,410,335,411,412,54,1509,347,456,455,455,455,455,455,348,455,686,758,346,319,347,728,435,149,672,280,281,280,281,280,1510,1004,1264,253,254,419,637,148,854,574,745,1511,573,574,1512,429,149,672,280,281,280,281,280,281,280,281,1513,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1515,131,1516,258,339,1517,755,846,495,496,689,496,496,496,496,1222,255,1518,537,799,403,900,901,1265,303,1519,303,304,303,788,549,610,182,183,1520,1521,1413,460,179,147,277,696,696,696,696,696,696,278,1522,280,281,280,281,674,712,696,696,696,696,696,696,712,696,696,278,150,446,1523,1325,1524,1525,745,1526,982,357,302,303,1527,149,994,673,819,820,449,439,669,179,346,319,1528,1529,1530,1031,333,1232,335,336,337,44,45,1531,1532,467,291,292,324,253,254,984,390,391,494,495,1461,370,433,434,347,686,413,278,591,150,446,447,447,447,592,447,447,447,447,447,447,592,447,447,447,447,1533,178,179,147,355,383,519,990,1534,1535,23,1099,916,1101,917,386,1074,1536,1537,918,291,297,1538,29,291,292,324,1539,276,179,382,518,1540,1541,1542,1101,860,1101,1101,1543,1314,1544,333,334,335,336,337,44,45,1545,1077,1078,1078,1078,340,340,1546,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,1547,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,1546,1548,826,1282,829,830,831,832,832,832,832,832,832,966,146,147,510,573,629,190,1549,193,194,1072,148,149,759,1550,153,103,467,467,467,467,1152,1551,419,1552,1544,1229,1553,152,954,955,956,1225,628,146,147,148,854,629,190,1554,1196,1197,1555,211,212,1556,618,178,179,382,510,573,574,1557,1558,518,519,520,1559,640,148,429,149,562,281,280,281,280,281,280,281,280,281,280,281,622,180,181,921,1560,744,188,189,240,1174,744,188,189,239,1165,1561,1164,1323,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1562,1563,507,1564,859,1565,1566,640,390,391,494,80,1567,298,1568,1569,510,696,696,696,696,1570,510,696,696,696,696,278,511,446,447,447,447,512,549,1571,278,759,446,447,447,447,592,447,447,447,447,636,69,224,216,449,439,266,1366,68,350,115,1046,1047,1298,333,410,335,336,337,44,45,1346,1572,357,302,303,304,303,304,303,304,303,304,303,304,303,305,303,304,303,304,303,1504,1573,731,268,1294,270,270,270,270,270,270,270,270,270,270,1488,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,680,1574,99,111,112,99,161,328,329,101,225,226,120,289,109,110,99,111,112,99,100,101,102,103,104,135,136,137,1287,139,140,141,680,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,124,125,126,228,229,1106,687,688,495,505,690,1403,117,201,202,243,244,313,314,315,316,1575,902,303,1576,549,729,161,328,329,101,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,367,368,399,400,179,147,510,573,629,190,1549,193,194,1577,1578,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,1218,1087,1579,340,340,340,340,340,340,340,340,340,340,1580,427,428,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,178,179,382,401,356,519,1128,1581,367,368,399,1582,999,549,1571,117,201,202,326,327,99,111,112,99,826,1282,829,1583,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1584,117,201,202,243,244,175,176,177,379,169,170,1585,439,669,179,346,319,347,686,331,113,101,472,157,216,449,439,669,179,346,319,347,1215,403,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,492,509,172,1586,193,194,1577,1587,1588,99,111,112,99,161,101,162,163,164,165,1589,1590,1591,169,237,238,184,185,186,190,745,80,1592,134,122,123,124,125,126,374,178,179,382,355,383,384,1593,379,169,1026,319,454,348,455,944,835,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,905,1116,394,395,1594,396,1595,764,1596,1331,1597,99,113,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,102,103,291,297,298,29,127,128,129,1424,808,809,809,809,840,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,1007,1031,333,410,418,23,237,743,744,188,189,241,185,186,190,1598,1599,152,961,962,1600,1601,1602,105,1603,507,808,809,809,809,809,809,809,811,812,899,814,815,900,1604,68,69,1605,169,178,179,382,401,356,502,1606,650,1607,1608,1609,1610,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,203,204,584,585,222,223,224,644,222,223,224,216,449,439,669,179,147,1406,1482,145,146,147,401,383,502,634,536,1611,699,172,382,532,526,769,1612,1613,1614,1615,147,601,295,1616,147,148,854,629,190,1617,1618,390,391,494,495,505,496,640,260,261,262,263,264,432,371,1505,495,1619,504,1374,222,223,1620,1621,981,1245,727,434,347,581,455,348,455,455,1318,1622,1413,1130,1383,1623,1386,1385,1385,1385,1385,1386,1624,394,395,396,553,439,266,267,268,1625,271,270,270,270,1626,375,376,1627,1331,1332,1331,1628,355,383,383,1629,276,179,390,391,494,495,689,496,690,496,691,752,330,332,1630,616,689,496,691,1178,696,696,712,696,696,278,1243,280,281,280,281,280,561,1106,172,180,181,311,1631,248,1632,333,410,335,411,412,637,1633,712,696,696,696,712,696,696,696,1634,492,172,382,355,383,384,558,557,1348,557,1635,383,534,1636,1637,541,1638,172,382,510,1639,463,713,101,225,226,120,289,109,110,99,111,112,117,113,158,1640,227,123,134,122,123,124,125,126,500,146,231,1641,243,244,175,176,177,379,169,178,179,382,148,854,574,1598,1642,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1410,251,332,333,410,335,411,412,435,99,161,328,329,101,251,252,253,254,419,145,146,231,232,233,190,1643,1044,1045,127,128,129,819,919,1644,1645,1646,1647,23,467,467,1107,299,369,370,371,1505,495,655,140,141,959,156,157,101,624,625,626,627,628,146,346,319,454,1215,637,330,1073,752,1116,394,395,1594,396,1648,1649,1650,332,333,334,418,1651,369,400,179,382,510,573,1652,920,492,509,1288,1653,228,229,230,146,147,401,356,502,634,537,1242,758,954,955,1324,333,334,418,823,231,232,233,190,1654,848,1655,351,229,909,146,231,232,311,181,233,190,986,1044,1045,330,1073,442,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,460,1120,1121,1071,694,204,594,595,596,379,169,352,353,146,147,401,383,556,559,560,295,1616,162,163,164,165,361,619,620,169,460,179,147,597,556,558,1482,99,113,101,283,284,420,421,422,1023,1656,154,135,136,137,138,139,136,137,138,139,1657,300,301,302,303,304,631,570,1658,54,1659,1194,352,1660,1661,1662,495,976,622,275,473,474,475,179,147,1663,1664,1665,333,1666,1667,268,1294,272,403,383,519,990,1534,180,181,921,232,233,239,1668,1288,1289,1596,1332,521,1669,231,232,233,239,185,926,1670,756,268,269,271,1671,134,216,1042,439,266,267,554,270,1672,69,278,1522,280,281,280,281,280,281,918,1673,673,195,196,1506,295,466,1073,1178,436,978,587,434,454,686,549,1674,1141,1142,1147,1148,1528,1318,291,1675,1676,80,1381,1382,1677,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,609,169,460,179,147,597,402,1678,252,253,68,69,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,429,445,445,149,751,839,400,179,147,510,573,629,190,986,1044,1189,727,434,347,581,348,455,455,455,455,686,835,109,110,99,111,112,99,100,489,490,216,1042,439,266,267,554,270,1294,1680,902,303,903,303,305,303,788,835,410,418,419,357,302,303,304,303,304,303,304,303,305,303,304,303,304,303,788,549,1338,1681,300,301,711,665,666,667,725,439,266,267,554,269,1682,1462,1463,1683,1683,1464,1464,1464,1684,1685,1686,69,1687,1688,1689,1690,1100,1101,1101,1101,1100,1101,295,982,467,291,297,1538,1691,304,303,304,303,304,303,306,1456,101,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1694,401,383,402,302,303,788,758,1695,1696,1697,291,292,324,253,254,984,150,1698,230,146,147,355,356,534,535,611,1699,278,672,280,1281,988,1700,1701,1702,179,390,391,494,495,689,1703,148,429,445,445,445,1704,990,1705,1663,1706,1707,1708,736,179,173,948,949,950,1709,1037,1031,333,410,418,1710,180,181,233,190,191,1711,1141,1142,1147,1148,347,1109,179,346,319,1528,1712,1713,1714,330,332,333,410,335,411,1715,1037,1031,333,410,418,23,104,135,136,137,138,139,140,141,680,687,688,495,689,690,496,496,496,690,690,1083,1074,1323,1716,1130,1717,278,1243,280,281,1718,287,1719,1720,1721,68,1455,815,841,80,1592,666,667,1722,1723,613,614,615,1724,1286,602,603,603,602,603,602,603,603,602,603,602,603,602,603,603,602,603,605,1163,232,233,190,191,192,193,194,1725,712,696,278,1726,502,634,536,537,537,663,435,370,824,765,1727,148,429,149,759,446,447,447,447,1728,597,502,634,663,549,1313,399,400,179,180,181,233,241,1729,366,330,252,253,254,255,254,1032,1730,69,959,696,712,712,712,696,278,672,281,280,752,959,977,696,712,696,278,150,446,447,1731,162,163,796,216,449,439,450,1200,1732,1733,1734,1735,1218,1736,355,383,1737,668,439,669,179,382,597,402,402,302,303,305,303,304,303,304,303,548,549,610,554,1738,1739,687,688,495,689,496,690,711,467,291,1675,1740,1741,1742,278,150,446,592,447,447,592,447,447,1743,755,668,439,669,179,390,391,494,616,1744,497,498,1745,1746,1747,206,207,208,388,936,937,1748,777,846,616,689,496,690,496,691,673,756,554,1672,403,1749,383,534,535,611,537,538,663,549,1338,995,1052,980,780,1750,781,780,780,780,1751,1752,985,1753,696,696,712,696,696,696,278,591,672,442,1754,1060,1755,1756,696,696,712,696,696,278,150,446,592,447,512,426,1086,1757,846,495,689,496,1758,1294,270,270,271,272,549,800,460,179,147,518,534,535,611,538,1759,350,346,319,454,686,758,553,439,440,859,746,445,1760,685,434,347,455,945,686,435,959,1761,1762,1245,278,150,446,447,447,636,758,735,216,542,1012,1013,1763,1764,355,383,384,654,557,557,558,557,558,557,557,558,557,558,557,1635,300,301,302,303,304,303,788,549,610,502,634,537,1472,835,300,301,302,303,548,69,1765,507,1766,1767,1385,1385,1386,1385,1385,1385,1768,386,140,141,959,429,1769,291,292,324,253,254,255,147,148,854,629,190,1549,193,194,1577,1770,445,445,149,562,280,561,1771,278,759,446,592,447,1772,1773,562,1774,1775,1158,1594,396,1776,1777,352,791,172,231,1641,1778,276,179,346,319,347,455,1779,348,455,455,455,348,455,1215,549,610,1060,1755,80,1780,401,443,999,426,455,455,348,455,1781,1493,1305,1782,1783,355,383,384,1784,1275,241,1165,184,185,186,190,1785,597,519,520,521,1786,1573,731,268,269,270,271,270,270,270,726,549,1571,370,433,434,347,455,455,695,1424,510,696,712,712,278,591,150,446,447,447,1787,1012,1788,149,562,281,281,280,605,1789,1790,1791,454,728,435,149,150,446,447,592,447,447,447,636,664,1159,1160,1436,1792,1522,280,281,280,281,280,281,442,148,445,462,999,435,376,377,1793,1794,683,233,190,1795,147,518,357,534,535,536,538,537,537,663,1796,668,439,669,179,390,391,494,616,1797,690,496,496,496,496,1111,1286,602,603,603,602,603,602,603,603,602,603,602,603,602,603,602,295,982,154,105,1719,1074,1323,518,357,302,303,305,303,305,303,304,303,304,303,304,303,305,303,304,303,1798,442,502,634,537,799,549,708,352,791,1288,1799,510,573,574,941,1800,1801,495,496,1802,690,496,1803,382,355,383,519,990,1804,1804,1363,383,556,1348,557,558,557,557,558,752,445,445,462,1805,292,324,253,254,1402,943,319,454,581,348,348,455,455,455,455,1109,170,1585,439,266,267,554,1806,69,346,319,454,348,1110,130,564,216,1042,439,266,267,268,270,1807,69,519,1793,1808,572,489,665,666,667,725,439,440,859,1762,295,1616,366,1809,1810,816,1226,1182,347,1239,549,610,401,356,502,634,537,799,69,696,696,712,696,696,696,712,696,278,150,1811,170,171,687,688,495,691,839,254,1402,278,150,446,1812,553,439,669,179,390,391,494,1813,401,356,356,519,990,1804,1408,266,267,268,1814,1815,952,1816,496,1802,690,496,496,496,1222,782,613,614,615,495,496,1817,442,454,455,1779,1215,403,1317,188,386,1159,1160,1161,435,1818,422,1819,1435,1436,1437,1439,1216,147,148,445,429,445,445,149,994,386,1820,735,216,449,439,669,179,346,319,1821,454,1822,403,332,333,334,335,336,1823,454,456,455,348,348,348,455,686,637,1824,23,149,1825,355,383,534,535,611,537,538,537,1759,69,251,332,333,1826,149,759,446,592,1827,237,743,744,188,189,241,185,186,239,185,186,190,1828,802,80,1829,534,535,538,799,1216,554,270,1134,271,272,549,760,687,688,495,690,1342,711,1830,439,450,889,1831,1832,1832,1832,1833,265,266,267,883,1276,1834,1835,557,558,557,558,557,557,558,557,558,1836,468,1837,1838,685,434,347,1839,548,549,1338,1032,173,185,1222,347,1840,1822,69,346,319,454,455,728,758,278,562,1774,1265,303,305,1841,1216,462,463,435,696,712,278,672,280,281,281,280,1510,278,150,446,592,592,592,447,447,593,419,519,990,1804,1025,445,445,429,445,445,149,150,446,447,448,449,439,669,179,346,319,454,768,1822,403,278,562,281,281,280,281,280,281,280,281,280,605,340,1078,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,1078,340,340,340,340,340,340,340,340,1078,1078,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,1547,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1842,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,101,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1112,1843,1844,1845,549,610,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,467,104,135,136,137,138,139,140,141,959,117,161,328,329,101,283,284,420,801,120,289,367,368,369,400,179,382,510,573,629,190,245,1409,1044,1846,118,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,510,278,1847,145,146,147,355,356,519,1128,1848,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,1074,366,1074,1323,1116,394,395,1849,1850,396,1838,685,434,454,1215,69,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,101,225,226,120,289,109,110,99,111,112,117,113,158,123,134,206,207,208,388,1167,1693,1012,1851,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,292,324,253,254,419,117,161,328,329,152,249,1157,1158,396,265,266,267,554,1135,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,143,144,125,126,145,146,231,232,233,190,1852,193,194,195,1853,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1854,310,1562,1289,1855,1080,1856,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,99,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,1857,117,201,202,326,327,99,111,112,99,100,273,1117,1858,1859,117,113,158,123,124,125,126,159,128,129,1424,117,113,227,123,134,122,123,124,125,126,374,229,1015,172,382,510,696,696,712,1634,152,954,955,1324,1860,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,1015,172,382,510,573,574,575,1861,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,229,1015,587,434,454,455,944,69,1862,1121,68,758,117,100,101,118,119,120,121,367,368,399,400,179,382,148,854,629,190,1863,1196,1864,1865,489,665,666,667,797,169,1866,950,1867,950,1868,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,351,460,179,147,461,445,149,150,1869,117,161,328,329,152,153,103,467,467,467,467,467,467,1107,1702,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,330,1870,225,226,120,121,367,368,399,613,614,615,561,201,202,427,428,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,145,146,147,355,383,534,535,538,538,1759,664,127,128,129,130,100,273,274,227,123,124,125,126,228,229,230,146,147,148,854,1871,530,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,276,179,147,597,556,1348,557,558,557,558,557,557,557,1245,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,1424,100,101,102,103,467,467,467,467,467,467,1506,1872,1873,254,419,337,44,45,1346,1874,1875,393,572,489,490,101,624,625,928,489,665,1876,422,1023,1877,1878,1879,1880,169,237,238,184,185,186,241,185,186,190,1881,1044,1189,387,101,283,284,420,801,120,289,109,110,99,111,112,117,161,328,393,394,395,396,265,266,1882,243,244,1123,1124,1125,316,1575,902,1883,1884,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,154,135,136,137,138,139,136,137,138,139,1304,1885,117,201,202,427,428,99,111,112,117,113,414,415,487,101,251,1701,299,161,328,329,101,472,157,206,488,101,114,119,120,121,367,368,399,400,934,1886,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,117,201,202,427,428,99,111,112,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,961,962,963,135,136,137,138,139,140,141,680,326,327,99,201,202,243,244,1123,1124,1125,379,169,1887,859,1888,746,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,1562,765,1290,1291,523,44,45,524,1281,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,147,401,383,556,558,557,558,559,560,1245,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,99,113,101,472,157,101,251,332,333,410,418,984,258,761,260,261,836,837,1352,179,300,1889,947,226,120,121,367,368,399,400,179,231,232,921,967,1890,608,169,1086,333,410,1891,156,157,101,283,284,285,286,467,104,135,140,307,308,1892,373,330,252,253,68,435,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,460,179,147,597,502,634,537,799,1455,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,1893,774,23,153,1325,1894,959,947,226,120,121,367,368,399,400,179,382,148,445,670,545,1188,1199,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,1573,731,268,270,1895,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,472,157,275,473,474,475,179,147,589,670,545,1188,1846,158,123,124,125,126,351,1026,319,347,348,944,549,760,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,1084,439,440,859,1762,622,1107,1568,133,123,134,101,114,119,120,121,367,368,369,1896,23,1107,299,118,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1177,172,180,181,233,190,575,192,193,194,195,1897,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,158,123,124,125,126,310,727,434,454,456,455,455,455,455,455,348,455,455,455,455,1898,808,811,812,899,814,924,179,346,319,347,456,455,734,122,123,124,125,126,197,492,172,382,510,712,696,696,696,712,696,696,696,696,696,696,278,511,446,1444,500,146,147,401,356,356,519,520,1628,114,119,120,121,109,110,99,111,112,99,161,101,114,119,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,201,202,1899,1900,99,111,112,117,161,101,251,332,333,334,335,336,337,44,45,524,507,225,226,120,121,109,110,99,111,112,117,201,202,427,428,99,111,112,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,472,157,206,488,101,114,119,120,121,367,368,369,1159,1901,68,1902,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,1903,1904,1905,23,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,114,119,120,121,367,368,399,400,179,382,355,443,999,549,1338,101,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,351,229,1015,587,434,1821,347,1109,1003,1004,1264,253,68,69,118,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1906,333,1907,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,367,368,369,641,657,1908,1751,442,122,123,124,125,126,127,128,129,1424,258,761,260,261,836,837,262,263,264,1595,764,1596,1331,1332,1332,1331,1909,413,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,727,434,454,455,643,1318,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1910,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,401,383,556,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1718,143,144,125,126,145,146,390,391,494,495,505,496,496,496,496,496,496,496,496,496,691,918,197,145,146,147,355,356,357,302,303,304,303,304,303,304,303,305,303,304,303,548,549,1338,1074,1323,367,368,369,400,179,382,401,383,302,1469,156,157,216,1042,439,266,267,554,1294,270,270,270,270,270,270,726,549,1338,229,909,146,147,510,278,591,150,446,447,447,447,447,447,447,1827,1218,290,367,368,369,400,179,382,148,854,629,190,986,1044,1189,99,201,202,203,204,313,314,315,379,169,460,179,147,518,534,535,538,1395,403,102,103,467,104,135,136,137,138,139,140,307,308,1892,295,1911,102,103,104,135,136,137,138,139,140,141,959,492,172,382,510,712,696,696,696,278,591,150,446,447,447,636,426,117,201,202,1899,1900,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,1254,1255,1256,1912,253,68,664,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,975,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,584,585,222,223,224,221,586,565,1913,117,113,101,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,131,132,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,1914,1915,442,1037,1916,746,152,249,250,101,251,332,1917,808,809,809,811,812,1918,1350,153,103,104,135,136,137,1287,287,1919,143,144,125,126,492,172,346,319,454,581,455,1318,103,104,135,136,137,1287,139,140,141,959,101,114,119,120,121,109,808,811,812,899,814,815,816,1226,1182,347,1132,1216,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,146,147,401,383,1733,472,157,489,665,735,216,449,439,266,267,1920,270,732,1921,549,1922,283,284,285,286,467,104,135,136,137,138,139,140,141,680,122,123,124,125,126,374,229,909,146,390,391,494,616,690,505,690,690,691,782,114,119,120,121,367,368,399,400,179,382,148,854,629,190,1554,1196,1197,1923,367,368,369,1924,1925,709,60,61,73,1926,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,725,439,440,859,1101,1927,1222,178,179,147,510,278,562,281,280,281,280,281,280,281,280,674,458,459,169,170,1928,146,390,391,494,870,1929,640,1761,1690,1930,203,204,458,459,169,237,743,744,188,189,190,1931,1932,1199,249,250,101,114,119,120,121,367,368,399,400,179,382,148,854,629,190,1933,326,327,99,201,202,203,204,594,595,596,316,317,345,509,172,382,601,507,1456,101,162,163,796,216,449,439,669,179,346,319,347,1934,500,146,147,401,356,356,556,654,557,558,557,558,557,558,557,558,557,558,1935,291,297,436,1936,1219,1107,299,291,292,324,253,68,664,367,368,399,400,1120,1121,68,426,109,1074,1323,370,824,765,1596,1332,521,522,523,44,45,1006,69,947,226,120,121,109,110,99,111,112,99,161,101,102,1059,1060,1937,249,250,101,118,119,120,121,367,368,399,400,179,231,232,182,181,233,239,1165,1938,1939,275,473,474,475,179,147,1663,697,698,1824,23,399,400,179,382,510,573,629,190,986,1940,161,328,393,394,395,396,531,777,846,80,1941,1942,156,157,216,1042,439,266,267,268,1294,1626,145,146,147,401,356,556,654,557,558,557,558,557,558,557,558,752,291,297,1943,127,128,129,683,178,179,382,401,383,402,383,519,520,521,1944,102,103,104,135,136,137,138,139,140,141,959,346,319,454,686,69,99,113,101,283,284,285,286,467,291,297,436,1538,29,808,809,809,811,812,899,814,1945,333,410,418,1946,291,297,468,1947,1304,1305,1306,69,375,376,1627,1331,1331,1331,1332,1628,468,29,1667,243,244,166,167,638,169,460,179,147,518,534,535,611,537,537,1948,310,727,434,454,455,455,1149,549,1338,808,840,809,809,809,809,809,809,809,809,809,809,1949,1950,959,1015,172,382,510,712,278,430,280,281,280,281,280,281,281,280,281,280,281,280,1211,113,101,156,157,101,624,625,928,206,488,216,449,439,1951,1952,156,157,101,114,119,120,121,109,110,99,111,112,99,826,1282,829,830,831,832,1953,180,606,607,545,671,467,1506,1281,1954,1955,666,667,885,886,1693,1693,1693,1693,1693,1693,1012,1013,1013,1956,148,429,445,445,149,751,752,988,1957,823,492,172,382,1286,602,603,1178,180,181,921,1560,744,188,189,190,1828,192,193,194,1958,351,229,1015,172,382,148,429,854,574,1959,1104,80,1105,367,368,369,370,371,1505,616,1960,622,110,99,111,112,99,100,158,123,124,125,126,492,172,382,401,383,519,520,1332,1909,69,178,179,147,401,356,502,634,538,1961,572,489,665,666,667,1962,333,1232,335,336,337,44,45,524,1718,460,179,147,597,502,634,536,538,538,537,1759,664,297,1963,197,145,146,147,510,278,1522,280,281,280,281,280,281,281,280,1353,147,148,445,854,629,190,245,1964,1074,1965,352,600,172,180,181,921,1966,549,800,1323,243,244,175,176,177,316,317,703,146,390,391,494,495,690,1817,442,1074,366,367,368,399,400,179,231,232,233,190,1967,483,484,485,486,669,179,346,319,454,456,455,528,571,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1968,1969,110,99,111,112,99,100,227,123,124,125,126,145,146,147,510,573,1970,1218,1667,662,169,1268,1971,744,188,189,240,1174,1972,1973,292,1974,1975,355,383,1976,1804,1363,114,119,120,121,109,110,99,111,112,99,100,227,123,134,216,1042,439,266,267,268,1977,1553,152,249,250,565,1978,23,102,103,104,135,136,137,138,139,140,141,959,954,955,1507,1222,178,179,382,401,383,519,1192,1025,1665,333,1232,335,336,337,44,45,524,1275,1114,23,1007,1031,333,1232,335,336,337,44,45,46,47,1059,1060,1979,80,1980,401,383,556,654,679,237,238,184,185,186,239,185,186,240,188,189,240,1174,744,188,189,241,1981,145,146,147,510,696,712,278,150,446,1982,489,665,666,667,1983,23,416,244,1123,1124,1125,379,1084,439,266,267,883,1276,1984,100,101,624,625,626,627,1985,938,939,1986,504,1374,586,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,1615,1366,254,255,258,761,260,261,836,837,262,263,264,265,266,267,554,269,271,270,270,270,726,549,1674,346,319,1094,23,228,178,179,382,355,383,1987,1400,439,450,889,1832,1988,1989,1990,1031,333,1232,335,336,1991,1304,1305,1992,1993,1099,916,1100,1994,104,135,136,137,138,139,140,141,959,231,967,1995,1107,299,1564,1996,859,295,296,492,172,382,510,712,696,696,696,278,759,446,447,636,835,467,467,467,467,291,292,324,253,254,1032,1424,352,791,172,1317,188,1997,549,1338,366,161,328,329,216,1042,439,266,267,1387,193,194,1998,382,510,712,712,696,278,672,280,674,1999,330,332,333,410,335,411,412,713,1107,1691,755,609,169,1099,916,1101,2000,330,252,253,68,435,369,400,179,382,148,1220,1222,369,2001,899,814,815,841,2002,2003,603,602,603,602,2004,1585,439,266,267,268,272,1241,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,140,141,1303,350,351,229,909,146,147,401,383,502,2005,23,577,578,123,124,125,1150,145,777,778,2006,386,113,489,490,216,1042,439,266,267,554,271,2007,1896,23,148,429,429,429,149,150,446,447,447,447,512,1368,436,2008,1562,1289,1855,522,523,2009,1073,782,115,1046,1047,2010,1049,2011,258,259,260,261,262,263,264,763,764,765,1596,1909,403,1074,1323,237,743,744,188,189,239,185,186,190,745,2012,1107,2013,2014,208,2015,388,936,2016,398,2017,148,429,429,429,149,672,280,281,280,281,2018,2019,808,811,812,899,814,815,816,1226,1182,454,455,1149,549,708,146,390,391,494,495,496,1817,295,506,237,238,184,185,186,2020,2021,1148,347,455,1149,549,1571,277,712,278,430,280,281,280,281,280,281,898,2022,333,410,335,336,337,44,45,1545,148,149,759,446,592,447,447,636,69,103,104,135,136,137,138,139,140,141,959,100,158,123,124,125,126,920,492,509,172,382,355,356,384,558,2023,109,110,99,111,112,99,100,122,123,124,125,126,500,146,147,510,712,2024,746,187,188,189,2025,909,146,346,319,320,193,194,1170,104,135,136,137,138,139,140,141,680,1003,1004,2026,355,356,357,302,303,548,549,1093,743,744,188,189,239,185,186,190,986,1940,355,383,534,535,536,538,537,663,435,347,1501,455,528,1658,2027,777,846,495,505,690,496,496,496,1111,238,184,185,186,241,185,186,240,188,189,190,1828,1861,127,128,129,683,379,169,2028,1777,2029,492,172,382,510,712,696,278,150,446,447,1731,400,179,180,181,233,190,1554,1196,1197,2030,105,2031,665,735,489,665,666,667,725,439,266,1041,1071,461,429,429,2032,104,135,136,137,1000,522,523,44,45,2033,819,2034,2035,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,2036,117,794,795,707,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,147,355,383,2037,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,665,735,489,665,666,667,1564,859,1565,1566,861,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,382,355,383,526,545,671,117,201,202,326,327,99,111,112,99,161,328,329,101,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1694,117,201,202,427,428,99,111,112,99,258,761,260,261,762,262,263,264,2038,463,549,2039,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,346,319,454,455,528,570,1658,54,55,2040,2041,117,201,202,427,428,99,111,112,99,161,328,393,572,206,488,489,665,666,667,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,382,148,445,670,769,2042,113,101,225,226,120,2043,2044,69,243,244,166,167,609,169,178,179,382,148,445,429,429,149,672,280,281,2045,326,327,99,111,112,99,161,328,329,122,123,124,125,491,492,172,382,355,383,534,535,538,538,2046,549,610,262,263,264,553,439,2047,613,685,434,454,455,528,570,1658,54,2048,203,2049,1915,1915,2050,1915,2051,1915,2052,180,181,921,967,1890,545,2053,1116,572,489,490,489,665,666,667,797,169,178,179,147,401,383,502,634,538,538,537,537,1395,413,102,103,467,291,292,2054,193,194,1577,2055,101,162,163,164,165,313,314,315,169,178,179,180,181,233,239,2056,243,244,166,167,662,169,460,179,147,597,502,634,538,2057,2058,367,368,399,641,642,434,347,2059,203,204,584,585,586,221,222,223,224,206,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2060,113,414,415,487,206,488,489,490,227,123,124,125,508,317,703,146,390,391,494,495,689,690,496,691,1222,472,157,473,474,475,179,382,532,533,874,204,458,459,169,460,179,147,518,384,654,557,558,557,558,557,558,557,558,557,557,557,558,557,558,557,386,545,1188,1846,121,367,368,399,641,2061,2062,477,478,785,786,452,460,179,147,461,445,429,429,445,445,445,149,150,446,2063,145,146,147,148,149,279,281,281,280,281,281,280,1353,2064,2065,2066,1189,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,2067,500,146,147,401,383,402,302,303,304,303,304,303,304,303,304,303,305,2068,2069,644,222,223,224,216,449,439,266,267,268,1294,270,272,549,1338,2070,2071,2072,146,390,391,494,2073,2074,243,244,166,167,638,169,229,1015,172,390,391,494,495,690,1817,282,109,110,99,111,112,99,100,227,123,124,125,126,228,460,179,147,1406,442,113,101,472,157,473,474,475,179,382,589,653,570,571,109,110,99,111,112,99,100,101,624,625,626,627,1985,938,939,130,122,123,124,125,491,127,128,129,130,109,110,99,111,112,99,113,122,123,124,125,126,1573,731,268,1214,403,100,101,624,625,626,627,628,146,346,319,347,728,69,127,128,129,819,2075,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,510,998,463,758,127,128,129,131,132,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,172,390,391,494,495,690,496,689,690,690,1111,393,572,489,665,666,667,668,439,669,179,382,597,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,788,549,1338,1518,950,951,515,1658,54,55,633,367,368,399,1435,2076,2077,352,791,172,147,148,149,279,280,281,281,281,280,281,280,281,1281,182,606,607,769,770,2078,2079,2080,99,113,101,102,154,135,136,137,138,139,136,137,138,2081,180,181,182,606,607,698,490,227,123,124,125,508,317,345,509,172,180,181,1163,232,233,239,185,2082,2083,346,319,454,455,528,570,1658,54,55,2084,162,163,2085,157,216,449,439,669,179,346,319,1094,23,453,476,477,478,785,2086,147,148,149,150,2087,2088,485,2089,54,55,2040,2090,148,445,149,279,280,281,1774,703,146,147,1286,603,602,603,602,603,295,1616,374,178,179,147,355,443,2091,491,228,178,179,382,601,605,2092,1734,2093,491,228,178,179,382,401,383,502,634,537,611,538,663,664,374,352,353,146,147,148,429,429,429,149,511,446,592,592,447,2094,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,924,179,1586,193,194,195,2095,495,2096,711,99,113,101,472,157,473,474,475,179,382,589,653,570,2097,328,329,101,225,226,120,121,367,368,399,400,179,231,232,921,967,1890,545,1188,1846,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,237,743,744,188,189,190,1654,848,2098,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,172,382,148,149,759,446,592,447,592,592,636,549,2099,374,178,179,382,148,429,429,149,759,446,592,592,447,790,161,101,162,163,164,165,1589,1590,1591,169,229,230,146,147,510,696,278,591,2100,547,172,382,148,445,445,429,149,1522,442,1887,916,860,1100,1100,1101,1101,1101,1101,1101,1543,564,565,2101,179,1824,23,102,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,2102,134,216,449,439,669,179,346,319,347,581,455,1109,394,395,396,265,266,267,268,1294,271,271,271,726,435,567,568,1425,2103,1427,148,429,149,672,280,281,839,727,434,347,581,455,455,455,455,455,348,1839,815,816,817,333,410,335,336,337,44,45,1006,69,2104,687,688,495,496,1744,782,231,967,1890,769,2105,233,190,2106,483,484,485,2107,100,227,123,124,125,126,228,229,230,146,147,355,383,384,557,654,1635,167,609,169,352,2108,860,1101,1101,1101,1100,1994,492,172,382,601,603,603,603,1350,400,179,382,355,383,514,632,435,662,169,178,179,382,148,445,445,445,429,149,2109,725,439,266,267,554,270,1672,835,472,157,473,474,475,179,147,1663,697,769,770,2110,355,383,526,545,714,508,317,703,146,346,319,347,348,728,69,162,163,164,165,361,619,620,169,352,621,146,147,355,383,383,384,558,282,147,401,383,526,545,2053,2111,2112,1915,2113,699,172,382,513,533,502,634,611,538,538,537,537,663,549,1313,352,798,172,180,181,182,181,311,2114,467,467,467,467,104,135,136,137,138,139,140,141,959,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,628,727,434,347,728,758,472,157,489,490,216,449,439,1951,2115,2116,523,44,45,2117,2118,2119,2120,1106,172,382,148,445,149,430,280,1281,798,172,382,148,429,445,445,429,149,430,280,281,373,147,148,429,429,429,445,445,429,149,511,446,447,447,2121,2122,382,1663,1706,2123,943,319,347,581,455,455,348,348,455,455,588,131,820,243,244,313,314,315,169,460,179,147,1835,558,1482,369,400,179,147,510,573,629,190,191,802,80,2124,2125,665,735,489,665,666,667,668,439,669,179,346,319,454,2126,528,571,390,391,495,1744,497,498,2127,100,216,1042,439,266,267,268,1134,270,271,270,726,664,145,727,434,347,581,455,455,455,455,1215,1368,178,179,147,148,149,759,446,592,592,447,447,592,592,447,512,1216,1887,859,2128,563,587,434,320,2129,203,204,458,459,169,352,2130,184,185,186,241,1165,184,185,186,190,2131,472,157,473,474,475,179,382,532,514,570,571,367,368,399,2132,2133,2134,2135,508,317,345,509,172,382,148,429,445,149,279,280,281,280,1222,197,145,146,147,148,429,429,429,429,445,445,149,150,446,447,636,1241,460,179,147,277,696,696,2136,520,2137,352,600,172,382,148,429,149,150,446,592,592,636,69,445,429,429,429,429,445,149,759,446,592,593,2138,1031,333,410,335,411,412,54,2139,2140,400,179,382,510,278,672,1411,347,1840,1822,403,526,769,770,2141,145,146,147,510,696,712,278,1243,2142,401,383,556,558,692,445,445,429,149,759,446,447,447,512,758,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1007,1008,2143,193,2144,2145,454,2146,549,2147,237,238,184,185,186,239,185,186,239,185,186,190,1828,802,1526,296,589,670,2148,400,179,180,181,921,967,1890,2149,228,756,554,1214,549,2147,401,356,502,634,538,611,537,537,537,537,663,549,1093,180,181,233,241,948,949,1138,549,800,2150,2151,375,376,377,2152,2073,495,497,498,617,1237,589,653,570,2153,665,666,667,1514,1693,1693,1693,543,2154,384,557,654,557,557,558,295,506,694,204,594,595,596,316,317,703,146,147,355,356,2155,2156,147,513,526,545,714,490,227,123,124,125,508,317,703,146,147,148,854,1871,530,231,232,921,967,2157,2158,394,395,1594,396,553,439,266,1366,68,69,251,332,333,410,335,411,412,1455,1163,967,2159,2160,1288,1563,386,180,181,921,967,1890,769,770,2161,251,465,442,783,570,571,233,190,2162,483,484,485,486,531,727,434,454,2126,2163,457,577,578,564,565,566,1544,333,2164,401,383,526,769,2165,638,169,2166,774,47,180,181,233,190,2167,2168,416,244,1123,1124,1125,379,169,352,798,687,688,495,1330,258,761,260,261,836,837,1352,179,1586,435,547,172,382,148,429,149,430,280,281,281,281,280,281,280,281,280,746,2169,2170,2171,735,216,449,439,669,179,390,391,494,495,496,2172,497,498,1745,870,142,1638,172,382,510,573,629,190,245,1409,1044,1189,1116,394,395,1594,396,265,266,267,554,1294,270,270,2173,943,319,347,456,2059,645,646,2174,1490,23,148,429,429,445,445,429,149,591,672,280,281,1211,190,2175,2176,498,617,2177,2178,417,333,334,418,1402,589,747,2179,2179,2180,2179,2180,2179,2181,510,998,463,350,231,232,182,181,2182,1424,703,146,147,510,712,696,696,998,999,2083,258,259,260,261,262,2183,687,688,80,2184,103,291,297,2029,1866,2185,537,950,2186,950,2187,2188,472,157,489,490,489,665,735,216,1042,439,450,1200,2189,2190,891,2191,472,157,216,1042,2192,203,204,458,459,169,178,179,180,181,921,2193,102,103,104,135,136,137,138,139,140,141,959,222,223,224,644,222,223,224,216,1042,439,266,267,2194,345,509,172,382,510,712,696,696,998,999,403,346,476,2195,2196,485,2197,178,179,382,401,383,402,383,402,356,502,2198,2199,616,2172,497,2200,460,179,147,597,402,302,303,304,303,304,303,788,549,708,355,383,534,535,536,1611,429,429,429,445,149,562,281,280,295,982,172,382,401,383,383,556,558,2201,2202,180,181,921,232,233,190,745,80,1941,2203,492,172,382,148,429,429,445,149,759,446,2204,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2205,346,319,347,1501,455,2126,528,571,1254,1255,1256,2206,2207,352,1660,2208,2209,237,238,184,185,186,240,188,189,190,2210,2211,472,1018,1019,1020,423,424,1021,1022,2212,488,489,490,227,123,124,125,491,145,146,147,401,356,502,634,538,537,611,538,663,549,1313,148,429,149,759,1698,180,606,2213,231,232,921,1560,744,188,189,239,1165,184,185,186,190,1617,2142,2214,2215,2216,756,554,1294,270,2217,401,383,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,305,2218,102,103,104,135,140,141,1095,522,523,44,45,1006,403,641,2061,2062,477,478,785,2219,491,228,352,600,172,180,181,233,190,575,192,193,194,1577,2220,2221,266,267,268,270,732,1815,1658,54,55,1238,162,163,796,101,225,226,120,121,109,110,99,111,112,99,100,2222,2223,128,129,905,231,232,182,606,2224,2225,491,228,1026,319,347,1284,510,696,697,545,1188,1189,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,145,146,147,401,356,556,918,318,319,347,349,549,1338,2096,497,498,617,561,237,238,184,185,186,239,185,186,239,185,186,241,1165,184,185,186,190,2226,2227,2228,2229,2230,180,606,607,2231,146,147,401,356,502,634,611,538,537,537,537,663,758,149,759,446,592,592,447,447,592,592,447,447,2121,2232,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2235,346,476,477,2236,2237,735,489,2238,1348,557,557,557,557,2239,665,735,216,449,439,266,267,554,2240,2241,2007,866,99,113,565,566,128,2242,211,2243,367,368,399,400,179,147,401,383,2244,2245,109,110,99,111,112,99,113,122,123,124,125,126,374,375,376,1627,1331,521,522,523,2246,147,1663,697,545,714,662,169,460,179,147,461,445,445,149,1310,393,394,395,396,699,172,382,513,533,402,302,303,305,303,305,303,304,303,304,303,304,303,304,303,304,303,788,637,500,146,147,401,356,356,556,1348,442,777,846,495,690,505,496,690,690,496,496,496,2247,146,147,589,590,445,429,429,445,445,445,445,149,2248,355,383,526,545,1188,2249,178,179,382,355,383,519,990,1804,1363,2250,774,23,554,2251,403,211,2252,318,319,347,581,455,455,455,455,686,549,2147,777,846,495,2096,497,659,2253,2253,2253,2253,2254,2253,2253,2254,2255,1178,883,554,1921,403,1288,765,2256,432,824,1596,521,522,523,44,45,524,1718,641,656,642,434,347,528,570,952,2257,168,169,178,179,382,148,445,445,2258,589,590,429,429,149,562,281,280,281,281,281,280,281,2045,369,2259,147,355,383,384,1348,557,2201,2260,237,743,744,188,189,239,185,186,190,745,2261,491,492,172,382,355,356,384,558,1245,1663,697,2262,180,181,233,2263,1254,1255,1256,2264,492,172,390,391,494,616,1960,1222,557,558,557,2265,373,429,429,2266,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,1007,1031,333,410,418,23,347,455,768,528,1658,54,55,1238,1990,1031,333,1232,335,2267,390,391,494,495,496,497,2268,974,207,208,388,2269,23,147,510,696,697,545,2053,508,317,345,509,172,180,181,1163,232,233,190,992,2270,1499,1555,130,2132,2133,2134,2271,445,670,545,1188,1846,345,509,172,382,148,149,759,446,447,447,592,592,512,426,148,854,574,910,2272,1317,188,2273,631,570,516,2257,168,169,352,791,172,231,232,921,1966,350,461,445,445,445,429,429,445,149,150,446,636,69,573,629,190,191,192,193,194,1577,1942,1890,769,770,2141,2274,738,2275,2276,2276,2277,2277,2276,2276,442,139,140,141,680,943,319,347,348,455,455,643,457,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1286,1281,489,665,735,216,736,179,300,1376,2278,472,157,473,474,475,179,147,1663,783,570,571,458,459,169,178,179,147,148,445,445,445,429,149,511,446,2279,777,846,495,690,690,1275,104,135,136,137,138,139,964,352,600,587,434,347,455,581,455,455,455,1215,549,1093,390,391,494,495,2096,497,659,2253,2253,2280,148,445,670,545,1188,1846,2281,211,1778,247,101,624,625,626,627,1638,172,1586,193,194,1577,2220,2282,216,804,544,401,356,556,654,557,557,558,557,558,557,692,206,207,208,2283,2284,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,2285,490,216,449,439,669,179,346,319,454,348,971,665,666,667,730,731,268,270,2286,1815,571,375,376,377,2287,168,169,170,1585,439,838,23,369,1435,2288,1010,2289,1575,1265,303,305,2290,403,2291,2292,523,44,45,2117,2118,2119,2120,1317,188,2273,2293,927,683,808,811,812,899,814,815,2294,1281,683,509,172,382,355,356,1733,147,597,402,302,303,305,303,305,303,305,303,2295,482,483,484,2296,2297,2249,735,489,490,216,1042,439,2298,2299,2108,1100,1690,2300,1218,583,382,401,383,526,769,2301,276,179,346,319,454,1149,1241,370,433,434,347,455,528,2302,149,2303,2304,2305,447,447,447,592,592,447,447,512,549,1338,429,429,445,429,429,149,150,446,2306,2307,355,356,357,302,303,305,303,788,69,641,775,382,401,356,2308,1887,916,1100,917,563,591,150,446,447,447,592,512,331,147,148,462,463,549,1313,140,141,2309,510,696,1343,300,2310,454,581,2311,103,467,104,135,136,137,138,139,140,141,680,545,1188,1189,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,513,526,2262,460,179,147,518,384,654,557,558,557,558,557,557,557,558,557,557,557,558,557,558,557,622,145,727,434,347,581,348,348,2313,532,526,545,2314,597,402,302,303,304,303,304,303,305,303,305,303,304,303,304,303,304,303,788,403,370,824,765,2315,2316,2317,523,44,45,1531,2318,330,252,253,68,69,492,172,382,601,603,603,602,603,602,603,602,603,602,655,382,148,429,429,429,429,429,445,429,429,445,149,759,2319,727,434,347,348,581,455,686,69,2320,254,255,147,355,356,534,535,538,537,1395,637,1954,80,2321,2322,291,292,324,253,254,255,161,101,162,163,164,165,577,578,123,124,125,1150,276,179,2323,18,526,769,770,2324,233,190,2325,2087,2088,2326,703,146,346,319,454,348,1239,413,352,353,146,147,148,429,445,429,429,445,149,279,280,281,280,281,752,277,696,696,712,278,150,446,636,2083,148,149,759,446,592,447,592,592,447,447,2327,460,179,147,461,429,429,429,429,149,759,446,447,592,636,664,251,332,333,410,418,255,233,240,2328,2329,950,951,570,1658,54,2330,730,731,268,1814,1815,952,2331,2331,2332,2332,2332,2332,2333,959,921,967,1890,545,1188,1846,401,383,402,383,502,634,537,611,537,2334,1595,642,434,320,2335,455,2336,528,571,291,292,324,2337,251,465,1872,161,101,162,163,164,165,1589,1590,1591,169,229,2338,1213,267,554,1214,549,1338,2274,738,2134,2339,2340,2341,180,181,921,1560,744,188,189,190,986,1044,1199,149,759,446,447,592,592,447,447,2342,231,232,233,190,2106,483,484,2343,486,1314,1544,333,334,335,336,337,44,45,822,2344,148,429,429,429,429,445,445,445,445,429,1704,2287,228,178,179,300,2345,302,303,305,303,305,303,548,435,148,445,149,759,446,512,549,2147,190,2346,454,945,455,455,455,348,1215,403,665,735,489,665,666,667,2347,179,147,513,2348,549,1338,1518,2349,148,429,429,445,429,149,759,2350,429,429,149,1522,280,281,280,281,280,1774,810,840,840,809,809,809,809,809,840,809,809,809,1378,1379,2351,523,44,45,1006,549,1093,690,976,605,2249,243,244,313,314,315,169,375,1462,1463,2352,549,760,178,179,382,148,149,150,446,592,592,447,447,512,69,231,232,311,181,233,190,910,192,193,194,1170,355,356,356,384,558,977,123,124,125,1150,492,172,382,401,383,502,634,537,1422,178,179,2353,239,948,2354,549,610,783,570,571,665,735,216,449,439,1951,1952,445,445,445,445,149,759,1054,146,147,401,356,502,634,538,538,2355,426,545,671,557,557,558,557,558,557,558,557,558,557,558,746,453,476,2195,2196,2296,2356,2357,797,169,1026,2358,102,1059,1060,1061,1526,296,504,644,586,565,566,128,2242,211,2359,231,232,233,190,1598,2360,498,2127,178,179,382,401,383,502,634,1759,664,572,489,490,216,1042,439,440,2361,918,370,433,434,347,455,528,515,516,2362,352,798,172,382,148,149,759,446,447,447,592,592,636,549,1093,2363,1499,1555,211,1410,2364,565,566,1544,2365,549,610,513,514,515,516,529,666,667,725,439,266,267,268,1294,270,270,270,270,2366,231,967,1890,769,770,2367,460,179,147,461,149,2368,251,1073,977,148,445,445,445,149,150,446,447,447,512,69,371,372,2369,659,2370,885,2371,1121,68,713,104,135,136,137,1287,139,1304,1305,1306,435,473,474,475,179,382,513,526,545,671,1530,1031,333,1232,335,336,337,44,45,46,23,206,488,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,352,791,172,147,601,602,603,602,603,602,603,602,603,603,603,602,603,602,603,1350,1288,765,1290,1291,523,44,45,1346,2372,783,515,516,2373,461,149,150,446,447,447,447,512,69,190,1967,483,484,2374,54,55,2040,2375,2224,2056,666,667,668,439,266,267,554,1815,516,529,430,280,281,280,281,280,281,2045,300,2376,472,157,216,2377,149,150,446,447,447,512,713,231,232,233,190,1549,193,194,2378,2379,774,23,251,1073,295,466,709,60,61,73,2380,66,93,94,2381,1421,403,367,368,399,400,179,382,355,2382,382,401,383,526,769,770,2383,508,317,345,509,172,382,148,149,430,280,281,1774,149,759,446,592,592,592,512,549,1028,1854,1132,69,1663,2384,2180,2179,2179,2179,2179,2179,2180,2385,2386,370,433,434,347,455,728,549,800,237,238,184,185,186,240,188,189,190,1931,2270,1499,1555,211,1667,216,449,439,669,179,390,391,494,495,2096,497,659,2253,2253,2253,2253,2254,2253,2253,2255,561,656,764,765,2387,2388,2389,608,429,445,445,445,429,1704,990,2390,510,696,573,2391,2392,439,266,267,554,271,271,1895,460,179,390,391,23,756,2393,23,102,1254,2394,161,101,162,163,164,165,577,578,123,124,125,702,580,345,509,172,382,148,854,629,190,745,80,2124,2125,500,146,147,148,445,149,562,281,280,281,281,281,280,281,2395,769,770,2396,54,55,2040,2397,401,356,556,1348,605,390,391,494,495,690,1342,561,564,565,1978,23,1218,2398,346,319,347,455,582,304,1469,570,516,2257,2175,2176,659,2399,438,439,440,80,81,401,383,526,698,1579,340,340,340,1079,1669,2400,157,101,624,625,928,2401,2402,2403,607,545,671,352,600,172,180,181,1163,232,233,190,1931,2270,1499,1555,1218,2404,2405,950,951,570,952,2406,461,445,445,445,445,429,149,591,150,446,447,2407,1665,2365,435,1663,697,769,770,2408,460,179,147,597,402,302,303,788,549,1922,445,429,149,511,446,447,447,447,447,636,2409,613,685,434,320,193,194,2410,482,483,484,485,486,1575,1265,303,903,303,304,303,598,2411,181,233,190,2412,1196,1197,1555,1218,1736,485,486,2413,1915,2050,1915,2051,1915,2414,1915,2414,1915,1718,429,429,429,149,591,150,446,447,592,2415,2416,332,333,2417,367,368,399,400,179,231,232,182,183,1367,231,232,233,190,2325,1811,2175,2176,2418,2419,228,352,600,172,382,510,696,712,278,150,2420,531,146,147,589,590,429,429,429,149,511,446,447,447,636,549,729,383,556,2265,918,390,391,494,2073,495,690,496,690,690,496,373,346,319,454,528,571,545,2421,154,135,136,137,138,139,136,137,138,139,1304,1885,1830,439,440,916,1690,2128,1371,1179,1180,1181,1182,454,455,455,1149,403,182,606,2422,1084,439,838,23,777,778,1064,781,2423,579,580,345,509,172,180,181,2424,403,172,346,319,454,2425,455,768,528,952,2426,355,383,2244,2427,352,2428,2300,346,476,2195,2196,485,486,148,445,149,591,150,446,447,447,447,512,549,1093,355,383,519,990,1408,2195,2429,2430,538,536,1759,69,149,562,281,281,280,281,280,281,280,281,1371,379,169,352,2431,2056,764,765,2387,2432,2317,523,44,45,1531,80,2433,547,172,382,148,854,574,2434,193,194,195,2435,510,696,1706,2436,613,685,434,347,1839,601,603,603,603,602,603,603,603,602,603,602,442,556,654,557,558,557,558,557,558,557,977,450,1200,1831,2437,268,1294,270,1921,835,147,589,670,545,671,382,510,278,150,2087,2088,2438,2356,2364,216,1042,439,2439,2440,178,179,147,148,149,2368,601,603,602,603,603,603,602,603,602,603,602,603,602,603,977,2338,1213,267,554,1244,403,460,179,147,518,384,1784,640,149,759,446,592,592,592,447,447,592,592,447,447,636,69,489,665,735,216,449,439,838,23,449,439,669,179,346,319,347,728,549,2147,429,445,429,149,430,2441,709,60,61,2442,2443,23,311,181,233,190,1549,193,194,2444,356,2445,2166,774,23,2446,348,1840,2447,626,627,628,146,147,510,573,629,190,1549,193,194,2448,453,319,347,455,1239,549,1571,229,1015,172,382,148,149,759,2449,1663,697,545,2314,429,429,445,429,429,429,1704,520,2450,460,179,147,461,429,429,429,445,445,429,149,1053,1550,532,526,545,742,542,1693,1693,1693,543,2451,149,430,281,2452,382,401,383,502,634,1472,637,2214,2453,480,2454,776,777,846,616,505,496,496,690,690,496,690,690,496,496,691,711,614,615,616,496,497,659,2370,136,137,138,139,140,141,959,1644,2455,2456,2457,2458,510,712,712,278,591,672,2459,117,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,2336,528,952,2460,102,103,291,292,324,253,254,419,2461,147,148,445,670,545,2462,352,600,172,382,601,602,603,603,602,603,602,603,602,603,602,603,602,692,445,149,591,150,446,592,592,592,447,592,592,447,636,435,102,103,104,135,136,137,138,139,140,141,1771,356,556,557,558,557,1348,557,557,558,622,445,445,429,149,2463,266,267,554,1921,1368,330,332,333,334,335,336,337,2464,383,556,654,557,558,557,558,655,180,181,233,241,2465,149,2466,2360,498,617,2467,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2468,1413,277,696,278,150,446,2469,149,150,2087,2088,485,2089,2129,271,2286,1921,403,211,2075,608,2470,650,2471,2472,369,2473,823,228,2379,774,23,532,2244,2474,2475,902,303,903,303,548,435,1076,726,758,1120,1121,68,69,237,743,744,188,189,190,745,1526,982,556,1348,557,558,557,557,557,557,2476,526,545,1188,1189,590,1769,429,149,591,150,446,447,447,636,69,142,1528,455,2126,528,571,2411,181,233,190,1195,1196,1197,2477,2478,632,54,55,2479,382,148,429,149,150,446,447,512,758,300,301,2480,950,951,570,571,237,238,184,185,186,241,185,186,240,188,189,190,1598,1599,345,509,172,180,181,233,190,191,192,193,2481,589,670,545,671,502,634,611,537,537,537,537,538,537,1422,2482,727,434,454,1239,549,1338,147,148,429,149,759,446,447,512,435,512,549,1093,44,45,1006,1368,130,1639,463,637,130,616,690,496,689,496,690,2247,2483,271,2484,549,1674,178,179,382,510,278,672,2485,1116,572,489,665,735,216,449,439,266,267,883,1276,2486,783,570,2153,1150,492,172,180,181,233,190,2487,2488,197,492,587,434,1094,23,586,216,449,439,669,179,147,597,556,558,1351,346,319,454,348,581,455,348,1318,519,520,521,522,523,44,2489,172,382,401,383,556,654,1836,269,270,271,272,69,1967,483,484,2438,2356,934,2490,2491,1573,731,1387,193,194,2492,702,580,703,146,147,510,1639,999,549,2147,2035,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1078,1079,1080,1081,713,1002,1286,602,442,416,244,1123,1124,1125,379,169,756,554,2493,758,231,967,1890,545,1188,2249,510,278,994,605,547,172,382,148,429,149,430,280,793,2494,383,402,302,303,305,303,305,303,304,303,305,303,788,426,2228,570,2495,589,670,545,2314,1074,1950,1268,1971,744,188,189,190,745,80,1381,2496,2497,2498,2499,2500,149,562,281,280,281,281,281,295,2501,401,356,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,1453,808,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,811,812,899,814,924,179,2502,23,1840,528,2503,1037,1031,2504,148,149,150,2087,2088,2343,2505,2506,229,1015,172,382,510,712,696,2136,520,2507,547,687,688,495,690,505,496,690,690,746,511,446,592,592,447,512,331,178,179,147,355,383,357,384,558,559,560,2201,2508,587,434,347,348,581,455,348,348,455,455,348,2509,383,556,1348,557,557,557,558,1482,756,554,270,270,2510,549,708,959,730,731,554,1814,1815,952,2331,2331,2511,403,820,145,146,147,401,383,556,746,777,846,495,1817,1222,237,743,744,188,189,241,185,186,240,2512,2513,780,692,909,146,231,232,311,181,233,239,2514,161,101,102,154,135,136,137,138,139,136,137,138,139,140,141,1771,1167,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,401,383,2515,547,172,382,510,573,574,469,2270,1499,1555,211,2516,1564,859,1565,2517,692,2518,495,689,690,496,691,711,322,1428,1526,296,2519,147,510,2520,197,145,777,846,495,689,690,691,782,203,204,175,176,177,169,352,776,146,147,518,519,990,1363,1696,938,939,1986,148,149,279,280,281,1222,2254,2254,2254,2254,2253,2521,2522,537,950,2186,950,951,1658,54,55,2040,2523,252,2524,808,811,812,899,814,815,816,1226,1182,454,455,348,455,1239,549,610,1106,172,147,518,384,558,559,385,746,844,938,939,211,2525,597,402,302,303,304,303,304,303,304,303,304,303,2526,665,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,601,602,2527,2134,2339,1955,180,181,233,240,2528,510,696,696,278,591,1243,782,514,570,2153,347,455,528,2529,2530,564,565,566,1544,2531,311,2532,549,800,1696,938,939,130,461,429,429,445,429,429,445,149,751,782,149,591,150,446,592,592,447,592,592,447,1444,810,809,810,809,1007,1031,333,410,418,23,390,391,494,2533,496,2172,373,300,301,302,303,304,303,788,549,1338,330,332,333,1907,532,514,570,2503,145,146,231,232,233,190,2534,1184,1185,2535,1268,1971,744,188,189,240,1174,744,188,189,240,1174,2536,2537,2538,376,2539,295,2540,608,147,148,149,2541,281,280,692,1598,839,513,514,515,2542,730,731,554,1815,1658,426,445,429,429,445,429,149,430,280,281,280,281,673,769,770,2543,1766,1767,1385,1925,401,383,526,545,1188,1189,1084,439,266,267,554,2544,467,467,467,467,467,467,467,291,1675,2545,1663,783,570,571,178,179,231,232,182,183,184,185,186,2546,510,696,697,545,1188,1189,237,238,184,185,186,239,185,186,240,188,189,2547,603,602,603,602,603,602,1350,355,356,357,384,558,559,560,1935,300,2345,302,303,305,303,304,303,305,303,305,2548,2549,657,1908,2369,498,617,561,1814,1815,952,2550,549,1338,556,654,557,557,557,558,557,558,557,557,558,684,278,591,150,446,447,636,403,696,697,545,2421,149,511,446,447,592,512,713,356,556,654,557,557,557,558,605,554,2551,271,2552,727,434,454,686,413,995,996,299,231,232,182,606,607,769,2105,127,128,129,130,103,104,135,136,137,138,139,140,141,680,149,430,280,281,280,281,281,281,280,281,280,281,280,793,145,146,346,319,347,581,348,348,348,348,455,348,348,455,455,348,2553,2224,2554,149,591,672,281,752,149,511,446,592,592,447,592,592,447,512,549,1338,666,667,725,439,266,267,554,1214,549,1338,545,1188,1189,445,445,149,150,446,447,790,461,445,429,429,445,445,445,462,999,435,1059,1361,1178,589,653,570,571,495,689,496,690,496,1619,231,232,233,190,986,1460,889,1988,1832,890,2555,452,579,580,345,172,346,319,320,193,194,2556,1331,2557,148,149,430,280,674,460,179,147,461,429,429,445,429,149,591,2558,1618,429,429,429,149,759,446,592,447,447,447,447,512,758,777,846,616,2559,442,924,179,390,391,494,616,496,690,976,655,429,149,591,150,446,592,447,447,592,512,549,1313,824,765,2315,2316,2317,523,44,45,1531,2560,1693,1693,1012,1013,1013,1013,1515,518,534,535,611,537,537,537,538,1759,69,402,302,303,2561,657,1908,779,561,148,149,511,446,447,512,549,2562,149,511,446,592,636,835,2563,496,497,2564,104,135,136,137,1287,139,140,141,680,180,181,233,190,1598,2360,498,1745,2177,2178,147,401,383,2244,2565,401,356,502,634,537,2566,1611,145,146,147,401,383,502,634,611,663,69,445,149,279,280,281,280,281,280,281,280,281,280,507,2567,839,429,429,429,149,150,446,447,447,447,636,69,447,447,592,592,636,549,610,237,743,744,188,189,190,2568,193,2569,1518,950,951,570,516,2570,329,216,449,439,669,179,346,319,454,456,455,455,348,455,686,331,2231,291,292,324,2571,356,534,535,611,538,1759,69,511,446,592,592,447,447,636,69,100,565,1978,23,1920,270,2240,1815,1658,2572,367,368,399,400,179,147,510,573,629,190,745,442,147,1663,697,527,355,356,2573,2574,538,2575,549,800,683,1487,777,846,616,2559,673,429,149,591,150,446,447,447,447,2576,756,883,554,555,921,967,1890,2577,745,80,1941,1770,146,147,148,149,591,150,446,592,592,592,447,592,592,512,549,1338,519,2578,769,770,2579,23,445,445,445,149,279,280,281,280,282,300,2345,302,303,304,303,304,303,304,303,304,303,304,303,2580,2101,179,300,301,2581,295,982,104,135,136,137,138,139,140,141,959,1317,2328,2329,950,951,570,516,2230,383,2037,258,761,260,261,836,837,262,263,264,265,266,267,268,270,271,1244,69,510,712,278,591,994,918,401,383,502,2198,2582,231,232,311,181,233,190,1863,1196,1197,1500,511,446,592,593,454,455,456,1215,69,1644,2455,2583,2584,1820,170,171,687,688,495,505,690,496,496,690,690,690,1619,429,149,591,672,280,281,746,680,545,742,1828,2585,653,570,1658,54,55,2586,2587,2588,1101,1565,2134,2339,2589,666,667,797,169,2590,2591,1101,1565,2592,1222,147,510,573,629,190,191,2585,844,938,939,130,370,433,434,454,528,632,54,55,2593,147,148,149,672,280,281,280,281,280,281,280,1211,1424,632,413,477,478,2594,2595,1323,2596,1645,2597,2598,193,194,1577,2599,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,1283,460,179,147,518,534,535,537,2057,1611,2206,2207,1074,1323,2600,333,1232,418,984,1243,280,281,280,281,281,1245,566,1544,333,410,1329,980,780,2601,563,148,445,653,570,2503,2602,2603,2604,23,149,1243,281,280,281,280,281,280,281,280,281,1350,777,846,495,689,690,1245,2605,182,183,184,185,186,241,1165,184,185,186,190,2606,2211,301,2480,950,951,570,1658,54,55,2084,1106,172,382,510,696,696,278,2607,445,149,591,150,2608,1562,1289,2256,2609,782,653,2610,461,445,149,672,280,281,280,281,2611,553,439,266,267,1387,193,2612,581,1215,403,2369,2613,442,641,764,765,2387,2614,445,670,545,2053,102,103,104,135,136,137,138,139,140,141,959,346,319,347,348,581,455,455,455,348,1318,756,268,1294,271,270,2615,229,909,146,147,510,712,696,278,2466,1599,1436,2616,549,1338,149,150,446,447,447,447,512,426,1254,1255,1256,1912,253,68,350,346,319,347,348,581,455,348,1215,69,759,446,592,592,447,447,447,512,69,1026,319,454,456,1215,549,2617,352,600,172,382,401,383,502,634,537,2046,435,383,534,1636,2618,2619,2073,495,752,154,135,136,137,138,139,136,137,138,139,1304,1305,2620,426,394,395,1594,396,432,2621,1188,2249,102,103,104,135,136,137,138,139,140,141,959,401,383,502,634,1242,637,2622,2297,2623,777,846,2073,495,690,496,691,692,2101,179,390,391,616,1083,714,591,150,446,447,636,549,1571,149,562,281,281,281,280,281,280,281,280,281,280,281,1718,353,146,231,232,233,190,910,2624,2478,570,1658,54,55,2625,2626,783,570,516,2627,2189,1832,2628,735,216,449,439,2629,382,355,383,534,535,2630,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,2631,390,391,495,2096,497,498,617,2589,401,383,402,302,303,305,303,304,303,305,303,305,303,304,303,304,303,788,426,149,279,280,281,280,281,281,752,510,712,278,150,2632,149,759,446,447,447,636,435,445,429,149,591,672,281,1222,429,149,759,446,447,447,2342,382,510,573,629,190,630,145,146,147,401,383,556,558,557,654,557,557,557,558,557,558,557,1350,632,54,55,2633,2041,1761,860,1222,816,1226,2634,724,492,172,382,148,149,591,1243,280,281,280,281,280,281,280,281,2018,2635,390,391,494,495,690,689,1758,455,768,528,952,2636,662,169,2379,774,23,162,163,164,165,594,595,596,169,229,909,146,346,319,454,1839,959,526,769,770,2637,735,489,665,735,216,1042,439,266,267,883,268,2638,2274,738,2639,2162,483,484,2640,207,208,388,936,2641,68,1368,2642,669,179,346,319,454,2336,528,571,597,556,654,557,557,557,557,557,557,558,557,558,557,1353,2643,2644,1792,149,759,446,592,447,1787,808,809,809,810,1458,1459,398,237,238,184,185,186,241,185,186,190,2645,2646,1599,147,510,573,629,190,191,192,193,194,2556,168,169,352,791,687,688,616,752,1015,172,180,181,233,190,992,1932,1045,1304,1305,1306,835,231,232,182,606,607,698,438,439,266,267,268,2241,1135,712,2647,697,545,1188,1199,2533,2648,1111,1171,148,445,2649,943,319,347,1215,713,346,319,454,768,528,516,2332,2332,2332,2550,403,253,68,664,608,445,445,149,279,280,281,280,281,280,281,605,2343,2505,2650,2533,496,2651,1350,104,135,136,137,138,139,140,141,959,352,2652,2653,184,185,186,190,1828,2654,352,353,146,147,148,854,574,910,2272,178,179,382,601,603,602,711,382,148,854,629,190,191,576,573,574,2655,2470,650,651,603,602,603,602,603,602,603,602,603,602,2656,532,533,384,1348,557,558,557,558,557,558,563,347,2311,2657,54,55,633,725,439,266,267,268,1214,403,770,2658,382,510,712,278,591,994,1222,1026,319,454,348,728,549,1338,266,267,268,270,1807,549,1338,150,446,512,835,810,809,809,809,809,811,812,899,814,2659,253,254,255,616,2660,496,2096,497,498,2661,390,391,495,2662,497,498,2419,443,2663,2069,644,222,223,645,646,647,648,649,650,2664,2665,492,172,382,148,429,149,591,1243,281,280,281,281,1036,145,146,346,319,347,728,69,1638,172,2666,429,429,149,279,280,281,1774,727,434,347,1239,549,1093,700,874,1086,333,410,2667,445,445,429,149,591,150,446,447,636,549,610,1304,2668,747,2669,429,149,1522,280,281,281,281,280,281,280,281,1245,737,738,2134,2215,390,391,494,2670,709,60,61,2671,2672,66,2673,66,67,254,984,460,179,1586,193,194,195,965,609,169,178,179,180,181,233,190,1643,987,2674,148,445,590,2675,170,1928,146,2676,960,180,2677,182,606,607,769,2678,54,55,633,518,534,535,611,537,537,1759,435,2679,2680,2681,2682,237,238,184,185,186,190,1931,2270,1499,2683,1159,1160,1436,2684,403,429,149,279,1178,149,672,280,281,280,281,280,673,356,502,634,538,611,1759,69,149,150,446,447,447,593,346,319,320,193,194,2556,2622,2297,860,1100,1565,739,740,1085,103,104,135,136,137,138,139,140,141,959,2685,2686,2687,1286,602,2527,2134,2453,2688,134,216,449,439,266,267,554,270,1294,271,1626,346,319,347,768,528,516,2332,2332,2332,2511,758,905,300,2689,1984,590,429,429,149,562,281,280,281,280,281,280,281,673,1159,1901,2690,355,383,2691,735,489,490,216,1042,439,266,267,268,270,726,549,2147,498,2692,480,2693,154,135,136,137,138,139,140,141,680,510,712,712,278,2694,149,279,280,281,281,655,1579,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1078,340,340,341,342,343,1081,426,726,69,148,445,462,999,69,300,301,358,2695,2696,1216,233,190,1967,483,484,485,2505,2697,1120,1121,254,419,231,967,1890,769,2678,54,2698,571,401,383,402,383,402,383,402,302,303,304,303,304,303,304,303,304,303,304,303,788,637,2157,2699,371,1505,616,497,498,617,618,545,2700,511,446,447,512,549,708,180,181,233,2701,642,434,454,528,570,952,2570,401,383,502,634,611,537,537,538,538,537,538,2702,592,447,447,447,447,512,69,1814,2703,959,613,614,615,616,496,497,659,660,355,383,526,769,2678,54,55,56,2693,769,770,2408,147,148,854,574,2704,576,730,731,268,732,1921,549,1313,2325,2087,2088,485,2622,2705,510,278,2466,2360,2268,2370,490,216,1042,439,440,859,860,1101,1101,1101,1101,1543,2268,974,390,391,495,1744,497,498,617,618,1822,403,402,302,303,304,303,304,303,304,303,304,303,304,303,304,303,788,549,1338,518,357,302,303,304,2706,680,178,179,382,401,2707,429,149,759,446,512,69,663,549,708,369,400,179,180,181,921,232,233,190,1554,2708,696,1706,2709,1317,188,2273,631,570,1658,54,55,2479,390,391,494,495,690,505,496,2710,510,712,278,511,446,2711,2232,1830,439,440,916,1690,507,670,545,671,429,149,759,446,447,592,2712,2713,2714,401,356,502,634,536,538,2715,502,634,611,538,538,537,537,1759,1455,352,600,172,382,401,383,502,634,538,538,2716,453,319,454,945,695,401,356,502,634,611,538,537,537,1759,1368,252,2717,2425,455,1840,528,2718,885,2719,439,266,267,1387,193,194,1072,370,371,1505,2720,369,400,179,382,510,696,2721,1549,193,194,2722,147,148,979,1663,1706,696,278,562,281,280,1178,1424,1084,439,2723,2724,1706,278,562,280,674,571,526,769,770,2396,54,55,633,2379,774,23,590,2725,554,271,2493,331,2108,860,1101,1100,1100,1101,605,355,383,519,2726,2727,1915,1915,2050,1915,2051,1915,1915,2728,1718,2729,496,2096,497,498,2730,237,238,184,185,186,239,185,186,240,188,189,190,2731,401,383,526,698,547,172,382,148,149,562,280,373,400,179,147,401,383,502,634,538,799,549,1922,402,383,556,1348,557,558,557,1351,445,149,150,446,447,1787,510,573,574,2732,1550,587,434,347,581,348,348,348,455,455,455,455,686,403,534,535,611,537,538,538,537,538,538,537,537,537,2733,607,545,2700,2734,346,319,347,348,581,348,348,455,455,1898,1254,1255,1256,1257,2735,401,356,502,634,538,611,537,538,538,537,538,2736,557,557,558,557,557,557,1222,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,811,812,899,814,1945,333,1232,418,2737,2551,270,2240,1815,516,2738,2739,369,400,179,180,181,921,232,233,187,2160,489,490,216,449,439,838,23,532,2740,300,301,302,303,548,549,610,134,216,1042,439,440,859,860,1101,1101,1101,1101,711,510,573,629,2741,653,2742,101,162,163,2085,157,216,449,439,266,267,554,1294,270,726,403,239,948,949,950,951,570,2743,526,769,770,2744,148,445,149,672,280,281,280,281,295,506,445,445,429,429,445,445,149,150,2745,401,356,1275,251,252,253,254,984,687,688,495,691,1281,1744,497,659,2254,2253,2254,2253,2399,1133,537,2046,549,2746,2747,1031,333,1232,335,336,337,44,45,46,23,1411,2538,2748,2689,1277,346,476,2195,2196,2438,2749,148,445,653,570,2750,725,439,450,1200,1831,1832,2751,346,319,347,455,528,570,516,2373,182,606,607,2752,429,429,149,150,446,447,447,636,69,2753,191,192,331,460,179,390,391,494,495,1083,518,534,535,611,537,537,537,537,537,537,537,2733,671,477,2236,2754,2755,1260,44,45,1531,2756,240,188,189,241,1165,1520,2440,2388,2757,456,348,2758,995,2759,180,606,2478,570,952,529,1644,1645,2760,2761,2762,429,445,445,149,150,446,447,1731,445,149,150,446,447,447,447,790,2763,2360,498,617,2764,2765,2766,2767,2768,2270,1499,1555,2769,346,319,347,455,686,2770,510,696,696,2136,1793,1794,2771,245,2772,2325,2087,2088,485,2773,586,216,449,439,669,179,390,391,494,782,149,562,281,280,563,2590,1100,1565,2774,2775,995,2776,361,619,620,169,352,621,146,231,232,182,181,182,183,1561,1164,102,103,104,135,136,137,138,139,140,141,959,511,446,447,447,592,2777,149,591,751,692,1967,483,484,485,2505,2297,445,445,429,149,591,150,446,447,447,512,403,445,445,149,150,2778,536,537,1759,549,610,2236,2779,23,222,223,224,644,222,223,645,646,647,1065,1265,303,1519,303,305,303,305,303,304,303,305,303,305,303,788,403,514,570,952,529,346,319,347,2313,1112,2780,445,445,445,445,429,2781,2782,1501,455,2783,664,2132,2133,2784,2785,460,179,147,597,502,634,538,1394,330,1073,563,703,146,147,1286,603,602,752,591,150,446,447,447,636,549,800,495,496,497,498,1745,480,2786,207,208,388,2269,23,636,758,237,743,744,188,189,187,188,189,239,185,186,190,1549,193,2787,237,238,184,185,186,190,575,192,193,194,1072,502,634,538,611,537,538,663,549,708,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2788,714,2348,403,429,149,1522,280,281,281,280,1510,611,537,538,538,537,537,537,2733,1163,232,233,190,2434,193,194,2789,455,1318,300,2345,2480,950,951,570,571,355,383,526,2790,1026,319,347,456,348,455,686,2791,727,434,454,581,455,455,455,348,348,455,455,1215,549,708,2792,422,2793,172,390,391,494,2073,495,690,496,690,690,496,746,756,554,1294,271,271,270,270,272,549,2147,2794,2795,1431,1431,2796,1872,959,756,554,270,1294,270,272,403,252,253,68,69,545,671,527,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2797,2798,1501,2799,291,297,436,1538,1568,147,401,356,556,692,460,179,300,2800,2801,2384,2669,170,171,587,434,454,1109,147,148,429,429,429,149,430,280,281,281,281,280,281,563,2802,536,538,1759,426,686,549,800,601,602,2004,2803,147,2804,429,429,149,591,150,446,447,447,447,636,435,1713,2805,2806,23,390,391,494,495,505,496,496,496,691,782,545,2421,382,401,383,2807,1424,300,301,2480,950,951,570,571,178,179,147,355,383,519,990,2808,231,232,233,190,1549,193,194,195,2809,355,356,384,654,557,557,2201,2260,2810,2143,193,194,1577,2811,1299,401,356,502,634,2812,1611,182,181,233,190,910,192,193,2144,2145,591,672,280,1245,546,519,520,1597,1762,563,1546,1546,340,340,340,340,340,2813,1413,1526,296,180,181,182,183,184,185,186,190,1828,192,2335,1084,439,440,916,2814,694,204,594,595,596,316,317,703,146,147,401,383,874,613,685,434,347,455,528,570,2718,355,383,534,535,537,2815,727,434,347,1779,2799,231,232,233,241,1165,2816,2817,1109,401,383,502,634,536,538,538,2733,178,179,382,510,696,2136,2818,2819,2820,496,505,496,496,496,977,1159,1160,2821,2822,2823,616,497,498,1745,2824,2825,497,2826,743,744,188,189,241,185,186,240,188,189,190,2827,193,2828,698,692,178,179,382,355,356,357,1396,664,330,332,333,334,335,336,337,2829,589,670,545,1188,1846,460,179,147,461,445,429,149,591,150,446,447,592,636,549,2830,401,356,556,654,557,557,558,557,558,557,557,557,558,557,558,557,559,1593,1188,2249,556,654,557,557,557,558,557,1351,1288,1289,1290,1291,523,44,45,524,918,237,238,184,185,186,240,188,189,190,2831,2832,687,688,616,691,692,276,179,346,319,347,455,1149,549,2833,2325,2087,2088,485,2834,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2060,270,1814,2835,2836,383,556,1348,373,352,776,146,346,319,347,945,582,1169,439,266,267,268,2251,549,1338,1573,731,268,269,726,435,429,149,591,150,446,447,592,592,447,447,636,403,401,383,402,502,634,537,799,69,355,383,534,535,536,2837,149,511,446,447,447,447,447,1731,1169,439,266,267,2393,23,300,2345,302,303,305,303,304,303,2838,277,712,278,511,446,512,835,1744,497,498,499,515,1658,54,2839,2145,445,445,445,149,150,446,447,592,592,447,447,2063,545,671,666,667,668,439,838,23,440,916,860,2128,295,506,472,157,206,488,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1968,154,105,1603,507,687,688,495,496,2559,282,149,591,150,446,592,447,447,592,592,512,549,708,712,278,591,994,655,654,557,557,558,557,557,557,558,557,558,1351,2840,611,537,537,1759,403,581,455,686,549,760,2503,2552,445,149,150,446,447,447,447,447,636,1241,276,179,390,391,494,616,505,690,2247,527,672,281,281,752,149,150,446,447,636,435,258,761,260,261,836,837,262,263,264,265,266,267,268,270,271,1672,549,1922,2446,455,528,571,2841,1245,1169,439,266,267,554,726,835,222,223,645,646,647,648,649,2012,2842,1112,2843,2844,2845,69,2331,2331,2332,2332,2332,2333,696,1664,375,2846,2847,2848,2849,1522,281,281,280,281,281,281,280,281,280,281,561,1294,272,69,613,614,615,495,496,505,496,496,496,496,1111,238,184,185,186,187,188,189,190,2850,1642,542,1693,1693,1693,543,1354,1334,355,383,534,2851,1651,172,382,401,356,519,1128,2852,304,303,304,303,304,303,788,549,1338,149,591,150,446,447,592,636,549,760,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2853,1413,348,1822,2156,104,135,136,137,138,139,140,141,142,102,154,135,136,137,138,139,136,137,138,139,1304,1305,1306,2854,500,727,434,320,193,194,2556,2855,2856,2411,181,233,190,745,1526,982,445,445,149,562,281,280,1510,2497,2857,2858,1585,439,266,267,554,271,1294,271,271,270,270,270,270,272,69,355,383,384,557,654,557,557,557,557,557,557,558,557,558,557,558,557,558,557,559,2859,666,667,730,731,268,2860,549,1338,2861,2862,445,445,445,462,463,69,355,356,534,535,538,537,2355,331,1885,514,570,571,278,150,446,447,592,512,549,2863,369,400,179,180,181,233,190,745,2012,417,333,410,418,23,1706,2864,951,1658,54,55,2040,2865,504,2866,586,216,449,439,669,179,180,181,233,190,986,1044,1846,2867,2868,254,1032,776,777,778,779,780,780,2869,1846,149,150,446,447,447,592,512,2854,149,591,1243,281,280,386,1632,333,410,335,2870,1612,658,80,2433,429,445,445,445,149,994,295,2871,429,149,430,281,281,280,281,281,386,187,188,189,2872,401,383,502,634,611,538,1759,758,592,592,1728,375,376,377,990,1804,1363,2336,528,571,1721,68,69,532,526,545,1188,1199,145,146,147,401,356,556,558,557,558,559,560,1935,2028,2873,382,148,445,149,150,446,2874,1585,439,266,267,554,271,1294,271,271,270,270,271,2875,445,445,149,150,446,447,447,2712,1015,172,382,148,149,150,1811,1304,2876,172,346,319,1821,347,348,1215,69,2763,2360,659,974,268,269,271,270,271,2638,147,401,356,2877,357,302,303,305,303,304,2706,366,590,1769,2700,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,669,179,390,391,494,495,690,496,1817,1237,777,846,616,2660,496,2662,2878,1179,2879,179,2880,180,181,921,232,233,190,245,1409,987,2881,921,967,2882,2883,1171,429,445,429,429,445,2884,687,980,779,781,781,780,780,780,780,780,2885,231,232,311,181,233,190,234,848,1045,148,854,629,190,986,2886,2887,2888,984,231,232,921,1966,69,305,303,305,303,304,303,304,303,304,303,304,303,548,758,2326,1835,558,557,558,557,557,655,2343,2089,54,2839,2145,769,1612,148,429,429,445,445,445,445,149,2889,429,429,445,149,759,446,1444,2890,2824,2891,496,2662,497,2564,2892,300,2345,302,303,304,631,515,1658,54,2893,2466,2360,659,2370,545,2894,1876,422,1023,1877,1514,1693,1693,2895,254,419,561,429,429,445,149,150,446,592,2896,514,515,516,2570,2897,1274,2898,232,182,181,1163,1641,149,591,150,446,592,592,447,592,512,549,1313,921,232,233,190,745,80,1381,1382,2387,2388,2899,2900,1133,611,538,538,537,538,538,1759,403,511,446,447,592,592,1772,664,2446,455,1840,528,952,529,178,179,180,181,233,190,2606,2211,233,190,2325,2087,2088,485,486,147,401,383,402,383,502,634,663,69,510,696,783,570,1658,54,55,56,2693,638,169,178,179,147,401,356,556,1593,429,445,445,2901,669,179,346,319,347,456,455,455,348,455,1109,2180,2179,2385,1026,319,347,1132,403,2902,1169,439,838,23,390,391,494,616,690,505,690,690,690,690,1461,1990,2903,333,1232,2904,400,179,382,510,573,2905,530,1575,1265,303,903,303,788,350,266,267,554,1294,270,270,271,271,272,426,485,2622,2749,538,537,1759,69,680,1304,1305,1306,2906,237,238,184,185,186,190,575,2907,513,2515,172,382,148,429,429,445,149,759,446,512,549,610,346,319,347,456,348,686,435,259,260,2792,2908,1598,2360,659,660,687,688,495,496,505,690,690,496,496,691,622,591,150,446,512,403,2909,918,1973,2662,497,2268,2370,1099,859,1101,1690,1101,1100,2128,605,1549,193,194,195,1853,2910,150,2778,147,148,149,150,446,512,549,1338,2911,147,513,2912,1314,1544,333,334,335,336,337,1233,2913,346,2914,237,238,184,185,186,2546,1522,281,280,281,280,281,280,281,280,281,373,2915,1074,1323,180,606,607,2475,2700,2916,2128,605,251,332,333,334,335,2870,2563,497,498,617,2824,2917,698,510,696,278,150,446,592,447,1204,401,443,463,1216,653,516,2331,2333,2483,271,2286,2918,2919,190,2920,670,2149,239,1165,2921,549,1338,460,179,147,597,556,654,557,558,557,558,557,558,557,558,2201,2202,657,658,1526,2922,460,179,147,461,445,149,672,280,281,280,561,205,101,624,625,928,565,2923,23,2924,376,377,1128,1129,776,146,147,518,519,990,1408,1759,1241,2196,485,2197,511,446,512,758,445,429,149,1522,280,281,281,281,280,281,280,281,280,1281,348,1779,2553,2925,355,356,519,990,2926,281,2441,2927,1281,778,2928,780,2369,2613,2929,1423,2930,2931,2162,483,484,485,486,769,770,2657,1241,233,190,2932,645,646,647,1065,1265,303,1519,303,305,303,305,303,304,303,304,303,788,549,800,237,238,184,185,186,241,185,186,239,185,186,190,191,2933,300,2345,302,303,304,631,570,2743,454,581,1215,758,445,149,759,446,592,447,592,592,447,1787,727,434,347,456,348,686,713,149,150,2087,2088,2343,2505,2697,355,356,384,654,557,557,2201,2260,820,2934,23,402,302,303,305,303,304,303,305,303,305,1164,401,356,556,654,557,557,558,557,558,557,557,557,558,557,918,2935,1822,1241,2533,496,1744,497,498,1745,2936,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2937,1413,147,1663,697,545,671,666,667,1564,916,1565,2774,1565,739,2565,291,292,324,253,254,419,382,532,526,545,2700,147,148,429,149,759,446,447,447,447,636,637,747,2180,2179,2179,2179,2180,2179,2180,2179,2180,2179,2180,2179,2180,2205,536,537,538,2938,1294,270,270,270,270,270,2007,2268,2253,2253,2254,2253,2253,2254,2254,2255,295,982,698,2939,47,149,562,280,281,281,281,280,281,280,281,280,782,149,759,446,592,447,592,636,549,760,382,597,556,558,557,2940,513,526,769,2605,727,434,1094,47,180,181,1163,232,233,190,2768,470,471,714,2941,2942,254,724,178,934,2490,1691,532,533,874,553,439,266,1366,254,984,251,1073,640,518,534,535,611,537,537,537,537,663,549,1338,2943,346,319,454,455,2944,2945,54,55,2633,2946,417,2947,592,592,447,447,447,593,998,999,835,2948,515,952,2406,518,384,654,557,558,557,558,557,561,538,538,538,538,538,537,537,537,2349,769,770,2396,54,55,2040,2949,178,179,180,181,233,239,1165,2921,549,2863,2228,515,2495,1026,319,454,1027,549,708,429,445,429,149,1522,280,281,280,1211,608,2393,23,581,455,528,1658,2950,2951,2952,401,383,2953,587,434,1821,347,582,278,2466,2360,498,617,2954,689,496,690,690,1330,2955,355,383,384,654,557,558,1718,764,765,2387,2432,2317,523,44,45,822,23,548,713,607,545,1188,1199,134,216,1042,439,838,2956,2957,1220,602,2958,570,516,2257,345,172,346,319,347,348,1502,2470,2002,602,673,291,292,293,1719,233,190,2959,140,141,959,330,332,333,334,335,2267,178,179,147,148,445,149,591,2960,429,429,445,149,759,446,592,447,447,790,429,429,149,562,281,280,281,281,281,280,281,280,673,148,429,445,445,1704,990,1705,700,502,634,611,538,538,537,2961,2962,1406,558,557,673,149,591,150,446,447,447,636,549,1571,490,216,449,439,669,179,390,391,494,495,690,1083,1356,2963,2964,2965,2966,1490,23,1995,2967,1121,68,403,528,784,370,433,434,454,528,570,952,2627,641,656,642,434,347,528,570,516,2257,545,1188,2249,382,148,149,591,150,446,447,636,403,2505,2968,671,345,509,172,382,510,573,629,190,191,1285,1924,2133,2784,2969,148,552,233,190,1863,1196,1197,2970,2971,502,634,611,538,538,538,537,538,538,537,663,549,2972,2879,934,2490,2207,697,608,383,534,1636,2582,402,302,303,305,303,305,303,305,303,305,303,304,303,304,303,548,426,454,455,581,455,1215,2973,2544,680,1188,2249,171,687,980,781,780,2423,191,802,80,1829,743,744,188,189,241,185,186,240,188,189,190,2974,445,445,149,994,918,658,495,497,498,617,480,2693,777,778,779,282,445,429,149,591,150,446,447,512,403,2700,537,663,350,557,1348,557,558,557,558,1281,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1694,1924,1384,1386,561,355,383,534,535,2185,1492,2812,537,950,2186,1138,758,467,467,104,135,136,137,138,139,140,141,680,148,149,150,2087,2088,485,2505,2749,2763,386,906,808,1007,2975,819,2976,820,2977,333,410,335,336,337,44,45,1006,549,1028,2387,2388,2978,2979,2980,495,689,690,496,691,692,429,429,445,445,445,445,445,149,150,2632,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2981,770,2657,54,2839,2145,510,696,1343,305,303,305,303,305,303,305,303,305,303,304,303,304,1164,2982,686,713,375,376,1627,1331,1332,1331,521,522,523,44,45,1545,1317,188,2273,1670,145,146,147,148,445,149,150,446,447,512,549,1338,513,526,608,1269,184,185,186,240,1174,744,188,189,2983,211,1736,278,430,280,281,1513,2984,2985,495,2559,507,819,820,587,434,347,455,944,758,777,846,495,505,496,496,496,1222,556,654,557,557,558,557,558,557,1482,1931,2270,1499,2986,149,759,446,592,447,592,592,447,2987,370,433,434,347,455,2146,413,2988,2989,1152,1551,398,390,391,494,616,496,497,498,2419,148,445,670,769,770,2990,1863,1196,1197,1555,1002,2359,2525,150,446,2991,671,526,769,770,2992,237,238,184,185,186,190,2768,1932,1199,562,281,281,281,281,280,281,280,281,280,605,2993,2994,1379,1380,1081,1241,443,2995,231,1560,2536,2996,149,759,446,592,447,447,447,447,512,426,810,809,809,809,1489,774,23,2997,1525,2049,1915,1915,2998,1915,507,2999,3000,146,231,232,233,190,910,3001,178,179,147,355,356,357,302,303,548,69,390,391,494,616,690,496,3002,346,319,454,348,581,455,455,455,686,331,3003,3004,1348,1353,149,759,446,592,592,447,592,592,790,3005,3006,600,1288,765,1596,1909,426,270,271,2615,2185,3007,3008,468,2207,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1701,1691,687,688,495,976,442,216,449,439,266,267,1387,193,194,3009,492,172,382,148,854,574,2534,1184,1185,3010,909,146,231,232,233,3011,382,1286,2004,687,688,616,3012,402,302,303,305,303,788,758,355,383,384,654,557,558,559,1593,1903,1904,1905,23,356,402,1718,240,2328,2329,1138,549,800,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1956,703,146,147,510,573,629,190,1617,3013,281,280,281,280,281,280,281,1510,3014,469,2270,1499,1555,211,1736,382,148,854,629,190,191,192,193,2787,510,278,759,446,592,512,549,1922,511,446,592,592,447,592,592,2306,511,446,447,512,69,231,232,233,190,191,1415,47,187,188,189,240,188,189,190,3015,382,510,278,562,280,281,280,281,793,586,3016,1632,333,410,418,1032,510,696,696,2136,990,3017,1262,556,654,1351,136,137,138,139,1304,1305,3018,3019,1182,320,193,194,1577,3020,445,445,429,149,511,446,447,512,549,800,190,2487,3021,745,80,1941,2599,1638,1288,3022,1582,999,426,743,744,188,189,187,188,189,239,185,186,190,3023,1409,987,3024,3025,429,3026,2244,2339,1178,3027,383,502,634,537,611,538,1759,435,149,759,446,592,592,447,447,592,592,636,69,626,627,628,146,147,510,573,629,190,191,2654,980,781,779,780,780,780,780,780,1751,782,2331,2331,2332,2331,2331,2332,2331,2902,454,455,348,1132,549,1338,401,383,519,3028,295,2540,300,2345,302,303,304,631,570,516,2362,149,1522,280,281,280,281,280,1774,571,3029,767,1100,1994,300,301,2480,950,951,570,571,1084,439,266,267,268,269,270,1488,375,376,377,990,3030,769,770,3031,445,445,445,149,150,3032,279,281,281,280,281,281,281,280,281,280,673,375,3033,902,1164,237,238,184,185,186,190,1931,470,471,375,376,377,990,1363,2254,2253,2253,655,140,307,308,3034,587,434,347,2146,637,685,434,320,193,194,195,1897,455,2126,528,571,1107,299,103,104,135,136,137,138,139,140,141,959,147,355,356,356,519,520,3035,3036,1692,216,542,1012,1039,1764,1077,340,2813,1413,3037,3038,769,770,2657,835,492,172,180,181,233,240,1174,3039,426,147,510,573,629,190,1598,1642,1169,439,266,267,554,270,270,2510,549,1571,3040,1241,271,271,270,271,271,270,270,1322,653,570,952,529,992,2270,1499,1555,1487,429,3041,322,1428,1429,3042,295,2540,346,319,1528,1822,331,240,188,189,240,1174,744,188,189,2983,103,104,135,136,137,138,139,140,141,959,401,383,502,634,538,537,537,1395,713,492,172,382,3043,3044,266,267,554,3045,510,712,278,591,150,446,1812,148,149,150,1811,783,570,952,529,2343,486,382,401,383,519,1793,1794,608,777,846,616,505,690,496,2710,573,574,745,2764,2075,1338,3046,2369,498,1745,480,2786,131,3047,346,476,2195,2196,485,2622,3048,638,169,3049,999,435,764,765,3050,605,401,383,556,654,557,558,557,558,557,557,557,558,557,558,557,558,673,237,743,744,188,189,239,185,186,241,2056,545,1188,1846,601,602,603,602,603,3051,1692,216,804,3052,545,1188,1189,3038,1099,859,1101,2591,3053,355,356,384,1348,557,1351,147,355,443,463,69,263,264,1595,642,434,320,193,194,2722,266,267,554,270,269,1626,1663,1706,696,712,712,278,591,751,673,3054,231,967,1890,608,769,770,3055,921,967,2882,3056,382,510,696,278,150,446,447,3057,1644,1645,2597,3058,172,390,391,3059,149,1243,281,282,790,266,1041,68,2854,180,181,921,232,233,190,1643,2886,3060,149,1243,281,280,442,429,149,430,280,281,280,746,3061,3062,558,557,558,1482,3063,355,356,534,535,538,536,3064,1026,319,454,581,348,348,348,348,455,348,348,455,455,686,403,3065,1821,454,3066,291,292,324,253,68,69,2462,584,585,586,644,222,223,645,646,647,1065,902,303,3067,240,2328,2329,950,951,515,571,148,445,445,445,445,149,150,446,447,636,549,708,149,591,150,446,592,592,592,447,447,447,2991,1562,1289,1289,1855,1080,1081,403,347,768,528,952,2331,2331,2332,529,608,149,150,446,447,592,592,447,636,1368,149,430,280,746,867,3068,3069,3070,3071,3072,445,149,2558,2142,429,429,149,759,446,447,447,447,636,637,2591,1101,1565,3073,295,982,3074,69,233,190,745,80,1381,3075,510,696,697,769,770,3076,1687,288,203,204,175,176,177,169,375,1462,1463,1683,3077,1188,1846,3078,537,538,1395,435,737,738,2784,2277,2785,105,2031,2424,549,1093,356,534,535,611,538,1759,713,149,591,150,446,447,592,512,549,1338,1514,1693,1693,1693,1693,1693,1693,543,2451,820,402,302,303,305,303,305,303,304,303,304,303,304,303,3079,277,712,712,278,759,446,512,549,760,686,549,1571,2274,738,2784,2785,271,271,270,3080,502,634,611,538,537,537,538,1759,69,949,950,951,570,1658,54,55,2040,2397,2126,528,571,104,135,1493,3081,725,439,266,267,1276,1984,1099,859,3082,178,179,382,401,383,556,654,557,558,557,558,557,558,295,1911,1074,366,1026,319,347,348,455,348,1149,403,390,391,494,495,505,496,496,496,496,690,1330,515,952,2362,461,445,149,150,446,592,512,69,538,538,1759,549,1338,1519,303,788,713,1304,1305,3083,401,383,402,383,502,634,537,2575,403,445,445,429,429,445,445,3084,3085,510,573,574,3086,149,1243,281,280,281,281,281,280,281,746,2452,808,840,810,840,840,809,809,809,809,809,840,809,1007,1031,333,410,418,23,3087,1721,254,255,3088,3089,390,391,494,495,496,497,3090,3091,3092,937,938,939,130,460,179,147,518,519,520,1559,752,1713,3093,254,1032,1288,1289,765,1289,1290,1291,523,44,45,822,1402,3094,725,439,266,267,883,554,2007,346,319,320,193,194,195,2095,511,446,636,549,610,429,445,445,149,279,280,281,918,3095,545,1188,1189,148,149,1522,280,3096,224,216,1042,439,266,267,554,1294,270,270,270,726,549,1338,445,445,149,562,280,640,3097,605,865,549,3098,567,568,3099,765,3100,211,3101,361,619,620,169,352,621,146,147,355,383,383,519,990,1408,356,356,556,654,557,557,557,557,558,557,557,557,558,557,558,557,558,782,347,528,570,516,2257,608,445,445,149,279,280,281,280,373,355,383,384,385,563,278,150,2087,2088,2343,2505,3102,1317,2328,2329,950,951,570,516,2460,401,356,556,1482,454,2163,3103,3104,383,556,654,557,558,557,558,752,3105,3106,463,664,1528,3107,697,545,2053,231,232,233,190,2763,1642,3029,149,591,150,446,447,592,592,447,636,426,150,446,592,592,447,447,636,69,2657,54,55,2040,2090,429,149,1243,281,280,281,280,507,2622,2297,3029,149,562,281,280,281,281,281,280,746,447,447,447,636,549,1093,1744,497,498,617,3108,402,1396,435,2195,2196,485,2505,3048,240,188,189,240,188,189,239,1165,184,185,186,239,1165,1561,1164,320,193,194,195,196,285,286,104,135,136,137,138,3109,147,401,383,556,1348,557,558,557,558,442,148,429,149,591,672,281,281,373,3110,3111,148,429,445,445,445,445,429,3112,1193,1744,497,659,2254,2253,3113,455,528,515,2495,2518,240,188,189,240,188,189,190,3114,347,455,528,570,3115,502,634,1472,426,768,528,571,1675,1740,3116,1752,148,854,629,190,191,2624,135,136,137,138,139,140,141,680,1099,859,1101,1101,860,1100,1100,2128,782,445,429,1704,1793,1808,534,535,1242,403,149,150,446,447,512,69,502,634,538,1242,549,1093,1073,295,1250,390,391,494,495,690,505,496,690,691,782,454,348,3117,549,3118,1199,2345,2480,950,951,570,1658,54,3119,558,557,558,557,558,692,570,516,2570,1101,1565,2517,1565,2134,2339,3120,367,368,399,400,179,382,3121,355,383,384,558,557,557,654,373,1059,1361,1752,382,401,356,556,1348,557,557,558,557,558,1281,149,591,672,281,281,280,281,280,281,977,390,391,494,495,505,1403,689,690,690,496,1330,3122,3123,453,319,347,1109,445,149,150,3032,870,178,179,147,355,356,384,558,373,545,714,490,216,449,439,669,179,390,391,494,616,689,1083,149,759,446,592,1728,194,195,1897,455,1529,178,179,382,355,356,357,3124,545,1188,3125,1887,859,2441,401,356,502,634,536,3064,777,846,495,690,2559,282,150,446,447,447,447,512,1368,240,2328,2329,950,951,632,54,55,1238,581,348,686,549,1922,347,581,348,348,348,455,348,348,455,455,1109,2169,3126,938,3127,538,611,537,3128,150,446,447,447,592,592,447,447,636,69,417,333,334,335,336,337,44,45,3129,356,357,386,231,232,921,1560,744,188,189,190,3130,2254,2254,2254,2253,2253,2254,2254,2254,660,538,950,2187,3131,616,2172,497,498,617,480,3132,764,765,2387,2432,2317,523,44,45,1531,80,1941,3133,670,545,742,332,333,410,418,1032,2692,3134,2421,510,696,696,696,278,759,1054,1658,54,2139,3135,3136,3137,1094,23,696,697,2577,241,1165,184,185,186,190,3138,1912,253,1122,697,545,3139,515,952,2257,429,149,430,280,281,280,281,280,281,280,281,280,673,1846,1322,988,3140,1476,382,401,383,2037,783,570,2503,485,3141,148,445,653,570,3142,1268,1269,184,185,186,241,1165,3143,653,516,2331,2550,331,455,1149,1455,443,463,69,190,469,2270,1499,3144,3145,539,149,279,280,281,280,281,280,281,280,281,280,782,482,483,484,485,2197,571,548,549,2147,616,497,659,660,382,355,383,383,534,2851,960,2405,1492,433,434,347,2313,1169,439,266,267,268,271,1214,713,429,429,445,445,149,2248,279,280,281,898,3146,1740,3147,270,270,270,1626,3148,3149,148,429,429,445,445,149,150,446,447,636,69,149,672,898,3150,3151,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,3152,46,23,687,688,495,689,496,690,496,1330,150,446,447,447,447,3153,1283,1026,319,454,728,549,610,1294,272,549,760,609,1084,439,266,267,554,1214,549,2863,526,545,3154,587,434,347,348,455,455,944,403,651,603,602,603,602,603,602,603,602,603,602,2656,429,429,429,429,149,511,446,447,592,592,3155,2478,570,3142,980,780,780,3156,149,1522,280,281,281,281,280,281,280,281,1222,2503,2623,1288,3157,571,742,3091,3158,1120,1121,68,350,3159,748,1920,270,2286,1921,69,178,179,180,181,311,834,69,401,356,356,556,558,557,558,559,385,918,382,510,573,574,2534,1184,1185,3160,536,538,1759,549,2147,590,3161,442,150,446,447,447,636,350,1675,3162,193,194,195,3163,671,952,3164,445,445,445,445,429,149,511,446,512,549,1571,1188,1199,1178,455,1215,549,1338,149,150,446,447,447,447,3165,840,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,924,1120,1121,68,758,2336,528,571,2111,2112,1915,3166,1752,482,483,484,2326,316,317,703,146,147,1286,602,1275,1730,426,429,429,445,429,149,759,446,447,447,636,713,1112,2843,3167,1845,549,1922,355,356,384,558,2201,2202,690,505,690,690,496,690,1222,445,429,149,759,446,447,592,3168,700,874,2803,390,391,494,616,497,3169,570,952,2257,2064,2065,2066,1846,430,655,382,355,443,999,549,2099,2096,497,498,1745,2948,3170,333,410,3171,2379,1490,23,727,434,347,728,403,134,216,1042,439,266,267,554,270,2510,549,1313,811,812,899,814,815,841,2002,602,603,603,602,2656,601,603,603,603,602,603,602,442,670,545,2421,3172,355,383,357,383,357,383,534,535,2046,435,2503,777,846,495,689,977,2882,2528,241,185,186,239,185,186,240,1174,744,188,189,241,1165,3173,149,591,150,446,636,549,1338,1835,557,557,558,557,558,557,557,295,506,773,774,23,3174,537,537,538,538,663,426,455,528,571,140,307,3175,1368,1171,178,179,382,401,383,1976,1804,1025,148,445,445,445,501,355,383,526,545,2462,804,544,239,185,186,3176,465,1872,859,1100,1101,860,1101,1101,1543,346,319,347,581,348,455,1318,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3177,3154,669,179,346,319,347,455,581,348,348,455,455,686,549,1338,558,1635,3178,549,610,502,634,2575,713,2262,207,208,388,3179,333,410,335,411,3180,840,1949,1536,1921,549,1313,442,367,368,369,370,433,434,347,455,1284,477,478,785,3181,725,439,838,23,3182,401,383,502,634,611,537,537,537,537,3183,149,430,1774,3184,545,671,2303,2304,2305,447,592,592,447,592,512,549,1571,455,686,549,1338,769,770,2078,149,279,280,281,281,281,280,281,280,1245,305,303,305,303,305,303,304,303,304,303,305,303,305,303,306,180,181,921,232,182,3185,2325,2087,2088,485,486,1564,859,1565,3186,1222,149,1522,281,280,281,280,281,1774,716,717,722,403,348,3074,426,130,247,3187,722,758,909,146,147,355,383,534,535,611,1759,637,375,2846,3188,3189,193,194,3190,700,556,654,557,557,557,558,557,558,557,558,557,558,557,558,711,952,2257,384,1348,557,1351,844,938,939,211,3191,485,2505,2749,2274,738,2134,3192,727,434,454,581,455,455,348,348,455,348,348,455,1215,1241,680,1188,2249,2713,445,149,150,446,447,447,447,2342,3193,190,2434,193,194,3194,545,671,346,476,477,478,785,3195,1014,547,172,180,181,233,241,1165,2816,3196,382,355,383,1976,1363,311,606,957,549,1313,239,185,186,240,188,189,190,3197,1044,1846,536,537,537,538,663,3198,478,785,3199,3200,759,446,592,447,592,3201,608,671,759,446,592,447,592,3202,3203,992,3204,1663,697,698,180,606,607,769,770,3205,3206,2652,3207,510,712,3208,410,335,336,337,44,45,524,295,3209,445,429,3210,147,148,429,149,430,280,281,280,281,280,561,382,277,2136,3211,147,518,357,302,1164,556,654,557,557,557,558,557,558,557,558,1281,1127,216,449,439,669,179,346,319,454,695,756,2483,2615,149,430,281,280,281,280,281,281,280,561,3212,3213,622,169,178,179,147,148,462,463,549,1338,641,764,765,2315,3214,3215,3216,1268,1971,744,3056,3217,1350,318,319,347,455,581,348,348,455,455,686,549,3218,266,267,554,1294,271,271,270,271,1322,3219,3220,240,188,189,190,1643,2886,471,581,455,455,455,455,686,403,538,538,538,3221,239,948,949,950,951,515,1658,54,2839,2145,292,3222,601,602,603,602,603,602,603,602,603,603,603,602,603,602,603,2471,3223,445,149,1243,281,793,1026,319,347,348,581,455,686,403,3224,903,303,305,303,548,435,429,429,445,429,149,591,672,280,752,348,1822,403,2563,496,2096,497,3225,808,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,3228,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,1007,1031,333,410,418,23,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,810,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1489,774,23,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,1007,1031,333,410,418,973,810,840,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3229,3230,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,1007,1031,333,1232,335,336,337,2829,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,810,809,809,809,809,3231,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3226,2724,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,3231,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1249,1222,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,809,809,809,3226,2724,1579,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1078,340,340,340,340,1079,1944,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1546,3232,1078,1078,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,3233,808,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,1007,1008,1009,47,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,809,3234,810,840,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,809,1007,1031,333,410,418,3235,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,809,809,1007,1031,333,1232,335,336,337,44,45,46,23,810,809,809,809,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,1007,1031,333,410,418,23,826,3236,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,3237,1078,1078,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,1274,808,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,809,809,3238,3239,3240,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1078,340,340,340,340,340,340,1079,3241,104,135,136,137,1287,139,140,141,3242,114,119,120,121,367,368,369,400,179,231,232,233,241,948,949,950,3243,109,110,99,111,112,99,794,795,707,99,111,112,99,201,202,1899,1900,99,111,112,99,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,1644,3244,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,1037,1031,333,1232,335,336,337,44,45,1398,54,2893,161,328,329,101,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,146,231,232,311,181,233,190,191,802,3245,794,795,707,99,111,112,99,161,101,472,157,489,665,666,667,797,169,1086,333,3246,225,226,120,121,109,110,99,111,112,117,113,101,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,467,104,135,136,137,138,139,140,141,959,118,119,120,121,109,808,809,809,809,809,811,812,899,814,815,816,817,333,410,3247,1364,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,211,132,114,119,120,121,109,110,99,111,112,99,100,133,123,143,144,125,126,492,687,980,779,780,780,780,780,780,780,782,122,123,124,125,126,127,128,129,1002,374,229,909,146,147,401,383,556,654,557,557,558,557,558,557,558,655,152,249,250,101,330,252,3248,3249,3250,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1632,333,334,335,2870,134,101,114,119,120,121,109,1074,1323,808,809,809,811,812,899,814,1945,333,1232,335,336,337,44,45,1545,148,445,429,445,445,149,672,280,281,280,281,280,281,280,295,2871,102,103,104,135,136,137,1287,139,140,141,959,285,286,467,104,135,136,137,138,139,140,141,680,1037,1031,333,410,418,23,102,103,104,135,136,137,138,139,140,141,959,367,368,369,641,657,1908,779,780,780,2423,110,99,111,112,99,100,158,123,124,125,126,492,587,434,347,455,728,69,815,900,901,902,303,903,303,548,2770,197,145,146,390,391,392,251,465,295,982,118,119,120,121,367,368,369,400,179,147,510,573,629,187,2528,117,100,133,123,124,125,126,1194,2379,774,23,367,368,369,400,179,382,510,696,696,696,696,712,696,696,696,278,279,295,1616,310,146,147,401,383,502,634,537,536,537,537,537,2289,115,983,253,254,724,117,201,202,1899,1900,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,154,135,136,137,138,139,136,137,138,139,975,117,201,202,427,428,99,111,112,117,113,414,415,487,101,330,332,333,410,335,411,412,637,161,328,329,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,472,157,489,665,666,667,885,2719,439,266,267,554,3251,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,291,1675,1740,3116,442,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,145,727,434,347,581,348,455,455,455,1215,413,152,249,250,101,330,465,295,466,1074,1323,490,216,449,439,669,179,382,510,2024,386,420,801,120,289,109,110,99,111,112,99,100,489,665,735,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2468,1413,374,178,179,382,355,356,384,1784,373,153,103,467,291,297,3252,1568,133,123,143,144,125,126,145,777,846,495,689,496,691,1222,251,332,333,334,335,336,337,44,2489,101,114,119,120,121,109,1074,1323,472,157,275,473,474,475,179,300,2345,2480,950,951,570,571,102,103,104,135,136,137,1287,139,140,141,3182,104,135,1493,1305,1782,3253,367,368,399,641,657,658,3254,99,201,202,203,204,458,459,169,352,2130,184,185,186,239,1165,184,185,186,239,3255,134,101,114,119,120,121,367,368,399,1435,1161,193,194,195,1897,147,510,712,278,511,446,447,447,447,681,114,119,120,121,109,110,99,111,112,99,100,227,123,134,216,1042,439,266,267,268,270,726,403,109,110,99,111,112,99,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2853,1413,243,244,166,167,609,169,237,238,184,185,186,190,1643,987,3256,736,934,1473,1474,3257,823,197,492,172,382,355,356,357,302,303,304,303,304,303,3258,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,229,1212,1213,267,554,2251,549,1922,203,204,458,459,169,178,179,147,355,383,357,356,357,383,357,2155,549,1093,225,226,120,121,109,110,99,111,112,99,100,152,954,955,1324,333,410,418,419,206,488,101,330,332,333,410,335,411,412,331,161,328,393,394,395,396,699,172,382,513,514,516,3259,179,300,301,2480,950,1868,400,179,147,510,696,696,696,712,696,278,3260,1642,104,135,136,137,1287,139,1235,100,158,123,124,125,126,159,128,129,211,3047,168,169,178,179,382,401,383,402,3261,145,777,846,495,976,295,506,154,135,136,137,138,139,140,141,680,45,1006,1455,367,368,399,400,179,382,148,854,3262,382,737,738,2134,2339,480,3263,367,368,399,400,179,231,232,233,190,2325,2087,2088,485,3264,1254,1255,1256,1257,819,755,161,328,393,572,489,665,735,216,449,439,669,179,390,391,494,495,1744,640,961,962,963,135,136,137,1287,139,1304,1305,3265,1074,1323,367,368,369,400,179,180,181,2424,2770,136,137,138,139,140,141,959,460,179,147,277,278,562,281,280,281,280,281,280,281,281,280,281,280,281,2018,1642,140,141,959,330,1073,1281,367,368,369,400,179,147,510,1639,463,426,110,99,111,112,99,100,158,123,124,125,126,920,492,3266,382,510,696,783,515,1658,54,2839,2145,467,467,467,467,467,291,297,978,995,1052,127,128,129,905,467,467,467,467,104,135,136,137,138,139,140,141,959,351,229,909,727,434,454,581,455,455,1215,69,808,811,812,899,814,815,900,901,902,1469,297,3267,148,445,149,150,446,447,636,549,760,460,179,147,597,556,2265,1935,1400,439,440,859,1101,1927,561,461,429,429,429,149,150,446,447,447,636,435,99,113,101,1456,101,251,465,673,367,368,399,1582,999,549,1338,1276,1984,467,467,104,135,136,137,138,139,140,141,680,332,333,410,335,411,412,69,1493,1305,1782,3268,102,103,104,135,136,137,138,139,140,141,959,3269,422,423,424,3270,104,135,136,137,138,139,140,141,959,131,1516,1171,1015,172,382,355,383,384,557,1348,557,558,557,839,472,157,275,473,474,475,179,147,589,670,545,1188,1846,961,962,963,135,136,137,138,139,140,141,959,114,115,983,3248,258,259,260,261,262,263,264,1776,3271,1003,1004,1005,1229,211,2404,467,467,291,1675,1676,80,81,2910,1325,1524,1525,680,370,824,765,1596,1332,521,522,523,44,45,822,823,518,519,520,1332,1332,3272,310,146,147,510,998,463,435,146,147,355,356,534,535,537,1395,3273,1222,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,400,179,382,355,443,463,331,142,291,292,324,3274,797,169,352,3275,1526,296,149,591,2558,2142,367,368,399,453,319,1094,724,258,3276,1281,101,624,625,626,627,628,1562,765,1290,1291,523,44,45,1006,713,1456,101,251,332,333,1907,601,602,1224,156,157,101,624,625,626,627,1179,2879,179,382,518,534,535,537,538,3277,249,250,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,3278,1544,333,410,3247,3279,109,110,99,111,112,99,100,122,123,124,125,126,500,146,231,232,233,239,1165,2921,549,1571,3280,1120,1121,68,549,610,467,291,297,3281,148,149,1522,280,281,280,281,295,982,1059,1361,295,3209,761,260,261,836,837,262,263,264,265,266,267,554,271,3282,3283,735,216,449,439,669,179,390,391,494,495,496,497,659,660,3284,553,439,838,47,253,933,103,467,291,3285,193,3286,1074,1075,162,163,164,165,577,578,123,124,125,1150,145,146,147,355,383,534,535,2046,549,708,995,3287,1304,1305,3288,3019,229,909,146,147,510,712,712,278,591,150,446,447,512,549,1313,3289,1424,148,149,562,280,281,280,281,782,291,292,293,294,622,500,146,147,510,712,278,591,672,280,281,280,281,281,280,281,280,281,622,1000,522,523,44,45,3290,193,194,3291,1562,1289,1289,3292,243,244,175,176,177,379,169,3293,605,283,284,285,286,467,104,135,136,137,138,139,140,141,959,374,229,1015,172,382,355,383,534,535,538,2046,549,3218,326,327,99,201,202,203,204,594,595,596,379,169,1026,319,454,581,348,1934,124,125,126,492,172,346,319,454,455,728,69,492,1288,765,1596,521,522,523,44,45,1006,69,352,791,172,147,355,383,534,535,2046,426,1171,429,445,445,149,751,655,251,332,333,410,2667,3224,113,489,665,735,216,736,179,382,513,3294,3295,2565,3296,243,244,166,504,644,586,565,2101,934,2490,29,1553,152,961,962,963,135,136,137,1287,139,140,141,680,100,101,624,625,626,627,1179,2879,179,346,319,454,728,549,1922,1141,1142,1143,80,3297,666,667,1564,1996,859,282,3298,1524,3299,954,955,1507,752,920,492,172,346,319,347,455,695,1663,1706,696,2136,3300,808,811,812,3301,549,1571,146,147,510,278,511,446,447,447,447,592,447,512,435,167,662,169,237,743,744,188,189,240,188,189,190,2210,3302,1074,1323,702,580,2602,3303,2292,523,44,45,1531,3304,3305,3306,3307,3308,1116,572,206,207,208,388,3309,3310,3311,509,172,180,181,233,190,1246,1409,1044,1045,504,1374,222,223,224,216,449,439,669,179,382,510,998,463,549,760,1007,3312,333,410,335,336,337,1001,2031,1675,1676,3313,1015,172,180,181,921,1966,549,2147,228,352,3314,2536,3315,2867,2868,68,69,291,297,298,29,416,244,1123,1124,1125,379,169,756,268,1807,549,1338,147,1663,783,570,571,322,1428,1430,1431,605,115,1046,1047,1298,333,334,335,336,337,44,45,3316,683,346,319,1528,455,768,528,571,3317,295,1250,1424,231,232,182,183,184,185,186,187,1174,3318,252,253,68,69,1774,115,1046,1047,1790,1791,320,193,194,1202,3319,467,467,467,467,467,291,292,293,3320,808,1007,3227,3321,2106,483,484,485,2197,243,244,1123,3322,216,449,439,669,179,346,319,347,349,549,1338,1730,835,367,368,369,1159,1160,1436,3323,3324,130,297,468,1568,251,1073,640,454,456,455,528,3325,3326,510,712,696,278,1847,600,587,434,3327,104,135,136,137,138,139,1304,3328,3329,1171,1638,172,173,185,3330,3331,401,356,519,1793,3332,1413,510,278,150,446,592,447,447,2469,104,135,136,137,138,139,140,141,959,148,429,149,150,446,447,447,512,69,3289,145,777,846,616,496,1817,1245,2035,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1548,1078,1546,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1548,117,794,795,707,99,111,112,99,161,328,329,101,102,103,1506,386,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,3242,201,202,203,204,458,459,169,178,179,382,401,383,402,383,556,558,507,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,2175,2176,2200,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,203,204,205,101,624,625,626,627,628,146,346,319,320,193,194,3333,427,428,99,111,112,117,113,101,225,226,120,121,109,709,60,61,73,65,1421,549,1338,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,609,169,460,179,147,518,534,535,611,537,537,537,663,331,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,148,429,429,429,445,445,429,149,511,446,3334,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,251,252,253,254,419,117,201,202,326,327,99,111,112,99,161,328,393,394,395,396,531,146,147,513,700,402,302,303,305,303,305,303,304,303,304,303,788,549,708,367,368,399,400,179,180,181,921,967,1890,698,1171,102,103,104,135,136,137,138,139,140,141,959,427,428,99,111,112,99,161,328,393,394,395,396,265,266,267,268,269,726,426,1595,642,434,347,945,348,348,455,455,348,686,549,1338,102,103,104,135,136,137,138,139,140,141,959,472,157,216,449,439,669,179,346,319,347,455,1149,403,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,756,1387,193,194,2556,589,590,429,149,1522,281,281,280,281,281,280,295,1616,1116,572,489,490,489,490,216,449,439,266,1366,254,419,2070,2071,2104,172,390,391,494,2533,496,497,2418,3027,99,113,101,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,146,147,355,383,384,557,558,557,2265,1635,99,113,414,415,487,206,488,489,665,735,489,490,216,542,1693,543,1354,2491,99,113,101,102,103,104,135,136,137,138,139,140,141,959,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,547,687,688,495,505,690,1461,243,244,313,314,315,169,178,179,382,355,383,519,990,1804,3335,113,122,123,124,125,126,127,128,129,1218,1087,243,244,166,167,609,169,178,179,382,148,445,429,429,445,149,759,446,592,512,713,329,122,123,124,125,491,492,172,382,401,356,502,634,538,611,538,538,537,538,538,663,549,1338,99,113,489,665,666,667,725,439,440,916,2588,861,662,169,857,3336,184,185,186,240,1174,3337,145,777,846,495,505,690,690,496,496,691,1245,414,415,487,206,488,489,490,227,123,124,125,491,228,352,600,172,382,148,429,445,445,429,1704,3338,3339,374,3006,600,172,382,355,383,384,557,559,560,295,1616,147,148,445,445,445,429,149,759,446,447,512,549,3218,3340,333,1232,418,255,322,1428,803,2072,727,434,454,686,69,243,244,2069,644,222,223,645,646,647,3341,472,157,473,474,475,179,147,1663,3342,243,244,166,167,638,169,352,1133,537,1103,403,472,157,473,474,475,179,231,967,1890,545,714,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,401,383,519,990,1804,1804,1804,1804,3343,352,353,146,147,355,383,384,654,557,557,557,558,557,558,557,557,557,558,557,558,1178,1424,231,232,233,190,482,483,484,485,486,572,206,488,489,490,227,123,124,125,491,547,172,382,510,573,574,575,3344,472,157,473,474,475,179,147,513,3148,819,820,162,163,164,165,1589,1590,1591,169,460,179,147,518,357,302,303,305,303,305,303,304,303,788,549,1093,572,489,665,666,667,725,439,440,859,860,1101,1101,1100,1100,1101,1101,295,506,1074,1075,438,439,440,859,782,182,606,3345,665,735,216,449,439,669,179,346,319,454,2425,455,528,1658,3346,472,157,489,665,666,667,797,169,1866,537,950,2186,950,951,571,225,226,120,121,109,110,99,111,112,99,161,101,102,1356,2963,2964,3347,193,194,3348,328,329,101,225,226,120,121,367,368,399,400,179,231,232,182,606,607,769,770,3349,367,368,399,400,179,382,510,696,3350,3217,746,225,226,120,121,367,368,399,400,179,147,355,383,526,769,770,771,458,459,169,352,776,146,390,391,494,80,1941,1942,547,172,382,148,149,150,446,447,447,512,713,100,216,1042,439,450,3351,3352,508,317,345,172,346,319,347,348,455,3353,699,172,382,589,747,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2180,1752,665,735,489,665,666,667,725,439,838,47,367,368,399,400,179,231,232,921,3354,352,600,172,382,148,445,429,445,429,149,511,446,447,512,549,1028,668,439,669,179,147,461,429,149,1522,280,281,280,561,3355,3356,403,509,172,382,401,356,302,303,304,303,304,303,304,303,304,303,548,713,590,445,429,149,591,150,446,447,592,592,447,636,69,266,267,554,270,732,2638,346,319,454,2425,455,2336,528,1658,54,55,2633,2825,166,167,168,169,460,934,1473,1474,3357,193,194,1072,613,685,434,347,455,528,570,952,2570,203,204,584,585,586,644,222,223,645,646,647,648,649,650,602,2004,180,181,182,606,607,3358,665,666,667,730,731,268,732,1921,3359,355,383,534,535,2349,401,383,556,654,557,557,557,558,1222,808,809,809,840,1949,1323,490,216,449,439,266,267,3360,233,190,2412,1196,1197,1555,211,897,276,179,390,391,494,495,496,505,690,1461,374,460,179,1317,1174,3361,3362,3363,154,135,136,137,138,139,136,137,138,139,140,3364,100,101,624,625,626,627,3365,3366,434,454,455,455,1109,508,317,703,146,390,391,494,2073,495,3367,3368,3369,3370,1323,666,667,797,169,2587,1101,1565,1566,1565,2134,2339,480,3371,291,297,468,1568,285,286,291,1675,1676,3372,161,101,162,163,164,165,594,595,596,169,229,909,146,231,232,233,190,910,192,3373,490,227,123,124,125,491,228,178,179,382,148,445,445,149,3374,367,368,399,1159,3375,23,508,317,703,146,346,319,347,348,455,456,1215,549,2147,393,394,395,396,531,146,346,319,347,768,528,516,2331,2511,3376,367,368,399,400,179,231,232,921,967,3089,504,221,222,223,224,206,488,489,490,227,123,124,125,491,145,727,434,347,581,455,455,348,3377,178,179,382,148,149,562,281,281,280,281,280,281,280,281,280,442,1530,1031,333,410,3378,211,2243,348,348,455,348,348,455,457,510,278,759,446,592,1731,508,317,345,509,172,180,181,1163,232,3379,472,157,473,474,475,179,147,513,700,3380,228,352,600,587,434,347,581,455,455,1215,549,800,500,146,231,232,233,190,3381,1409,1044,2249,233,190,1598,2360,498,617,3382,1840,528,571,467,467,104,135,136,137,138,139,140,141,680,104,135,136,137,138,139,140,141,959,102,103,104,135,136,137,138,139,140,141,959,416,244,1123,1124,1125,379,169,352,798,172,382,355,383,383,534,535,536,663,758,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,662,169,170,171,587,434,347,581,348,455,455,348,1215,549,1922,147,510,278,430,280,622,808,809,809,840,1378,1379,3383,1074,1323,352,798,172,382,148,149,1522,281,281,280,281,281,281,280,281,1245,611,538,538,538,537,663,549,760,276,179,390,391,494,616,3384,442,808,811,812,899,814,924,179,390,391,494,746,510,278,591,672,280,1245,1406,977,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1040,3385,3386,1121,68,549,1338,638,1084,439,3387,147,461,429,429,149,591,1243,281,280,281,280,281,280,281,280,281,280,442,808,810,1007,3388,2143,193,194,3389,587,434,2446,455,2126,528,571,490,489,665,666,667,797,169,178,179,147,510,278,2909,1599,367,368,399,400,179,382,148,445,670,545,1188,2249,472,157,473,474,475,179,300,2345,2480,950,951,570,571,346,476,477,2064,2065,3390,472,157,473,474,475,179,231,967,1890,608,145,146,147,401,356,556,654,557,557,558,557,558,563,1007,1031,333,1232,335,336,337,44,45,46,47,453,476,477,478,3391,3392,178,179,382,148,445,445,445,462,463,69,197,276,179,3393,1317,188,2273,631,2529,2362,382,1286,3394,3395,547,172,382,401,356,556,1348,557,557,558,557,557,558,752,1026,319,454,581,348,348,455,455,455,1215,403,401,383,526,769,2165,147,355,383,526,3038,382,510,696,696,278,591,150,446,512,69,1314,1544,333,410,3247,3396,458,459,169,178,179,147,401,383,402,383,402,383,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,2147,101,162,163,2085,157,216,449,439,669,179,346,319,454,456,455,455,686,549,708,146,147,148,429,429,445,149,672,280,281,280,839,526,608,2470,650,651,603,782,665,735,216,449,439,669,179,346,319,454,2783,69,104,135,136,137,1287,139,140,141,3242,99,113,101,102,103,3289,638,169,756,268,757,549,2863,367,368,369,400,179,180,181,233,190,191,1415,47,382,401,383,526,545,742,258,761,260,261,262,263,264,432,371,1505,80,3397,100,227,123,124,125,126,2233,2234,832,832,832,832,832,832,832,966,168,169,375,2846,3398,3399,193,2144,2145,145,146,147,355,383,384,654,557,557,558,557,557,557,558,557,558,557,558,557,558,557,782,641,656,657,658,495,497,498,617,1955,1887,859,1690,1100,1101,1100,3400,943,319,347,455,1149,426,628,146,390,391,494,495,496,1718,233,190,1967,483,484,485,486,492,172,382,401,383,556,1348,557,558,557,557,558,692,445,429,429,445,149,279,280,507,318,319,347,728,403,589,670,545,1188,1846,602,603,603,603,602,603,602,603,602,605,145,146,147,355,356,534,535,611,538,652,162,163,164,165,577,578,123,124,125,1150,753,2942,254,255,2483,271,3401,3402,1121,68,435,103,104,135,136,137,138,139,140,141,959,148,445,590,3403,401,383,3148,231,232,182,606,607,769,770,2990,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,508,317,703,146,231,1641,145,146,390,391,494,1526,296,687,688,495,505,496,496,690,1461,147,148,445,429,429,445,429,149,1522,280,281,280,1774,1575,3404,545,1188,2249,180,181,233,190,3405,3406,148,429,149,511,446,592,592,447,447,636,835,361,619,620,169,1887,859,373,1638,172,382,148,854,629,190,3407,703,727,434,1821,347,348,455,348,348,455,686,549,2863,1887,916,1690,782,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,2392,439,266,267,268,271,2240,1921,69,162,163,3408,3409,101,251,332,333,410,335,411,412,426,109,110,99,111,112,99,161,101,102,1059,1060,1979,80,2433,228,229,230,146,1317,188,3410,109,110,99,111,112,99,100,101,624,625,626,627,2898,232,233,190,1863,1196,1197,1555,1218,755,127,128,129,131,2359,659,660,237,238,184,185,186,240,188,189,240,188,189,239,1165,184,185,186,190,3411,532,526,545,1188,2249,229,1015,172,173,185,2082,1455,1967,483,484,485,486,2727,1915,1915,2050,1915,2051,1915,2414,1915,442,369,1159,1160,1483,3412,820,641,2061,2062,2195,2196,485,2089,54,55,2040,3413,352,791,172,147,148,445,445,149,279,280,281,281,281,280,281,280,281,280,1718,102,103,104,135,136,137,138,139,140,141,959,460,179,1586,193,194,3414,959,367,368,369,400,179,390,391,494,616,691,746,508,317,345,172,346,319,347,348,581,455,348,3103,162,163,164,165,594,595,596,1084,439,440,859,2128,782,1215,403,401,383,556,654,557,558,557,558,557,558,557,558,557,558,557,558,282,231,967,1890,545,1188,1199,134,216,1042,439,266,267,554,269,272,435,147,148,429,149,759,446,592,592,1204,709,60,61,73,93,94,3415,66,3416,1421,403,229,1106,1288,765,1596,3272,1692,216,542,1012,1013,1013,1013,2312,134,216,1042,439,440,859,860,1101,1101,1101,1101,1101,1100,3417,591,1243,281,280,281,281,281,280,281,1411,178,179,180,181,233,190,3418,3419,237,238,184,185,186,241,1165,1520,3420,146,147,355,383,384,558,559,3421,559,1593,401,356,556,557,654,557,558,557,558,557,558,557,558,557,3422,355,383,514,570,516,2530,542,1693,543,2154,1239,435,609,169,375,2846,3423,3424,180,606,2478,570,571,103,104,135,136,137,138,139,140,141,959,169,178,179,382,510,712,3425,401,383,700,874,581,455,348,455,1318,572,489,665,666,667,730,731,554,2241,2007,2175,2665,266,267,2393,23,400,179,382,510,573,629,190,745,80,3426,3427,1219,545,742,460,179,147,461,445,445,149,759,446,592,447,512,758,382,1663,1706,3428,180,181,233,239,948,949,950,951,515,516,2570,680,460,179,147,518,534,535,1103,435,445,149,150,446,447,592,3429,1579,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,3430,616,496,3431,295,982,467,467,467,467,467,104,135,136,137,138,139,140,141,959,162,163,164,165,361,619,620,169,178,179,390,391,23,300,301,302,303,304,631,3432,355,383,526,545,1188,2249,180,181,233,190,2325,2087,2088,3433,178,179,147,148,445,445,445,445,445,429,149,759,446,447,447,512,664,1026,319,347,456,348,455,1215,403,460,179,147,461,149,150,446,636,758,597,402,302,303,305,303,305,303,305,303,305,303,548,549,1093,3150,3151,832,832,832,832,832,1584,764,765,2387,2388,2899,3434,514,570,3435,665,666,667,725,439,266,267,268,269,271,271,270,3436,190,2175,2176,659,2370,206,488,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2937,1413,145,146,147,401,383,502,634,537,611,537,537,537,537,1611,180,181,233,190,1549,193,194,2378,347,1501,455,3054,237,743,744,188,189,190,910,3437,1099,859,1101,1101,2128,673,330,332,333,334,335,336,337,44,45,1006,713,276,179,346,319,347,3438,147,589,590,445,429,149,511,446,447,592,592,636,403,2162,483,484,485,3439,148,429,149,591,672,280,281,280,839,352,353,146,147,148,429,429,149,511,446,592,592,592,636,435,586,216,449,439,669,179,147,518,534,535,3440,3441,429,445,429,429,445,149,3442,767,860,1101,1100,1100,1101,1101,1101,282,586,216,449,439,3443,1663,783,515,516,2257,172,390,391,494,495,690,1817,711,492,172,382,355,356,357,302,303,304,1164,450,1200,2189,1832,2190,891,3444,3445,1564,916,1565,3186,1565,3446,2300,3447,442,102,1356,2963,2964,3448,3449,346,476,2195,2196,485,2505,2297,228,460,179,147,518,384,654,557,558,557,558,557,558,557,558,557,558,557,558,386,429,149,430,280,281,280,281,281,281,280,281,280,281,1510,182,606,607,545,1188,1199,401,383,502,634,538,1395,549,1338,168,169,352,776,777,846,616,505,673,429,429,445,445,445,445,445,445,3450,492,1288,3451,724,1007,1031,333,410,418,23,346,319,347,348,455,581,686,758,445,445,445,462,3452,694,204,594,595,596,379,169,178,179,147,355,383,519,821,169,1632,333,410,335,411,412,403,445,445,149,1243,281,280,281,280,281,280,605,117,826,1282,829,2890,3453,777,778,780,2369,2613,2369,498,1745,2340,2375,229,909,146,390,391,494,495,496,1178,390,391,495,497,498,617,2340,3454,798,172,382,148,854,574,2768,2270,1499,1555,211,2398,382,513,526,608,228,178,179,147,148,149,562,281,280,281,281,1774,148,445,429,429,429,149,591,672,1774,492,172,382,355,383,384,654,557,558,1635,147,401,383,526,769,770,3205,1042,439,266,267,1387,331,545,3455,2916,1100,3456,1281,921,967,2228,570,516,2362,2855,2856,1663,697,545,1188,1189,510,696,697,545,1188,1199,180,606,2478,570,571,547,172,180,181,233,190,1931,2270,1499,1555,1002,390,391,494,495,1744,497,498,3457,840,810,840,840,809,809,809,809,809,840,809,1007,3458,352,1133,537,1759,549,1338,467,467,467,467,104,135,136,137,138,139,140,141,959,231,232,233,190,2106,483,484,2343,486,147,148,445,670,545,671,1663,697,545,1188,1846,147,510,278,150,2087,2088,485,2089,54,55,2040,3413,508,317,703,146,390,391,494,2073,495,3367,3368,3369,3370,352,600,172,382,148,445,429,445,445,445,149,150,446,636,1241,237,743,744,188,189,240,188,3459,526,608,1100,2128,918,3460,1121,68,350,330,465,977,318,319,347,581,455,455,455,455,1109,382,461,445,429,149,430,280,281,563,687,688,495,690,689,496,496,2441,401,356,519,990,1804,1804,3461,943,319,347,581,455,455,348,348,455,1215,403,429,429,429,429,149,1522,280,281,280,281,280,281,1211,2157,740,666,667,668,439,669,179,2880,584,585,586,2866,222,223,224,216,449,439,669,179,3462,482,483,484,485,2505,3463,243,244,313,314,315,169,237,238,184,185,186,239,185,186,190,3464,2211,148,149,150,2087,2088,485,2089,54,1659,352,798,172,382,510,712,712,278,759,446,512,350,149,3465,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,1156,579,580,703,146,147,510,573,629,190,1549,193,194,1072,345,172,390,391,494,495,505,690,690,690,496,690,690,496,691,752,1598,2360,2268,660,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1032,735,489,490,216,1042,439,266,3466,398,182,606,607,545,1188,1846,756,554,270,2493,549,1338,769,2678,54,55,2040,3467,382,148,445,445,445,445,445,429,429,445,149,150,446,512,435,1120,1121,254,419,725,439,266,267,554,270,2510,549,1922,1435,3468,2616,435,460,179,147,518,519,520,521,1786,233,190,2325,2087,2088,485,486,725,439,266,267,554,1294,270,270,270,270,271,3469,149,430,281,281,280,281,280,281,280,655,172,180,181,233,190,575,1415,47,345,509,172,382,148,854,629,190,1643,1044,1846,727,434,347,581,348,686,713,180,606,607,545,2803,808,811,812,899,814,924,179,346,319,454,455,686,758,127,128,129,1424,934,2490,1108,680,616,690,496,3470,2162,483,484,485,486,390,391,494,495,2729,496,1744,977,216,449,439,669,179,147,510,1639,463,549,760,147,401,383,514,570,952,2257,180,181,233,190,2106,483,484,2374,54,55,633,390,391,495,497,498,3471,369,400,179,382,510,573,3472,791,172,147,355,383,357,356,534,1636,3473,416,244,1123,3322,216,449,439,838,23,145,3474,3475,591,150,3032,149,591,150,446,447,592,636,549,708,669,179,147,518,519,3476,240,2328,2329,950,951,570,571,460,179,147,597,556,654,557,558,557,558,557,558,1935,429,429,149,759,446,447,447,447,447,512,331,850,1409,1044,1045,148,445,670,545,1188,2249,665,735,489,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,277,278,759,3477,3478,3479,2483,270,3480,549,2099,959,399,400,179,382,148,854,629,190,2412,1196,1197,2477,113,122,123,124,125,126,197,145,146,231,232,233,2020,1171,1074,1323,725,439,266,267,554,270,3481,382,1663,783,570,784,597,402,302,303,305,303,305,303,304,303,305,3482,147,148,149,2248,785,786,3483,231,967,1890,545,714,735,489,665,666,667,668,439,669,179,346,319,347,528,571,2405,950,951,570,952,2570,2132,2133,2134,3217,2340,3454,207,208,388,936,3484,68,549,1571,149,279,280,281,280,281,1774,258,761,260,261,836,837,262,263,264,3485,798,172,180,181,182,181,233,3486,3487,472,157,473,474,475,179,382,1663,697,769,1612,355,383,3488,162,163,164,165,1589,1590,1591,169,229,230,777,846,495,1817,655,601,605,318,319,320,193,194,1577,2055,390,391,494,495,505,496,496,691,1245,1846,131,1736,401,383,556,558,557,1348,752,401,356,356,502,634,538,611,538,538,537,537,537,1759,549,1252,607,545,742,545,1188,2249,3489,355,383,384,2201,2260,145,146,346,319,454,1215,549,1093,149,1522,281,280,281,280,281,1774,510,696,697,545,714,2106,483,484,2343,486,1268,1269,184,185,186,240,1174,744,188,189,239,1165,3490,429,429,149,511,446,447,447,447,636,403,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,3491,846,2563,605,988,3492,526,545,2053,489,490,216,449,439,669,179,390,391,494,616,496,496,1817,752,1288,765,765,1596,1909,69,638,169,943,319,1821,3493,460,179,147,461,429,429,149,591,150,446,592,512,69,382,355,383,357,302,303,305,303,304,303,548,549,1313,1846,429,445,429,429,149,150,446,447,512,758,148,149,150,446,592,592,447,447,447,447,636,549,1674,146,346,319,454,348,455,455,1149,835,3029,178,179,147,510,278,2694,495,690,505,690,690,496,496,496,496,691,692,700,3380,382,355,383,526,769,770,2744,146,147,401,383,502,634,1242,1455,402,302,3494,1830,439,440,859,1100,3456,673,330,332,333,3246,382,355,383,383,534,535,536,2188,554,271,271,270,272,435,3495,3496,1719,162,163,164,165,313,314,315,169,178,179,346,3497,1169,439,266,267,268,271,1672,1241,231,232,233,190,2162,483,484,485,486,1026,319,347,348,455,581,455,1318,492,172,382,148,429,429,429,429,149,150,446,592,592,447,3155,510,696,278,511,446,1787,532,2244,3498,170,1585,439,266,267,554,1294,271,271,271,270,271,270,2007,149,150,446,592,592,447,592,592,512,2770,352,621,146,147,355,383,383,534,535,1103,549,708,1610,216,449,439,669,179,346,319,347,1132,2156,500,146,147,510,712,278,2248,666,667,3499,295,1250,429,149,3500,203,204,205,101,624,625,626,627,628,146,147,148,854,629,190,245,1409,1044,1189,3501,54,55,2479,2166,3502,429,429,445,445,429,429,445,462,3503,703,146,231,232,311,181,233,190,191,192,413,401,383,383,556,558,559,385,561,735,216,1042,439,266,1366,68,435,671,370,433,434,347,455,528,515,516,517,769,2605,182,606,607,545,2314,777,778,779,780,780,1751,782,532,526,545,3154,390,391,494,2073,495,3367,3368,3369,3370,401,356,502,634,611,538,537,537,537,537,537,2349,1973,589,670,545,742,1887,859,1100,1888,507,277,278,279,280,281,746,279,280,281,280,281,280,295,982,178,179,147,401,383,502,634,1472,69,231,232,1163,1560,3504,3505,429,429,429,149,150,446,447,447,2063,2069,644,222,223,224,216,449,439,669,179,346,319,347,581,348,582,1099,859,1101,1100,1101,295,1616,1059,1361,295,1250,1924,2133,2784,2969,382,513,526,608,103,104,135,136,137,138,139,140,141,959,291,292,324,253,254,985,690,496,689,691,386,265,266,267,554,269,271,271,726,426,2282,216,1042,439,266,267,268,271,269,726,549,1093,410,335,411,412,69,554,271,3506,3469,2691,453,476,2195,2196,2343,2107,149,150,446,447,447,447,447,512,664,653,570,571,486,783,570,571,222,223,224,644,222,223,645,646,3507,3508,154,135,136,137,138,139,1304,1305,1782,1416,2522,611,537,950,951,952,2257,292,324,253,68,403,1106,172,180,181,233,187,1174,1228,373,145,146,147,401,356,502,634,611,538,537,1611,844,938,939,1002,345,509,172,390,391,494,495,690,505,496,690,691,692,777,846,495,2096,497,659,2254,2253,2253,2254,2253,2253,2255,746,2325,2087,2088,485,2622,3048,1824,823,1522,281,281,281,280,281,280,281,692,3509,2046,1796,2195,2196,485,2505,2749,3510,148,429,429,429,149,591,672,281,280,373,702,580,703,727,434,347,2311,815,900,901,3404,154,135,136,137,138,139,136,137,138,139,1304,3511,346,319,347,348,456,348,3512,607,545,1188,1189,725,439,3513,1325,1524,3299,182,606,607,545,2314,390,391,616,1744,497,498,617,2340,3514,180,606,2224,3515,276,179,346,319,347,686,549,1313,206,207,208,2283,2284,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,345,172,390,391,494,3516,460,179,147,461,445,445,429,149,430,280,281,280,281,280,281,2045,1124,1125,379,169,178,179,147,355,356,534,535,538,1395,758,239,948,949,950,951,570,1658,54,55,1238,2325,2087,2088,485,2505,2697,1996,859,3367,3368,3369,3370,1562,1289,1855,1080,1081,350,952,529,3517,148,149,150,446,447,592,592,512,69,690,3367,3368,3369,3370,508,317,703,146,346,319,347,581,348,588,178,179,382,355,356,384,3518,2529,3519,207,208,388,389,1120,1121,254,541,659,2253,2254,974,100,3520,3521,179,2676,960,687,688,495,2729,690,2172,497,3522,3523,23,181,233,190,245,3524,216,449,439,838,23,587,434,347,581,455,348,455,348,348,686,69,1949,1965,300,301,302,303,304,631,570,952,3525,148,445,445,445,445,445,501,149,591,150,446,592,592,447,592,592,447,636,69,180,181,1163,232,233,190,3526,2325,2087,2088,2296,3527,239,1165,1938,386,149,1522,280,281,280,281,1774,454,581,455,455,686,435,216,3528,1575,1265,303,1576,435,429,429,429,149,511,446,447,592,592,512,549,2833,545,2700,346,319,347,348,348,455,686,549,1338,2676,724,709,60,61,73,74,66,3529,66,67,254,255,374,229,909,146,390,391,494,616,690,505,691,711,1074,1323,382,355,383,526,545,2421,231,232,182,183,184,185,186,239,1165,184,185,186,190,3530,180,181,1163,232,233,239,185,2082,549,800,460,179,147,461,445,445,429,149,591,150,446,447,447,2121,1442,149,759,446,592,447,447,447,447,636,664,460,179,147,518,357,3531,148,854,3532,3533,3534,429,149,3535,316,317,345,172,346,319,347,2313,178,179,382,148,429,3536,355,383,384,654,557,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1275,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,1817,1350,291,292,324,253,254,255,382,355,383,534,535,611,3537,178,179,180,181,233,190,1643,987,3538,547,587,434,347,728,549,1338,161,101,162,163,164,165,361,619,620,169,237,743,744,188,189,241,185,186,190,3539,3540,508,317,703,1562,1289,2900,2236,2754,2755,1260,44,45,1531,480,2786,369,400,179,231,232,182,181,233,190,1549,193,194,195,1853,3541,2455,3542,3543,510,278,279,280,281,281,281,280,782,352,798,172,180,181,182,181,921,1560,3544,943,319,347,1239,549,610,666,667,1564,916,1565,2517,1565,2134,2339,2948,445,445,429,501,390,391,494,495,505,690,691,563,697,545,1188,1846,346,319,454,455,1132,549,1922,346,319,320,193,194,195,196,383,556,654,557,557,557,558,557,558,557,558,557,558,557,684,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1007,1031,333,410,418,541,146,147,513,2348,426,237,743,744,188,189,239,185,186,3545,102,103,104,135,136,137,138,139,140,141,959,735,489,665,666,667,1962,333,2164,2700,291,292,293,294,295,296,237,238,184,185,186,190,745,80,3546,1159,1160,3468,3547,3548,1317,2328,2329,950,951,570,1658,54,55,2633,3549,251,1073,282,382,401,383,402,302,303,304,303,304,303,304,303,304,1469,1159,3550,23,1059,1361,839,3182,1086,333,1232,335,336,337,44,45,1006,1227,591,150,446,592,447,447,636,69,2128,442,291,292,324,253,254,398,1254,1255,3551,3552,777,778,780,780,2869,175,176,177,169,3553,1718,698,577,578,123,124,125,579,580,345,509,172,382,148,854,629,190,191,192,193,194,1577,3554,237,743,744,188,189,241,185,186,239,185,186,190,745,3555,1638,172,382,510,573,629,190,2325,1811,567,568,3556,3557,1427,687,688,495,496,505,690,2710,445,149,759,446,1728,1179,3558,901,1265,303,3559,3560,390,391,2073,616,497,498,2692,2340,2375,1990,1031,333,410,418,23,178,179,382,401,356,502,634,538,536,1759,69,276,179,390,391,494,495,505,496,496,496,496,1461,510,696,696,278,430,280,918,509,172,382,148,429,429,429,149,672,898,616,2660,690,2172,782,104,135,136,137,138,139,140,141,959,276,179,390,391,494,3561,538,1472,664,369,613,685,434,320,835,231,232,233,190,245,1409,987,1248,513,533,556,1348,557,558,557,558,557,558,692,240,2528,147,355,356,534,535,2046,69,429,429,445,429,149,591,672,373,382,461,2781,601,602,2527,2134,3562,518,384,654,557,558,839,445,445,445,429,429,149,759,2420,3563,717,718,3564,722,403,1171,1554,1196,1197,1555,211,2243,447,447,447,593,838,23,1887,916,2128,746,148,445,670,545,3154,371,1505,495,496,497,498,617,480,3132,147,1663,783,570,571,147,1663,697,545,671,148,445,445,429,149,1522,280,281,281,281,692,149,759,446,592,592,592,592,447,512,549,1674,357,561,352,600,172,147,518,534,535,1242,1241,300,301,302,303,305,303,305,303,304,2218,777,778,1765,782,346,319,347,768,528,516,2332,2331,2331,2332,2331,2331,3565,669,179,346,319,347,3566,1037,3567,2724,686,549,800,454,945,348,348,348,348,455,455,455,455,1215,403,1059,1361,295,466,1314,1544,333,410,3568,149,430,280,281,622,808,809,809,809,809,810,811,812,899,814,815,816,1226,1182,347,581,582,496,497,498,1745,480,3263,178,179,147,355,356,519,3569,532,514,515,2495,662,169,178,179,382,401,383,519,520,1332,1597,2195,2196,2343,2622,2749,1887,859,1100,1101,860,1100,1100,1101,2128,1222,756,268,1294,270,271,271,270,272,3570,905,589,3571,190,1828,802,2560,2478,570,2495,148,854,629,190,745,80,3572,401,383,402,383,556,654,557,558,557,558,557,557,557,558,557,558,557,2441,346,476,477,2236,3573,2157,3574,148,445,445,429,149,759,446,447,512,413,2240,1921,1227,307,308,3575,549,2147,154,135,136,137,138,139,136,137,138,906,3576,3577,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,460,179,147,597,402,302,303,548,549,610,149,1522,280,281,280,563,3578,1031,333,1232,335,336,337,44,45,46,47,2533,497,2268,974,356,502,634,538,611,537,538,538,537,537,1759,69,709,60,61,72,71,73,74,66,2381,66,2381,66,67,254,985,182,606,607,545,1188,1189,2421,1294,271,271,270,271,272,664,1304,1305,3579,1402,2157,740,355,383,384,3421,557,558,1351,3580,266,267,554,269,270,272,435,429,445,429,149,759,446,447,447,636,549,800,1084,439,669,179,346,319,347,455,455,944,549,1028,1744,497,498,1745,3581,390,391,494,2073,3582,370,433,434,347,455,528,570,516,2570,168,169,170,171,172,390,391,494,1526,296,2563,497,498,3583,356,502,634,536,538,537,663,1216,429,429,429,149,511,446,592,592,447,512,403,909,777,846,616,496,1342,295,1616,148,445,670,545,3584,173,1165,3490,514,515,3115,3585,356,556,557,654,557,558,557,557,557,558,557,561,1130,1383,1386,1624,1887,916,2128,655,237,238,184,185,186,241,185,186,239,185,186,190,1933,429,149,591,150,446,592,592,447,592,592,3334,810,809,1949,1323,2747,1031,333,1232,335,336,337,44,45,46,23,102,1254,1255,1256,1912,253,254,419,680,694,204,594,595,596,379,169,460,179,147,518,534,535,538,799,549,1571,699,172,382,513,700,556,654,557,558,557,558,295,506,532,526,2231,384,654,557,557,557,558,386,921,232,182,3185,2421,513,526,545,1188,1199,147,355,383,534,535,1103,435,2132,1386,3586,231,232,311,181,1163,1966,1241,149,279,2441,276,179,390,391,494,495,496,690,1236,373,429,429,445,445,149,279,280,673,345,509,172,382,510,573,629,190,191,192,193,194,2448,178,179,382,1730,835,454,686,69,237,743,744,188,189,241,185,186,240,188,189,187,3587,2478,3588,172,382,148,429,149,511,446,447,592,636,637,382,148,429,429,429,429,149,759,446,636,331,278,562,281,280,281,280,3589,3590,239,185,186,239,185,186,239,1165,184,185,186,239,1668,1286,602,2527,2134,2339,2340,3591,1658,54,55,3592,240,188,189,190,191,802,442,657,658,495,1802,690,690,690,690,496,496,496,496,691,442,3593,3594,3595,3235,896,807,445,149,150,446,592,512,1227,149,591,150,446,447,512,69,231,232,311,181,2424,549,1313,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,883,554,3596,367,368,369,613,685,434,320,3597,680,149,150,2087,2088,3598,237,238,184,185,186,239,185,186,190,3599,680,495,505,690,496,690,690,746,197,492,172,382,148,429,429,445,445,429,149,759,446,447,447,512,664,276,179,346,319,347,2146,69,764,765,2315,3600,149,2303,2304,2305,447,447,447,592,592,447,636,549,800,526,769,770,2543,564,216,1042,439,838,23,477,478,3601,1527,2195,2196,2343,2505,3048,401,383,526,2231,485,486,429,149,1522,280,281,281,281,280,281,280,281,3589,3602,382,510,573,629,190,3603,496,3604,1275,347,686,549,3218,460,179,300,301,358,359,3605,382,355,383,526,545,1188,1846,458,459,169,352,776,777,846,616,505,496,1222,369,3606,541,148,445,445,445,149,2909,3607,1522,280,281,281,1222,3608,2575,664,2834,180,181,233,190,575,3609,769,770,2992,401,383,526,545,1188,1846,2169,3126,3610,492,172,382,148,149,562,281,280,281,281,281,280,281,280,839,147,148,854,629,190,245,3611,816,1226,1182,454,3117,549,1571,742,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,2249,268,1214,435,3612,390,391,80,3613,1116,572,489,490,216,449,439,266,267,554,270,1322,666,667,1514,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,237,238,184,185,186,239,185,186,190,2731,148,429,429,149,759,446,592,512,549,1338,3614,346,319,347,581,686,69,510,712,712,712,1343,697,545,2314,258,761,260,2792,422,3615,148,445,445,429,429,149,279,280,281,280,563,216,542,1693,1693,1012,1039,3616,148,854,574,3381,3524,1171,271,1294,271,271,270,270,270,272,549,610,355,383,384,557,654,557,558,557,558,557,558,557,558,557,558,557,558,563,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,3238,616,689,496,497,498,1745,3617,104,135,136,137,1287,139,140,141,959,670,545,1188,3125,400,179,346,319,876,147,510,573,629,190,745,80,3618,429,445,429,149,511,446,2342,2347,179,2502,3235,537,2349,429,429,445,429,149,591,751,1222,401,356,502,634,611,538,538,538,538,537,537,537,537,663,758,902,303,1576,549,708,241,948,949,1138,549,800,429,429,445,429,429,445,462,463,637,445,149,150,446,447,636,549,1571,665,666,667,730,731,2483,1815,1658,426,1956,632,54,55,1238,601,603,603,602,603,603,603,602,603,918,810,1949,366,889,1832,890,891,892,3619,2172,605,777,846,561,2216,2338,1213,267,268,269,272,403,943,319,454,2425,457,3620,383,534,535,2046,758,3621,565,2101,934,1473,3622,495,497,498,2692,870,356,556,557,654,557,558,557,557,557,558,557,558,557,711,556,692,1294,270,272,403,653,570,1658,54,2839,2145,1632,333,334,335,336,337,44,45,1006,350,291,292,3623,149,562,281,280,281,3330,149,591,150,446,447,592,592,447,447,512,549,550,3624,3625,3626,291,1675,3627,2572,251,252,253,254,255,698,1893,774,23,516,2570,318,319,347,581,455,455,455,1215,2770,500,146,147,148,149,759,446,592,592,447,447,447,447,447,512,435,1553,565,2101,179,3462,1254,3628,3252,3352,690,690,496,690,690,691,295,1616,401,356,302,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,1338,591,150,446,592,592,592,447,592,592,3629,390,391,495,1744,497,498,3027,2061,2062,477,478,723,398,3630,401,383,556,1348,442,402,302,303,305,303,3258,1171,510,696,697,545,2462,148,445,149,279,280,281,280,1178,136,137,138,139,1304,1305,1306,1455,394,395,1594,396,763,642,434,1094,23,454,2425,455,3074,549,2147,1171,808,811,812,899,814,924,179,390,391,494,495,496,496,1960,295,506,147,510,278,150,2087,2088,2296,2697,1665,333,410,3631,178,179,147,148,445,445,149,1243,281,280,563,149,430,281,281,281,280,281,280,281,280,281,280,281,1211,2343,486,1075,346,319,347,581,3632,390,391,494,2073,616,3633,2977,333,1232,418,985,573,574,3634,1498,1499,3635,145,146,231,232,233,1404,665,735,216,1042,439,838,47,727,434,347,3636,300,301,2480,950,951,570,571,445,445,445,445,445,149,150,446,447,512,549,800,1007,3637,3638,2590,2591,1101,1565,2134,2339,480,3132,154,135,136,137,138,139,136,137,138,139,140,141,680,231,967,1890,769,770,3639,251,3640,665,666,667,730,731,268,2286,1921,713,300,2345,302,303,305,303,305,303,304,303,305,303,305,303,304,303,548,69,564,565,3641,429,445,429,149,591,150,446,636,403,1034,3642,2228,570,2216,1225,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,3643,613,614,615,495,496,497,498,2661,3482,601,603,603,603,603,602,603,603,603,746,247,101,624,625,626,627,2411,181,233,190,1643,1044,849,2462,251,465,282,769,770,2543,2126,1822,403,455,2336,528,2503,796,101,225,226,120,121,109,110,99,111,112,99,100,2222,3644,3645,3646,523,44,2489,510,278,2466,2360,659,2370,237,743,744,188,189,240,188,189,239,185,186,190,986,3647,613,614,615,495,1461,237,238,184,185,186,190,2768,2270,1499,1923,401,383,502,634,611,538,538,538,538,537,537,537,1759,549,550,3648,2976,770,3055,672,280,281,281,281,280,281,281,281,280,281,280,281,280,2018,2142,3649,355,383,1540,3650,557,557,558,557,558,557,793,175,176,177,169,352,3651,3652,2249,382,510,696,2136,3653,513,700,556,654,557,557,557,558,557,557,557,558,557,558,557,3654,616,2172,507,348,1840,1822,69,231,232,182,183,184,185,186,190,2827,193,194,1170,369,400,179,382,510,1639,463,1241,609,169,237,743,744,188,189,240,188,189,240,188,189,190,191,802,782,460,179,147,518,534,535,536,537,1759,549,1571,172,346,319,454,456,946,1150,3655,1872,777,846,495,505,690,690,496,496,496,752,510,696,697,608,3656,355,383,384,558,1482,3657,570,3142,1026,319,1528,1839,1330,401,356,561,482,483,484,2343,486,616,689,496,1330,454,348,1132,549,800,465,640,2126,528,3658,2522,537,950,3659,950,951,1658,54,55,3592,453,476,477,478,3660,18,665,666,667,668,439,266,3466,23,207,208,388,389,179,390,391,23,147,401,356,402,1396,549,1338,178,179,147,401,383,402,383,502,634,537,537,799,549,1338,401,356,502,634,611,538,538,538,1759,1368,230,146,147,355,383,534,535,538,2046,549,1338,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,2478,570,571,2195,2196,2374,54,55,56,57,769,770,2543,401,356,502,634,538,611,537,537,537,537,1759,435,182,3661,2600,333,2687,3662,1967,483,484,2296,2297,356,534,535,538,537,799,435,429,429,429,149,759,446,447,592,592,447,447,636,549,2863,511,446,447,636,549,2863,322,1428,2794,2824,3663,1920,270,3596,2551,270,1815,952,3664,467,467,104,135,136,137,138,139,140,141,680,352,621,146,231,232,233,241,185,2082,637,510,696,783,570,516,2257,1744,497,2268,974,382,1663,783,570,516,3164,2977,333,410,335,336,337,44,45,1006,403,1179,2879,179,2502,47,401,443,463,69,587,434,454,455,944,69,355,356,357,655,518,534,535,537,538,538,1611,769,770,2396,54,55,56,2693,1112,3665,3666,3667,581,455,455,455,455,455,455,1109,149,150,2087,2088,3668,3669,3670,382,3671,2784,3672,782,645,646,3673,2680,3674,3675,237,238,184,185,186,190,1931,2270,1499,1555,130,783,570,571,352,600,172,382,148,445,429,445,429,429,445,462,999,664,145,146,147,148,429,429,445,445,429,149,591,994,622,233,190,1654,1498,1499,1555,1218,755,545,1188,2249,3676,23,515,1658,54,55,56,3132,401,356,556,1348,557,557,558,557,558,559,2859,672,280,281,1774,345,509,172,346,319,347,348,348,944,549,1571,148,462,463,549,1338,3455,304,303,1519,303,305,303,305,303,304,303,788,331,3677,146,147,148,854,629,190,1195,3678,455,3679,3487,375,2846,3680,3681,709,60,61,73,93,94,3682,182,606,2478,570,1658,331,485,486,238,184,185,186,240,188,189,240,188,189,190,1828,802,2688,3179,333,1232,335,336,337,44,45,524,3683,332,333,334,335,336,337,1233,3684,237,743,744,188,189,190,2831,3685,653,516,2332,2331,2331,2332,2332,2332,2511,435,3686,744,3687,910,802,80,3688,502,634,537,611,538,538,537,1759,758,712,278,591,1243,673,382,510,712,696,3689,1025,346,476,2195,2196,485,486,233,190,910,192,193,194,3690,3691,3692,3693,2478,570,952,2570,148,445,854,574,1643,3694,1304,1305,3695,532,514,570,3142,178,179,147,355,383,519,990,1408,703,146,346,319,347,348,2313,382,148,445,445,445,445,445,149,2558,1642,601,602,603,603,603,602,603,603,603,2441,366,390,391,494,80,3696,2339,618,1598,2360,498,2419,465,295,466,1026,319,347,348,455,456,348,1215,403,447,447,447,512,69,777,846,495,691,1281,147,355,383,519,990,3461,3091,3697,3698,3699,1866,3700,1721,68,3701,147,589,670,545,2700,534,535,538,538,3702,1286,602,295,506,3703,492,172,382,401,356,556,1348,557,557,558,557,1351,2108,1690,1101,1101,3704,383,502,634,537,1395,435,493,1644,2455,2583,2584,3705,3706,549,1338,3707,587,434,347,581,348,455,348,348,455,455,3708,429,445,445,429,149,430,1245,279,281,281,280,281,281,281,280,281,280,281,280,711,134,216,449,439,669,179,346,319,454,581,3377,712,278,430,280,281,280,507,442,791,687,688,495,673,916,1245,240,2328,2329,950,951,570,1658,54,55,2040,3709,1249,507,885,2371,1121,933,662,169,1268,1269,184,185,186,190,630,607,545,3710,401,383,526,608,591,672,1599,178,179,231,232,233,3711,671,172,382,510,712,278,150,446,592,2874,429,149,591,150,446,447,447,512,549,800,277,696,278,994,977,445,590,2725,2228,515,952,2570,383,502,634,611,537,1759,435,265,266,267,554,1294,270,3712,389,934,1886,1300,401,383,556,654,557,558,557,558,557,1353,281,281,839,348,455,944,403,148,854,3713,1206,142,952,2257,330,332,333,410,335,411,3714,510,712,278,2558,1599,402,302,303,304,303,304,303,304,303,304,303,304,303,788,549,610,369,400,179,390,391,494,495,692,148,149,591,150,446,447,592,592,447,512,403,211,1516,727,434,454,348,348,686,664,3402,1121,68,758,3715,2175,2176,659,2370,355,383,357,302,303,2580,511,446,592,592,447,447,447,447,636,549,610,826,1282,829,3716,254,47,410,335,411,412,54,55,56,3371,103,104,135,136,137,138,139,140,141,959,276,179,1586,193,194,3333,2325,2087,2088,485,2197,714,382,148,445,429,445,2258,401,383,502,634,536,537,1759,1368,278,150,2087,2088,485,2505,2297,252,253,254,985,2657,54,2839,2145,742,228,756,1387,193,3717,771,148,445,670,769,770,2396,54,55,2586,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1040,390,391,494,2073,616,3718,429,149,1522,280,281,280,281,280,281,1281,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,811,812,899,814,924,934,1473,3622,2425,1215,549,610,147,401,383,402,1396,403,382,532,526,769,770,3719,367,368,369,400,179,231,232,233,190,191,802,782,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,172,346,319,1094,23,345,509,172,382,148,429,429,429,445,149,759,446,592,447,447,2991,589,670,545,1188,2249,2442,2443,23,148,429,445,429,429,445,445,462,999,331,429,445,149,562,280,282,231,232,233,187,1174,3039,637,429,429,149,1243,281,280,281,280,281,1371,712,712,712,3720,320,193,194,3721,3691,251,252,253,254,419,510,696,573,574,3405,3722,1499,2477,278,430,2018,2019,486,1703,769,770,3723,564,216,1042,439,266,267,268,270,1214,549,610,178,179,147,601,603,603,602,603,603,1350,237,238,184,185,186,239,185,186,240,188,189,190,2412,1196,1197,2477,390,391,494,616,496,497,498,617,782,461,429,149,511,446,2712,402,1275,777,846,495,496,1330,714,429,445,149,150,446,447,447,1731,178,179,180,181,182,183,1520,2440,134,216,1042,439,3724,277,696,696,278,759,446,447,512,713,485,3441,1076,272,758,447,447,447,447,512,549,1338,495,689,690,496,1330,838,23,3725,1767,3726,401,383,526,545,2053,597,519,520,1332,1332,1628,453,319,320,1241,355,383,534,535,536,663,331,149,1522,281,281,281,280,281,281,281,280,281,280,281,655,2037,698,402,302,303,305,303,304,303,304,303,304,303,788,435,3727,769,770,2543,510,696,696,278,591,3728,1265,303,304,303,1519,303,305,303,305,303,788,435,449,439,669,179,346,319,2446,528,571,348,581,455,455,455,1318,485,486,2108,860,1101,1100,2128,282,149,430,281,281,281,280,281,280,281,280,281,280,281,1222,558,557,557,558,692,1579,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,1079,1080,1856,320,193,194,195,1897,154,135,136,137,138,139,136,137,138,139,140,3729,665,735,489,665,735,216,1042,439,266,267,268,3730,258,761,260,261,762,262,263,264,763,642,434,3731,3732,3733,171,687,980,781,779,780,780,780,780,1751,1222,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,1641,347,348,581,455,455,348,348,348,1839,518,534,535,611,537,537,537,537,1759,549,1313,147,401,356,302,303,548,69,2700,3734,1498,1499,2030,846,495,689,690,690,282,3735,3736,735,216,449,439,266,267,554,2551,271,2286,3737,180,181,182,606,607,545,1188,1846,1663,783,570,571,1074,1323,943,319,454,455,349,403,589,590,445,429,429,445,149,759,446,592,447,512,549,1338,514,570,571,1644,2819,3738,3739,383,556,654,557,558,557,558,557,558,557,558,557,558,557,1935,375,1462,1463,1464,1464,2352,713,698,548,549,3740,1887,80,1592,3741,916,1100,1690,2128,1178,591,1243,281,281,280,281,280,281,280,281,1281,1562,1289,3742,270,1814,1815,1658,426,883,268,1921,713,233,240,2328,2329,950,951,3743,756,554,270,270,2510,435,247,101,624,625,626,627,1179,2879,934,1473,1474,3744,478,785,3745,3746,172,346,319,347,581,348,455,455,455,455,455,686,435,769,2678,3747,80,3748,538,611,538,538,537,538,538,537,537,663,2770,545,714,1074,366,587,434,347,455,581,348,348,1215,549,1028,445,149,150,446,592,592,636,549,800,382,401,356,402,302,303,305,303,304,303,2580,1099,859,1101,1690,1101,1100,2128,692,759,446,447,447,447,447,447,1731,1661,1662,616,1960,692,268,270,3480,69,466,231,967,1890,545,1188,1189,564,216,1042,439,266,267,268,271,3749,352,600,172,382,401,383,502,634,536,538,537,663,403,3275,3750,1835,558,557,558,557,558,557,558,557,558,557,558,557,558,1635,2343,486,240,188,189,241,1165,184,185,186,190,986,1044,1189,3751,515,3752,1967,483,484,485,486,182,181,921,1966,549,2863,902,303,305,303,3753,549,800,445,149,1243,281,280,655,613,685,434,347,348,2163,457,1037,1031,333,1232,335,336,337,44,45,3754,3755,2523,3756,445,445,445,429,149,511,446,447,512,549,1338,346,319,347,348,944,69,2286,1815,1658,637,104,135,136,137,138,139,140,307,3757,641,3758,485,3759,400,179,147,355,383,384,1348,557,557,1635,1928,146,346,540,541,149,511,446,447,447,636,549,610,769,770,2543,1537,442,266,267,554,1294,726,69,1706,3760,346,319,320,758,581,455,1215,403,477,2236,3761,54,2330,3212,3762,714,148,429,149,591,150,446,447,592,592,1728,271,271,270,270,271,271,270,272,69,2660,496,2172,497,498,1745,1955,2364,216,1042,439,266,267,268,1294,272,549,1338,366,490,216,1042,439,266,267,1276,3763,1796,147,401,383,402,302,303,304,303,548,549,2039,1665,333,1232,418,419,355,383,357,383,534,535,1103,758,2249,231,232,233,3764,2092,147,148,149,150,446,512,1241,2347,179,3675,3716,254,23,1528,455,1840,528,1658,54,2330,352,791,172,382,518,384,2202,1706,3765,173,185,926,1670,3766,401,383,502,634,611,537,537,538,3221,2106,483,484,485,2505,2650,608,1971,744,188,189,190,3023,1409,987,1248,498,2127,1059,1361,782,687,688,616,1960,295,1616,44,45,1006,1455,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,601,602,603,603,603,602,603,602,603,602,752,1317,2528,2446,455,3074,758,2223,128,129,1002,233,190,482,483,484,2326,777,778,781,2423,390,391,495,2662,497,498,2419,355,356,302,303,304,303,305,303,788,413,149,150,446,592,512,549,1922,429,149,591,150,446,447,592,592,447,447,636,403,149,759,446,447,447,447,447,636,758,3441,556,654,557,558,557,558,692,148,149,3768,331,1965,1286,603,602,603,603,1224,597,402,302,303,304,303,305,303,305,303,304,303,305,303,305,303,304,3482,429,149,591,994,1245,514,570,516,2257,601,603,602,603,602,603,1371,347,581,348,348,348,348,455,686,69,1084,439,440,859,1690,3053,3769,885,3770,1101,1565,2774,977,495,1744,497,659,3771,1761,3772,663,69,1708,376,1627,1331,1332,1332,1909,69,445,445,429,429,445,149,150,446,636,69,2053,460,179,147,597,502,634,1242,758,429,445,429,429,429,1704,990,3773,735,489,665,666,667,668,439,266,267,268,1814,1815,952,2331,2550,435,670,698,709,60,61,73,93,94,3774,66,67,1071,149,279,280,281,280,281,507,3775,810,809,809,809,1378,1379,1380,1081,69,270,271,1322,1015,1288,1289,825,1435,3468,1438,2684,549,1338,601,602,2527,2134,2453,480,2786,178,179,382,355,383,534,535,1759,2854,589,653,570,952,529,690,496,690,691,1178,601,603,603,603,603,602,603,603,602,1353,2662,497,498,617,480,2786,429,445,149,279,280,281,1350,3776,712,3350,2565,3777,454,2126,528,571,571,266,267,554,270,1322,688,495,496,690,1083,587,434,454,2163,971,3778,2286,1921,69,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1040,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1694,237,743,744,188,189,190,745,80,1381,3779,440,859,860,1101,1101,1100,1100,1101,1101,861,330,332,333,410,3780,3781,3763,350,587,434,347,348,581,455,455,348,348,455,686,549,610,266,1041,1071,382,355,356,534,535,1242,1241,258,259,867,3782,668,439,669,179,346,319,1094,973,355,356,384,654,557,557,557,558,557,558,557,558,557,558,557,558,557,711,237,743,744,188,189,190,910,3783,777,846,616,690,690,691,782,2325,2087,2088,2343,2622,2356,597,402,302,303,304,303,548,549,708,725,439,266,267,554,1214,549,1922,854,629,190,1598,3784,1239,758,270,2240,1815,952,3259,237,238,184,185,186,240,188,189,239,185,186,239,1165,184,185,186,239,1165,1520,3785,3786,3787,375,376,377,3788,607,769,2605,687,980,779,780,781,781,780,781,1223,445,445,445,149,150,446,1728,778,781,1349,692,370,824,765,2387,2388,3789,3790,502,634,611,538,538,537,537,537,538,3221,769,770,3791,823,1965,545,2421,943,319,347,3792,616,691,793,150,446,447,447,2711,3793,3794,23,759,446,447,447,447,636,1216,737,738,2275,2785,352,798,172,382,1286,602,603,602,605,3795,3796,700,3531,510,278,150,446,592,447,512,549,1571,346,319,454,582,429,429,445,429,149,1522,280,281,280,281,563,632,54,55,2633,3797,3798,445,149,150,446,447,447,1812,714,1890,2577,735,216,1042,439,266,267,554,1814,2241,3469,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,548,549,1338,2345,2480,950,951,570,3435,641,657,1908,781,3799,3800,591,150,446,1787,3801,1840,528,2216,222,223,645,646,3802,1281,573,629,190,1554,1196,3803,990,1534,608,509,172,382,148,429,445,445,149,1847,401,356,502,634,538,536,537,538,1422,3224,659,974,645,3804,3805,1890,2714,2214,740,510,3806,3807,908,429,149,1522,280,281,280,679,712,712,3808,239,1165,2816,3196,455,528,3809,382,148,429,979,127,128,129,211,248,1967,483,484,485,486,1188,1189,447,447,447,447,447,512,637,382,510,278,759,3810,980,1765,918,502,634,611,538,538,3811,2111,1915,2050,1915,2051,1915,977,680,355,443,2995,390,391,494,616,2096,497,659,2253,2253,2255,1752,147,148,445,149,150,446,447,1787,3734,1498,3812,429,149,430,280,281,281,281,280,281,280,281,793,538,3813,810,809,1007,1031,333,1232,335,336,337,44,45,46,47,450,1200,3814,826,1282,829,830,831,832,832,832,832,832,832,1584,356,384,673,472,157,489,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,808,811,812,899,814,815,841,650,2664,1281,355,356,357,302,303,305,303,2295,1516,371,1505,616,497,2826,149,150,446,1444,527,1188,1846,280,281,280,281,280,281,280,655,513,526,545,1188,2249,231,232,1163,3815,401,383,402,383,402,302,303,548,549,708,1286,602,603,603,839,810,809,1007,1031,333,1232,335,336,337,44,45,46,23,779,3816,3817,149,2303,2304,2305,512,549,760,231,232,233,190,3818,556,507,454,581,348,686,549,1571,355,383,384,1784,711,653,570,2750,1544,333,410,335,3819,149,150,446,592,592,447,447,3202,401,383,556,654,557,557,557,557,557,558,557,558,557,3820,1821,347,582,671,2064,3821,54,3822,429,445,3823,3824,587,434,347,455,1027,403,732,1815,1658,54,55,56,3825,1663,697,769,770,2543,513,514,570,516,2530,2017,2826,665,735,489,490,216,449,439,838,23,2898,232,233,190,191,802,3750,1598,2360,498,2419,346,319,347,348,581,455,455,455,455,686,637,429,445,429,429,149,279,280,295,1616,1084,439,450,889,3826,460,179,180,2114,1199,2657,54,55,2040,2825,759,446,3827,616,1836,445,429,429,149,3828,840,809,809,1007,1031,333,410,418,47,1288,3829,3830,3831,1425,3557,3832,100,101,624,625,626,627,3833,3834,240,2328,2329,950,951,570,571,513,526,545,3154,180,606,607,545,1188,1199,348,728,549,1922,240,188,189,190,745,782,460,179,147,597,556,2940,105,1603,640,429,429,445,445,149,279,280,281,280,2775,346,319,347,456,455,455,348,348,455,695,490,216,1042,439,266,3835,3836,150,446,447,447,447,447,3837,384,654,557,557,557,558,557,558,557,557,557,558,557,558,557,3820,3838,2096,295,506,2850,977,1169,439,3839,442,237,238,184,185,186,187,188,189,3840,697,545,714,687,980,781,780,2423,149,591,1243,280,281,280,282,683,3249,3841,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,1924,3842,977,262,263,264,1595,642,3843,826,1282,829,3844,266,267,1387,193,3845,510,696,998,3452,928,565,2101,179,300,301,3846,477,2236,3847,492,172,180,181,233,190,3848,1254,3628,1538,3352,2079,3849,3850,23,1026,319,454,456,686,549,1093,179,147,597,402,302,303,305,303,788,549,1338,1171,608,170,171,172,231,232,233,190,1643,2886,2887,2888,985,3851,3852,601,602,603,603,602,603,602,603,602,603,602,603,793,402,302,303,305,303,305,303,304,303,304,303,788,549,1338,355,383,534,535,538,1472,549,760,601,602,2527,2134,3217,2340,2946,743,744,188,189,239,185,186,241,1981,952,3853,727,434,320,193,194,2378,2462,768,528,952,2332,2332,3854,2894,3855,1099,859,1101,860,1101,1101,1101,1101,1101,3417,592,3856,840,809,840,3857,2928,780,2369,2613,2369,498,1745,3858,142,147,532,526,545,742,492,172,382,401,356,502,634,538,611,537,663,664,1967,483,484,2374,54,55,633,2600,333,410,335,336,337,44,45,822,1402,601,603,603,603,602,603,602,603,602,603,602,603,602,603,3859,461,429,429,462,999,758,237,238,184,185,186,190,992,2270,1499,1555,211,3860,819,1516,742,1084,439,266,267,554,1806,350,382,401,383,3861,495,690,689,496,690,1281,187,188,189,240,188,189,190,3023,1409,1044,849,735,216,3862,3863,254,255,278,150,446,592,636,435,554,1672,549,1338,2746,1522,281,280,281,386,3864,768,3865,1320,577,578,123,124,125,1150,492,172,390,391,494,495,752,697,769,770,2657,54,1509,697,769,770,2543,1013,1013,1013,1013,1013,1014,510,278,150,3032,355,443,463,549,1922,1716,355,356,534,535,538,537,1395,3273,149,562,281,281,281,280,281,280,281,280,281,280,281,280,1774,180,181,233,3866,616,497,3867,3312,333,410,335,336,337,44,3868,130,384,1348,557,557,655,769,770,2110,502,634,538,536,663,69,453,319,454,457,2551,270,2240,3737,147,355,383,534,3869,3870,1424,3871,23,401,383,526,769,770,771,641,656,657,1908,2369,498,3872,154,135,136,137,138,139,136,137,138,139,1304,1885,382,401,383,556,654,977,429,445,429,429,445,149,3873,697,769,770,3874,518,384,559,560,561,147,510,278,591,150,446,2711,3875,482,483,484,485,2622,2356,180,181,1163,232,233,190,3876,656,642,434,347,528,2529,2627,266,267,554,1814,1815,952,2332,2332,2332,2332,2331,2426,305,303,305,303,304,303,548,549,1338,573,629,190,3877,2935,401,356,302,303,305,303,305,303,304,303,304,303,304,303,3878,149,511,446,592,592,447,592,592,512,435,455,2357,148,429,3879,921,967,3089,224,216,449,439,669,179,346,319,1094,2956,786,787,2411,181,233,190,1549,2335,819,3224,3880,586,565,2101,934,1473,1474,3881,785,3882,1573,731,1387,2335,429,429,429,445,429,429,445,445,3883,838,23,687,980,781,779,780,781,780,3884,355,383,534,535,611,538,538,538,538,3811,362,216,1042,439,266,267,1387,193,194,2789,1921,664,1287,3885,453,476,2195,2196,2296,3527,347,455,581,348,348,1318,490,216,1042,439,450,1200,1832,3886,261,836,837,262,263,264,265,266,267,554,1244,69,450,889,891,3887,1188,2249,460,179,147,518,534,535,537,1395,549,1338,266,267,1920,2007,3888,727,434,347,581,455,455,686,69,510,696,696,3889,727,434,454,455,970,1318,840,840,809,809,809,809,809,840,809,810,809,1949,1950,1562,3890,1424,300,301,2480,950,951,515,571,2323,23,654,557,557,557,558,557,558,557,558,557,558,557,558,557,1275,370,433,434,347,455,528,515,2718,485,486,1632,333,334,335,336,337,44,45,1006,3891,2840,611,538,538,538,537,537,537,537,537,663,403,172,390,391,494,2533,1083,280,1281,149,2303,2304,2305,447,592,592,447,592,592,447,512,403,149,759,446,592,447,447,447,512,69,2224,2056,149,759,3178,549,1313,382,148,854,574,2768,2270,1499,1555,130,779,780,780,780,780,1751,1836,777,846,616,505,690,690,690,690,690,295,506,401,383,556,557,557,558,557,558,559,560,918,1171,1890,769,770,2744,352,776,146,147,597,519,1192,3892,145,146,147,148,854,574,2534,3893,1248,180,181,1163,232,233,190,469,2270,1499,1555,211,3894,737,738,2134,2453,480,2454,3895,554,270,2510,549,1338,537,799,403,149,759,446,447,592,592,447,1204,149,279,281,281,280,281,280,281,280,281,280,281,2452,657,658,1131,240,1174,1228,563,727,434,347,945,1318,696,712,712,278,591,150,2350,401,383,556,558,557,558,561,1573,731,554,1626,445,445,429,149,1522,280,281,280,281,295,1616,401,383,502,634,611,537,1759,331,266,267,268,1294,270,726,1455,390,3794,23,808,811,812,899,814,924,179,2323,724,3896,3897,3898,2252,2106,483,484,485,2505,2297,1518,950,951,3899,727,434,454,455,944,350,318,319,454,3117,713,197,145,146,147,148,445,1760,346,319,347,581,348,348,455,348,686,331,150,446,447,1787,537,2057,2702,533,2581,172,390,391,494,3094,346,319,347,348,581,455,455,348,348,1215,69,1549,193,3900,383,556,654,557,558,557,558,557,558,557,558,1351,533,502,634,611,538,538,537,537,538,538,537,2837,1077,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,2927,977,1815,1658,54,55,2586,698,532,514,570,952,529,149,150,446,592,592,636,549,2830,429,429,429,445,445,429,429,445,149,3901,1086,333,3902,233,239,1165,2816,3903,3904,3905,3906,149,279,280,281,280,281,1211,608,460,1120,1121,68,350,527,519,520,2557,587,434,347,581,348,455,3907,1281,147,510,1639,1056,502,634,611,538,538,537,2349,698,450,1200,1831,3908,680,1029,696,697,545,2803,921,967,3669,2669,180,181,1163,232,233,190,245,1409,987,2881,591,3909,148,445,149,3910,150,446,447,447,447,447,592,592,447,447,512,549,1338,445,429,3112,991,2089,54,55,633,1562,765,1596,1628,433,434,454,1822,549,1028,450,3911,1568,534,535,537,3813,2017,2315,2316,3912,224,216,1042,439,2439,2440,440,859,1927,711,266,267,554,1214,549,2863,2073,616,1353,641,2061,2062,2195,2196,2343,2622,2697,375,2846,3913,386,687,688,495,690,1342,605,148,445,670,769,770,3205,207,208,388,3904,3905,3914,445,429,149,1522,280,281,281,281,280,281,280,563,382,355,383,357,357,302,303,304,303,305,303,548,403,355,383,526,545,2894,147,401,383,519,990,1804,1363,2053,300,301,2480,950,951,515,571,390,391,494,495,2096,497,2268,2253,2253,2254,2255,640,510,573,574,850,1409,1044,2098,429,445,429,979,562,281,281,280,281,280,281,280,281,280,281,280,281,280,507,390,391,494,495,690,1083,689,1222,178,179,147,1286,602,295,2871,2073,495,497,659,3915,356,1976,1408,1887,916,917,746,1706,2721,460,179,147,461,445,445,149,562,281,2045,149,1243,281,280,281,280,281,280,1211,346,319,347,1215,435,785,786,3908,936,3916,3917,523,44,45,524,640,357,3918,3154,347,348,581,455,455,455,455,686,549,1571,429,429,445,445,429,149,591,150,446,447,447,636,637,180,181,1163,232,233,190,1931,2270,1499,1555,1218,2925,545,1188,2249,645,646,647,648,649,650,2664,3919,401,383,402,383,402,302,303,304,303,304,303,304,303,304,303,548,549,1922,268,269,1433,1007,1031,333,1232,335,336,337,44,45,46,47,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,1007,1031,333,1232,335,336,337,44,45,46,23,519,3338,3920,460,179,147,518,384,654,557,1351,489,490,216,1042,439,266,267,1276,1984,154,135,136,137,138,139,136,137,138,139,1304,2876,251,1073,386,233,190,1598,2360,2200,329,216,449,439,266,267,554,2251,637,666,667,725,439,266,267,1387,193,194,195,3921,297,803,518,534,535,611,538,1422,429,445,149,150,446,592,592,447,636,713,3922,1644,2455,3923,430,281,280,281,563,3689,3924,510,696,696,712,696,696,3689,3925,239,948,949,950,951,570,1658,331,240,1174,744,188,189,241,2056,182,183,3490,3926,1031,333,410,2667,375,2846,3927,3928,295,2540,589,670,545,2314,238,184,185,186,187,188,3929,355,383,534,535,1242,549,1093,1821,347,348,348,1109,671,346,319,347,455,581,348,1215,69,916,860,3417,357,302,303,304,303,305,303,305,303,598,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,3789,3930,1169,439,266,267,268,270,2493,549,1338,564,565,2101,179,390,391,392,149,511,446,447,447,592,592,447,512,549,1313,485,2505,2749,533,2581,148,429,149,430,280,281,280,295,1616,581,455,528,571,440,916,1101,3456,295,506,300,2345,358,3362,3931,1544,333,410,3247,3932,147,510,278,279,563,460,179,147,461,149,591,1310,101,162,163,3091,3933,396,265,266,267,554,1294,726,1241,3139,3934,179,300,2689,1984,149,562,281,281,281,281,280,281,281,281,280,281,280,1245,3935,1543,700,3936,672,281,281,280,918,443,2091,769,770,2543,346,319,454,348,581,1215,325,347,348,455,581,686,403,429,149,150,446,2306,485,486,810,1007,3388,1009,973,690,3604,561,3937,2536,303,304,3938,631,571,251,465,1178,241,185,186,239,185,186,241,1165,184,185,186,239,2056,743,744,188,189,187,188,189,240,188,189,190,1190,556,558,1635,2893,445,445,429,149,511,446,447,512,549,1028,3939,347,456,686,549,1093,1706,3428,445,445,149,562,281,977,509,172,3462,777,846,616,496,691,1245,401,383,502,634,611,538,537,538,538,663,637,686,549,2863,2017,147,148,501,3940,3941,541,756,268,3942,147,401,356,556,1348,557,557,295,1616,1692,216,3943,3944,934,3945,1436,1438,3946,304,303,304,303,304,303,304,303,304,1884,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,1026,319,1094,3235,3947,3025,860,2128,746,510,696,278,1522,1411,2405,950,951,570,516,2460,1112,2843,3167,3948,69,1690,1101,1565,2134,2339,618,418,973,519,520,1331,521,522,523,44,45,1545,589,653,570,571,736,934,3949,134,216,1042,439,266,3950,23,1967,483,484,485,486,445,445,429,149,759,446,447,447,447,447,1787,1638,172,382,510,2024,602,3951,3533,670,3817,2108,1690,1100,1100,1101,1994,231,232,233,241,1165,1938,752,3952,422,3953,3954,986,1044,2098,148,149,279,280,281,280,281,280,281,280,673,558,559,385,563,601,602,673,485,3441,332,333,334,335,336,337,44,45,524,561,191,192,193,194,2789,147,518,534,535,537,1395,758,401,383,526,608,1268,1269,184,185,186,241,2056,3732,1296,422,1023,1877,2069,644,222,223,645,646,647,648,3955,3956,1555,1388,896,807,2053,515,1658,54,3957,502,634,536,537,538,663,835,1973,449,439,669,179,390,391,3059,597,519,520,1332,521,522,523,44,45,1346,1572,149,279,280,281,280,281,280,281,280,1281,502,634,611,537,663,637,3958,402,302,303,304,303,304,303,304,303,304,303,304,303,548,758,3154,2336,457,105,294,295,296,3148,180,181,182,183,184,185,186,241,3959,777,846,616,2660,1403,319,320,3960,2274,738,2784,2277,2277,2276,2276,2277,3961,3962,2073,495,690,496,496,690,690,496,1461,2474,187,188,189,239,185,186,190,745,80,1780,742,2622,3048,2343,486,2347,179,390,391,494,616,3963,636,637,3214,3964,271,2286,1921,435,1692,216,542,1012,1013,1013,1013,1013,1763,3616,526,545,3584,178,179,231,232,921,1560,744,188,189,241,1165,184,185,186,239,1165,1561,2537,180,181,233,190,992,2270,1499,1555,211,755,613,685,434,347,455,528,515,2495,669,179,390,391,494,3965,747,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2180,2179,2180,1222,2356,3966,429,149,591,672,752,1632,333,410,418,985,545,742,430,280,281,1774,537,1759,549,1313,526,608,366,375,3967,401,383,402,302,303,548,69,810,809,1007,1031,333,410,418,47,1472,549,1922,142,735,216,736,179,147,3706,1455,1059,1060,1979,80,1941,3020,239,948,949,950,951,570,516,2257,149,279,280,281,280,281,280,281,281,281,280,281,1036,1406,558,1371,401,383,556,654,557,558,557,558,557,557,558,282,712,712,712,2520,573,629,190,2412,1196,1197,3968,1573,731,554,270,1294,271,271,272,69,756,268,1294,270,270,270,271,726,549,1338,3969,533,3380,429,429,445,429,149,430,280,1178,768,1822,664,1493,1494,1687,1719,180,181,182,606,607,2713,460,179,147,461,462,999,435,628,146,346,319,454,455,2146,413,149,759,446,447,636,549,708,660,2470,80,1829,149,759,446,592,512,549,1313,259,260,261,262,263,264,553,439,266,267,883,3970,132,148,429,445,429,429,445,149,150,446,2712,591,150,446,447,3971,591,672,280,3096,2992,511,446,447,592,592,636,549,3972,131,2359,3973,1281,140,141,680,346,476,477,2236,3761,2027,743,744,188,189,190,2768,470,3974,2061,2062,2195,2196,2343,3975,2941,3976,1413,149,591,150,446,447,447,592,592,447,636,426,583,2134,3977,320,193,194,3978,1323,1744,497,498,1745,442,3979,3980,211,3047,266,1366,254,985,1169,439,266,267,554,1244,69,1314,128,3981,713,777,846,2073,495,690,690,690,496,496,496,496,679,2175,2176,498,1745,1178,3982,988,3983,287,288,387,216,449,439,3984,482,483,484,485,2089,2129,382,148,149,279,280,281,281,281,280,281,1211,346,319,347,581,348,348,455,455,455,455,686,69,2105,429,429,445,429,149,430,280,281,280,746,1579,340,340,340,3985,2470,2002,3986,1224,300,301,3987,759,446,592,592,447,512,69,776,727,434,454,581,455,455,348,348,455,348,348,455,455,1215,549,1313,636,549,1922,432,371,372,3988,780,781,781,1751,563,1575,1265,303,548,403,2343,2505,2506,1654,1498,1499,2970,3989,430,280,281,281,281,3096,300,301,302,303,304,631,570,952,3990,1314,3991,1836,251,332,333,334,335,336,1715,489,665,735,216,542,1693,1693,1012,1956,3063,2966,774,23,401,383,502,634,611,538,538,537,538,538,537,537,537,539,252,253,68,69,1339,463,350,571,68,350,366,3507,1375,333,410,418,255,3992,1764,389,934,1473,1474,3993,193,3717,280,281,281,281,280,281,280,839,1658,54,55,3994,3995,542,1693,1693,543,805,445,429,149,591,150,446,447,512,2770,1706,3996,1528,1839,382,532,3997,815,3998,47,355,383,3148,532,3656,172,346,319,1821,347,348,455,1318,601,602,603,603,603,602,603,603,603,602,603,602,603,711,347,455,1149,403,508,317,703,146,147,510,1639,3999,601,603,602,603,602,603,295,982,4000,1018,1019,1020,507,492,172,390,391,494,495,691,692,445,445,445,149,2909,4001,590,2675,792,1178,2279,4002,23,2126,1822,331,104,135,136,137,138,139,140,4003,4004,2162,483,484,485,2773,346,476,477,2064,4005,316,317,345,509,172,346,319,347,1215,549,610,4006,401,383,502,634,536,4007,149,1522,281,281,281,280,281,281,281,280,281,280,1510,1188,1846,1835,558,557,558,557,558,557,558,557,557,977,608,486,346,319,347,348,455,581,455,455,455,686,2083,149,150,446,447,447,447,447,4008,316,317,345,509,172,4009,498,4010,382,355,383,534,535,663,549,1338,727,434,347,348,581,1215,69,545,1188,1846,2185,4011,2214,2453,2936,241,185,186,239,185,186,190,745,4012,492,1288,765,1290,1291,523,44,45,4013,491,145,146,231,232,233,190,4014,3722,1499,4015,4016,149,279,281,280,1245,454,581,686,549,1338,783,570,1658,54,2839,2145,355,383,384,557,2265,295,1911,149,150,446,447,592,592,447,447,636,549,800,659,660,4017,149,672,281,1836,616,496,3384,673,742,346,319,347,455,528,515,2503,357,1396,549,800,537,538,538,537,537,537,663,758,429,429,445,445,445,149,150,446,512,435,1949,1950,1223,352,798,172,382,148,854,1871,979,2677,1026,319,454,348,1027,637,147,401,356,502,634,536,538,537,537,663,69,4018,148,429,429,445,149,279,280,1222,510,696,696,4019,1562,3451,255,1675,1676,618,782,445,445,429,429,429,4020,597,502,634,611,537,1759,69,347,768,528,952,2550,2854,429,429,445,149,150,446,512,69,1086,333,1232,418,255,401,356,502,634,663,413,671,149,279,280,281,280,281,605,1007,1031,333,1232,335,336,337,44,45,46,47,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,811,812,899,814,815,816,817,333,410,335,336,337,44,45,1006,549,1338,980,2006,1222,628,727,434,320,193,194,1577,2055,2343,2505,3102,756,554,271,1672,549,1338,2863,240,2328,2329,950,951,515,2503,355,383,534,535,611,538,537,537,537,537,537,537,537,1422,538,538,538,537,537,538,538,537,537,1759,549,1313,844,938,4021,3025,602,2527,2134,2453,2954,1461,591,672,280,281,280,281,280,281,280,281,280,2018,1642,4022,545,671,533,599,977,534,535,611,537,538,538,537,537,537,2349,1065,4023,193,194,195,2435,356,357,302,303,788,403,2478,570,516,2460,149,759,446,592,447,447,447,447,3837,3280,1120,4024,4025,340,340,340,340,340,1546,340,340,340,340,3430,2286,1815,1658,54,1659,330,3111,369,1518,1422,1171,472,157,216,449,439,669,179,346,319,347,455,643,457,460,179,147,597,556,1348,557,558,622,538,611,538,538,537,663,549,1338,545,1188,2249,518,534,535,611,537,537,538,538,537,537,537,3183,142,1188,2249,278,150,446,592,636,1455,2483,1135,1099,859,860,1101,1101,1100,1100,282,657,658,495,497,498,499,465,295,2540,943,319,347,455,4026,2243,527,1007,3388,2143,193,194,3389,537,950,3659,950,951,952,3259,352,798,172,180,181,233,187,188,561,247,3187,718,4027,589,670,545,661,665,666,667,2347,179,147,737,738,4028,4029,237,743,744,188,189,241,185,186,239,185,186,190,745,80,1381,4030,1499,1555,130,782,591,1243,281,281,280,281,281,281,280,281,640,1059,1361,442,4031,1564,916,1565,2517,1565,2275,2277,2277,2276,2277,2277,2276,2276,4032,373,497,498,617,618,485,486,1519,303,304,303,305,303,788,835,687,688,2073,616,1350,810,809,840,840,809,809,809,809,809,840,809,809,1949,366,737,673,472,157,216,449,439,669,179,346,319,1094,1010,2325,2087,2088,485,486,2345,2480,950,951,570,516,2373,1179,3558,901,902,303,305,303,3753,69,4033,23,510,696,2136,990,3773,587,1491,724,150,446,592,592,447,592,592,447,1787,410,335,336,337,44,45,3316,2529,2570,180,181,233,190,745,80,4034,180,181,1163,232,233,190,992,2270,1499,1555,211,820,570,571,685,434,347,455,528,570,2503,1073,282,401,443,463,549,1338,149,759,446,3202,100,565,4035,4036,1294,270,1815,516,529,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,382,355,383,357,295,1911,2325,2087,2088,2326,4037,2470,2002,651,603,373,737,738,2784,2277,4032,1222,3975,1954,1017,430,281,281,280,281,280,1211,2314,632,637,239,1165,184,185,186,241,1165,1520,2440,642,434,454,528,570,952,3525,4038,1121,68,69,429,429,445,429,429,462,4039,237,743,744,188,189,239,185,186,190,910,802,80,4040,456,686,549,1338,2446,455,2163,971,251,465,977,589,670,769,770,2543,1835,558,1718,278,591,672,295,982,4041,541,355,383,357,383,384,558,559,385,1245,519,990,1804,1804,1804,3773,146,147,148,149,511,446,447,512,403,2600,333,410,3247,4042,231,232,311,181,233,239,1165,2921,549,1922,1294,726,549,800,3324,735,216,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,148,445,149,4043,2380,66,93,94,4044,1314,1544,333,1232,418,1402,562,281,281,281,280,281,280,281,280,295,1616,838,23,2563,496,1744,2441,995,996,299,2750,2069,4045,222,223,645,646,4046,373,382,355,383,534,535,536,663,758,228,2166,774,23,148,429,429,149,150,3032,645,646,4047,537,538,538,537,538,538,2715,1696,938,939,211,212,952,4048,2309,456,348,348,348,455,1457,2127,2244,2158,149,591,150,446,512,549,1028,3148,4049,4050,4051,231,4052,713,816,1226,1182,347,2146,350,783,570,1658,54,55,4053,700,4054,180,181,233,190,191,4055,601,602,603,603,603,602,603,602,603,602,603,1178,712,278,759,446,592,2711,1442,248,429,149,591,150,446,636,549,1313,592,592,447,447,447,447,512,549,2147,696,712,998,999,69,240,188,189,240,188,189,190,1643,2886,471,1871,2725,1100,1101,1100,4056,295,506,348,348,348,2313,1356,2963,2964,1155,3019,3154,356,519,2287,756,554,4057,4058,597,556,558,1371,101,624,625,626,627,628,727,434,347,455,1502,614,615,616,496,497,4059,1268,1971,744,188,189,241,1165,184,1981,267,268,1294,4060,346,319,320,193,194,3348,1288,765,1596,1909,758,383,502,2198,1637,23,324,4061,240,2328,2329,950,951,570,571,149,751,442,680,179,147,518,384,654,1353,429,149,672,280,281,280,281,1211,356,1281,1026,319,347,686,637,773,774,23,589,670,545,3584,240,188,189,190,1643,1044,4062,589,653,570,571,346,319,347,348,581,1215,637,149,511,446,592,447,447,592,636,69,534,535,538,611,538,538,538,537,537,537,663,549,1338,149,150,446,592,592,447,447,447,447,636,549,1093,2657,54,2839,2145,356,384,1348,977,390,3794,23,429,429,149,150,446,592,592,636,664,1514,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1763,4063,556,557,654,557,558,557,558,1351,778,779,780,781,781,780,781,282,1908,2369,498,617,4064,4065,496,2096,782,728,549,4066,170,1585,439,266,1041,68,435,4067,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1956,482,483,484,2326,587,434,347,455,581,455,455,686,403,510,998,463,435,382,148,445,445,429,1704,3338,4068,1893,774,23,1906,333,410,335,336,337,4069,456,686,549,1338,370,433,434,454,3907,2559,605,514,570,3115,347,455,528,570,516,2627,149,150,446,512,69,838,23,1188,1846,4070,23,608,278,591,150,446,447,592,2121,3875,537,2349,3145,1138,713,451,1832,2190,2555,4071,1920,271,2484,713,1304,1305,1312,1783,495,2096,497,498,2127,1026,319,454,348,349,549,1922,266,267,554,1214,350,382,148,445,149,150,446,447,592,512,69,4072,769,2678,4073,2314,653,1658,4074,1114,23,1667,3874,461,445,445,429,149,4075,1518,4076,1241,2075,356,384,654,557,295,982,455,944,549,1571,1586,193,194,2789,401,383,502,634,2188,419,238,184,185,186,187,188,189,240,188,189,3545,698,224,216,449,439,266,1366,254,985,820,671,601,602,603,603,602,603,602,603,602,603,602,603,602,711,445,445,149,279,280,281,280,281,442,2079,4077,1872,502,634,537,536,663,4078,592,592,447,592,592,2874,4079,324,3248,510,696,1343,402,302,303,304,303,305,303,305,303,304,303,305,303,305,303,304,303,548,549,4080,590,1769,180,181,233,187,1174,1228,295,506,1114,23,382,510,573,2905,4081,172,382,355,356,384,557,654,655,239,185,186,240,188,189,190,3023,1247,987,3060,355,356,534,535,2349,2185,1611,2404,860,1100,1100,1100,1100,1101,1101,4082,401,383,383,502,2005,23,1846,1325,1524,3299,149,1522,280,295,506,2453,4083,4084,71,73,74,66,1420,1421,549,2833,269,270,270,1322,429,429,445,429,429,149,150,1811,1949,1323,348,2126,1822,549,2617,808,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,809,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3229,2724,810,840,810,809,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,809,1007,1031,333,410,418,3235,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1031,333,410,418,973,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,810,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,973,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,4085,810,809,809,1007,3388,1009,973,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,973,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,23,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,4085,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1031,333,410,418,23,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1008,1009,47,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,809,809,809,809,1007,3227,2597,3228,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,3231,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,3231,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,1007,1031,333,410,418,973,1579,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,4086,4087,1078,1546,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1517,1078,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,340,1079,4088,810,810,809,809,809,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,4089,1078,1546,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,2036,101,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,567,568,3556,4090,161,328,329,101,472,157,275,473,474,475,179,180,606,2478,570,571,326,327,99,201,202,203,204,594,595,596,379,169,178,179,147,148,149,562,281,295,506,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,145,146,147,355,356,384,1784,1350,101,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,1074,1323,102,103,104,135,136,137,138,139,140,141,959,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,102,103,104,135,136,137,138,139,140,141,959,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,147,510,696,696,696,696,696,696,278,430,280,673,122,123,124,125,126,145,146,147,510,712,278,672,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,280,281,280,442,99,113,489,665,735,216,736,179,382,589,4091,637,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,467,104,135,136,137,138,139,140,141,959,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,492,172,382,401,383,502,634,611,663,1368,351,178,179,382,510,696,696,696,696,278,150,446,447,1731,143,144,125,126,145,146,147,355,383,357,1396,549,1338,197,492,172,382,401,356,402,302,303,304,303,548,549,2863,330,1073,1275,201,202,203,204,584,585,586,1374,222,223,224,216,449,439,669,179,382,355,443,999,1368,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1076,726,1368,285,286,467,104,135,136,137,138,139,140,141,959,367,368,369,400,179,346,319,454,455,2425,4092,500,146,147,510,712,712,696,278,672,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,280,1178,808,811,812,899,814,815,900,901,1265,303,903,303,4093,808,1007,1031,333,1232,335,336,337,44,45,46,47,110,99,111,112,99,100,158,123,124,125,126,159,128,129,4094,276,179,346,319,347,455,2146,758,355,356,356,356,534,1636,2618,1099,916,1101,917,977,367,368,399,400,179,382,510,696,696,696,712,696,696,696,696,696,278,1243,280,281,280,281,280,281,295,506,101,225,226,120,289,109,110,99,111,112,99,113,101,947,226,120,121,367,368,399,400,179,231,232,233,190,1967,483,484,485,3441,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,330,332,333,410,335,2870,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,609,169,237,743,744,188,189,239,185,186,241,1165,3173,117,113,101,283,284,420,801,120,289,367,368,369,453,319,347,1132,637,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,683,152,153,103,291,292,324,253,254,419,133,123,134,101,102,103,291,292,324,253,254,255,251,465,752,249,250,101,114,119,120,121,367,368,369,400,179,382,510,573,4095,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,145,146,147,510,696,278,759,446,447,636,549,708,866,99,258,259,260,261,4096,3955,4097,109,110,99,111,112,99,100,227,123,124,125,126,228,943,319,347,581,455,1109,351,229,1015,172,382,355,383,534,535,538,536,537,537,1759,1455,472,157,275,473,474,475,179,147,532,526,698,153,103,104,135,136,137,138,139,140,141,959,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,580,345,509,172,382,510,1639,463,69,330,332,333,334,335,336,337,44,45,822,255,109,110,99,111,112,99,100,489,665,735,216,736,179,382,589,4098,367,368,399,400,179,231,232,233,190,245,1409,1044,1655,203,204,458,459,169,352,776,727,434,1821,454,686,549,1571,251,465,1281,374,229,1015,172,382,148,429,149,511,446,447,447,447,447,636,69,399,1130,1383,1623,4099,159,128,129,131,212,382,355,383,534,535,536,537,537,538,537,663,549,1338,808,811,812,899,814,924,179,346,319,347,581,348,455,455,455,455,1109,1775,1158,1594,396,553,439,669,179,346,319,4100,808,811,812,899,814,924,179,390,391,494,616,976,295,506,182,606,2150,3670,361,619,620,169,417,2365,637,113,489,665,735,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,285,286,467,104,135,136,137,138,139,4101,330,1073,782,467,467,104,135,1493,2876,154,135,136,137,138,139,4102,1074,1323,140,141,959,156,157,489,665,735,216,736,179,147,4103,68,4104,104,135,136,137,138,139,140,141,959,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,101,114,119,120,121,109,808,1007,1916,977,367,368,399,400,179,147,510,278,150,2087,2088,485,2505,2697,102,103,291,297,298,4105,995,1052,1074,366,4106,310,146,231,232,233,190,1643,1044,1045,178,179,147,355,356,384,654,557,557,558,557,558,557,558,1351,460,179,147,277,278,2248,815,816,1226,1182,454,581,1318,168,169,1314,3991,507,197,145,146,147,355,356,534,535,536,537,537,1759,331,243,244,166,167,662,169,237,743,744,188,189,241,185,186,239,185,186,190,4107,156,157,152,954,955,1673,673,275,473,474,475,179,147,513,526,545,742,954,955,1324,333,410,1329,909,146,231,232,233,190,1654,1498,4108,1077,1546,340,340,340,340,340,340,340,2927,640,258,761,867,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4109,492,687,688,495,496,1960,1350,638,169,178,179,382,355,383,384,654,373,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1448,1413,211,2404,1107,29,1456,101,162,163,796,216,449,439,669,179,346,319,454,455,455,349,549,800,260,261,836,837,262,263,264,265,266,267,268,2251,835,147,355,383,526,769,770,2408,156,157,101,114,119,120,121,367,368,369,641,4110,823,352,600,172,382,1286,603,602,1350,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,131,1716,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,3019,134,216,1042,439,266,267,268,270,269,726,403,161,328,393,394,395,396,531,146,390,391,494,495,1744,497,659,2255,295,982,1003,1004,1264,253,254,984,819,4111,961,962,963,135,136,137,1287,139,140,141,1742,567,568,1425,4112,514,515,516,2570,587,434,454,457,472,157,101,624,625,626,627,628,777,846,495,496,3470,432,371,1505,3555,429,149,672,442,115,1046,4113,4114,2563,1403,467,1506,1178,4115,809,809,811,812,899,814,924,179,390,391,494,616,679,237,238,184,185,186,240,188,189,239,185,186,190,3023,1409,4116,297,436,1538,2207,909,146,147,355,356,302,303,305,303,305,303,304,303,304,303,548,1368,239,185,186,240,188,189,241,3959,1553,152,961,962,963,135,136,137,1287,139,140,141,959,2014,208,2015,388,1167,1693,1693,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,467,467,467,291,1675,4117,130,161,328,393,572,489,665,735,216,449,439,669,179,346,319,1094,23,229,1106,172,390,391,494,616,496,925,357,302,303,304,303,304,303,305,303,304,303,4118,147,355,383,384,1348,557,558,373,291,292,324,253,68,549,2147,510,278,562,281,280,281,280,281,280,281,281,280,281,280,281,561,995,996,1568,815,816,1226,1182,347,581,348,455,455,455,455,686,549,800,2106,483,484,485,2197,113,101,114,119,120,121,1037,1031,333,1232,335,336,337,44,45,1398,54,4119,961,962,963,135,136,137,138,139,140,141,959,100,101,624,625,626,627,1179,1180,1181,1182,347,1239,403,467,467,467,467,3289,815,841,650,2003,673,743,744,188,189,239,185,186,240,188,189,190,1828,4120,115,1046,1047,1048,1049,1337,1281,375,1462,1463,1683,4121,4122,4123,442,1212,1213,267,554,1322,1317,4124,401,356,502,2198,1637,23,564,216,542,1012,1013,1013,1013,1013,1614,4125,712,712,696,696,696,278,430,280,281,1752,203,204,458,459,169,460,179,147,597,556,1348,557,558,557,558,692,102,103,104,135,136,137,138,139,140,141,959,104,135,136,137,138,139,140,141,959,367,368,369,2132,4126,692,988,4127,269,271,270,270,270,271,270,270,272,549,1338,293,4128,489,665,666,667,730,731,268,865,758,251,465,1281,180,181,233,190,986,1940,156,157,101,624,625,928,206,207,208,388,936,937,938,939,4129,118,119,120,121,109,110,99,111,112,99,100,133,123,134,216,1042,439,838,23,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,564,216,1042,439,4130,240,188,189,239,1165,184,185,186,190,4131,756,268,269,271,271,270,270,270,271,726,331,251,332,333,410,335,411,412,637,147,510,712,712,573,574,575,192,193,194,1577,1942,572,489,665,735,489,665,735,216,1042,439,266,267,554,732,1921,549,1313,145,727,434,347,581,348,455,455,455,455,1215,1241,641,642,434,454,686,403,2079,4077,4132,175,387,216,3940,178,179,147,510,278,4133,2304,2305,636,549,3972,367,368,399,400,179,180,181,2424,549,1922,109,110,99,111,112,99,100,158,123,124,125,126,492,172,382,401,383,556,558,1351,961,962,963,135,136,137,138,139,140,141,959,178,179,382,148,149,150,446,447,512,4078,1005,333,334,1329,382,4134,140,141,1095,522,523,44,45,524,640,4135,4136,4137,400,179,382,148,854,629,190,4138,883,4139,956,4061,3557,4140,454,686,331,109,808,811,812,899,814,924,179,390,391,494,495,690,1236,752,159,128,129,131,820,1116,394,395,1594,396,4141,1451,1107,29,104,135,136,137,138,139,140,141,680,900,901,1265,303,903,303,304,303,305,303,304,303,1527,104,135,136,137,1287,139,140,141,680,1074,1323,143,144,125,126,492,687,688,616,689,496,690,496,496,691,752,2070,2071,2747,3227,4142,4143,230,146,147,401,383,502,634,537,4144,4145,4146,4147,4148,610,148,429,854,574,3411,99,113,101,283,284,285,286,467,467,104,135,136,137,138,139,140,141,1449,680,382,737,738,2134,2453,618,584,585,586,1374,222,223,224,216,449,439,669,179,147,148,445,1704,3338,4149,460,179,300,301,358,2695,2695,359,359,359,360,549,800,1673,295,466,147,510,278,430,280,281,280,281,280,3096,113,565,1978,23,1493,1305,4150,386,222,223,224,221,222,223,224,216,542,1693,4151,2243,352,791,172,147,148,979,1600,1601,1602,135,136,137,138,139,140,141,680,4152,295,1250,326,327,99,201,202,203,204,594,595,596,316,317,703,146,346,319,1821,347,348,1215,549,708,662,169,352,776,777,778,779,1751,692,680,841,2002,3051,1455,1013,1013,1013,1013,1039,1968,216,1042,439,838,23,467,104,135,136,137,138,139,140,141,680,1304,1305,1306,549,610,1320,330,332,333,410,335,411,412,69,1721,254,255,276,934,2490,4153,4154,148,445,854,1970,104,135,136,137,138,139,140,141,959,1171,1120,1121,68,713,173,3515,510,696,278,591,672,280,281,280,281,281,280,281,280,281,280,692,1169,439,4155,23,104,135,1493,1494,797,169,352,798,172,382,401,383,383,402,1396,758,332,333,410,335,411,412,69,150,2632,465,561,980,918,467,467,291,292,324,253,68,1241,3047,2035,1546,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,1548,2070,2071,2747,1031,333,410,418,47,161,328,329,101,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,99,113,101,102,103,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,182,606,2224,4156,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,662,169,1665,333,3246,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,102,103,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,148,429,149,150,446,592,592,636,549,800,203,204,458,459,169,460,179,147,461,445,445,429,462,999,835,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,665,735,489,665,666,667,3170,333,1232,335,4157,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,1171,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,145,146,147,355,383,384,654,557,1281,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,460,179,147,461,445,445,445,429,149,1522,280,281,280,281,752,99,113,101,225,226,120,121,109,110,99,111,112,99,100,3187,718,4158,4159,472,157,473,474,475,179,382,513,526,545,2421,161,101,102,103,104,135,136,137,138,139,140,141,959,508,317,703,727,434,347,348,581,348,348,455,455,455,1215,549,2617,367,368,399,400,179,382,510,278,150,2087,2088,2343,3264,113,122,123,124,125,126,500,146,147,510,278,4160,102,103,104,135,136,137,138,139,140,141,959,167,662,169,170,1585,439,266,267,554,269,270,2615,1573,731,268,269,270,1488,276,179,346,319,347,1109,101,624,625,626,627,1179,1180,1181,1182,454,728,403,1116,572,489,490,489,665,666,667,797,1084,439,669,179,346,319,347,348,455,455,944,403,99,258,761,260,261,262,263,264,553,439,838,23,472,157,206,488,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2797,328,329,101,225,226,120,121,367,368,399,2132,2133,2784,2969,203,204,175,176,177,169,352,791,172,382,597,502,634,1103,435,225,226,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,1099,916,3367,3368,3369,3370,367,368,399,4161,703,146,390,391,494,2073,495,4162,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,382,401,356,502,634,611,1422,490,227,123,124,125,491,492,172,382,401,383,556,558,557,558,559,385,2814,367,368,399,400,179,180,181,233,190,2325,2087,2088,485,486,162,163,164,165,361,619,620,1084,439,266,267,2393,823,345,509,172,346,319,347,348,581,348,348,455,946,369,1159,1901,68,435,127,567,568,1425,1426,4163,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,352,600,172,382,510,712,696,1343,393,572,489,665,666,667,668,439,669,179,147,461,429,429,429,429,445,149,562,281,280,281,280,281,1718,508,317,4164,641,2061,2062,477,478,4165,169,352,621,146,147,510,573,574,910,4166,564,565,2101,179,390,391,80,2124,4167,472,157,473,474,475,179,390,391,495,1744,497,2268,660,169,352,1133,537,537,1395,549,4168,102,103,1107,29,203,204,458,459,169,178,179,147,148,149,4133,2304,2305,512,549,1338,225,226,120,121,367,368,369,453,319,454,728,549,1338,101,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,113,122,123,124,125,126,145,146,147,355,356,384,558,1351,400,179,147,148,445,4169,2699,472,157,473,474,475,179,382,1663,697,545,3139,326,327,99,111,112,99,161,328,329,122,123,124,125,508,317,345,509,172,346,319,347,348,1239,403,346,476,477,2236,4170,680,609,169,352,798,172,382,148,149,591,1243,281,280,281,280,281,280,281,280,281,280,605,492,172,180,181,233,190,2167,4171,3980,211,820,134,216,449,439,669,179,346,319,454,456,1215,69,231,232,233,239,948,949,950,951,570,1658,758,2069,644,222,223,224,216,449,439,669,1120,1121,4172,197,492,172,382,148,149,591,150,446,592,447,447,592,592,447,447,1731,147,401,383,526,545,2421,128,129,1424,508,317,703,146,346,319,347,348,581,455,348,1215,69,394,395,396,699,172,382,513,533,502,634,611,538,538,537,537,537,2349,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1949,1323,467,467,467,467,467,104,135,136,137,138,139,140,141,959,285,286,104,135,136,137,138,139,140,141,959,641,2061,2062,477,478,4173,1116,572,489,490,216,449,439,669,179,390,391,23,161,101,102,103,104,135,136,137,138,139,140,141,959,231,967,1890,545,1188,1189,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,460,179,147,461,445,445,149,150,446,447,3155,808,809,809,840,1949,1323,453,476,2195,2196,2374,426,577,578,123,124,125,1150,145,146,147,148,149,2694,146,346,319,347,1132,1796,355,383,514,570,1658,2027,374,229,909,777,846,616,690,496,2247,382,532,700,4174,1887,859,1100,1762,1281,1406,558,557,558,557,557,557,558,559,4175,416,244,1123,1124,1125,379,169,352,2108,4176,295,506,102,103,104,135,136,137,138,139,140,141,959,148,445,653,570,952,2257,458,459,169,178,179,382,401,383,402,356,402,356,502,634,4177,1026,319,347,456,348,686,403,510,696,697,545,671,2070,2071,2392,439,266,267,554,1921,69,1171,367,368,399,400,179,390,391,494,616,1281,127,128,129,1424,382,355,383,526,545,3154,102,1254,1255,1256,1912,253,68,1241,178,179,147,148,445,445,149,562,281,280,281,280,281,280,674,810,1949,1323,190,2162,483,484,485,2505,3048,179,390,391,494,495,496,976,692,145,146,231,232,233,190,4014,4178,4179,1171,162,163,164,165,1589,1590,1591,169,229,230,146,147,148,445,149,1847,1074,1323,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,147,148,854,574,2763,1599,147,532,526,545,1188,1199,3280,934,2490,1691,959,687,688,495,505,690,690,496,496,496,1111,277,712,278,1522,280,295,982,237,743,744,188,189,239,185,186,190,245,1409,987,471,2072,727,434,454,728,549,2147,243,244,166,167,168,169,352,2652,4180,2886,4181,162,163,164,165,313,314,315,169,352,1660,3366,434,454,1027,435,161,101,102,103,104,135,136,137,138,139,140,141,959,3269,422,423,4182,665,735,489,665,666,667,4183,1071,243,244,313,314,315,169,237,238,184,185,186,239,185,186,240,188,189,241,4184,147,510,696,697,608,4183,254,255,1663,697,769,770,4185,148,149,2466,2360,498,1745,2824,4186,345,509,172,382,510,712,696,278,562,752,145,146,147,148,429,429,429,3966,943,319,320,4074,4187,3025,228,352,600,172,382,355,383,384,557,654,557,1718,352,353,146,147,148,445,429,149,591,150,446,447,447,447,790,1579,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1546,340,1548,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,178,179,382,355,383,534,535,663,435,826,1282,829,3716,68,54,55,4188,167,609,169,1418,23,382,355,383,534,535,1242,549,1338,237,238,184,185,186,241,185,186,239,185,186,4189,694,204,594,595,596,316,317,703,146,346,319,320,193,194,1577,1587,382,401,383,526,545,2700,564,565,2101,179,173,2056,665,666,667,3593,4190,563,472,157,216,449,439,669,179,147,148,854,629,190,191,2272,228,178,179,382,355,383,357,711,258,259,260,261,262,263,264,1838,685,434,320,193,194,4191,460,179,147,518,357,1396,403,401,383,502,634,536,538,538,1759,713,1663,697,545,1188,1189,547,687,980,781,780,779,780,780,1751,295,506,808,809,809,840,1949,1323,100,216,1042,439,440,859,2128,295,1911,1171,1713,930,4192,367,368,369,400,179,382,510,573,629,2546,229,1106,687,980,781,780,2601,1275,367,368,399,400,179,147,401,383,526,545,3584,178,179,390,391,494,616,496,3002,345,509,172,382,355,356,302,303,304,303,304,303,788,69,683,401,383,502,634,538,537,611,537,537,1759,549,1338,429,429,429,429,445,429,149,511,1811,231,232,233,190,482,483,484,2326,589,670,545,2421,147,510,278,511,446,512,549,1338,4193,23,1171,147,148,429,149,511,446,447,636,1241,2175,2176,498,2127,579,580,703,146,346,319,454,1215,549,760,581,348,348,1318,453,476,477,478,479,2824,4194,460,179,147,597,502,634,537,799,1216,113,101,102,103,467,467,467,467,467,467,467,104,135,1493,1305,1782,1783,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,472,157,473,474,475,179,382,513,526,2714,665,735,489,665,666,667,730,731,268,1921,403,491,374,178,179,147,401,356,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,760,145,146,147,355,383,534,535,538,538,538,4195,370,371,1505,495,691,782,145,146,1824,18,147,737,738,2134,3498,838,47,178,179,147,148,445,445,445,149,279,280,281,2018,1642,382,355,383,384,654,557,558,557,557,557,557,557,558,557,558,557,918,564,565,2101,179,173,2056,808,811,812,899,814,815,816,1226,1182,347,455,944,403,696,697,545,1188,2249,352,791,172,147,148,445,445,149,759,446,592,447,512,435,1074,1323,798,172,382,355,383,383,357,302,1670,472,157,489,490,216,449,439,669,1120,1121,68,69,472,157,473,474,475,179,382,513,526,545,671,102,103,104,135,136,137,138,139,140,141,959,203,204,458,459,169,237,743,744,188,189,240,188,189,240,188,189,190,986,1044,1189,251,252,3248,162,163,164,165,577,578,123,124,125,702,580,345,509,172,180,181,233,190,191,192,193,194,195,1897,393,394,395,396,531,146,346,319,1094,4196,379,1084,439,838,23,492,1288,765,1290,4197,429,429,149,430,280,281,280,281,507,178,179,382,355,356,357,302,303,305,2706,1074,4198,148,445,429,2955,346,319,454,348,581,348,348,348,455,455,348,348,455,455,3708,769,770,2396,54,55,2625,460,179,147,461,429,429,445,445,445,149,150,446,2121,1442,2676,23,322,1428,1429,1430,746,104,135,136,137,138,139,140,141,142,178,179,382,401,383,402,356,402,383,519,3338,4068,4199,1061,4200,382,148,149,591,150,446,636,403,300,301,2480,950,951,515,571,367,368,369,400,179,382,401,383,977,460,179,147,597,402,1275,401,383,556,654,557,557,557,558,557,1718,508,317,345,172,390,391,494,2073,495,691,711,4201,68,713,1692,216,542,1012,1013,1013,4202,382,401,356,302,303,304,303,304,303,304,303,304,303,304,303,304,1884,641,656,764,765,2315,3214,4203,510,696,697,769,770,2141,460,179,147,518,384,654,1935,207,208,388,3309,3310,4204,4205,4206,1081,4207,178,179,147,401,356,519,520,1331,2557,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,2104,587,434,347,4208,549,1338,1990,2810,1009,47,131,2252,641,764,765,2387,3172,369,1339,463,403,491,228,352,600,587,434,347,581,455,686,403,500,146,147,401,383,402,302,303,305,303,305,303,548,69,147,589,590,445,445,445,429,149,591,150,446,636,69,783,570,952,2460,240,2328,2329,950,951,570,571,1026,319,1821,347,348,455,348,348,686,549,1338,178,179,382,148,429,429,445,429,149,1522,280,281,711,399,1130,1383,4209,782,291,297,4210,299,3355,3356,403,943,319,347,581,455,455,455,2059,355,383,384,654,557,558,557,557,557,557,557,558,557,558,557,558,557,558,557,558,2201,2202,601,3394,561,628,1187,500,146,147,148,429,429,429,429,149,759,446,447,512,69,401,383,526,545,671,1169,439,266,267,268,270,2493,435,489,665,666,667,797,1169,439,266,267,554,270,2493,2770,300,2345,2480,950,951,632,54,1509,1171,243,244,313,314,315,169,460,179,147,518,534,535,611,1759,1241,472,157,473,474,475,179,382,589,670,545,1188,1189,100,101,624,625,626,627,1179,3558,901,902,303,548,325,1906,333,410,335,336,337,44,45,524,561,921,967,1890,545,1188,1189,400,179,382,148,149,672,280,1774,638,169,460,179,147,461,445,1704,4211,727,434,347,581,455,348,348,455,348,348,455,686,69,586,216,449,439,669,179,382,518,534,535,3440,369,400,179,180,181,182,181,233,190,245,1409,1044,2098,251,252,253,68,69,300,2345,302,303,305,303,305,303,305,303,304,303,304,303,304,303,304,303,548,2083,2169,2170,4212,4213,4214,355,383,514,570,516,4215,330,252,253,68,835,461,445,429,149,430,280,281,281,281,280,281,4216,510,696,712,712,278,511,446,636,435,808,811,812,899,814,815,816,817,333,410,335,336,337,44,45,822,419,348,1027,549,1338,662,169,170,171,587,434,454,348,1027,549,1028,291,297,468,2207,374,460,179,147,597,556,558,559,385,295,506,510,278,150,2087,2088,485,2505,4217,103,291,292,1974,253,4218,756,554,270,270,2493,549,1313,513,700,402,302,303,304,303,304,303,304,303,548,549,1338,356,356,502,634,536,538,538,538,537,4177,526,2262,1169,439,266,267,268,270,3506,1322,429,429,429,445,445,149,279,280,281,295,506,1286,602,603,2004,318,319,454,581,455,686,403,482,483,484,2374,54,55,4219,362,216,1042,439,266,4220,23,429,445,149,562,281,280,281,782,2405,950,951,570,952,529,182,606,2478,515,1658,54,55,2040,2523,172,382,401,356,556,557,654,557,442,148,445,445,445,429,429,445,462,999,69,687,980,2369,4221,711,460,179,390,391,494,616,1330,1097,4222,173,948,949,950,951,570,516,4223,547,172,382,401,383,402,302,303,304,303,305,303,305,303,304,303,548,713,322,1428,1429,561,485,4224,178,179,147,1486,835,445,445,445,429,429,429,3112,1193,1286,3394,1245,146,147,1286,603,602,603,602,2471,4225,589,2725,401,383,556,558,557,1348,557,557,558,373,429,462,4226,1575,1265,303,305,2290,549,789,390,391,495,1744,497,659,660,4227,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,180,606,607,769,1612,394,395,1594,396,4228,433,434,1094,23,169,237,238,184,185,186,190,575,802,80,1829,399,641,2061,2062,2195,2196,2343,2505,4229,251,252,253,254,255,99,113,414,415,416,244,1123,1124,1125,316,317,703,727,434,347,728,549,1338,487,206,488,489,490,227,123,124,125,491,2600,333,410,1891,180,181,921,967,1890,608,756,554,269,270,726,403,197,145,146,147,148,149,511,446,592,592,592,447,447,2121,3875,1388,346,476,2195,2196,485,2505,2297,172,346,319,454,581,686,69,180,181,233,190,4230,169,352,353,146,147,355,383,357,874,390,391,494,495,505,691,977,382,148,429,429,149,511,446,592,592,447,592,592,447,636,69,231,232,233,190,745,80,4231,1254,1255,4232,4233,523,2246,3614,147,401,383,502,634,611,537,537,537,537,2733,355,383,302,4234,808,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,809,809,1007,1008,1009,47,4146,4235,1171,382,148,149,150,2087,2088,485,2622,3048,638,169,178,179,147,401,383,556,558,557,1784,561,2538,376,1627,4236,547,687,688,495,690,505,496,295,506,1903,1904,1905,23,3212,3213,443,463,549,1338,2106,483,484,485,3439,460,179,147,461,149,150,446,447,447,447,592,636,331,1458,4237,4207,145,146,147,401,356,502,634,536,538,537,537,1759,549,1313,4238,2813,1413,4239,355,383,357,383,384,1784,295,506,531,146,346,319,347,2336,528,516,2511,549,610,1763,1764,266,267,268,269,270,270,272,403,2522,950,4240,950,2187,3064,467,104,135,136,137,138,139,140,141,959,1585,439,266,267,554,270,726,549,1093,1074,1323,147,532,526,769,770,2992,367,368,399,400,179,147,148,445,149,751,782,662,169,178,179,147,355,356,519,990,2926,699,172,382,1663,1706,696,712,712,712,998,999,69,178,934,2490,3352,709,60,61,73,93,4241,352,600,172,180,181,233,190,469,2270,1499,1555,1218,820,477,2236,2779,47,2622,2356,168,169,237,238,184,185,186,239,185,186,241,1981,382,597,556,654,557,558,557,558,557,558,557,558,557,559,4175,3578,1031,333,1232,335,336,337,44,45,46,23,4242,645,646,2174,4243,4244,401,383,383,502,2198,4245,1413,709,60,61,2671,2672,66,2673,1421,69,400,179,180,181,233,241,2056,229,909,146,390,391,494,495,496,496,1236,1178,345,1288,4246,4247,3061,80,1496,2470,2002,602,2471,4248,673,532,526,545,671,1007,1031,333,410,418,23,445,445,149,759,446,636,713,375,376,377,1230,4249,146,390,391,494,495,976,373,2064,2467,390,391,494,616,496,497,659,660,147,510,278,2541,280,281,280,281,280,3096,318,319,320,193,194,4250,1549,193,194,195,2809,3381,1409,1044,1199,429,429,445,445,445,445,4251,148,149,150,446,592,592,447,1787,4252,838,23,510,696,712,712,696,2136,520,4253,472,157,473,474,475,179,382,532,526,545,1188,1846,162,163,164,165,1589,1590,1591,169,229,230,146,346,319,347,1239,549,1093,180,181,182,606,607,545,2314,666,667,730,731,554,1814,1921,435,203,204,175,176,177,169,237,238,184,185,186,241,185,186,187,1174,2536,2537,477,2064,4254,702,580,703,146,147,510,573,629,190,1617,4255,401,383,402,302,303,304,303,304,303,305,303,305,303,548,69,921,967,1890,769,2605,2195,2196,2343,2505,3102,735,489,490,216,449,439,266,267,883,268,2835,366,4256,442,4257,23,554,1294,270,270,270,270,272,403,127,128,129,819,2925,4258,265,838,23,162,163,164,165,361,619,620,169,178,179,382,401,383,519,990,1804,1408,641,657,658,4012,228,460,179,147,1835,558,557,558,557,558,557,2023,231,232,233,190,2175,2176,498,4259,172,382,401,383,556,557,1348,557,558,557,558,1222,352,353,146,147,355,383,384,1348,557,557,557,558,1482,1026,319,1528,582,737,738,2134,2565,147,401,356,556,654,557,557,558,557,558,557,692,147,589,590,429,429,445,445,149,759,446,592,447,447,512,549,610,3322,216,449,439,4260,131,132,149,511,446,447,512,69,147,401,356,402,302,303,305,303,304,303,788,549,3098,461,429,429,445,149,150,446,447,4261,352,4262,1561,4263,485,2622,2297,1962,333,1232,335,336,337,44,45,1006,549,1338,147,510,696,696,1343,1573,731,554,1294,270,2875,104,135,136,137,1287,139,140,141,959,489,490,216,449,439,266,267,554,270,270,726,403,489,665,666,667,3170,333,1232,335,336,337,44,45,1006,835,180,606,2478,3588,375,2846,3423,4264,1368,735,216,449,439,669,934,4265,547,4266,541,429,429,149,591,1243,281,281,280,281,280,281,280,281,280,746,769,770,2658,513,526,545,671,492,687,688,495,505,496,690,690,496,496,691,782,3447,563,542,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,2214,2245,231,232,233,190,1549,193,194,1072,513,700,402,302,303,305,303,305,303,304,303,304,303,548,403,2563,497,498,2692,2340,2946,347,1781,1254,1255,1256,1912,253,254,255,532,526,545,1188,1199,694,204,594,595,596,379,169,237,743,744,188,189,190,1654,1498,1499,1555,1218,755,1084,439,4260,401,383,502,634,537,538,4267,172,180,181,233,190,745,1526,296,486,653,570,952,2460,375,2846,4268,4269,4270,80,4271,149,511,446,592,447,447,447,512,331,2162,483,484,2343,486,1317,2328,2329,950,951,570,1658,637,211,820,1435,1436,1438,4272,549,1338,382,401,383,556,558,2441,149,150,446,447,592,4273,311,181,233,190,245,1409,2886,471,231,967,1890,769,770,2543,510,278,562,281,977,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,811,812,899,814,924,179,2502,23,4101,352,2652,2653,184,185,186,190,2827,193,194,2722,375,1462,1463,4274,549,729,670,527,180,606,607,2518,356,357,302,303,304,1884,265,266,267,554,269,270,271,271,271,726,713,589,4091,69,1821,347,348,455,455,348,348,455,455,1215,69,180,181,182,606,2478,570,952,2636,601,602,752,460,179,147,597,502,634,663,758,429,429,149,279,280,281,1774,1044,1846,1106,172,382,510,696,696,998,999,69,1317,2328,2329,950,951,570,1658,54,2839,2145,148,429,149,591,672,280,281,692,180,181,233,239,185,2082,835,810,809,809,809,1007,1031,333,410,418,23,390,391,616,1744,497,498,617,480,2454,808,811,812,899,814,924,179,346,319,347,1132,1241,1304,1305,1306,637,641,2061,2062,4275,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,4063,589,590,429,149,591,672,280,281,281,281,280,281,280,281,280,673,764,765,2387,2432,2317,523,44,45,3290,193,194,1577,1587,680,231,232,182,834,664,101,162,163,3091,3933,396,432,824,1290,1291,523,44,45,1346,4276,2064,2065,4277,617,2340,3454,171,687,688,495,690,505,690,690,496,690,690,690,1330,735,216,449,439,266,267,554,732,1815,516,2332,4278,247,101,624,625,626,627,2411,181,233,190,1643,4279,1518,950,951,632,54,55,56,2454,4280,390,391,392,445,670,545,1188,1846,1314,567,4281,300,301,302,303,304,631,4282,1906,333,410,335,336,337,44,45,1006,69,727,434,320,193,194,4283,1632,333,334,335,336,337,44,45,3129,149,759,446,592,447,447,512,549,1338,485,486,776,146,147,597,4284,4285,258,761,260,261,762,262,263,264,4286,355,383,526,545,2700,147,510,573,629,190,191,802,1526,296,149,430,280,281,280,281,280,1774,698,180,181,921,232,233,190,986,4287,162,163,796,101,225,226,120,121,109,808,811,812,899,814,1945,333,410,335,411,412,435,147,589,670,545,1188,2249,547,172,382,355,356,384,558,1350,148,445,429,149,591,150,446,447,447,512,549,1313,1026,319,347,348,455,455,944,549,1338,450,889,4288,1832,4071,2343,486,4289,1323,680,180,181,233,190,469,2270,1499,1555,1218,820,2538,376,2539,295,506,346,319,347,455,528,570,3142,4290,429,429,445,445,149,279,280,281,3589,3602,661,735,216,449,439,669,179,346,319,4291,577,578,123,124,125,4292,370,433,434,454,455,1149,350,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,382,148,445,429,429,445,429,149,430,280,281,782,1015,172,382,355,443,463,835,4293,3078,611,537,538,538,537,663,403,653,516,2332,2331,2550,4207,489,665,666,667,3170,333,410,418,985,346,319,347,348,455,581,348,348,4294,4295,445,670,545,1188,1199,510,696,278,150,446,592,512,549,1338,591,150,446,447,636,403,429,429,149,591,672,561,808,840,840,840,3229,2724,490,216,4296,504,2866,586,216,449,439,669,179,382,401,383,519,4297,231,232,233,190,2162,483,484,485,486,178,179,300,301,302,303,548,69,142,104,135,136,137,138,139,140,141,4298,943,319,454,581,1215,549,1338,429,149,591,672,280,281,280,605,2924,376,1627,1331,521,522,523,44,45,524,507,231,232,233,190,3381,1409,1044,1045,375,376,377,990,1705,587,434,347,455,728,435,149,279,280,281,280,281,281,281,280,281,280,1510,1675,3627,193,194,195,2435,320,193,3286,2855,2856,665,735,489,665,666,667,668,439,266,267,554,1814,1815,952,2332,2332,2331,2331,2332,2332,2550,69,545,714,1663,1706,2721,148,149,279,280,281,280,281,280,281,280,1510,429,445,429,149,759,446,512,758,727,434,347,686,3376,172,147,1286,602,1222,1007,3388,2143,193,194,3389,589,670,608,178,179,147,401,356,502,634,4299,1311,149,562,281,281,281,280,281,280,281,281,281,280,281,280,281,3589,3602,492,1288,1289,1596,1909,69,173,948,949,950,951,3743,601,603,603,602,1350,352,600,172,382,148,149,150,446,4300,178,179,300,2345,302,303,304,303,304,303,305,303,548,637,756,554,1294,270,270,271,270,2007,197,492,172,382,148,445,979,178,179,147,401,383,402,383,556,654,557,558,557,558,557,558,557,558,557,684,445,445,445,445,149,150,446,447,4301,382,148,445,1704,990,3461,455,455,944,549,1338,2303,2304,2305,636,549,708,1150,492,172,382,355,356,534,535,663,549,1338,145,146,231,232,233,190,2704,4302,238,184,185,186,241,185,186,240,188,189,239,1165,184,185,186,240,1174,2536,4303,429,429,429,445,445,445,149,994,839,785,3195,190,191,192,193,194,1577,2599,178,179,231,232,1163,1560,2536,1164,429,445,149,562,281,280,281,280,281,1411,447,636,403,769,2105,190,3634,4304,149,279,711,608,696,278,4305,280,281,280,281,280,1350,149,150,446,592,682,266,1041,254,398,1821,454,1822,403,638,169,943,319,4306,500,146,390,391,494,616,1461,231,967,1890,545,1188,1199,1074,1323,170,1585,439,266,267,554,271,269,272,549,4307,145,146,147,148,445,445,445,445,149,150,446,447,512,426,179,231,232,233,190,4308,4309,4179,233,190,1967,483,484,485,2089,54,55,4219,1514,1693,1693,1693,1693,1693,1012,1614,4125,1435,1436,1437,4310,591,759,2745,237,238,184,185,186,190,1931,4311,1248,429,445,149,279,280,281,280,281,442,510,278,591,1243,280,442,2325,2087,2088,485,2197,352,600,172,147,597,502,4312,180,181,233,190,850,1409,3694,490,216,1042,439,266,267,554,1244,549,708,810,1949,1323,840,840,809,809,809,809,809,840,809,809,809,1007,1031,333,410,418,47,401,383,526,545,3584,237,743,744,188,189,239,185,186,190,4313,680,101,162,163,2085,157,216,1042,439,266,267,554,1807,435,532,2953,2282,216,1042,439,838,23,2108,860,1100,1100,1101,1101,1101,1101,1101,3053,3340,333,4314,258,761,260,261,836,837,262,263,264,265,838,23,4315,69,2085,157,216,449,439,669,179,390,391,494,616,505,496,496,496,4316,1706,3996,4317,724,665,735,489,665,666,667,1564,916,1565,4318,507,510,712,278,511,446,592,512,4319,492,172,180,181,233,239,1165,2921,69,460,179,147,597,502,634,536,4320,2398,656,764,765,2315,4321,1171,390,391,494,616,3367,3368,3369,3370,429,445,445,429,429,445,149,693,769,4322,2252,4323,1517,149,279,280,281,280,281,280,281,605,1112,2843,4324,4325,4326,549,1571,147,510,573,4327,490,216,1042,439,266,3950,23,291,292,324,253,68,350,318,319,347,455,455,944,549,1252,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,346,319,347,581,348,348,455,455,455,455,3377,714,554,4328,4329,4330,370,4331,2111,1915,4332,346,476,2195,2196,2640,581,455,455,348,348,455,455,686,403,2096,497,659,2370,542,1693,543,1354,4333,300,4334,149,759,446,592,447,447,593,134,216,1042,439,838,47,231,232,233,239,185,4335,489,665,666,667,725,439,440,859,3772,661,1254,1255,1256,1912,253,68,331,147,148,445,445,429,429,445,445,429,4336,3954,777,846,495,505,690,690,496,496,496,496,1111,688,616,2172,711,420,801,120,289,109,110,99,111,112,99,100,489,665,735,216,736,179,147,532,2348,549,550,4337,147,148,429,854,872,873,589,670,608,366,171,687,688,495,505,690,496,1178,429,429,429,429,445,429,149,591,2558,2142,231,232,233,190,234,1498,1499,1555,211,1716,783,570,1658,54,1659,445,149,150,446,592,592,447,592,592,447,447,790,497,659,3915,2806,23,429,149,591,150,446,447,512,549,1338,727,434,1821,347,348,686,549,1571,401,383,402,383,519,990,2808,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,241,948,949,1138,403,3943,4338,4339,4340,510,712,278,430,280,1718,266,267,554,271,270,270,4341,154,135,136,137,138,139,136,137,138,906,400,179,231,232,233,190,245,1409,1044,849,154,135,136,137,138,139,1140,352,798,587,434,347,456,1215,1240,460,179,147,518,534,535,611,3064,515,516,2373,430,280,281,281,281,280,507,2405,537,799,69,178,179,147,510,278,562,2045,943,319,347,581,455,455,348,348,455,686,403,597,502,634,611,537,538,538,537,538,538,663,549,610,2879,179,390,391,494,616,1960,977,154,135,136,137,138,139,4342,1719,545,1188,2249,382,148,429,149,591,150,446,447,592,592,447,447,512,549,800,810,840,840,809,809,809,809,809,810,809,809,809,1007,1031,333,410,418,47,656,642,434,454,528,632,637,472,157,489,490,216,449,439,669,179,346,319,347,686,549,1338,162,163,164,165,594,595,596,169,229,909,146,147,355,383,519,990,991,2478,570,1658,758,145,146,147,148,429,149,430,280,281,1774,2898,232,233,190,2850,1599,482,483,484,2326,401,356,4343,777,846,495,690,505,496,496,496,496,496,1461,2096,497,498,2661,346,319,454,455,581,1215,549,1093,347,581,348,1109,145,146,147,355,383,534,2851,398,3078,537,1472,549,1338,356,302,303,304,303,304,303,304,1469,1026,319,347,581,686,403,265,266,267,554,1294,270,270,270,272,69,810,809,809,811,812,899,814,1945,333,1232,335,336,337,44,45,4344,291,292,324,253,68,1241,495,4345,382,601,602,603,1222,1015,172,180,181,233,190,2768,2270,1499,1555,1002,147,1663,697,527,757,549,1674,492,172,382,148,429,429,149,562,281,280,281,280,281,280,281,280,281,280,605,178,179,382,1286,602,603,507,231,232,233,190,3634,1498,1499,4346,807,526,3358,545,3154,743,744,188,189,240,188,189,239,185,186,190,1881,2886,1248,1920,1815,516,2426,390,391,494,80,1062,526,769,770,2657,54,2839,2145,777,846,616,689,691,752,140,141,1095,522,523,44,45,1006,664,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,809,811,812,899,814,815,3998,23,680,2563,497,498,617,4347,815,816,1226,1182,454,349,403,346,319,454,455,528,570,1658,54,55,2040,4348,445,149,150,446,447,512,435,1112,1843,1844,4325,4349,664,3620,292,324,4350,231,232,233,187,1174,1228,561,149,759,446,592,592,447,447,447,447,2991,355,383,357,302,303,305,303,788,413,355,383,526,545,1188,1846,508,317,703,146,346,319,3781,1834,770,4351,513,526,545,1188,2249,148,149,562,281,280,281,280,281,280,281,280,373,429,149,430,281,1774,460,179,300,301,358,4352,4353,584,585,586,2866,222,223,224,216,449,439,838,23,680,229,909,146,346,319,454,348,3792,1518,950,951,570,952,2570,959,172,346,319,1821,3781,2486,572,489,665,666,667,1564,4012,147,597,519,520,521,522,523,44,45,524,4354,148,445,670,769,770,3723,445,445,429,429,149,279,442,216,449,439,669,179,346,540,960,666,667,725,439,266,267,554,1294,270,270,270,271,1488,759,446,592,592,592,592,447,447,4261,478,3660,4355,495,2729,1111,445,445,429,149,759,446,636,549,1338,180,181,233,241,185,2082,403,390,391,494,1813,2413,2112,1915,3166,1915,373,276,179,346,319,454,1027,403,173,948,949,950,951,570,2503,472,157,216,449,439,669,179,346,4356,178,179,147,148,445,445,149,150,446,592,592,3334,725,439,440,859,860,1101,1101,1100,3400,178,179,147,148,149,150,4357,514,570,571,502,634,611,538,538,537,537,1759,69,400,179,382,510,573,629,190,245,1409,2886,3060,698,461,149,150,446,447,592,592,2121,3793,445,429,149,759,446,447,447,512,413,3580,266,267,554,269,270,271,271,2875,533,402,302,303,305,303,305,303,304,303,304,303,304,303,788,69,322,1428,4358,2795,4358,2795,1429,295,466,4359,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1074,1323,251,332,333,410,4360,352,600,172,382,401,383,502,634,538,611,537,538,663,549,800,533,556,559,4361,589,670,769,770,2396,54,55,1238,366,375,2846,4268,4362,4363,679,607,769,770,4364,641,642,434,347,1132,549,2147,390,391,494,616,496,1836,149,150,2350,1239,403,514,570,952,2570,148,445,149,511,446,512,426,532,533,534,535,611,538,538,537,537,537,537,537,663,549,708,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,1949,1323,4266,724,1268,1269,184,185,186,187,1174,744,188,189,190,4365,4366,247,101,624,625,626,627,1638,172,382,510,573,629,190,1554,1196,1197,4367,820,379,169,352,798,172,382,355,383,383,357,1396,549,708,756,554,1294,726,549,1313,1692,3122,4368,1037,1031,333,1232,335,336,337,44,45,46,23,401,356,556,654,557,557,558,557,558,557,558,557,558,557,558,655,429,429,149,279,280,281,281,281,280,281,280,281,1510,401,383,519,990,4369,149,279,280,281,281,281,605,429,149,591,672,281,386,509,172,180,181,1163,232,233,190,245,1409,1044,849,147,510,712,712,696,696,2136,3338,3339,670,2518,348,455,456,455,695,375,4370,921,967,2228,570,952,2362,554,271,4371,926,4234,840,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,815,900,1604,254,419,104,135,964,1171,1663,697,545,3154,1317,2328,2329,950,951,515,952,2570,148,429,149,591,150,446,447,592,592,447,512,549,1338,366,4372,1383,4373,305,303,305,303,304,303,305,4374,206,488,216,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,783,570,571,382,401,356,556,557,654,557,558,557,557,557,442,943,319,454,581,455,348,348,455,348,348,4375,2175,2176,498,3583,934,1473,4376,2491,510,696,696,2136,4211,759,446,592,447,447,592,4273,345,509,172,180,181,2424,549,2147,703,146,147,148,149,511,446,447,447,636,549,1093,2723,1621,330,252,253,254,419,382,148,445,653,570,952,529,2166,774,23,429,429,445,149,759,446,592,4261,777,778,780,4377,782,251,465,1237,590,4378,401,356,519,1230,4379,1586,193,194,3333,1356,1357,1108,980,2006,977,687,980,981,752,3472,440,916,1690,442,783,570,952,2636,172,382,148,149,759,446,592,447,592,592,512,435,322,1428,4380,100,3520,4381,23,142,2149,508,317,345,509,172,180,181,233,190,2175,4382,438,439,266,267,554,2240,1921,350,653,570,571,445,445,445,462,999,713,149,150,446,447,636,413,316,317,703,146,390,391,494,1526,982,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1842,148,149,1522,280,281,280,281,280,281,280,281,280,281,280,442,1012,1039,3616,150,2087,2088,485,3759,1549,637,429,429,445,429,429,1302,591,150,446,592,447,447,592,592,447,636,435,2747,3227,2597,3058,291,292,324,253,254,419,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,401,383,2244,2245,736,179,390,391,494,616,782,148,445,429,429,445,429,149,591,672,280,281,507,737,738,2275,2785,149,4383,2138,1031,333,410,335,411,412,54,55,2625,1554,1196,1197,1555,211,2243,727,434,347,581,348,348,455,455,686,549,1338,2763,2360,498,3583,671,4384,725,439,266,267,554,1294,271,271,270,270,270,270,270,2007,390,391,494,1526,982,3289,382,401,383,556,558,1836,769,770,2408,665,735,216,4385,4386,300,301,2480,950,951,570,3752,756,554,269,271,726,403,429,149,591,150,446,592,592,447,512,549,610,921,967,3669,2669,356,384,654,692,148,429,429,445,429,429,149,150,446,636,435,445,429,149,591,150,446,447,592,592,636,403,1887,916,860,2128,1752,581,348,455,348,348,455,455,1215,69,149,759,446,592,447,512,69,149,759,446,592,636,549,1338,429,149,511,446,592,592,447,592,512,549,1338,2073,495,497,498,617,480,4387,2195,2196,2374,54,2839,2145,534,535,536,663,758,148,149,1522,281,280,281,280,281,280,281,442,320,193,194,2378,4388,100,227,123,124,125,126,145,146,147,401,356,502,634,1103,69,352,600,172,382,401,383,556,1348,557,1351,545,671,628,146,346,319,1821,454,4389,148,149,562,281,281,281,281,280,281,692,190,2850,2142,556,654,557,557,557,557,558,1718,4390,23,656,657,658,495,497,498,3027,1960,622,4391,769,770,3205,305,303,788,69,2840,611,538,538,538,538,538,537,538,538,1759,403,687,688,495,1817,2958,1171,2714,352,353,146,390,391,494,3094,1317,188,2273,631,515,1658,637,148,445,429,445,429,149,591,672,2485,492,172,382,510,712,278,591,994,782,401,383,526,545,3584,998,999,4392,1133,611,538,537,1422,231,232,233,239,1165,2921,435,2387,2432,2317,523,44,45,1531,80,3546,346,319,454,1027,549,1338,726,549,1313,1042,439,266,267,268,1807,4392,586,216,449,439,669,179,147,518,384,654,1178,445,149,562,1774,490,216,449,439,669,179,390,391,494,616,496,1960,1353,429,445,429,149,511,446,447,447,4393,146,346,319,454,457,258,761,260,261,836,837,262,263,264,432,433,434,1094,23,180,181,233,190,2325,2087,2088,485,2505,3527,178,179,382,148,429,149,759,446,447,592,592,447,447,512,1216,756,268,1294,271,271,271,271,271,270,271,726,664,1830,439,266,267,554,269,726,4394,347,455,455,1110,589,590,429,429,445,445,429,429,429,1704,3338,4395,743,744,188,189,239,185,186,240,188,189,190,4396,2197,382,510,573,629,190,2412,1196,1197,4397,180,181,1163,232,233,190,745,80,1829,2231,653,570,1658,54,2839,2145,597,556,654,557,557,557,558,557,558,557,558,557,558,557,684,511,446,447,447,447,447,636,549,1313,4398,687,688,616,2651,563,702,1903,1904,1905,23,1663,697,2713,316,317,345,172,346,319,347,686,435,4198,147,401,443,999,1227,270,2493,435,278,2466,4399,453,319,1821,454,1839,2345,302,303,304,303,304,303,304,303,788,435,591,150,446,592,592,447,592,592,447,447,636,549,1338,356,356,502,634,538,611,537,537,537,663,549,1093,1169,439,266,267,268,757,664,355,383,534,535,663,4319,445,445,429,149,511,446,447,447,636,758,348,348,455,455,686,69,149,511,446,592,512,403,840,809,809,1949,366,104,135,136,137,138,139,140,141,959,147,589,653,3743,608,589,653,515,516,2257,564,565,2101,179,300,301,4400,2274,738,2784,2277,2277,2277,4401,2662,497,4402,3750,2575,4207,445,445,429,149,591,759,4403,587,434,347,456,455,455,1215,713,276,179,346,319,454,455,4092,429,149,279,280,281,918,573,629,190,191,802,782,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4404,2478,632,54,55,4405,1644,1645,2597,3228,142,297,4406,370,824,4407,3065,532,526,545,1188,2249,429,149,591,672,281,1752,532,533,534,535,611,537,538,538,537,537,537,2349,4408,611,1759,549,1571,366,390,391,494,495,2559,622,456,455,686,549,2972,1890,527,581,455,348,1110,597,502,634,536,537,538,538,538,538,537,4409,178,179,147,355,356,384,4410,1171,2262,237,743,744,188,189,241,185,186,239,185,186,190,1828,576,665,666,667,668,439,669,1120,1121,68,664,4411,1383,295,296,1042,439,266,4412,1356,2963,2964,4413,4414,4415,4416,4417,759,446,592,592,447,636,4418,180,606,607,545,1188,1199,300,2345,302,303,304,631,570,1658,54,55,3592,383,402,443,463,549,1313,2754,2755,1260,44,45,46,47,429,429,445,429,429,445,445,3084,429,445,149,150,446,592,4419,510,696,278,591,150,446,3155,300,301,302,303,788,758,562,281,281,281,280,281,282,346,319,454,455,1132,3376,1317,2328,2329,1138,69,375,4420,401,356,356,556,558,557,655,532,526,769,770,2992,134,216,1042,439,440,916,1101,1101,3456,373,266,267,554,1294,270,270,271,271,270,726,549,1338,587,434,347,348,455,456,686,69,1610,216,542,1693,1693,1693,1693,1012,2312,300,2345,1733,545,671,601,602,603,602,603,602,603,2004,642,434,347,528,570,516,3519,2169,3126,1697,759,446,592,592,512,69,429,429,149,511,446,592,592,512,549,1571,1026,319,347,455,695,570,516,529,429,445,149,562,281,280,1774,1663,1706,696,712,696,998,999,69,810,840,840,809,809,809,809,809,840,809,1007,1031,333,410,418,47,680,346,476,477,478,785,4421,390,391,494,616,690,497,2418,2419,382,510,712,278,150,446,592,636,403,513,533,502,634,611,538,538,538,538,537,537,537,538,1422,278,759,446,592,4261,1967,483,484,485,2505,2697,601,602,603,602,603,603,603,602,603,603,603,602,603,602,603,602,507,934,4422,383,556,559,4423,4424,4415,1269,1561,4425,445,445,429,149,1522,280,281,280,281,3096,2343,2089,54,55,2625,2834,136,137,138,139,1657,383,502,634,611,537,537,537,537,663,637,281,281,280,281,280,563,178,179,382,148,1220,3051,110,99,111,112,99,100,2222,2223,128,129,819,3224,347,1132,549,2863,777,846,495,505,1461,180,181,311,4426,769,770,2657,2572,586,216,449,439,669,179,382,518,384,558,557,558,557,1784,640,148,429,429,429,429,445,429,429,445,445,462,463,331,4427,445,445,445,445,4251,778,779,781,781,605,727,434,347,686,435,149,759,446,2121,3875,534,535,611,538,538,538,538,538,538,537,537,537,2349,1486,549,1338,819,132,278,759,446,636,549,1338,222,223,645,646,4428,1121,254,419,2821,3763,350,4429,680,100,101,624,625,626,627,3833,4430,2061,2062,477,478,785,4431,23,510,696,697,769,770,2579,23,4432,445,149,150,3032,613,685,434,454,455,528,515,516,2627,1042,439,266,3950,23,150,446,592,592,447,447,447,4433,429,429,149,759,446,592,636,549,610,2262,976,673,149,511,446,447,592,592,3334,266,267,268,270,270,4434,2213,663,549,610,510,278,511,446,447,636,549,1571,149,279,280,281,280,281,1774,1575,902,303,304,303,903,303,304,303,1798,4296,628,146,147,510,573,629,190,986,2886,1248,258,259,260,261,1352,179,2676,398,401,383,526,769,770,4435,460,179,147,597,502,4436,23,429,149,759,446,592,447,447,447,447,512,435,258,761,260,261,836,837,262,263,264,265,266,267,554,269,271,271,270,1626,608,1730,435,4411,1383,2133,739,2245,429,149,430,280,281,295,1616,587,434,454,581,348,1318,562,281,281,281,281,442,1906,4437,154,135,136,137,138,139,136,137,4438,172,390,391,494,495,690,505,691,1718,149,759,3477,4439,1431,4440,1431,1432,1431,1431,4441,237,238,184,185,186,240,188,189,239,185,186,240,1174,744,188,189,190,3015,3033,1265,1164,696,697,545,2700,1169,439,838,23,510,696,278,150,446,592,512,758,587,434,347,456,348,348,686,549,4442,534,535,538,611,538,538,538,538,538,537,538,538,537,537,663,549,1338,4443,770,2992,383,402,383,402,302,303,304,303,304,303,305,303,305,303,304,303,4093,4444,3000,401,356,402,1396,549,800,383,357,302,303,305,303,304,303,788,549,1313,4445,382,510,712,278,150,1811,759,2350,301,302,303,304,631,632,54,2839,2145,943,319,347,348,686,549,2147,1059,1060,1061,80,1105,1846,767,860,1100,4446,727,434,347,581,348,686,549,1093,1928,146,390,4447,696,278,511,446,636,713,4415,4416,23,2763,2360,498,617,1178,666,667,725,439,266,267,554,271,2510,403,251,332,333,334,1329,486,1586,193,194,2789,429,149,591,150,446,447,593,769,770,3874,1838,614,615,2073,495,1403,104,135,136,137,138,139,140,141,959,301,2480,950,951,570,1658,54,55,4219,352,2130,184,185,186,240,1174,744,188,189,187,1174,2536,4448,510,696,1706,3996,382,148,445,445,445,429,149,430,280,281,280,281,280,281,280,442,1007,1031,333,1232,335,336,337,44,45,46,47,1663,783,570,571,1996,859,3367,3368,3369,3370,742,928,216,4449,4450,401,383,402,519,520,1332,4451,401,383,402,302,303,305,303,304,303,305,303,305,303,304,303,788,549,2863,502,634,611,538,538,537,538,538,537,537,663,549,1338,429,149,511,446,447,592,592,447,447,636,549,800,590,2725,1218,2359,1573,731,554,270,1294,270,270,4434,567,568,3556,1426,1427,769,770,2657,2335,180,181,233,240,1174,3039,835,3487,2478,570,952,2257,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,300,301,2480,950,951,570,3142,777,846,495,1461,241,185,186,241,1165,4452,617,480,4387,700,556,1348,1935,4453,182,606,607,3358,429,429,149,279,1281,429,149,2694,3381,1409,2886,3060,4454,271,271,270,270,726,549,1571,1288,4455,190,191,802,80,81,1031,333,1232,335,336,337,44,45,46,47,773,774,23,352,353,146,231,232,233,190,234,1498,1499,1555,211,919,492,172,382,401,356,402,302,303,305,303,304,303,305,303,305,303,305,4456,455,455,348,348,348,2509,390,391,494,616,496,497,498,1745,3108,429,149,591,150,446,447,447,512,549,708,518,534,535,611,537,538,538,537,537,537,537,1611,239,185,186,187,1174,2536,1164,1890,545,2700,251,332,333,334,1364,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,429,445,445,429,149,591,150,446,512,426,1562,1289,1290,1291,523,44,45,822,398,4457,54,55,2040,4458,346,319,347,348,456,455,348,455,1839,1663,1706,278,150,446,447,592,592,636,549,1571,1323,489,665,735,216,736,179,300,2345,2480,1138,403,698,402,302,303,305,303,304,303,548,549,610,445,445,445,445,445,445,3450,697,545,742,547,687,688,2318,252,1622,1413,370,433,4459,1413,838,23,725,439,266,267,268,270,2251,69,401,383,556,654,557,557,557,558,557,1351,1120,1121,254,960,524,4460,233,190,1617,3013,512,549,1338,148,1220,602,839,1094,541,211,1087,147,355,383,2953,1639,463,69,680,2314,148,445,149,759,446,447,447,447,4261,445,429,462,2663,597,556,654,557,558,557,558,640,2773,447,512,549,2863,2046,2770,590,4461,2953,1644,1645,2597,2598,193,194,1072,277,696,278,150,446,512,69,205,101,624,625,626,627,1638,172,382,510,573,629,190,245,1409,2886,471,182,606,607,545,1188,1846,696,696,278,759,1550,1163,232,233,190,850,851,346,319,454,455,528,515,2495,399,400,179,147,510,573,629,190,191,192,193,194,1577,4462,211,212,1518,950,951,570,516,2570,445,429,149,759,446,4393,1965,150,2087,2088,485,2089,54,55,633,445,445,429,429,445,149,150,446,512,549,708,1160,1483,3468,4463,4464,180,2114,268,1814,1815,516,2332,2332,2550,1241,1179,4465,23,4466,382,518,519,1793,4467,938,939,211,1219,117,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,4468,2195,2196,485,2089,54,55,2479,727,434,454,348,456,1215,69,172,180,181,233,190,469,2270,1499,1555,211,3894,168,169,1893,774,23,429,429,429,429,149,591,150,446,512,549,1922,149,591,150,446,447,447,592,592,636,549,1922,346,319,454,348,581,455,348,3792,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,653,570,571,54,2330,518,384,1348,557,2201,2260,429,429,149,1243,373,716,717,718,719,718,720,718,721,718,4469,718,4470,318,319,454,455,456,686,69,2505,2749,3154,300,2345,302,303,304,303,304,303,305,303,305,303,304,3494,384,2476,498,617,605,233,240,1174,3039,4471,538,799,637,666,667,725,439,266,267,2393,23,355,383,526,545,4472,980,781,1064,781,622,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,4473,2338,1213,267,268,271,269,2366,3193,402,302,303,305,303,304,303,304,303,788,426,149,511,446,447,447,592,592,447,447,512,549,1338,352,791,172,382,597,502,634,2575,435,300,2345,302,303,304,631,570,784,1573,731,554,270,2007,1120,1121,254,724,769,2301,2249,2966,774,23,934,1473,1474,4474,562,281,281,280,281,280,281,280,281,280,281,280,281,280,295,982,2132,2133,2134,2565,556,558,559,560,977,1074,1323,147,532,526,608,168,169,170,1585,439,450,1200,2189,4475,346,319,454,3117,549,1338,1254,1255,1256,1257,687,688,616,689,691,442,445,445,429,429,149,759,1441,4476,401,383,556,654,1351,346,319,347,456,348,455,348,1109,445,429,429,445,429,149,591,672,280,1211,798,172,180,181,233,190,2434,193,3900,3365,3366,434,347,455,728,549,708,280,1245,545,1188,2249,148,445,670,545,1188,1199,172,382,401,383,502,634,611,1759,435,390,391,494,616,690,689,690,690,690,496,2247,510,573,629,190,1195,1196,1197,4346,4477,139,1304,1305,1306,1241,532,526,769,1612,665,666,667,725,439,838,23,2301,3563,717,4478,127,128,129,211,1516,2343,486,147,4479,4480,4481,237,238,184,185,2082,1241,1701,299,382,401,383,402,402,302,303,2295,608,357,302,303,788,664,2347,179,382,4482,69,382,510,573,629,190,245,1409,1044,1846,147,148,854,629,190,1643,2886,4483,641,642,434,454,1027,549,1313,346,319,454,348,455,348,349,549,1338,840,809,809,809,1007,1031,333,1232,335,336,337,44,45,1531,480,3371,1112,4484,4485,4486,549,2863,1169,439,266,267,554,1672,403,147,148,445,670,545,2421,477,2064,3821,4074,149,562,280,281,280,281,280,281,280,281,280,282,1424,278,2960,759,1054,149,591,1243,281,281,280,281,281,2441,231,232,233,239,1668,3821,54,55,2040,2375,772,148,149,150,446,447,447,592,592,447,592,592,636,413,1188,1846,382,148,854,574,4487,1184,1185,4488,390,391,494,495,690,496,1236,746,4489,295,1616,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,3616,382,355,383,2037,205,101,624,625,928,565,1978,23,3931,1544,333,334,335,336,337,44,45,524,918,665,666,667,730,731,554,1814,1921,664,148,149,150,2608,1934,445,149,2909,3602,4490,2109,587,434,347,456,348,348,3566,687,688,495,1817,1237,1665,333,410,418,984,1239,549,1338,536,538,538,1759,403,513,526,545,1188,1846,300,4491,4492,401,383,556,557,558,1351,668,439,3724,2249,526,698,231,232,233,240,2328,2329,950,951,515,2743,352,776,146,231,1560,4493,669,179,147,4494,758,485,486,532,700,519,990,1804,4495,2231,1522,280,281,1281,469,4311,1248,384,654,557,557,557,557,1752,254,984,172,390,391,724,445,429,149,511,446,447,592,592,447,447,512,549,2147,390,391,494,616,839,268,2286,1921,69,580,703,146,147,148,854,629,190,745,80,1941,4496,4497,460,179,147,1406,558,563,148,445,670,769,770,2110,2069,644,222,223,224,216,449,439,266,267,554,270,757,758,819,2976,478,4498,541,486,4499,356,556,557,2265,2201,2202,267,4500,276,179,390,391,494,495,689,691,282,806,807,2872,1053,2745,669,179,346,319,454,768,528,516,2331,2331,2331,2331,2332,2331,2511,549,708,4501,3732,4502,4503,2351,523,44,45,1006,403,402,302,303,305,303,304,303,2580,780,781,781,1751,442,756,554,270,757,403,1506,1718,641,642,434,347,1501,1318,231,232,921,1560,744,188,189,239,1165,184,185,186,4504,148,149,2466,2360,498,2692,4505,597,402,302,303,304,303,304,303,305,303,305,303,304,303,305,303,305,303,2580,148,429,429,445,445,149,150,2745,1487,4506,1416,683,3403,3047,237,743,744,188,189,239,185,186,190,1881,1044,849,149,562,281,280,281,280,281,280,281,280,281,622,645,646,647,648,649,2002,602,603,2471,3986,295,982,1947,548,549,708,759,446,592,592,592,447,447,512,69,3150,3151,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,178,179,231,232,311,4507,401,383,526,545,671,1026,319,347,348,581,455,455,455,686,435,1522,281,281,280,281,280,281,280,281,280,281,692,2106,483,484,485,2773,346,319,1094,23,562,281,280,281,752,149,562,281,281,281,281,280,1752,823,4508,999,549,1571,277,278,279,280,1350,2602,4509,1555,211,2925,545,1188,1199,3759,445,149,279,280,281,280,281,280,281,280,281,280,281,280,977,172,390,391,494,616,2172,692,251,252,253,254,255,180,181,233,190,1967,483,484,4510,382,510,1639,463,549,610,1356,1357,29,453,476,2195,2196,2343,3975,510,998,999,435,747,2179,2179,2179,2179,2180,2179,2180,2179,2180,2179,782,2478,515,571,304,303,304,303,4511,355,356,384,557,558,282,2505,4217,2424,350,346,319,347,348,455,581,348,348,455,686,1241,145,146,147,355,356,534,535,663,403,1954,1526,4512,387,216,449,439,266,267,1920,4060,148,445,149,994,295,982,597,502,2005,23,696,1343,2268,660,237,238,184,185,186,240,188,189,190,575,1285,251,252,253,254,419,182,606,4513,641,642,434,347,1132,403,4514,1544,333,334,335,336,337,1299,429,149,1522,281,281,281,1510,356,519,990,1804,1804,1804,1804,1804,1804,1025,2575,664,268,1294,270,271,271,270,270,726,549,1922,510,573,629,190,1549,637,4444,4515,545,742,3732,1296,422,1023,1877,4516,231,232,233,190,1266,3685,3558,901,902,303,305,303,4517,1164,429,149,1522,280,281,280,281,280,674,545,1188,1199,4518,4519,148,445,670,545,1188,1199,1084,439,440,916,1101,1543,1084,439,838,23,515,571,687,980,2369,4221,4520,2262,587,434,347,455,455,4521,4479,486,346,319,347,455,643,1318,1169,439,838,47,1562,765,1596,1909,835,3746,1288,1289,765,765,1290,1291,523,44,45,1006,69,687,688,80,3696,581,455,455,1215,403,320,193,194,195,3921,609,169,178,934,1473,1474,3257,1783,3242,1692,216,542,1012,1013,1013,1014,2262,347,348,456,455,1215,69,4522,735,489,665,666,667,668,439,266,267,554,865,69,172,346,319,347,348,581,455,455,686,549,1338,270,726,549,4523,900,901,902,4524,303,304,303,788,549,1338,401,383,556,654,557,558,557,558,557,557,557,558,557,295,1616,278,562,281,281,280,605,1288,1563,442,355,356,519,990,3773,2228,570,952,2362,355,383,357,383,357,383,519,990,4525,434,347,455,528,570,516,3203,268,270,4526,952,2570,147,401,383,502,634,538,538,538,1422,3242,228,229,1106,587,434,347,455,1149,69,509,172,180,181,233,187,1174,3361,4527,1663,697,545,1188,1199,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1515,2603,4528,23,591,751,605,383,357,4529,3154,130,1084,439,266,1366,254,419,519,3653,140,141,1095,522,1154,687,980,1064,295,982,727,434,454,581,455,348,348,455,455,455,1109,2325,2087,2088,2326,2819,4530,4531,4532,154,135,136,137,138,139,136,137,138,139,1390,346,319,347,455,528,632,54,55,56,4387,355,383,357,356,357,383,384,558,557,558,559,560,442,190,482,483,484,485,486,1294,270,270,726,549,4523,1288,2387,4533,2899,4534,2244,2215,4535,1288,765,1596,1909,758,2106,483,484,485,486,172,382,355,383,384,1348,557,558,782,543,1354,4536,2073,495,3367,3368,3369,3370,2570,735,216,736,179,147,589,4091,549,4537,591,150,446,592,636,549,1674,149,150,2087,2088,485,2505,2297,346,319,347,2336,1822,1368,460,179,147,1835,558,1482,709,60,61,73,2380,66,93,94,3529,66,67,254,419,824,765,2256,178,179,180,181,1163,1560,4538,492,172,390,391,494,616,505,691,507,390,391,616,2096,497,498,1745,4539,581,455,348,348,1215,426,641,642,434,1094,23,4540,4541,570,571,445,445,429,149,591,672,746,581,348,348,455,455,455,686,403,570,952,3990,268,270,4542,382,401,356,556,558,1482,148,445,445,429,149,759,446,512,435,1562,1289,765,1290,1291,523,44,45,524,977,4543,725,439,266,3466,3235,1721,68,69,3154,1074,1323,1026,319,347,1132,403,460,179,147,597,519,520,1332,1331,521,522,523,44,45,1346,4544,355,383,526,545,1188,1199,147,148,149,2303,2304,2305,447,592,636,403,148,429,429,445,149,150,446,790,3006,600,172,382,355,383,534,535,537,799,403,616,496,690,605,940,1188,1199,140,4003,4545,270,1294,270,270,270,1626,149,1243,280,605,231,232,233,190,1643,987,1248,435,455,4546,727,434,347,2336,528,516,2332,2331,2331,2332,2426,390,391,80,1941,3554,4547,666,667,1962,333,410,335,411,412,1241,1638,172,382,148,854,629,190,245,1409,1044,1846,369,400,179,180,181,233,190,191,4302,245,4548,357,442,445,429,149,511,446,447,447,593,616,497,2268,2399,149,150,446,1444,445,445,445,445,445,149,150,2745,4003,4549,608,581,348,1109,149,591,672,386,347,581,686,549,610,1314,1544,2365,69,429,149,591,150,446,592,592,447,447,512,549,708,149,279,280,281,280,281,280,281,280,1371,4550,653,570,571,145,146,147,401,356,556,557,559,622,2157,2339,4551,1150,145,146,147,148,854,574,3086,445,445,429,149,511,446,447,4261,640,510,4552,445,445,429,429,445,429,979,430,280,431,700,874,460,179,147,518,384,1935,542,1693,1693,1693,543,805,23,1486,69,759,446,447,447,592,512,69,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,1949,1323,222,223,224,644,586,565,1978,23,1188,1199,4553,774,23,150,446,592,592,447,447,447,636,549,1313,355,383,534,535,4554,352,791,687,688,495,1836,150,446,447,447,447,447,636,549,4555,1661,1662,616,496,496,373,224,644,222,223,645,646,647,648,649,2002,602,2471,4556,1094,398,445,445,149,4557,266,267,268,271,271,272,549,4558,402,302,303,304,303,548,549,4559,1199,356,556,557,1348,557,558,557,558,692,366,347,581,1215,758,4560,23,1039,3616,783,570,1658,54,55,2586,352,776,777,846,495,1802,2247,666,667,1564,1996,916,386,149,1522,281,280,1350,502,634,536,538,538,537,1759,3701,417,333,334,335,336,337,44,45,822,1032,300,2345,302,303,305,303,305,303,305,303,304,303,304,303,548,549,1338,401,356,302,303,304,303,548,69,276,179,390,391,494,616,496,691,507,154,135,136,137,138,139,140,4561,1018,1019,1020,423,424,4562,1022,2793,3092,4563,2244,4564,1244,69,680,589,653,2229,2460,545,671,237,743,744,188,189,240,188,189,187,1174,4565,355,356,534,535,1103,835,2061,2062,2195,2196,485,2505,4566,1348,557,622,180,181,1163,232,233,190,1931,2270,1499,1555,211,583,590,2675,1740,4567,1103,549,708,759,446,447,592,592,447,512,549,1338,430,280,281,280,281,281,281,295,2501,370,824,765,2315,3214,3215,3930,507,1472,758,429,149,430,280,281,280,1245,4568,547,172,180,181,233,190,575,4569,508,317,345,509,172,346,319,347,348,455,348,1502,1658,426,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4202,347,456,1215,69,191,802,782,130,632,54,55,2479,998,463,1241,148,445,445,445,445,445,445,2955,592,636,549,2147,1967,483,484,485,2505,2697,429,149,1522,280,281,280,281,280,281,280,281,692,347,581,455,455,455,686,758,769,770,771,1887,4012,233,190,482,483,484,485,486,609,4570,4571,216,542,1012,1014,769,770,3791,23,429,445,429,149,759,446,447,447,636,69,1522,281,281,280,281,1774,1268,1269,184,1165,3490,371,372,2369,659,2370,511,446,447,592,512,549,610,268,271,2493,549,1338,1514,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,3616,756,554,269,272,549,1093,1696,938,939,1218,2243,401,356,556,654,557,557,558,557,557,557,655,556,654,557,557,557,558,557,558,557,557,557,558,557,558,673,417,333,410,335,336,337,44,45,1545,370,371,1505,495,496,689,690,2710,2347,179,147,532,4572,447,447,447,636,549,760,735,216,4296,172,382,355,356,534,535,1242,1241,1288,1289,1289,1290,1291,523,44,45,4573,216,4574,462,999,549,760,703,146,390,391,494,495,690,505,496,496,691,692,549,1338,2364,565,566,4575,4576,1413,4577,23,239,1165,2921,549,610,2803,570,1658,54,55,4053,1288,1289,765,1289,1290,1291,523,2829,149,430,280,442,607,545,2462,4578,826,1282,829,3716,254,47,2411,181,233,190,1554,1196,1197,1555,4579,492,172,382,510,998,3452,241,1165,4580,258,761,260,261,836,837,262,263,264,265,266,267,554,271,3282,4581,382,510,696,3350,2453,2954,390,391,494,616,505,2710,429,429,149,759,446,592,447,592,592,447,447,4582,538,537,537,537,537,663,549,1338,429,445,149,150,446,636,549,1922,511,446,592,592,447,447,447,447,636,549,1338,1931,2270,1499,4015,1749,276,179,390,391,494,616,4583,498,617,480,4387,1575,4023,193,194,195,2435,253,254,255,390,4584,149,150,446,447,447,512,1241,613,685,434,347,455,528,2302,4585,467,104,135,136,137,138,139,140,141,959,513,526,545,2314,1171,178,179,180,181,921,1560,744,188,189,187,4586,537,537,537,538,2961,287,1719,346,319,454,455,528,570,2495,601,602,603,602,603,602,603,602,603,602,603,4587,148,854,629,190,2412,1196,1197,2970,2971,180,181,233,190,469,2270,4588,755,921,232,233,190,4014,4178,807,318,319,347,581,455,455,455,455,455,686,403,570,516,2530,154,135,136,137,138,139,136,137,138,139,1304,1305,3083,2359,355,383,534,535,663,549,610,429,445,445,445,462,999,69,608,690,2559,692,532,526,2262,638,169,460,1120,1121,254,960,149,511,446,447,447,447,447,512,549,708,401,356,402,302,303,548,549,1338,512,549,1338,300,2345,2480,950,951,570,516,2257,1522,280,281,280,281,280,281,280,281,280,1237,229,4589,80,1496,445,445,445,429,149,591,994,282,4590,696,573,629,190,4591,1286,602,2527,2134,2453,4592,1065,1265,303,305,1841,403,2405,537,3221,810,809,809,809,809,809,4593,4594,2292,523,44,45,2117,2118,2119,2120,1531,3304,3305,3306,3307,3308,291,292,324,2571,1074,1323,346,476,477,478,785,4595,547,172,382,401,383,402,302,303,304,303,304,303,788,664,2224,1981,361,619,620,169,375,3033,4596,1854,3159,3670,382,401,356,519,990,3773,533,534,535,611,537,538,538,537,538,538,537,537,663,69,4597,608,611,538,538,538,537,538,538,537,1759,713,1612,697,769,1612,905,445,445,149,150,446,447,447,447,447,512,331,278,3535,810,1007,1031,333,1232,335,336,337,44,45,46,47,1876,422,1023,4598,1039,3616,237,238,184,185,186,190,1931,1932,2249,287,1719,346,319,454,455,1239,435,178,179,382,510,278,759,446,448,680,401,356,556,557,558,557,1348,557,557,386,231,967,1890,769,770,3973,148,429,445,429,149,759,446,512,637,149,150,446,592,592,3629,735,216,449,439,266,267,2393,3235,429,429,149,672,280,281,280,281,280,507,496,1817,561,680,2678,4073,207,208,4599,1041,254,984,1077,340,340,340,340,340,340,340,340,1546,1078,1546,1078,340,340,340,340,4600,4601,1782,1156,1116,572,489,665,735,216,449,439,669,179,390,391,494,2563,497,2418,2419,1026,319,454,348,695,590,3741,511,446,592,592,447,512,350,737,738,2134,3217,870,276,179,346,319,347,1502,1159,1160,3468,3547,4602,1638,172,2676,18,355,383,357,357,302,303,304,303,548,758,771,4603,1887,916,3367,3368,3369,3370,347,1822,549,708,240,2328,4604,918,355,383,534,535,538,611,663,549,760,429,149,591,150,446,447,592,592,447,512,549,610,548,549,610,1163,4605,538,1242,549,4606,4607,254,1032,401,383,2244,2453,618,791,172,147,401,383,519,520,1332,1909,435,698,445,445,445,149,150,446,447,592,592,447,636,713,460,179,147,597,556,654,557,557,557,558,557,3820,240,2328,2329,950,951,515,1658,54,55,2040,2375,278,150,2087,2088,485,2505,2749,231,232,233,190,745,80,1941,2599,3468,1792,300,301,302,303,1527,934,1473,4608,193,194,1577,3020,687,688,495,505,496,690,1461,759,446,447,447,593,1304,1305,1306,549,1028,616,690,2710,311,181,233,190,234,1498,1499,1555,683,495,690,496,691,295,1911,445,462,463,1241,2136,1793,3332,1413,1093,3830,3831,1425,2103,1427,382,401,383,402,356,556,558,559,4609,173,1981,1663,697,545,2700,626,627,1638,172,382,148,854,629,190,191,2654,375,376,1627,1331,1331,1909,350,670,545,2421,883,4610,687,688,616,2559,507,149,150,2087,2088,485,3759,545,1188,1846,445,445,1302,608,2224,4611,355,383,357,383,357,356,534,535,652,382,355,383,534,3869,650,4612,1846,140,141,680,714,271,271,271,272,549,1313,149,562,281,280,281,280,442,545,3154,187,188,189,4613,291,297,3252,29,367,368,369,400,179,382,510,573,4327,513,526,545,714,1169,439,440,916,1100,917,386,3403,182,606,2214,2339,3581,3367,3368,3369,3370,429,429,429,429,445,445,445,149,759,4614,1418,3235,147,355,383,384,558,557,373,300,301,358,359,359,4615,401,383,502,634,611,537,537,538,538,4616,1286,4617,777,778,779,1751,782,3261,777,846,495,505,690,690,690,690,496,690,690,496,691,782,4618,4619,2857,4620,302,303,304,303,304,303,304,303,304,303,304,303,304,303,788,2854,1099,916,1101,860,1101,1100,1100,1101,1101,2128,295,1616,4061,921,967,4621,69,355,383,526,545,714,178,179,390,4622,4623,1037,1031,333,410,418,255,579,580,703,146,147,355,443,999,549,2099,300,301,358,359,3903,2411,181,233,190,245,1409,987,2674,518,384,654,557,558,557,557,558,507,149,759,446,592,512,549,550,4624,2323,23,534,535,538,2057,2733,187,1174,1228,295,506,149,511,446,592,592,447,592,592,447,512,549,1338,687,688,495,690,3384,782,769,770,3791,724,4625,4626,333,1232,418,985,2153,875,146,346,319,347,4627,665,735,216,3940,399,400,179,147,401,3124,216,1042,439,4568,401,383,526,769,770,2744,231,232,182,183,184,185,186,190,4065,445,445,149,150,446,447,4261,4628,23,3471,518,384,654,557,558,1351,570,571,554,1244,1241,556,654,557,3654,1522,281,281,280,281,281,782,390,391,494,495,689,496,690,496,496,1619,4198,591,150,446,447,592,592,636,549,760,356,502,634,538,1472,435,348,1839,330,332,333,4629,178,179,147,401,383,556,654,557,558,557,295,982,370,371,1505,495,782,291,292,2054,54,55,2479,172,390,391,494,495,496,1083,498,1745,4083,429,445,445,445,462,999,331,447,592,512,549,610,429,445,429,429,429,1704,4630,1693,543,1354,4631,924,179,390,391,494,495,689,655,149,591,150,446,447,592,592,447,447,512,549,1338,756,554,270,269,271,272,549,1338,1396,713,1169,439,838,23,490,216,449,439,669,179,346,319,454,1027,69,1658,2335,291,292,324,253,68,3891,3148,278,150,446,1523,429,149,279,280,281,280,1718,148,854,574,575,4632,253,254,960,367,368,369,641,642,434,454,2146,403,1890,545,2314,764,765,2315,2316,2317,523,44,45,4633,769,770,2990,134,565,2923,23,134,216,1042,439,266,267,554,1294,271,271,270,270,3080,654,557,558,557,558,557,558,782,430,281,281,280,281,281,281,280,281,280,442,383,502,634,611,537,537,537,2349,514,570,2750,934,1473,4608,193,2828,696,573,629,190,745,80,847,3089,149,759,446,592,447,447,3165,1595,657,1908,1750,781,781,780,780,781,1752,1163,232,233,240,1174,3039,637,271,1294,726,549,1338,4362,4363,1245,1348,557,558,557,557,557,557,558,1635,566,128,2685,4634,1744,507,905,613,685,434,454,455,528,570,1658,4073,352,776,146,1824,23,382,1286,602,603,602,603,507,527,390,391,494,495,690,839,1663,1706,278,150,446,592,1204,278,511,3810,2662,497,498,2419,355,356,384,1348,557,605,511,446,592,592,447,592,592,447,447,636,549,1338,447,447,592,592,447,447,512,69,1304,1305,1306,435,1189,597,556,654,557,557,557,558,1351,191,192,193,194,4635,727,434,347,348,4636,1598,2360,498,2419,1348,557,557,558,557,558,1482,1077,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,4637,237,238,184,185,186,241,185,186,3486,4638,513,526,545,661,69,1288,1289,1596,4639,1522,280,281,280,1510,180,181,1163,232,233,239,1165,2921,835,700,4640,266,267,554,270,269,272,69,1784,1275,689,605,330,252,253,254,419,545,1188,1846,300,2800,4641,271,271,270,270,270,2007,653,570,952,2570,356,534,535,538,538,538,799,549,2147,921,232,233,239,1165,2921,69,231,232,311,181,233,190,234,1498,1499,1555,1218,248,747,2179,2179,2180,2179,2180,2179,2179,2179,295,4642,2162,483,484,485,2505,4566,347,2336,1822,549,729,297,436,1538,1702,1013,1014,515,952,2406,182,606,2478,570,1658,54,55,2625,172,382,148,429,429,149,511,446,447,592,592,447,447,512,549,1028,2108,860,1100,1100,1101,1100,1101,3053,402,302,303,304,303,788,549,2863,727,434,347,348,944,549,708,616,2172,497,659,974,148,149,150,446,447,447,447,447,447,512,549,1674,728,835,583,149,759,446,790,1690,1100,1100,3417,1348,557,561,591,1243,281,1281,401,383,519,1128,1129,666,667,2347,1120,1121,254,985,670,769,2105,233,190,482,483,484,485,2622,2697,1339,463,549,760,149,591,994,561,401,356,502,634,611,538,538,538,537,537,537,2349,608,518,534,535,536,538,538,2702,537,2289,2053,445,445,429,149,511,446,447,636,549,610,417,333,410,418,960,755,518,534,535,537,2566,1611,402,302,303,305,2548,445,445,445,429,429,445,445,429,1704,3338,4068,587,434,454,2336,1318,1304,1305,3288,1783,154,135,136,137,138,139,140,141,680,1189,545,1188,1846,445,149,759,446,636,549,610,4643,774,23,270,1244,549,1338,149,759,446,592,447,592,592,512,664,346,319,454,686,69,587,434,2446,4644,3154,4645,2308,759,3178,4646,271,271,270,270,3080,2228,570,952,2570,510,696,2024,3951,4647,449,439,669,179,346,319,454,2336,4644,943,319,347,456,348,1318,680,148,429,429,149,759,1811,383,519,520,1597,300,2345,302,303,788,758,545,1188,1199,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1968,239,948,949,950,951,570,1658,54,4648,1562,1289,1289,4649,355,356,519,520,521,522,523,44,45,524,1275,769,770,3874,611,663,713,173,185,926,4650,601,602,603,2441,4651,1268,1971,744,188,189,241,1165,184,185,186,240,1174,2536,3560,591,150,446,592,592,447,592,592,447,447,636,426,777,846,495,2662,2648,1083,332,333,334,335,336,337,2829,231,967,1890,545,1188,1846,680,2338,1213,267,268,271,270,2251,549,1922,4652,169,178,179,346,4653,1171,154,135,140,141,1095,522,523,4654,703,146,390,391,494,2073,495,690,496,496,496,496,496,1111,149,591,1243,281,280,281,752,383,357,534,535,536,537,538,537,537,3131,2157,3217,3581,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,382,401,356,402,874,601,602,1275,3061,3062,558,557,1635,239,948,949,950,951,515,516,4655,783,570,516,2373,455,970,1318,462,999,549,1338,445,445,429,149,591,150,446,447,447,512,549,1338,854,574,2534,1184,1185,4656,382,2274,738,739,2245,251,332,333,334,335,336,337,44,3868,570,3142,147,355,383,514,570,952,2627,330,4657,180,181,233,190,1554,1196,4658,145,777,846,495,505,496,496,690,691,711,1887,859,860,1100,1100,1100,1100,1275,3556,1426,1427,445,445,445,149,3260,1642,759,446,592,4659,1658,54,3957,401,383,556,654,557,558,557,557,557,684,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,2462,654,557,558,557,557,557,558,557,558,557,605,271,271,271,270,270,271,272,549,1674,826,1282,829,830,831,832,832,832,832,832,832,832,832,966,2244,3217,2467,482,483,484,485,486,1042,439,4660,1243,281,280,281,281,282,278,759,446,592,636,549,4555,1744,497,498,4010,777,846,495,505,496,496,690,655,401,443,999,435,3360,820,147,510,573,629,190,1549,193,194,1202,3691,1830,439,266,267,2393,23,498,2419,670,2262,401,383,556,558,557,752,838,23,462,999,1368,601,602,2527,2275,4661,390,391,494,495,673,1013,1013,1039,3616,180,606,607,545,2421,510,696,697,545,1188,2249,504,644,222,223,224,216,449,439,669,179,346,319,4662,251,252,253,254,1032,532,700,2581,346,319,347,348,455,581,455,3708,3593,4663,332,333,2417,614,615,495,496,497,2268,2399,2538,376,377,990,1363,1007,1031,333,1232,335,336,337,44,45,46,23,756,554,2251,549,1093,2329,950,951,515,571,231,232,182,183,184,185,186,190,1785,2558,4664,1736,270,726,549,1571,134,216,1042,439,266,267,554,270,757,549,2830,516,2257,148,429,429,445,445,445,445,429,1704,520,4253,810,809,4665,4666,1152,1551,255,1456,216,449,439,669,179,147,518,519,990,1534,819,2243,513,526,545,2314,460,179,147,461,445,445,445,445,2884,149,430,281,280,281,280,281,1774,4667,148,445,445,445,445,445,149,150,1811,356,556,654,557,557,557,557,558,557,557,557,558,557,558,918,382,148,854,629,1404,526,769,770,2992,2652,2653,184,185,186,190,1643,1940,149,430,280,1510,485,486,4668,1552,128,3981,1241,709,60,61,2671,2672,1421,69,4669,4670,190,2325,2087,2088,485,486,178,179,382,355,383,519,990,1025,366,237,743,744,188,189,187,188,189,190,986,987,4671,1037,1031,333,410,335,411,412,4074,245,1409,987,2887,4672,3566,348,686,403,297,4673,398,581,1215,69,769,770,2744,461,445,445,429,149,591,150,446,447,512,549,1338,268,1814,1815,952,2332,2332,2331,2331,2332,2550,549,1338,1294,272,549,1571,449,439,4674,23,355,356,384,557,557,2265,1635,597,2308,430,280,281,280,281,280,281,280,281,280,674,1215,549,760,4675,132,240,2328,2329,950,951,515,571,171,587,434,347,348,455,455,1149,2770,547,587,434,347,348,695,613,685,434,454,455,528,570,1658,54,55,633,429,445,149,562,281,622,1962,333,1232,335,336,337,44,45,4344,4676,346,319,347,581,1109,2066,1199,2503,384,1350,429,149,511,446,447,447,447,790,149,1243,281,280,281,373,1613,4677,601,603,603,602,603,603,602,918,767,860,1101,1101,1101,1100,1543,375,376,1627,1331,521,522,523,44,45,524,3683,1424,764,765,2315,2316,2317,523,4678,148,445,670,545,671,229,4679,3366,434,347,2146,3198,586,216,449,439,669,179,147,4680,758,4681,348,4682,543,1354,1568,355,356,534,535,2575,758,460,179,147,597,402,1396,549,1571,305,303,305,303,304,303,305,303,305,303,304,303,304,303,304,1884,279,280,281,280,281,280,281,280,281,280,281,280,2018,2142,1887,916,2128,563,445,445,462,463,435,502,634,538,536,663,69,4683,333,334,335,336,337,44,45,3316,777,778,780,4684,570,571,1286,602,2527,2134,4685,300,301,302,303,304,631,570,2503,4686,687,688,495,505,690,690,496,496,793,149,591,150,446,447,512,435,356,502,634,538,538,799,69,348,455,695,553,439,4687,147,597,4688,173,948,2354,1796,281,918,345,509,172,382,510,712,2136,3338,4689,4690,949,950,951,570,952,529,1189,148,149,2303,2304,2305,447,447,447,592,512,69,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,4691,791,172,231,232,3379,355,383,526,698,4692,4693,149,511,446,592,1728,545,742,943,319,454,686,435,456,1215,549,1338,490,216,1042,439,266,267,883,268,4694,514,570,952,3853,348,944,413,510,278,759,446,447,636,758,2314,534,4695,23,1294,270,270,270,270,4696,454,2146,549,550,4697,1254,1255,1256,1912,253,254,255,601,602,2004,4698,1245,251,252,253,254,255,4699,147,401,356,556,654,557,558,684,791,172,147,148,445,445,429,149,511,446,447,447,512,758,490,216,1042,439,4260,769,770,2141,382,148,854,574,469,2270,1499,1555,4700,147,401,383,874,401,356,402,1733,4701,541,538,1395,549,2147,514,570,952,2362,4702,238,184,185,186,190,745,80,4034,332,333,410,335,411,412,69,1967,483,484,485,2197,584,585,586,644,222,223,224,216,449,439,669,179,390,391,494,495,4703,460,179,147,277,278,562,280,281,280,295,1616,742,2602,2603,4528,23,401,356,302,303,305,303,305,303,305,303,304,303,304,303,305,303,305,303,304,303,548,549,1338,429,149,759,446,447,447,447,512,549,1571,510,712,278,1522,280,2018,2142,557,558,557,557,1482,430,280,281,280,281,280,281,280,281,280,281,280,1275,148,429,445,445,149,150,446,447,2121,4704,445,429,149,759,446,447,592,512,1368,728,403,3855,496,1342,782,2274,738,2784,2276,2276,2276,2276,4032,295,1616,728,69,142,251,465,386,703,146,390,391,494,495,691,295,1616,1171,4705,4706,1291,523,44,45,46,541,587,434,347,581,455,455,1318,4707,134,216,1042,439,440,859,860,1100,1100,2128,1245,515,571,4708,149,511,446,447,447,636,69,348,348,348,348,348,455,348,455,3103,608,632,54,55,1238,383,402,383,556,654,557,557,557,558,557,558,557,282,1232,335,336,337,44,45,46,47,241,185,186,240,188,189,190,1828,4709,921,967,1890,769,770,2657,4710,534,535,663,549,1093,2028,4711,149,279,280,281,281,295,982,462,2663,510,696,696,278,591,1243,280,442,356,519,4211,1348,557,557,622,698,510,712,278,430,280,622,1436,4712,628,777,846,2073,495,1403,3462,980,781,779,781,1751,295,506,591,150,446,592,1728,553,439,838,23,616,2172,497,2418,4713,356,1629,4714,921,967,2228,570,3104,492,172,382,148,429,429,445,149,562,281,280,281,280,281,280,2018,2142,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,4473,1846,756,268,270,1806,403,149,279,281,281,280,281,280,281,280,281,280,281,280,640,485,2197,3193,270,270,270,726,350,278,150,446,447,4300,2898,232,233,190,2412,1196,1197,1555,130,149,279,280,281,280,295,1616,180,181,233,2546,486,3106,999,549,610,272,549,1922,885,4715,687,980,2369,4221,711,4716,154,135,136,137,138,139,136,137,138,139,4717,2470,650,651,603,3951,1206,502,634,538,611,537,537,538,538,537,2289,608,430,280,281,281,373,696,278,759,2778,1536,2224,1981,390,391,494,2073,495,3367,3368,3369,3370,642,434,347,945,455,348,686,403,571,545,3455,355,383,519,1128,1129,239,185,186,239,185,186,190,1828,192,193,194,195,4718,268,270,270,2007,3084,1528,2447,797,169,4398,587,434,347,1840,2163,4719,229,909,146,231,232,311,181,233,190,245,3611,1304,2876,564,216,1042,439,266,267,268,271,270,1214,549,708,375,1462,1463,4720,2073,495,497,498,2692,618,712,712,998,999,1216,1562,2315,4721,4203,2594,777,846,616,496,1342,1353,4722,355,356,534,535,663,69,559,560,1178,570,3142,502,634,538,536,1759,69,149,279,280,281,1245,454,455,348,686,413,591,672,280,281,280,507,686,549,2830,429,149,279,280,442,686,403,1506,1872,332,333,3246,197,492,172,382,510,573,4723,1995,401,383,502,634,611,537,537,537,537,4724,1101,3456,1718,454,728,549,1674,447,447,592,592,447,512,549,1571,558,557,558,557,558,557,558,557,558,557,558,557,1935,3193,1658,54,2839,2145,402,4725,231,232,233,190,4014,3722,1499,4015,1749,278,4726,1642,2394,401,383,502,634,537,1103,4727,390,391,494,495,690,505,690,690,496,496,496,1803,564,565,566,1544,2365,69,369,400,179,147,148,854,629,190,2175,4382,230,146,147,355,443,999,4392,1086,333,410,335,336,337,1233,4728,373,401,383,502,634,4729,445,149,279,280,1774,777,846,616,689,691,673,429,429,445,149,759,446,592,636,758,2244,2453,4064,608,820,180,181,182,183,184,185,186,240,1174,744,188,189,190,986,1044,1199,454,945,455,686,549,1313,477,2064,2065,2066,1189,455,686,549,2746,1214,549,800,687,980,4730,455,581,455,455,686,403,149,511,446,512,403,1199,190,4731,3926,1031,333,410,418,3235,776,727,434,1821,454,348,348,1215,69,1086,333,410,335,336,337,44,45,822,2344,1077,1517,490,216,542,543,1354,1702,2069,4045,586,216,449,439,838,23,698,147,510,573,574,234,1498,1499,1555,905,382,148,445,445,445,429,462,463,758,1690,1100,1543,3063,239,185,186,240,188,189,240,1174,744,188,189,239,1165,1561,3560,390,391,23,700,3936,4732,964,4733,422,423,424,425,4734,4735,149,562,281,280,281,280,782,3588,672,1618,4736,4737,4738,23,240,188,189,240,188,189,4739,211,4740,400,179,147,148,854,629,190,191,4741,1074,1973,2652,2653,184,185,186,241,1165,184,185,186,190,1643,2886,471,1242,549,1338,429,429,445,149,759,446,592,447,447,636,637,401,356,556,654,557,557,557,557,558,557,4742,266,267,883,554,4743,3242,237,238,184,185,186,190,575,802,80,4744,2470,650,602,603,2471,4745,373,510,712,278,511,446,636,549,2147,147,401,356,519,1192,3924,462,463,426,698,2262,329,216,449,439,266,267,554,2551,3469,810,809,840,840,809,809,809,809,809,810,809,1949,1323,370,371,1505,616,497,498,3649,278,150,2087,2088,485,2622,2697,736,179,147,4746,709,60,61,72,4747,54,55,2479,462,2995,511,446,447,447,592,592,447,512,403,777,778,1064,1751,711,62,93,94,4748,4749,68,549,1093,401,356,302,303,304,303,304,303,305,303,305,303,788,435,1835,557,557,557,557,557,558,557,558,782,671,756,554,270,271,2510,435,445,149,759,446,592,447,1772,4750,4751,1286,2004,839,440,859,1762,1222,496,1960,655,883,4752,1015,172,180,181,233,190,2768,1932,1045,943,319,1094,23,2478,515,952,2257,511,446,512,549,708,366,545,1188,1846,2089,54,2839,2145,1112,2843,4324,4753,511,446,592,447,1787,402,302,303,305,303,305,303,305,303,305,303,304,303,304,303,788,403,2505,2650,2570,231,232,311,181,233,3486,172,390,391,494,495,690,3367,3368,3369,3370,2301,783,570,1658,54,2839,2145,240,188,189,240,188,189,190,4754,1044,4755,429,429,445,429,149,759,446,2121,4756,2570,449,439,266,267,268,1814,1921,325,4757,477,2064,3821,54,55,633,382,510,2024,3951,4647,237,743,744,188,189,190,234,1498,1499,1555,130,1188,2249,687,688,495,689,496,1350,536,537,537,538,2349,295,466,608,346,319,3781,2486,447,592,592,2121,4758,231,232,233,190,191,192,193,2144,4759,4453,2762,1519,303,305,303,305,303,304,303,304,303,548,435,390,391,494,495,689,690,691,673,497,2268,3771,429,429,149,279,1513,810,1949,1323,170,4760,4761,4762,2881,2195,2196,2438,4763,460,179,147,597,502,634,536,538,663,549,1338,2162,483,484,485,2505,2356,587,434,347,581,455,348,1215,69,527,1518,611,538,663,549,2746,742,2130,184,185,186,190,1828,802,782,4764,4765,401,383,519,990,1408,492,172,382,355,356,384,1784,673,614,615,1511,486,745,80,1381,4766,840,809,809,809,811,812,899,814,815,816,817,333,410,335,336,337,44,45,524,839,645,646,4767,333,2164,1171,355,383,526,545,714,2387,2432,4768,401,383,402,383,502,634,611,537,537,537,612,382,1286,602,711,2854,1658,54,1509,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,548,69,355,443,999,549,800,1288,1289,765,765,4769,713,587,434,347,582,429,149,430,280,281,280,281,280,281,280,281,280,918,759,446,447,592,592,447,512,758,514,570,1658,54,55,4053,502,634,663,435,104,135,136,137,1287,139,140,141,1095,522,523,44,45,1006,664,514,570,952,2362,2262,687,688,495,496,505,690,4770,1294,270,726,549,2830,1787,429,149,591,672,280,281,280,2018,1642,512,331,3224,663,758,429,149,591,994,561,4771,272,69,769,770,4772,346,319,347,348,3566,330,3111,433,434,4100,1106,172,147,277,696,2136,990,4773,460,179,147,518,534,535,611,537,537,537,538,538,1759,758,429,429,149,1243,281,280,281,280,281,563,330,252,253,254,255,3580,4674,541,429,429,429,149,150,446,447,447,447,512,637,516,2373,454,686,637,2567,782,4774,4775,668,439,669,179,346,319,454,768,528,952,2331,2331,2332,2332,2511,664,447,512,637,291,292,324,253,254,985,347,581,1318,537,539,505,690,496,496,496,839,366,944,549,1093,513,2244,2699,921,967,1890,769,2301,1159,1160,3468,2616,549,1674,683,492,172,382,148,445,445,149,1310,769,770,4776,743,744,188,189,241,185,186,239,185,186,187,1174,744,188,189,240,1174,2536,1164,4777,4778,4779,422,1023,4780,556,654,557,558,557,558,557,557,557,977,429,429,445,4781,686,403,2478,570,952,3525,2533,497,659,660,777,846,2073,616,1245,495,691,793,291,292,2054,193,194,1162,601,602,2527,2134,2453,2824,2375,1657,808,1007,3388,2143,835,355,356,356,357,1396,403,771,4782,4783,2807,2228,570,571,2981,2880,3148,921,232,233,239,1165,1938,295,506,617,4539,224,3122,4784,1242,549,2863,462,999,637,2400,157,101,624,625,626,627,628,146,147,148,854,629,190,1195,3678,291,297,436,1538,1691,180,606,2224,4785,518,534,535,536,538,663,403,1323,4786,4787,356,502,634,538,538,799,435,709,60,61,4788,251,332,333,410,335,411,412,713,542,1693,1693,1693,1693,543,1354,2491,502,4789,454,686,549,610,4084,725,439,266,267,268,1294,270,270,271,726,549,760,4260,810,809,840,840,809,809,809,809,809,840,809,809,1007,1031,333,410,418,23,4790,575,192,193,194,195,965,352,621,777,778,2006,692,769,770,3639,943,319,320,193,194,2556,1965,231,232,921,1560,744,188,189,190,986,2886,3060,2596,2819,4791,4792,4793,1526,982,602,1362,3955,4794,4795,4796,4797,4798,601,602,603,602,603,602,295,982,2953,2073,495,3367,3368,3369,3370,976,3367,3368,3369,3370,355,383,383,384,558,559,560,2775,100,216,1042,439,266,267,554,269,271,726,549,800,943,319,454,348,348,1149,549,1922,355,383,534,535,538,1472,549,1338,346,319,1821,347,4799,4800,777,846,495,505,690,691,692,1501,971,995,4801,3365,1661,1662,80,1381,1382,1410,3148,3637,4802,4803,770,2141,4118,348,348,455,455,686,549,1338,727,434,454,455,1149,403,1169,439,4568,430,281,281,280,281,281,281,280,281,280,281,782,557,1348,557,558,561,519,1230,4804,587,434,347,348,581,455,348,348,2313,149,759,446,592,447,447,593,514,570,4805,4806,4807,4808,422,1023,4809,514,570,3142,2162,483,484,485,2089,54,3957,665,666,667,1514,1012,1851,207,208,388,3309,4810,4811,149,430,280,281,280,281,280,281,280,281,752,290,383,502,634,536,537,537,538,537,1759,403,445,149,150,446,447,447,636,549,3098,4812,2249,2404,2510,403,686,549,1922,2331,2331,2331,2331,2332,3853,271,271,270,270,1626,537,537,537,1759,403,443,4226,465,1872,532,700,4640,55,2625,147,355,356,357,384,1348,557,2201,4813,355,356,302,303,305,303,788,713,461,429,429,149,591,759,2745,2108,2128,977,149,1522,1411,390,391,494,616,496,691,673,510,278,759,446,447,636,758,2236,2779,23,611,538,538,537,663,4814,239,4184,502,634,4177,454,4815,440,859,1927,295,982,80,2433,686,69,1026,319,347,2146,331,1406,558,1482,4816,792,561,4817,2257,1099,859,1101,860,1100,1100,1101,1101,282,759,446,636,549,1338,1073,782,999,549,1338,148,149,511,446,447,636,549,1922,534,535,538,611,537,1759,549,1252,571,149,562,280,1371,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,2580,401,356,502,634,538,4818,1188,1189,2150,2151,355,383,384,558,1482,390,391,494,616,1960,563,840,809,809,1949,1323,1763,3616,1663,1706,4819,231,967,1890,769,770,4820,1665,333,334,4821,149,150,446,592,592,447,592,4822,1188,1846,266,267,883,554,1322,690,690,496,2247,2417,3451,1402,4823,746,2503,478,3660,4355,402,302,303,305,303,304,303,304,303,304,303,304,303,548,835,3145,3537,1579,340,1546,1546,1546,340,340,340,340,340,1078,340,1078,341,4824,645,646,647,1065,902,303,304,303,304,4825,664,230,146,231,232,233,190,910,4826,589,653,570,516,2627,536,538,537,612,429,429,149,150,446,2306,519,520,521,522,523,44,45,524,977,670,545,1188,2249,238,184,185,186,190,2434,193,194,1577,2811,149,591,150,446,447,592,592,447,447,512,549,1338,1804,1804,1804,1804,4525,735,216,1042,439,266,267,554,865,758,105,4827,601,602,603,603,603,602,603,603,603,602,373,150,446,592,592,447,592,592,512,69,2574,538,2575,549,4307,4828,507,2106,483,484,485,486,1268,1269,184,185,186,190,3023,1409,2886,3256,382,510,696,696,2136,990,1025,513,4829,4830,1026,319,347,581,348,686,403,149,759,446,447,592,4419,1002,278,2466,2360,2418,2661,1665,333,410,335,336,337,44,45,1006,549,1338,1667,4831,4832,1643,3694,587,434,347,581,686,403,4833,347,455,581,455,1215,2770,454,456,455,455,686,549,610,100,565,2923,23,840,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3229,2724,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,3231,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,810,3226,2724,810,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,3231,810,809,809,809,809,809,3226,2724,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,3226,2724,809,840,840,840,809,809,809,809,809,840,809,840,810,809,809,809,809,3226,2724,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,3226,2724,810,840,840,809,809,809,809,809,810,809,809,809,809,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,3229,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,3226,2724,809,809,809,809,840,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3226,2724,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3226,1621,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,3226,2724,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,3231,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,809,809,3238,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,810,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,3231,810,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,3226,2724,1546,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,3430,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1078,340,340,340,340,1274,1078,1546,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,4834,1078,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1079,3241,4388,285,286,104,135,136,137,138,139,140,141,959,283,284,420,801,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,369,370,433,434,454,2146,435,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,482,483,484,485,486,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,1687,1688,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,367,368,399,400,179,147,355,383,526,608,161,101,225,226,120,121,367,368,399,400,179,382,148,445,429,149,591,994,1245,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,687,688,495,505,496,496,691,1281,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,352,353,146,147,148,445,429,429,445,149,150,446,592,592,636,549,1338,149,591,150,446,592,592,447,592,636,549,1313,117,201,202,427,428,99,111,112,117,113,101,472,157,473,474,475,179,382,513,533,599,231,967,2228,570,571,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,613,685,434,347,455,528,570,3104,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,375,376,377,3476,472,157,216,449,439,669,179,180,181,233,190,191,192,413,203,204,175,176,177,169,178,934,1473,1474,3257,1156,225,226,120,121,367,368,399,400,179,231,232,182,606,2478,570,516,529,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,508,317,4835,4836,102,103,104,135,136,137,138,139,140,141,959,102,103,104,135,136,137,138,139,140,141,959,641,764,765,2315,4321,400,179,147,148,445,670,545,742,458,459,169,460,179,147,597,502,634,536,538,1759,835,4837,4838,4839,243,244,166,167,638,169,943,319,347,348,1027,549,610,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,1179,4840,23,117,161,101,225,226,120,121,109,110,99,111,112,117,161,328,329,101,472,157,473,474,475,179,147,1663,697,769,770,2543,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,145,146,390,391,494,495,505,496,496,496,691,782,117,113,101,472,157,473,474,475,179,147,1663,783,570,516,2902,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,382,355,356,534,535,2046,69,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,145,146,147,401,356,502,634,538,537,1472,4841,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,127,128,2307,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,326,327,99,111,112,99,161,328,329,101,1692,216,542,1693,543,2451,102,103,104,135,136,137,138,139,140,141,959,472,157,473,474,475,179,382,589,670,698,161,101,102,103,104,135,136,137,138,139,140,141,959,243,244,166,504,221,586,216,449,439,669,179,390,391,494,2073,616,1111,122,123,124,125,491,127,128,129,683,367,368,399,370,433,434,454,528,2529,2627,180,606,607,545,1188,1199,367,368,399,400,179,147,1286,602,2527,2134,2565,203,204,458,459,169,375,2846,3423,4842,549,610,2939,23,206,4843,4844,888,439,266,267,268,1921,549,1338,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,947,226,120,121,367,368,399,400,179,231,232,233,190,2162,483,484,2343,486,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,131,583,161,328,329,101,472,157,275,473,474,475,179,382,589,670,545,2314,326,327,99,201,202,203,204,594,595,596,316,317,703,146,147,148,149,511,446,512,549,1338,117,201,202,427,428,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,1304,1494,117,201,202,427,428,99,111,112,99,113,101,156,157,101,1456,101,162,163,4845,4846,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,367,368,399,400,179,147,148,4847,999,549,1571,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,330,465,442,161,328,1116,572,4848,243,244,313,314,315,169,1644,2455,4849,4850,4851,243,244,166,167,609,169,178,179,382,510,696,1343,156,157,101,114,119,120,121,367,368,399,4317,23,329,101,472,157,206,488,101,156,157,152,249,1157,1158,396,553,439,838,23,4329,4852,203,204,458,459,169,2079,3386,1121,4853,109,110,99,111,112,99,100,158,123,124,125,126,920,145,146,231,232,233,190,1959,1415,2956,114,119,120,121,109,110,99,111,112,99,100,152,153,1254,1255,1256,2264,99,113,152,249,250,101,283,284,285,286,467,467,104,135,136,137,138,139,140,141,959,283,284,285,286,467,104,135,1493,2876,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1194,178,179,147,355,383,534,535,537,1472,435,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,819,1667,104,135,136,137,138,139,140,141,959,136,137,138,139,140,141,959,1553,152,954,4854,808,811,812,899,814,924,934,1473,4608,835,4855,101,225,226,120,121,109,808,811,812,899,814,924,179,147,1286,602,603,602,655,313,314,315,316,317,345,509,172,382,401,443,999,435,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,563,80,4877,4878,4879,80,1381,4880,4881,3426,4880,4882,782,4883,4884,4885,4886,4887,752,4888,80,3426,4880,4889,4890,4876,4884,4885,4869,4891,4892,4893,4869,4891,4892,4894,4884,4885,4869,4870,4895,4894,4884,4885,4869,4891,4892,4867,4896,4897,4885,4869,4891,4898,2340,4899,4897,4900,4869,4891,4892,4884,4885,4897,4901,2340,4899,4902,4867,4903,4904,4897,4891,4892,4897,4884,4884,4885,4884,4885,4884,4885,295,4512,4905,4906,4907,4908,295,466,4870,4895,4909,4866,4884,4885,4884,4885,4884,4885,4910,4885,4884,4894,3367,3368,3369,3370,4911,4884,4885,4869,4891,4898,1746,2178,4912,782,4897,4913,4869,4870,4895,4884,4885,4884,4884,4884,507,4914,4884,4885,4884,4885,4884,4885,4884,4885,295,1911,2261,4915,4916,4906,4917,4906,3367,3368,3369,3370,4918,4919,2012,4897,4920,4897,4921,4906,507,442,918,442,295,4512,4884,4894,295,4512,295,4512,4922,4884,4885,4884,4885,4884,4885,295,4512,4923,2340,3663,4884,4885,4884,4885,4884,4885,4884,4884,4885,3367,3368,3369,3370,1941,4924,640,4925,561,563,4926,295,466,563,4884,4900,3367,3368,3369,3370,4927,605,752,605,4928,4929,295,466,4869,4868,4869,4891,4901,4930,746,507,4931,2688,4884,4885,4884,4885,4884,4885,4884,4885,4884,4932,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4933,4876,3367,3368,3369,3370,4886,4920,4216,605,4934,563,4935,4899,4897,782,442,4884,4885,4884,4885,3367,3368,3369,3370,3453,3367,3368,3369,3370,4936,295,4512,3367,3368,3369,3370,3367,3368,3369,3370,4886,4920,295,506,4887,4925,4891,4898,2340,4899,4885,4884,4884,4885,4884,4885,4884,4910,296,782,4937,4938,4939,80,3426,4880,4884,4885,4884,4885,4884,3410,4940,1526,296,746,480,481,4897,4885,4886,4887,1353,4917,4913,4936,3367,3368,3369,3370,3367,4941,4942,4943,4936,1718,3613,4893,752,3367,3368,3369,3370,4875,4884,4885,1371,752,673,4870,4871,3367,3368,3369,3370,295,4512,4906,3367,3368,3369,3370,4885,4884,4885,3367,3368,3369,3370,4892,4892,4886,4944,746,4943,4869,4903,673,2124,4945,1245,1381,4880,4884,4885,4884,4885,4884,1350,4886,4920,640,4946,1780,4884,4885,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4925,4947,4948,4949,373,295,4512,2395,4914,4897,4885,4884,4885,4884,4885,4897,386,4512,4950,2756,4870,4871,977,3367,3368,3369,3370,4951,3410,4896,4869,4891,4898,2340,2891,782,2433,2891,4887,1275,295,4512,4952,4925,4925,4897,4950,4870,4871,4884,4885,4869,4868,4869,4891,4898,2340,2891,282,4925,4885,442,4884,3410,4943,4869,4870,4871,4910,4953,4897,3367,3368,3369,3370,2340,2891,4914,782,4954,2688,752,4936,782,1872,4868,4869,4870,4871,3367,3368,3369,3370,563,4886,4887,373,4955,1526,296,4884,3367,3368,3369,3370,4956,4885,4869,4896,4869,4870,4871,4901,480,481,3367,3368,3369,3370,4957,4885,4869,4868,4869,4870,4871,4870,4871,4885,4869,4891,4892,4891,4892,4958,4884,4885,4884,4885,4884,4885,4884,4885,4884,711,4959,4913,4869,4870,4871,4869,4903,4960,4960,4961,4961,4961,4962,4963,4964,3367,3368,3369,3370,4867,4870,4954,480,481,4913,4869,4891,4901,480,481,673,4936,4965,2124,4945,4896,4869,4870,4871,4966,4967,4884,4885,4869,4868,4869,4870,4871,4936,295,4512,4901,2756,4884,4885,4897,4950,3367,3368,3369,3370,282,4870,4871,1371,4869,4868,4869,4911,295,4512,4913,4936,3395,4968,673,4896,4869,4870,4871,3368,3369,3370,4884,4884,4884,4885,4897,1526,982,4897,480,481,4870,4895,4969,295,4512,4897,4970,81,4871,4913,4869,4870,4871,3367,3368,3369,3370,4884,4910,4897,982,2954,4884,4885,4897,4966,4971,4884,4885,295,1616,4972,4950,4973,4966,4969,2441,4891,4898,2340,2041,4950,4884,4884,4885,4884,4885,4884,1245,4901,480,481,4885,4884,4885,4933,3371,918,2397,4891,4901,480,481,282,4913,4869,4870,4871,4966,4961,4961,3367,3368,3369,3370,4974,4975,4870,4871,4895,977,4887,3367,3368,3369,3370,4976,4868,4869,4870,4871,4977,4978,4917,4966,4967,1281,4936,3367,3368,3369,3370,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,295,1616,4969,4979,1245,4950,1105,4911,4892,442,4901,480,481,4898,2340,2891,4880,4891,4898,4930,4884,4885,4884,4885,4884,4885,4950,4885,4884,3367,3368,3369,3370,295,1616,4936,3367,3368,3369,3370,1353,80,4980,4981,3369,3370,4982,4869,4913,622,4964,4983,80,3426,4880,4884,1350,442,4984,4901,2824,2891,4966,4985,4884,4894,4884,4885,4884,4885,4884,782,4903,4969,4891,4898,442,4986,295,1616,4870,4871,4914,1281,480,481,4966,4967,4869,4891,4892,1237,4917,1350,4950,4867,4966,4985,4987,4936,3367,3368,3369,3370,4988,4989,4064,4936,507,4967,4990,4886,4887,782,1353,4884,4885,4884,4885,4884,746,1526,296,4991,4992,4901,2340,4899,4910,4884,4885,4884,4885,4884,4885,4884,3367,3368,3369,3370,752,4885,4886,4887,4897,4870,4871,4936,3367,3368,3369,3370,918,4966,4967,4897,4901,480,481,507,4894,3367,3368,3369,3370,4985,4869,4903,4961,1353,4993,4870,4895,4884,4885,295,4512,4884,4885,4884,3367,3368,3369,3370,4891,4898,4994,2340,2891,2560,4897,4870,4871,4885,4884,4885,4884,4885,4884,4885,1350,480,481,4995,1382,4996,4899,386,4867,4911,4034,4885,4884,4885,4884,4884,655,4997,1746,2178,4896,4869,4870,4871,4897,4997,2340,3413,4884,4885,4884,4884,1350,2340,4899,4903,4967,4869,4868,4936,442,4976,4903,4971,4892,4998,4936,4999,5000,563,4884,4884,4885,4884,839,5001,4933,4870,4871,5002,442,1955,4891,4901,5003,5004,3369,3370,4913,4869,4891,4898,2340,2397,5005,4869,4913,4936,3367,3368,3369,3370,4539,295,4512,1281,4997,5003,5004,3369,3370,4886,4914,673,2891,5006,4869,4913,4936,3367,3368,3369,3370,4966,4967,5003,5004,3369,3370,4903,5007,1930,1178,4898,5003,5004,3369,3370,4897,507,480,481,4884,4884,4885,4884,782,4988,5008,4892,1353,507,4943,4869,4870,4871,4885,4950,4910,480,481,4901,5003,5004,3369,3370,4950,4977,5009,4897,4961,4960,4962,4881,442,4903,4967,507,4884,4876,3367,3368,3369,3370,4891,4898,3306,3307,3308,4940,2824,3514,4895,3367,3368,3369,3370,5010,605,5003,5004,3369,3370,1245,4876,4884,4885,4884,4885,4884,918,4936,3367,3368,3369,3370,4943,4869,4870,4871,3367,3368,3369,3370,4897,2891,4898,2340,4899,4901,1955,4950,295,1616,4950,5011,3306,3307,3308,4903,4971,5012,1237,3306,3307,3308,1178,5003,5004,3369,3370,4954,4911,5013,5014,3369,3370,4884,4885,4884,4885,4910,4980,4981,3369,3370,4966,4971,1131,4898,5015,4966,4967,4871,5016,5003,5004,3369,3370,618,295,4512,4896,4869,4870,4871,5017,4978,4880,5003,5004,3369,3370,5003,5004,3369,3370,5018,563,803,4948,4979,782,5003,5004,3369,3370,4897,1245,5013,5019,4903,4985,3306,3307,3308,4900,622,1496,4950,4885,4886,4887,4925,3367,3368,3369,3370,1178,655,506,5020,1178,4968,5021,5022,5023,793,5024,4950,5014,3369,3370,4966,5025,563,4034,1281,386,4901,480,481,4951,622,1746,2178,4996,4910,5000,5026,4894,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,640,4891,4898,480,481,4898,3306,3307,3308,4936,295,4512,640,507,3779,4884,4884,4885,4884,3367,3368,3369,3370,4932,5027,622,1245,4885,4884,295,4512,3382,5028,5003,5004,3369,3370,4200,4870,4895,295,4512,4997,480,481,4871,2891,655,3696,4901,2177,5029,5030,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,1222,2891,5031,295,1616,480,481,4884,4884,4885,4884,4884,4884,4885,4884,4885,4897,4976,4884,4884,4885,4884,4885,4897,1350,4871,782,4997,480,5032,4885,442,1746,2178,4969,5033,4885,386,4933,4897,1371,1941,5034,4891,4898,480,3132,4897,4966,4967,5035,673,4870,4871,5036,4884,4885,4884,4884,4885,4897,1746,5037,4910,5003,5004,3369,3370,4912,4354,5038,3306,3307,3308,5039,4891,4898,3306,3307,3308,4884,4885,4897,4943,4869,4870,4871,4967,4936,295,4512,4952,4966,4967,5040,442,2775,1281,5041,4903,4967,4971,4997,5003,5004,3369,3370,4966,4961,4961,4960,4960,4960,5042,4885,4897,3613,4884,4884,4884,4884,4885,4884,4885,1222,673,782,4950,5043,4904,507,282,4997,480,481,3367,3368,3369,3370,673,5044,5045,4083,5003,5004,3369,3370,480,481,5046,80,4977,4978,4917,4936,1281,4961,5047,3367,3368,3369,3370,4884,4884,4885,4884,4884,4884,4885,4884,4885,4884,4885,4948,4979,3306,3307,3308,4964,5048,4936,3367,3368,3369,3370,1017,5030,4897,5036,4891,4898,480,481,5049,3367,3368,3369,3370,3306,3307,3308,442,4954,4898,5003,5004,3369,3370,3367,3368,3369,3370,5050,4885,4884,4885,4884,4884,4884,4897,5038,442,563,4903,4969,5051,295,5052,711,4936,3367,3368,3369,3370,4884,4885,4884,4885,4950,4960,4960,4961,4961,4961,4961,442,5003,5004,3369,3370,4950,1250,3410,640,4948,4979,4869,4891,4898,5003,5004,3369,3370,4911,4891,4898,3306,3307,3308,4897,4911,1752,5053,5054,4950,4952,5003,5004,3369,3370,1350,605,4885,4884,1353,4884,3367,3368,3369,3370,4903,4967,4933,4870,4871,4961,5007,282,5055,4898,2764,4987,2340,5056,4885,4884,1371,4968,4968,4968,5036,4876,4884,4885,4884,4885,1371,5057,2184,442,3367,3368,3369,3370,1178,2824,5058,373,4885,4884,4885,4884,4885,4884,4885,4884,3367,3368,3369,3370,4885,4884,4885,746,5059,1526,4512,1350,4925,1718,4886,4920,605,295,466,5003,5004,3369,3370,2891,442,4980,5060,4961,4961,4961,4961,4961,4962,655,1371,4880,4985,2441,3367,3368,3369,3370,5061,5003,5004,3369,3370,561,4884,4885,4884,4885,4897,295,4512,5062,4884,507,5063,4884,4885,4884,4884,4884,4885,4884,4885,4884,4886,5064,282,4948,4979,5036,4898,5065,5003,5004,3369,3370,1371,5013,5014,3369,3370,5020,4930,5003,5004,3369,3370,4968,4903,4985,442,2397,4895,1275,4933,3133,4885,4884,4885,4884,4885,4884,4885,4884,918,3382,5003,5004,3369,3370,3367,3368,3369,3370,1245,5066,3572,4980,4981,3369,3370,4985,507,4868,4936,3367,3368,3369,3370,5067,4950,4910,640,4920,295,982,4967,4885,295,506,4985,5067,1245,1872,1496,295,1616,4884,4884,4885,4950,1752,5036,1350,4933,4910,4884,4885,782,295,982,4898,5003,5004,3369,3370,1829,2433,4954,4884,4885,1281,3367,3368,3369,3370,5068,4960,4960,4961,4961,4961,4967,4972,5069,4885,4884,4884,4884,4885,4884,4885,4925,3367,3368,3369,3370,673,5070,563,480,2454,605,5003,5004,3369,3370,507,1275,5071,4886,4874,4903,4971,752,4911,4985,4969,4870,4871,4884,673,1245,2340,4194,4885,782,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,295,4512,563,4885,4884,4885,4884,4885,295,4512,563,5020,4910,5067,655,5003,5004,3369,3370,5003,5004,3369,3370,4910,4962,4884,2814,4884,673,5072,5073,5074,3369,3370,4876,3367,3368,3369,3370,1222,295,4512,4954,5075,3306,3307,3308,1836,5007,4964,1281,3367,3368,3369,3370,4894,295,982,1353,640,918,640,1353,1178,605,4885,4884,4885,4884,4885,4950,4933,1752,4903,4971,4933,4895,4884,4884,4885,4884,4885,4884,4885,1371,5051,4884,4885,4884,4885,1350,386,4997,2340,2090,1281,442,2340,5076,2688,2340,4458,2540,1350,4034,4925,5077,5003,5004,3369,3370,295,4512,4885,4950,507,4980,4981,3369,3370,4895,5003,5004,3369,3370,4960,3367,3368,3369,3370,295,2540,4954,295,982,507,4884,4884,442,5073,5074,3369,3370,640,4886,4944,1245,673,4925,5078,673,4884,4885,4950,1350,3367,3368,3369,3370,1941,5079,4933,918,5020,2340,5080,5081,3304,3305,3306,3307,3308,3304,5082],"category":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"subcategory":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"stringArray":["dyld","0x60df","cli","0x7126f","0x4826d7","0x7603f","0x609ef","0x6ac2b","0x483807","0x486697","libsystem_kernel.dylib","0x2474","0x6ae37","0x1e049f","0x464383","0x45cc2f","0x3ec73b","0x40e013","0x3e5c34","0x3eb5bb","0x407ebf","libsystem_platform.dylib","0x3674","0x3eadaf","0x3f2c94","0x3ea40f","0x3fb95f","0x3704","0x45cba3","0x45ba6b","0x45b04f","0x45a64b","0x4654f3","0x129c","0x3ed477","0x3e7f60","0x45cbf0","0x3ec6b7","0x409550","0x459c4c","0x3eab5f","0x40954f","0x3ec283","0x4095dc","0x3eb4a7","0x40473b","0x4bc3ef","0x4575f3","libsystem_malloc.dylib","0x271e3","0x26adf","0x566b","0x36f8","0x3ea3c0","0x1e05d3","0x1e0a3f","0x1e13bf","0x1e4293","0x1f6047","0x22eb","0x24bb","0x2d7f","0x6d84","0x1e4ba3","0x1e7e13","0x1d1187","0x1f71ef","0x1fbad3","0x1fc603","0x1f358f","0x1fc56b","0x1fd3e3","0x1fcfaf","0x4a038b","0x1380","0x1f6bef","0x1fbe27","0x1fb583","0x1fb71f","0x1fcb57","0x1fcfe3","0x1f2ed4","0x1e0dd7","0x1ef1c7","0x1f04ff","0x5eb3","0x63f8","0x1e0643","0x1d9f7b","0x23d6e7","0x1f3b17","0x238f6b","0x23fb93","0x1dcbb3","0x247da7","0x23d3eb","0x241d3b","0x1fb20f","0x1fc583","0x1f3723","0x1da083","0x26e81b","0x1dc553","0x1d8a03","0x142817","0x14984f","0x13f983","0x1a240f","0x2baf6b","0x2a9c63","0x1d44ff","0x281b5c","0x1da3db","0x146fe7","0x1a8def","0x1a99cf","0x14cff3","0x14eb47","0x1498cf","0x1a531b","0x1b0cc3","0x1ad224","0x1427c7","0x1a504b","0x1b0cef","0x1a7d9f","0x1b03df","0x140003","0x18417f","0x184937","0x184c87","0x184ff7","0x17fd73","0x28a557","0x311323","0x3df480","0x3df41f","0x3e0764","0x13fc7b","0x18440f","0x1d4423","0x1d4f5f","0x2afba7","0x216b3f","0x1e9747","0x1d4f1b","0x2b037b","0x219218","0x1848ef","0x1cdd37","0x17ebcb","0x29f81b","0x29ec47","0x295bcf","0x296227","0x2efbf3","0x2f917c","0x13fa97","0x1ab017","0x2baf8b","0x1e96b8","0x1a2b6f","0x1a66bb","0x13fec7","0x18001f","0x3112f8","0x1497c7","0x1a4a7b","0x1b0a2f","0x1b436f","0x13ee8f","0x18edcb","0x190dc3","0x195e6b","0x19696b","0x19cb0b","0x19921f","0x2a02f3","0x29eb4b","0x25b0a0","0x18ed47","0x191cc3","0x196283","0x19ed67","0x2be6c7","0x29eaf7","0x258da3","0x2a355f","0x267f9b","0x29463b","0x25aeaf","0x296c73","0x2a2ef7","0x25a417","0x296a4b","0x2a306f","0x2f495b","0x2e0977","0x22c7","0x353b","0x41fb","0x4318","0x180b6f","0x1804cb","0x2a08e7","0x298518","0x14cdff","0x187d7f","0x188477","0x189013","0x18cc7b","0x13f8cb","0x12a473","0x12a883","0x12935b","0x12dadf","0x3df4b7","0x3e0774","0x1a91cf","0x1accdf","0x1ad0bb","0x13f26b","0x1a095f","0x15b5b3","0x1add57","0x1ae0c7","0x13f763","0x1538d7","0x13e557","0x153b83","0x1a52eb","0x1b115b","0x13ff2f","0x1807fb","0x19d1fb","0x19a6ef","0x29ec2b","0x258bf3","0x2a35db","0x2f2d17","0x3065cc","0x18872b","0x19fc43","0x2972b7","0x2a2ddf","0x2a2e3f","0x2a2e9b","0x296c40","0x18835f","0x139bc3","0x2f497f","0x2cac2c","0x18cd43","0x3e06bc","0x1aba57","0x1ced57","0x1a26c7","0x287ecb","0x23f163","0x4a03b3","0x381c","0x18876b","0x13d72f","0x1498ff","0x13802f","0x14e05f","0x1502af","0x1327bf","0x13728b","0x132d77","0x1529ab","0x150ea7","0x1d7633","0x1d62df","0x1d6c3b","0x1d6c87","0x1d6cd7","0x1d6fdf","0x13fa43","0x1768bf","0x13f017","0x17f747","0x267bc3","0x295f2f","0x2eff5b","0x2ef347","0x2eefeb","0x1f5b8","0x1a4703","0x1beedb","0x1bf8f3","0x12c427","0x1e9697","0x281b28","0x1affdf","0x3e06f4","0x2a9ca3","0x27e457","0x20efcb","0x281b83","0x1f4af","0x340c","0x27e473","0x231a17","0x4c0458","0x29edaf","0x2a292b","0x296517","0x2a4b07","0x2a54ab","0x2a54fb","0x2a5518","0x2b03b3","0x2801b7","0x220b60","0x17ff73","0x2a359b","0x2a36cc","0x18ed9f","0x19371b","0x193d4f","0x1964bb","0x29e893","0x29c6c7","0x28f07b","0x29213b","0x41e4","0x1a99f3","0x1c4d80","0x20effb","0x14e4","0x188837","0x13e043","0x13f9f3","0x130693","0x1a2adb","0x2688c","0x287f27","0x49fcfb","0x4a675f","0x4a0513","0x4bfa93","0x49f7e7","0x45a4","0x137bf3","0x2b642f","0x2b658b","0x2b4787","0x2362ff","0x235df0","0x29c89b","0x29ea5b","0x292093","0x29315b","0x29327b","0x1408","0x1812a3","0x19ceab","0x197edb","0x2920c8","0x295a3b","0x296607","0x2687ef","0x2685bf","0x27478f","0x2747cb","0x18ed73","0x1901cb","0x1aa24f","0x1ca963","0x1aa793","0x200584","0x1a84e3","0x27d6f7","0x20c35f","0x2b25fb","0x2a108b","0x2ec373","0x1d44","0x1811ff","0x19fdaf","0x2ba353","0x29d2cf","0x29d020","0x1968cb","0x19e523","0x2be8e0","0x29eb13","0x296593","0x26885f","0x269adb","0x1f5fc","0x19183b","0x129407","0x12bd1f","0x29ee9f","0x2a25eb","0x2eb454","0x130c07","0x1312f7","0x1315fb","0x14118f","0x152383","0x3650","0x20c42b","0x2b27c3","0x295b5f","0x268833","0x1f250","0x146f2b","0x1a77db","0x210cef","0x22799b","0x2bbf1b","0x1d4ee4","0x4a6713","0x4bfac3","0x49f80b","0x48a0e8","0x13f687","0x185e43","0x186467","0x19f273","0x4a04e7","0x3804","0x1c01cb","0x1c03ef","0x2be023","0x2bdc93","0x25e5a3","0x2094fb","0x26880","0x1887f7","0x1357b7","0x29617b","0x2f0157","0x1d20","0x1520c7","0x2a0f0b","0x289d3f","0x26838","0x231737","0x234e80","0x152483","0x140e17","0x151313","0x1c709f","0x1cd4","0x29667f","0x2a3450","0x29611b","0x2f9157","0x2fa187","0x2fa144","0x1a1a77","0x1516a3","0x2ee447","0x2edf00","0x2b225b","0x2920d7","0x29310b","0x2930bf","0x2936a0","0x18ee77","0x19294f","0x19fbcb","0x267cfb","0x2962ab","0x2a3417","0x1a2ae0","0x287f7f","0x3430","0x2a9d47","0x23197b","0x2f31db","0x30630f","0x30f7f0","0x1a32f3","0x13f2fb","0x1ca43f","0x18ad13","0x28f1ab","0x31e257","0x2e41bb","0x2cfe8b","0x4e5f","0x6e18","0x2f5f43","0x32d6a3","0x3315db","0x2e6fb7","0x2e70f0","0x186f7f","0x129a17","0x13fa27","0x178b53","0x18511f","0x17e9ef","0x29617c","0x2eb4a7","0x2ea3ef","0x2ea807","0x2ea8d7","0x2e7b33","0x2e68e4","0x17fcc7","0x296224","0x2686eb","0x2a2350","0x19093b","0x2ea7cb","0x2f358","0x1f3a4","0x18507b","0x2a02d7","0x295a97","0x2efe03","0x2fa117","0x25883f","0x25ba5f","0x285ad3","0x285cfb","0x283fa4","0x267b67","0x26863b","0x29cf03","0x29a8cb","0x4b4db3","0x235e17","0x4587","0x1f498","0x25bc43","0x28076c","0x2934ff","0x2840d4","0x259c0c","0x152f13","0x258973","0x25bbfb","0x2686cb","0x2a221b","0x265b6b","0x265bb7","0x265c07","0x265960","0x28f1bb","0x371c","0x1a0aeb","0x2be5c3","0x2bc8e0","0x28077f","0x222e68","0x1808d3","0x2a54e7","0x1f20f","0x19e3","0x1c30","0x296168","0x151afb","0x1d629b","0x1d7208","0x26889b","0x26a05b","0x26d4eb","0x26a043","0x269ac7","0x1f2b8","0x2effc3","0x1f3b4","0x183bfb","0x13f89b","0x18a797","0x28a4c3","0x310d17","0x3e0244","0x285b8b","0x285cc4","0x130e6f","0x295f8b","0x2a3cd3","0x2f3b03","0x2e0b14","0x18ccdf","0x13fb4f","0x185607","0x29d6cf","0x29306f","0x292ea0","0x3e06e4","0x18cb63","0x13f733","0x1538a3","0x29fe6b","0x293160","0x25889b","0x259a37","0x2efe27","0x2fa463","0x2fa17c","0x18edf7","0x18fed3","0x19437f","0x267c8b","0x2a54c8","0x25a398","0x197d43","0x295cc3","0x298b2f","0x297f8b","0x298af4","0x1cfc","0x258e03","0x25c7a7","0x28079c","0x195c27","0x183c","0x265b1b","0x265c08","0x2b26af","0x2a1ef7","0x2ec61b","0x2ea40b","0x2e684f","0x4b70","0x190653","0x1954b7","0x1981b7","0x1f4cc","0x2f1098","0x1a46cb","0x1a636f","0x1b4fe7","0x1b8c13","0x267003","0x2a3b4f","0x2f7ec0","0x2a4eeb","0x285af7","0x2ce4","0x2a2367","0x265f24","0x2fa3eb","0x4c0440","0x195ddb","0x19e763","0x1f560","0x2b252f","0x2a162f","0x292fe3","0x13f4bb","0x154017","0x15432f","0x15666f","0x29d4b3","0x29dbc3","0x298533","0x298b17","0x265f38","0x2597ef","0x26d4d3","0x1cf0","0x2a188f","0x2a17af","0x2ebae7","0x2e7b27","0x2e5708","0x2234fc","0x195e2b","0x265bf3","0x1400","0x17917f","0x17988b","0x179c8b","0x17a4b3","0x15151b","0x259a83","0x2230f0","0x2f186f","0x1f3c0","0x2eefd8","0x13f83b","0x13a5b7","0x143c1f","0x142443","0x1f4c4","0x2193c8","0x2fa3b0","0x2fa38c","0x3df4a8","0x26a018","0x2a1d4f","0x293147","0x2a01fb","0x2eb77b","0x2ea7eb","0x2ea823","0x2ea817","0x1f5bc","0x2efc18","0x1869f3","0x292dc0","0x295e23","0x259377","0x280774","0x152d3f","0x25bbb7","0x265a9c","0x18566b","0x29c8db","0x29f140","0x14cd97","0x133877","0x17becb","0x178c","0x1a9407","0x1fb740","0x1f5f0","0x295e83","0x1378","0x222e64","0x2840b0","0x139bab","0x1d2673","0x1d2f9b","0x1d25fb","0x1d20cb","0x1d2057","0x1d2f87","0x2cff97","0x4c0464","0x17a163","0x1d6cc3","0x29f3c7","0x2930ab","0x17c8","0x17a793","0x1d108f","0x1d6f83","0x1d7098","0x29315c","0x179403","0x1a1e2f","0x258ad7","0x25e367","0x28729b","0x281ef4","0x2fa428","0x222e78","0x2972eb","0x294587","0x2f614f","0x1d18","0x25995b","0x25e300","0x1d4ebc","0x2f490c","0x2f187f","0x1f47c","0x17eea3","0x29abd0","0x3e06c0","0x19c6c7","0x1d69a7","0x26860","0x2efbff","0x16fc","0x137faf","0x132387","0x1527d7","0x2a138f","0x296367","0x259d4c","0x1986df","0x2933b7","0x280887","0x26db83","0x21f7a0","0x259378","0x19edef","0x275a4b","0x2a13b4","0x1975fb","0x29f723","0x2ebd8f","0x31d92b","0x31d967","0x31d983","0x4c03ec","0x2590e3","0x285d4c","0x2cfd3b","0x2e9817","0x2ee158","0x2a5593","0x1844","0x2fa6ec","0x197587","0x29fb57","0x4c03e8","0x14ce57","0x17d36b","0x1b29cb","0x17a64b","0x19861f","0x265a1b","0x16ac","0x1c09c7","0x2e0b83","0x1758c","0x1a08b3","0x2bc8a4","0x3114bf","0x3e017c","0x1a99e3","0x1af2cf","0x1aefb7","0x1af72f","0x25e7f3","0x1f3e2b","0x22734b","0x227c3f","0x29e0b7","0x28ba8b","0x271ec","0x3df437","0x3e0780","0x29d1a8","0x4577","0x365c","0x2a0c6b","0x296368","0x14989b","0x13ce13","0x1cbd47","0x14f6a3","0x131a6b","0x2b968b","0x2b938f","0x2b937c","0x268007","0x1350","0x132527","0x200327","0x15148b","0x1f3e4","0x1aef93","0x29e253","0x6220","0x14d9a0","0x2b1ecb","0x28c87b","0x2ebdd3","0x60c0","0x3066c7","0x3e010c","0x2f3b27","0x2cad48","0x188663","0x188913","0x296283","0x2e07f0","0x2a3a38","0x19cd63","0x18c643","0x1c708b","0x1c8e27","0x1c8d1c","0x4a65a0","0x13f6d3","0x154517","0x1d6f6f","0x17cedb","0x14dbcf","0x1404e8","0x19f7e3","0x17518","0x287f50","0x2a3ab3","0x2601b4","0x25a18c","0x19dbcb","0x292078","0x1c0e67","0x13464b","0x1c1b43","0x1b2bcb","0x1369b3","0x1b895f","0x1d6357","0x1d6928","0x17a5c7","0x125fe7","0x1b850f","0x127507","0x2ee457","0x2ee247","0x2ee3cf","0x2e77bf","0x2e91bc","0x17ab0f","0x1d3d30","0x31132f","0x3e06c8","0x2ef324","0x1f3d2f","0x29e09f","0x2a5b0b","0x2a48af","0x2a545b","0x2a4a38","0x3df474","0x1e975c","0x1a1aab","0x2bec04","0x19ac93","0x2f3e5b","0x4310","0x146ae3","0x1e89ff","0x29ee14","0x18c64b","0x1c70a7","0x1c8def","0x1f514","0x3e0734","0x180c5f","0x2a357b","0x258b9c","0x1b03e0","0x227e17","0x2ea740","0x296c03","0x2a5064","0x1b2ca3","0x1a1bf7","0x28a9db","0x28c723","0x2ded4b","0x4a0360","0x2be7ff","0x280f04","0x12bb83","0x28ae03","0x28c7bf","0x31ec6f","0x3e0718","0x2f323b","0x30516c","0x19c483","0x292f6f","0x293237","0x293434","0x1a4e53","0x25aef7","0x25c577","0x265943","0x25ef23","0x285cef","0x25bb98","0x1ab2a3","0x21607f","0x287bdb","0x25c82f","0x2f291c","0x219210","0x3668","0x1ab2c3","0x2bba5b","0x2a9923","0x1d4e54","0x437c","0x2b9390","0x258c53","0x25c194","0x268768","0x292f83","0x292eb4","0x2a179f","0x36e0","0x2e5724","0x1d4e90","0x2ea7fb","0x1f49c","0x234e38","0x259628","0x2eb737","0x31d91b","0x3420","0x1ad3a3","0x3814","0x380c","0x2f21b3","0x30287f","0x2a9fa3","0x21ec20","0x29cee7","0x29a334","0x2f3487","0x306448","0x2f185f","0x2a9f17","0x22266b","0x3e0714","0x295fb3","0x2a344b","0x216ceb","0x271d4","0x3df494","0x1bf92f","0x20575b","0x2af987","0x455b","0x1af573","0x2b5c3b","0x1f746b","0x3724","0x1a80a3","0x2be60f","0x2b6b73","0x2b6b74","0x19adfb","0x295e4c","0x5d80","0x1a71f7","0x16a3ab","0x2bcbd7","0x20949b","0x22767b","0x2bdd13","0x2bcf48","0x29a370","0x19c70f","0x292e2b","0x16f4","0x14279c","0x29fb78","0x2b539b","0x37f4","0x302890","0x2b27ab","0x677c","0x2ef340","0x1a801f","0x1d10","0x2b6ac3","0x2bad10","0x1d7583","0x1a16b7","0x1510fc","0x3028db","0x3e0124","0x1ad2ef","0x2ae22b","0x2ae6a7","0x2a817f","0x2a8ea3","0x2a8ce0","0x222698","0x2efe0f","0x2f92dc","0x180853","0x2a3494","0x287f44","0x49fbd4","0x2bb477","0x286e47","0x281a7f","0x627c","0x129948","0x31d94b","0x29d42f","0x2a4927","0x2a48f4","0x2f651f","0x2ef49f","0x2e3280","0x4a037c","0x3d7c","0x287f6b","0x1a960f","0x2005a8","0x19ec4f","0x14274f","0x2b63db","0x2b6477","0x4b4ddf","0x235e3f","0x17aaef","0x2ea664","0x1968f3","0x150ea0","0x19e447","0x3e0654","0x2f44bf","0x32ea7b","0x3311c3","0x330a9b","0x330b5f","0x17b0","0x29215f","0x2194eb","0x17f748","0x19ccb3","0x28faec","0x19fe33","0x1c8e7f","0x1c8e63","0x2f3d10","0x265b57","0x2e08d7","0x62f8","0x19a677","0x2a9e93","0x12d4","0x292e04","0x2936a8","0x2ea61c","0x19c6f7","0x31c2b3","0x2b2193","0x19e46f","0x130b87","0x1774af","0x177feb","0x17881f","0x2be6e3","0x29b5cf","0x4a03c8","0x18ed1b","0x191543","0x193a37","0x3c5c","0x18fa4b","0x29d137","0x29ceb8","0x2b20b7","0x175b4","0x293007","0x1980db","0x1d6e0b","0x1d6a30","0x2f5173","0x2ef440","0x26592f","0x25a394","0x1d4f60","0x1b0c77","0x20a4f7","0x2253c7","0x2297ff","0x22a537","0x22a374","0x22531b","0x28c9f3","0x292fcf","0x1856db","0x2a3a8b","0x2a9cb3","0x2aa33c","0x235de0","0x21ecb7","0x38ec","0x1cf247","0x1b16ff","0x2b1caf","0x2c03af","0x2bf553","0x3c3c","0x2a35b7","0x2a50a0","0x25ae8f","0x294618","0x12b6c7","0x2b6abc","0x196933","0x4268","0x219224","0x25c704","0x2ea654","0x25a3f7","0x268adf","0x25f8d0","0x182c7f","0x1f2cc","0x266633","0x29bc63","0x2895db","0x293fc7","0x2f2633","0x305b2f","0x3dfcdf","0x3df700","0x29f290","0x223243","0x3e0160","0x2f7e94","0x2b1f14","0x29d003","0x29a2dc","0x180e3f","0x2f481f","0x304303","0x30da83","0x30eb9c","0x3e0130","0x2ee413","0x2edfe8","0x3e3b","0x2df4c","0x2fa6c0","0x2a3b03","0x297d58","0x1ad52f","0x21868b","0x2b126f","0x3103df","0x2eefc0","0x19a60b","0x15072f","0x1d6c6f","0x293463","0x14f0","0x29f0a0","0x3df4eb","0x3e071c","0x29628b","0x297fb8","0x1f2e0","0x31d8bc","0x297f6c","0x23edf0","0x28ba07","0x1444","0x2689af","0x49fc6c","0x29d117","0x29e4dc","0x4a6703","0x2710f","0x45dc","0x1d4e88","0x2ea76b","0x1d3c","0x2c7c","0x2930f3","0x14b0","0x48a0dc","0x265b07","0x2f184f","0x1d6b83","0x1d1c","0x2f6fd3","0x2cad13","0x30f8bc","0x2b532b","0x3434","0x2931f8","0x16e0","0x2945c8","0x2bafc3","0x27e58b","0x213c1f","0x2a6858","0x31041f","0x2e351b","0x2e2f77","0x36a8","0x3e0768","0x2056fb","0x2af92f","0x2a486b","0x2f3ebf","0x2d6c54","0x19caa3","0x28fb03","0x2945a0","0x31d843","0x31d820","0x14b98b","0x2b6314","0x1f3f4","0x1d6323","0x1f9240","0x1a85cf","0x23f7b7","0x2046e0","0x1f494","0x13ce5b","0x2b925c","0x292ff8","0x2e0a5c","0x295b43","0x216c97","0x29faa7","0x296393","0x2684f7","0x2362d3","0x235e68","0x2ea65f","0x1d6beb","0x1a6c2f","0x1a747f","0x2bdcc0","0x2ae517","0x27078","0x3e0678","0x139c","0x296064","0x219393","0x1d4ec7","0x280ae3","0x21a603","0x28efc8","0x2a9e64","0x293180","0x2efc4c","0x2965f4","0x21a9cb","0x16b4","0x19ee13","0x310d6b","0x29305c","0x29ec7f","0x2936b4","0x1af210","0x2a9e74","0x2317f0","0x1d7230","0x20059c","0x287c3b","0x2bb187","0x20a95b","0x27cd34","0x2ae5d3","0x4a04c4","0x2ea644","0x29a887","0x29a847","0x29a774","0x12b4","0x23f150","0x2a819b","0x2a8e87","0x16d8","0x2b23df","0x180287","0x1d43f8","0x2ea6f3","0x258f9c","0x293118","0x1ad333","0x4457","0x1fcc","0x26d4e3","0x31d8f3","0x1cc0","0x26a054","0x13272b","0x1f3e8","0x2bc8c3","0x12e0","0x2bb04f","0x280323","0x2f97fc","0x2ae407","0x3df3f0","0x286e6b","0x297f60","0x29a254","0x4a04fc","0x2a235c","0x1d7577","0x29460c","0x1464","0x2afbdf","0x220bb8","0x1f2d4","0x184c5b","0x31b848","0x13f5cb","0x156f2f","0x2a29cb","0x31714c","0x1af76f","0x2bec17","0x2367c7","0x645b","0x6b90","0x2b3913","0x2b42ef","0x2b430b","0x2b4327","0x1d6343","0x3df4a0","0x193cfc","0x1d4e60","0x2e32bf","0x53bb","0x5bfc","0x265898","0x265a7b","0x296503","0x310317","0x5623","0x2be8","0x17fe03","0x29a8e3","0x37fc","0x2ea638","0x2a2f58","0x2e0a28","0x267c6f","0x2687dc","0x29a280","0x2cac37","0x3e0704","0x2ef2f8","0x2b9343","0x2eb264","0x2a8e67","0x2e0a3f","0x4c0470","0x2a9ed4","0x19c7f7","0x1fb28b","0x1fc50b","0x1fd3cf","0x26594c","0x2319ac","0x3df410","0x3e0283","0x3dee6f","0x4adc8c","0x1c4d97","0x1f01e7","0x1ed807","0x1f0477","0x1ed7fb","0x1d6930","0x3e0684","0x2b1f4f","0x2bf4ab","0x2bf9b7","0x2bfa03","0x2bfd5b","0x29a8ac","0x2f9067","0x2faeac","0x5374","0x2f933c","0x29a204","0x2b21b4","0x3102df","0x2b92b3","0x2191e4","0x2b224b","0x1d3b24","0x2ea6e4","0x2a5564","0x17e90b","0x13f8","0x1a2be7","0x29369c","0x1af66f","0x1f9907","0x3028ac","0x2ea694","0x2ba7ff","0x318747","0x317f6f","0x3180e7","0x2ece93","0x2ee8eb","0x2ee8c3","0x2a4afc","0x2226a4","0x2fa3b8","0x265ab3","0x280fcb","0x26dcc3","0x21d2b7","0x3820","0x280ad4","0x2a8ebf","0x2a8cd4","0x19fe13","0x28f1bc","0x26a03c","0x2bf567","0x2bf5d8","0x2a5524","0x295b1b","0x3df458","0x1d693c","0x1af597","0x275a07","0x289eaf","0x26596c","0x1d4faf","0x280a20","0x2f703b","0x6274","0x1e973c","0x3066eb","0x30d823","0x30e180","0x29301b","0x292ec0","0x2f187c","0x2a54ac","0x2ec3d7","0x2aa09b","0x287c7f","0x280350","0x28b0","0x2eefa8","0x5fb4","0x2f2104","0x2eef98","0x17a43b","0x2b6b60","0x3e0700","0x2b6208","0x2b232b","0x2a540b","0x269543","0x29a48b","0x2efe8b","0x2fa6ac","0x20aa13","0x27cc7c","0x5d4b","0x2a54c4","0x2920b3","0x293530","0x187ebb","0x567b","0x17624","0x2fa6d0","0x29a250","0x1a8117","0x200594","0x17eddf","0x234e97","0x23ee88","0x2687db","0x26d3f8","0x19b99f","0x1c8dc8","0x28a50b","0x445c","0x2b634b","0x2b6334","0x2b6220","0x2f2dab","0x2f92e0","0x2aa353","0x19278f","0x18720f","0x2f2def","0x30f27b","0x1abe93","0x2f2974","0x2a8d00","0x29a8ff","0x267e9f","0x29465b","0x29f077","0x29640b","0x17ac1b","0x1c8e97","0x1c21bb","0x60d4","0x1218","0x142704","0x258f64","0x1794","0x1f74","0x17f63f","0x13e003","0x29e80f","0x2a5447","0x4147","0x69c4","0x1497ff","0x2b62fc","0x29cdf4","0x2b24c3","0x131923","0x2b92c4","0x199083","0x29ee43","0x6ad8","0x1356b7","0x18ee23","0x18f753","0x194067","0x62a8","0x269ab4","0x14155b","0x152077","0x2684c3","0x29a78c","0x2f7ea3","0x2ef268","0x2a9a47","0x202f37","0x1e902b","0x281caf","0x2a5a5b","0x1966c7","0x2a23af","0x297d5c","0x18eb8f","0x1cb21f","0x193293","0x265f3c","0x26dbcc","0x3e0750","0x2b6b13","0x1d3768","0x3320","0x2f7e7f","0x2ef250","0x2ea6f4","0x153eff","0x2b8ed8","0x23edef","0x2b427f","0x2b4168","0x1d6db3","0x1d6980","0x29d27b","0x29a824","0x2687d0","0x49fce4","0x267fd8","0x19f2ff","0x2be7f4","0x258f1c","0x26a048","0x2a215f","0x2911c3","0x266f7b","0x295f77","0x184038","0x258bdc","0x2eee08","0x2f221f","0x19fc57","0x2bab03","0x2bf178","0x28c79f","0x151fa3","0x28f233","0x2abb98","0x4c0460","0x2a3a8c","0x29644c","0x2f326f","0x3e012c","0x2bcfdc","0x1d4f0c","0x285cbb","0x28ec","0x197967","0x2a1bfb","0x2ec063","0x2589e3","0x25927c","0x19e73b","0x4a6704","0x3e06a4","0x25ae80","0x4b4d4c","0x2a4ae4","0x1d6fc0","0x1d6c27","0x287c93","0x16c4","0x27e4c7","0x221c2f","0x25a3f8","0x296540","0x2b6a7b","0x1d7114","0x1a929c","0x1d7124","0x317f7b","0x318077","0x2ed17b","0x2ee96b","0x1e96b7","0x281bc8","0x19b957","0x1c8e47","0x12fc","0x1a26fb","0x2be643","0x2bad98","0x2aa0a8","0x132427","0x28c7a4","0x2f9078","0x265bd8","0x21eb88","0x287f4f","0x1210","0x2ea640","0x268357","0x29a218","0x25932b","0x295e24","0x13ef54","0x25efa4","0x3810","0x2e0820","0x2935a4","0x1a7b87","0x28ab7c","0x49f840","0x3e0754","0x2b3904","0x1f504","0x281cc4","0x4a6ef8","0x2a9eff","0x17a4e7","0x2bea78","0x2ea46c","0x41e8","0x2f18b4","0x259d30","0x2fa108","0x25af44","0x295c9b","0x2fa228","0x2ee054","0x25a218","0x19e4b3","0x29a15c","0x3e076c","0x2686b8","0x1d6ad4","0x4a0510","0x221aaf","0x2a6328","0x219600","0x2fa3d0","0x2ea8b7","0x2e697b","0x4d3b","0x7244","0x28c8e4","0x3e05b0","0x31d88b","0x31d977","0x1f5c4","0x3e0728","0x12c4c3","0x281953","0x5d14","0x49fcb8","0x2ea7fc","0x265d9b","0x259670","0x19b9bb","0x1c8e37","0x2b6a47","0x2bad78","0x31d95b","0x2ba903","0x2b392f","0x2b431b","0x259684","0x6914","0x2193ec","0x2fa68c","0x1e968c","0x2eefe4","0x1cf1c3","0x152447","0x29acd0","0x3e06dc","0x29328f","0x60b0","0x293178","0x21a5bf","0x38f4","0x26d4af","0x2f1dec","0x4b4db4","0x2fa3dc","0x2b6a30","0x2a9e44","0x2ae42b","0x28eb3f","0x2bf6fc","0x29cf57","0x29bb30","0x2f2d90","0x1420","0x2ea79b","0x2a52c8","0x268540","0x30526b","0x3df094","0x2ea77b","0x2ea808","0x29a35f","0x2a3454","0x1d6df7","0x1d6d9f","0x29ba48","0x2b53d0","0x2a9f9c","0x2f9050","0x2f9898","0x5d18","0x1d6f33","0x1d707b","0x283ecc","0x2ea7bb","0x153a2f","0x2bdcf4","0x281990","0x29214f","0x292e5b","0x49f7d8","0x29ee8b","0x2efed0","0x4a6714","0x2fa468","0x2f5a97","0x6100","0x17fbbf","0x2edf9f","0x2edfdf","0x2ee064","0x1f9180","0x267def","0x1d00","0x1240","0x1523b3","0x292db4","0x2932d7","0x2a4ba3","0x2b9330","0x31c123","0x32249f","0x322fab","0x3e0148","0x2efef8","0x29ce80","0x141343","0x1cf58f","0x2b692c","0x2f2c8b","0x42ec","0x3e0720","0x2963d7","0x235e30","0x311344","0x17801b","0x2bd614","0x49fbe4","0x2e0b48","0x19e583","0x2f4787","0x30da8c","0x14989c","0x19d8db","0x25ee67","0x25ef6c","0x2f9174","0x287f8c","0x2a38b7","0x1f4b4","0x1e88cb","0x201c","0x1c0d10","0x1792c3","0x2bcf74","0x18ee4f","0x192433","0x19508f","0x2f8383","0x1d75b0","0x2a4c0f","0x2a4ac4","0x280aac","0x280f50","0x19d63b","0x1c8e57","0x2a2804","0x25c237","0x4a0504","0x220dab","0x19eedb","0x20aa08","0x1d6c10","0x2b2143","0x43b0","0x292e14","0x188697","0x135113","0x2c02ff","0x13a0","0x29d63b","0x28fc87","0x260073","0x17f047","0x4a66ec","0x2eba83","0x29a7a7","0x3e06cc","0x3338","0x2a681f","0x18a980","0x13f98b","0x1c7e93","0x2b53af","0x49fd18","0x1f3e9f","0x281c18","0x1d62bb","0x1d69d7","0x1830","0x30e1b4","0x2b2757","0x2b4198","0x1fcb50","0x1c8e17","0x1992c7","0x1b0347","0x1f48c","0x2f296b","0x3063cf","0x2f21ac","0x293174","0x26a030","0x234e14","0x281974","0x2695e7","0x94870","0x3028a0","0x62bb","0x6970","0x231a08","0x4b4df0","0x227d57","0x3660","0x1300","0x265c58","0x1af9cb","0x200680","0x15159b","0x1d37f4","0x2b940c","0x1a3c3b","0x4d60","0x2b6a74","0x21ec93","0x418c","0x2f6fb3","0x2ea72f","0x265a54","0x17a3eb","0x231a34","0x2cab8c","0x200588","0x267f0b","0x2f620b","0x2bad18","0x29ecf4","0x2a3918","0x28fb73","0x268a0c","0x2005a0","0x20eeaf","0x23ede4","0x26865b","0x1d722c","0x18a877","0x281a47","0x6788","0x25ae74","0x2fa1a4","0x17aa7b","0x1f9238","0x26676b","0x3df490","0x25a198","0x2edf4b","0x2ee3a4","0x187fcf","0x49f7c8","0x21a5df","0x49f8d8","0x1c8d28","0x25c238","0x1c710f","0x296977","0x41a4","0x13f050","0x1c8df0","0x2b24e4","0x29854f","0x298b27","0x297f84","0x2a22ef","0x31d93b","0x1d6a1c","0x234e84","0x2708c","0x2ae667","0x2a8ca4","0x5d50","0x1258","0x12a10f","0x1292ab","0x28aef7","0x1d4e6c","0x2eefdf","0x2eedfc","0x2a2ec4","0x2ae183","0x28baf7","0x26a090","0x295f93","0x2a2fb0","0x2af90c","0x22cc","0x19d3d3","0x231850","0x30eb94","0x281b38","0x296228","0x4448","0x3e0604","0x17bef3","0x2b6430","0x25bc44","0x15283f","0x179c","0x2d5f","0x73a4","0x26dbb8","0x1afe2f","0x1f72bf","0x2ef334","0x2658ff","0x1510ec","0x2428","0x189027","0x1c5cbb","0x1c5b97","0x1c5b54","0x223050","0x20ef23","0x6984","0x25b0b4","0x265a2f","0x265de8","0x29310c","0x1d3784","0x2a14e3","0x28da3f","0x2f942c","0x2e4163","0x2c8beb","0x2cb6eb","0x1e972c","0x2a4a34","0x18cda7","0x17c2d3","0x1c9eff","0x17c763","0x2ea473","0x2ea404","0x3e0784","0x2bf4cb","0x2bf6ac","0x21f694","0x19d2a7","0x29b028","0x1e96dc","0x296bef","0x14cc","0x2c44","0x1b2ea7","0x2e97e0","0x2f90bb","0x2fab4b","0x2e70e7","0x73bc","0x2a3408","0x1a93e4","0x29a1f0","0x2fa6dc","0x43d4","0x2ea897","0x285d3c","0x3e015c","0x1724","0x2efbfc","0x18a89f","0x38fc","0x3dee37","0x17c62b","0x26dc28","0x2f5ff3","0x2e70fc","0x1986c3","0x2efdb8","0x21f798","0x188367","0x1c5cd3","0x1c5c90","0x258d6c","0x1d385b","0x23606f","0x5657","0x49bb","0x13d2f","0x18b4","0x2fa423","0x2facd0","0x2594ec","0x60c7","0x124dc","0x29332f","0x2e6804","0x1c8e73","0x2388","0x196e9b","0x2f3084","0x2b2777","0x2b43db","0x2872cf","0x281df8","0x26813f","0x29a948","0x185f93","0x294b","0xb33c","0x21f3e0","0x2eedf0","0x1f7447","0x344f","0x1a864","0x29305b","0x17bc","0x280734","0x280878","0x25c68b","0x25d90c","0x29cfa8","0x285d18","0x2bc8b0","0x2685ab","0x142c","0x25c127","0x281ea8","0x25c02b","0x25a48c","0x21f550","0x2f5e93","0x2934e3","0x4a6728","0x26db44","0x19ed4b","0x2f57eb","0x31754c","0x2b2287","0x2406e7","0x23b364","0x2ea867","0x1d6948","0x15720f","0x2f49bf","0x2d6ee7","0x4d93","0x7274","0x25dbc3","0x25e3f3","0x25dbbc","0x2a359c","0x136e7c","0x6404","0x265913","0x25ed7f","0x25ef07","0x265f04","0x2edf87","0x2ee223","0x2e7708","0x140db0","0x267ed0","0x1d62bc","0x31e323","0x323047","0x2e7144","0x2a22ab","0x290fa8","0x2e7b28","0x26a04f","0x26c28c","0x69d0","0x2fa470","0x25dbb0","0x2a6877","0x1290","0x2a1a2b","0x2a0658","0x2f550f","0x3172bc","0x2bdd9c","0x25c7a8","0x25c697","0x281d8c","0x285cd0","0x1d6d14","0x2a4a78","0x2e97cc","0x69a0","0x25c18c","0x13f31f","0x18b737","0x25c763","0x25ae44","0x2f836f","0x3029a8","0x25c0af","0x285b6b","0x2837c0","0x28074c","0x2faeec","0x180f83","0x2b89d3","0x2b9360","0x2e4147","0x2de9dc","0x178fec","0x26d4ec","0x1d6e53","0x1d705f","0x3112bb","0x3e077c","0x25bae7","0x281df0","0x271ac","0x2ea944","0x2efbe4","0x3e0110","0x17fd4b","0x1d6bd7","0x3e0738","0x2e590f","0x2e58f3","0x2e5903","0x259dbc","0x2837d4","0x259634","0x2b2234","0x26c298","0x1f42c","0x2808a4","0x2a3024","0x2a68a4","0x26d4c3","0x296204","0x4bfa94","0x2e7b1b","0x12bbef","0x3063f3","0x281e80","0x2e0b34","0x29698b","0x25895b","0x2872b7","0x27fca3","0x27fcbf","0x317160","0x2fa3b4","0x2e58e8","0x2964e4","0x18ce6f","0x129543","0x15914f","0x2b6948","0x1d6eab","0x29d1b4","0x2bf577","0x265be4","0x2a4c8b","0x2b2177","0x236213","0x2a4ecf","0x29e1e3","0x2a5538","0x2e6fa3","0x2e85ec","0x150eec","0x2599ac","0x1c6c30","0x26db04","0x285c90","0x2f0857","0x316c07","0x2ef583","0x2fa1b0","0x311498","0x268788","0x219608","0x2a2b24","0x293124","0x2b6a1c","0x293138","0x2230e0","0x259f8b","0x200223","0x4b4e83","0x5d2c","0x2f9128","0x2b1d73","0x612c","0x19fb78","0x29ead3","0x21f578","0x2f49a7","0x2e6f30","0x2fa690","0x25a45f","0x25bf67","0x2488","0x283b7b","0x283b2b","0x283824","0x265d7c","0x23dc","0x293407","0x23f064","0x19a633","0x281edf","0x4d4f","0x75bc","0x2fa430","0x2e6eff","0x2f378","0x2a276f","0x2f1e0c","0x17ab47","0x25bcdf","0x2658d8","0x2f9168","0x23679b","0x3182ab","0x29eae8","0x25c563","0x265d27","0x2e85b4","0x293420","0x28efac","0x3e0770","0x2ef2bb","0x1c70ff","0x2837bc","0x302c8b","0x18ce0b","0x49fcc7","0x1d6c7c","0x21f730","0x2effb4","0x31d99b","0x2e5a30","0x125f37","0x1fd8","0x283f9c","0x2e6f23","0x7314","0x2a2b00","0x1a1228","0x3c48","0x19fbaf","0x1fcb67","0x1fc497","0x2965d4","0x21fddc","0x25924f","0x25dba4","0x2594e4","0x259e43","0x214fdf","0x2274f4","0x29a2a8","0x2a3c60","0x17c5d7","0x1d6367","0x27e5cc","0x1d30","0x21fc7b","0x73f8","0x3e0758","0x2e5750","0x1bf9b7","0x14004b","0x28a673","0x2aa6c4","0x3e068c","0x2b2433","0x2840d0","0x2fa3a8","0x21fbf0","0x1f1f8","0x3ce4","0x266b0f","0x2f4887","0x139bd7","0x1c5b5b","0x2f9324","0x29fac8","0x4a6760","0x2e7aff","0x2e67f4","0x2f906c","0x2234f8","0x25c714","0x31d8cc","0x2a3707","0x292e3f","0x2838c0","0x281e10","0x1986f3","0x32302b","0x322904","0x19745f","0x21501f","0x614c","0x2f2937","0x43f4","0x2594f8","0x2ee050","0x2e6f97","0x150e43","0x29a570","0x48a148","0x1fb543","0x1fbe3f","0x3ef8","0x296638","0x2920f7","0x2936ac","0x3e24","0x2f912c","0x29a780","0x2bc8f0","0x2ef30c","0x281db3","0x6e80","0x2bab13","0x260f2b","0x27e69b","0x213334","0x2ef274","0x2840c0","0x2b2508","0x222e90","0x2efe80","0x270fc","0x25afa0","0x2eff67","0x4f6c","0x2b692f","0x2fa150","0x29c537","0x297f73","0x297bdc","0x2b22b3","0x281d68","0x2807c0","0x26d4b0","0x30e164","0x25c61f","0x2b94","0x25b947","0x3438","0x1405d4","0x1d62ff","0x1d6e3f","0x2ef294","0x1f9250","0x2f2623","0x305f4c","0x26a9c","0x280f33","0x12b8","0x3d60","0x1d6aeb","0x25bb40","0x285d64","0x6ba8","0x28da17","0x1dd2af","0x2aec7c","0x1a444c","0x33f4","0x29ee57","0x285d58","0x49fbf8","0x2e7127","0x2e85c4","0x29a70c","0x26c2a0","0x2931ac","0x1d6b4b","0x283b67","0x25a3e8","0x2eb70f","0x25b070","0x25bb50","0x3e0730","0x1c2217","0x2807dc","0x3e064c","0x295f2c","0x2e57e0","0x19d5f3","0x7474","0x23f06c","0x3e072c","0x2a54a0","0x297f9b","0x25a3dc","0x285b77","0x283f8c","0x49fbec","0x258e6b","0x2ea41f","0x2f2653","0x3df6b0","0x2945a7","0x2a4a54","0x181b3f","0x29d337","0x343c","0x2f0083","0x285d2c","0x21fc88","0x1d6c3c","0x221aa8","0x2a2e2c","0x2a3030","0x2a4a70","0x190028","0x283e83","0x1d6b97","0x1d69e4","0x292fb0","0x25af84","0x2ee3bf","0x3c74","0x29a704","0x2f1843","0x2ea7db","0x1779c","0x2a54b0","0x1824","0x2ea403","0x2e7abc","0x281d58","0x265a8f","0x2b1d8b","0x2f2ce3","0x352c","0x2838d4","0x23ee78","0x2298","0x25a1c0","0x266b7b","0x265b9f","0x2fa194","0x280788","0x29d0fc","0x21f4db","0x2a5550","0x25a1f4","0x290fa4","0x260eab","0x286ed7","0x2e0c5c","0x2c70","0x19dc1f","0x1c8ddf","0x1766c","0x19dc27","0x1c8e07","0x1c21cb","0x2d68","0x2cfdc4","0x292154","0x1884ff","0x2bf1b7","0x284eb3","0x6964","0x17eda3","0x31d853","0x29c3cb","0x290533","0x1d3e23","0x26db6c","0x2f553f","0x2efe28","0x2f9164","0x17f083","0x285bbc","0x2ef020","0x3854","0x31d1b7","0x214fcc","0x1d71f8","0x2bf9a3","0x15f8","0x290f9c","0x2b1d80","0x21a8ff","0x2a0c7c","0x2e711b","0x2599e4","0x2e0b44","0x2cbc","0x192928","0x28409c","0x2ee21c","0x150c08","0x265b40","0x2bac84","0x2f92ac","0x2be7","0x293fe3","0x2eedf8","0x284094","0x21f544","0x1d721c","0x2872c4","0x2e6fd4","0x28af13","0x2592c8","0x2a27f4","0x2bf967","0x2f584f","0x2ef44b","0x258fcc","0x2ea8cf","0x2599cc","0x2e84b4","0x2ea887","0x197563","0x296fcf","0x2e0924","0x2f1e20","0x297f78","0x21f417","0x21f718","0x227cfb","0x2ea71f","0x2e6990","0x2ea83b","0x2a3458","0x298b07","0x1f364","0x29ec50","0x4a6bfc","0x280a2c","0x25e314","0x5f98","0x1fb517","0x1fcaa7","0x1fc9a3","0x30f890","0x2595e4","0x29ea97","0x258de4","0x26dbc7","0x182557","0x1dd25f","0x288eb3","0x291b24","0x30e19c","0x2bfa3f","0x31198b","0x3e0337","0x4a6780","0x1f440","0x2a2aff","0x4a03bc","0x25bb64","0x2e6943","0x6f1c","0x2efc38","0x2747df","0x2749d7","0x2e7cec","0x241c","0x281ef0","0x223238","0x2a2ff4","0x265854","0x1d69c0","0x2f26f3","0x2e7df0","0x2a4a7c","0x296664","0x3041e4","0x2594fc","0x2ea7bc","0x2fa14f","0x2fa3f8","0x28071c","0x280874","0x265bd0","0x265c8c","0x23f068","0x285d90","0x1264df","0x2ea3e0","0x258ed8","0x41b0","0x150b73","0x2b8ef8","0x259c20","0x29d06c","0x188e37","0x1c5c43","0x2ea74b","0x2e691c","0x2f206c","0x2f3ea7","0x265888","0x2e6f98","0x18ae7c","0x265efc","0x3818","0x283fc3","0x3e0b08","0x25bd48","0x2a2fa4","0x285c8c","0x285cfc","0x21f7d4","0x2f9114","0x17a4","0x17c937","0x2ba6e7","0x2e7dec","0x285cf0","0x2edf14","0x280748","0x213c3c","0x2dec0f","0x4b7d9b","0x4e48","0x2274e8","0x292e70","0x22264c","0x2bf17b","0x1f9c58","0x259a84","0x2f7e97","0x17594","0x295b9c","0x19faff","0x31df94","0x2f3623","0x3df3e4","0x144c","0x1a0c0c","0x2cabd0","0x2e711c","0x1c21e7","0x1f500","0x222650","0x2fa238","0x2f92d8","0x2de9ef","0x31bd28","0x259690","0x1902fc","0x29331b","0x2872c3","0x27fae0","0x6e64","0x3868","0x2b6ad0","0x41d0","0x280778","0x48a0e0","0x15016b","0x2bdc24","0x1ecf7b","0x1ece9f","0x1ed9df","0x2b6b14","0x28089c","0x293678","0x2a2813","0x317128","0x2e9890","0x223234","0x258790","0x28ac04","0x1a81cf","0x2686e8","0x29a274","0x4388","0x2b5baf","0x693c","0x265ac7","0x2b6207","0x1f3f0","0x265db8","0x2695a7","0x274bd4","0x29cf48","0x2babeb","0x2b363c","0x2bf533","0x1f920b","0x1feb00","0x4da7","0x73fc","0x2e7b34","0x2f2c07","0x3884","0x4c0638","0x1838","0x2f3b67","0x2d6c3c","0x1790","0x2e715c","0x1d7228","0x222688","0x2658e8","0x2a54b8","0x242b","0x197ad7","0x2afbc3","0x25baec","0x31bf43","0x3220e3","0x2ef887","0x2ba863","0x2fdf17","0x2d51d7","0x2d6c60","0x2f7e8f","0x2a21a3","0x29ce5c","0x2b925b","0x2686c","0x14b373","0x20dc6c","0x1dd2f7","0x1c61a0","0x269b08","0x1d6f1f","0x137c53","0x2b9af4","0x17d4","0x2594dc","0x7744","0x13f703","0x2b1b03","0x23fe73","0x31d82c","0x4bfa68","0x3330","0x2a3008","0x29acc4","0x2fa418","0x1d6ffc","0x280a3c","0x268814","0x2ea6b8","0x29be9b","0x29ed98","0x30f818","0x25c1f3","0x25a4ec","0x29622c","0x31d590","0x30288f","0x30f89f","0x3e00cb","0x2efbc8","0x131c13","0x74b0","0x1fb138","0x24ac","0x2230f4","0x2be670","0x2fa494","0x1a098f","0x266c4b","0x22746b","0x259d2c","0x296040","0x2840c4","0x2b522f","0x4a04e4","0x2a37f3","0x26868","0x2e0968","0x2bdf3c","0x2effcf","0x1d4e4c","0x1c219c","0x25bad8","0x1e38","0x2a2020","0x25877c","0x19b93b","0x7550","0x1d7080","0x1d6e6c","0x2f2204","0x269593","0x2f38c","0x18a767","0x182637","0x3e07bc","0x29a244","0x2b64ab","0x31d8e3","0x31d804","0x180457","0x3170c0","0x2f5e80","0x2e0938","0x2a02ab","0x1d4ecc","0x4ba4","0x1d3767","0x265bd4","0x1326fb","0x26d4cc","0x19e35f","0x29abdb","0x2fa6a8","0x293490","0x2cfdbb","0x75a4","0x1d08f8","0x4f78","0x7758","0x1490","0x13ef97","0x2b61f0","0x25bc10","0x4b28","0x2596a8","0x372c","0x25c220","0x1f3c8","0x2f2940","0x2f10b4","0x265c20","0x25bc28","0x2803bb","0x26d92b","0x21ed90","0x17f72b","0x17a283","0x2e85f0","0x27f894","0x30e45f","0x30c124","0x1700","0x13bc","0x2f1e18","0x2b5094","0x3e0748","0x181913","0x22750c","0x19e2bb","0x29ac54","0x2b9354","0x131a44","0x2a3048","0x13eae7","0x2b9b90","0x30e194","0x2fa3ac","0x17a1bb","0x2ab848","0x21f3d4","0x2fa69c","0x21f420","0x1a2583","0x140177","0x2a33f8","0x2a4f48","0x17c4c7","0x1c5ca3","0x19e3eb","0x2fcaf8","0x2e0980","0x2ea76c","0x267103","0x26c3ef","0x17edb8","0x19d0ef","0x265870","0x1d4e98","0x3e0c","0x3df580","0x2a3014","0x1f51c","0x2ef244","0x259c18","0x2f2d60","0x13f878","0x29a214","0x21a9e3","0x3914","0x6948","0x305c7c","0x29635c","0x2f5abb","0x30f947","0x3e05a0","0x2961c4","0x2e698c","0x29cf43","0x2592d8","0x29a360","0x21f790","0x2f914c","0x2ba7a7","0x220ba8","0x29a77f","0x2eb434","0x3e0710","0x280780","0x26895b","0x2a4b47","0x296144","0x1f0803","0x295c24","0x14d964","0x1d6bf8","0x31d1e3","0x3e07c0","0x2e85d8","0x19e4df","0x25a0f3","0x298b0c","0x2bc8d8","0x1c8db8","0x2932b4","0x21f5b8","0x25a61c","0x2fa51c","0x284ec0","0x2eb468","0x30f80c","0x26682f","0x26c40b","0x25bb54","0x265f28","0x142818","0x292e44","0x2a5478","0x14014f","0x1d78c3","0x288fa0","0x2b27eb","0x1d3c08","0x1c2227","0x2932c3","0x6be4","0x21f520","0x317f5c","0x19777f","0x2a5574","0x1d6ca4","0x280a24","0x1c8e40","0x21a984","0x29611c","0x186be0","0x2f226c","0x2ea410","0x25bb2c","0x25c1a4","0x2e7b1c","0x1b516f","0x1b6deb","0x28abb3","0x2ea400","0x2a273c","0x2eefcc","0x2b63c7","0x1748","0x3e02b0","0x296384","0x3e0638","0x2e84b8","0x29367c","0x285d40","0x1a0904","0x1985df","0x2936b0","0x17628","0x1e9748","0x30eb88","0x287f38","0x268377","0x2e5780","0x2f5acc","0x285d48","0x2a625f","0x293223","0x1730","0x28d8","0x4d5c","0x295a28","0x13efa3","0x448960","0x2964e0","0x3e0138","0x2405e7","0x31e6e0","0x265f34","0x44e8","0x2f7e9c","0x265f30","0x6d64","0x68cc","0x176c8","0xb477","0x164f","0x174c","0x2f2174","0x2230d4","0x21f0ef","0x2e71ac","0x285ce4","0x269834","0x30f308","0x2b239f","0x27e5fb","0x2a620c","0x25bbb0","0x21f494","0x188577","0x2b67c3","0x2b939c","0x2fa450","0x223228","0x2fa3c4","0x31d86c","0x268538","0x1b6f97","0x25bc5f","0x3df6cc","0x259814","0x221afb","0x43f8","0x2837d0","0x2fa124","0x1c5c97","0x322187","0x2fa47c","0x2e7b0c","0x17a9bf","0x4a6bd4","0x214ff0","0x269818","0x29e75c","0x280173","0x2a2dcc","0x2b6a28","0x2f90a7","0x12b67b","0x49f7fc","0x2e97c8","0x2191cc","0x265bac","0x14936c","0x258dc4","0x1c2237","0x13f95f","0x2fdcdb","0x315f0f","0x4004","0x3e06d0","0x281d78","0x2807a4","0x4104","0x2e97a0","0x274530","0x2f82af","0x1358","0x2e97f0","0x27e5d0","0x2fa45c","0x2fa6b8","0x283fb0","0x3063f8","0x21f528","0x25c168","0x296fdc","0x295f98","0x3450","0x268358","0x29cec0","0x14275b","0x4489fc","0x2001ef","0x256f27","0x27cb38","0x281ea7","0x17b8","0x259e83","0x213ee0","0x265850","0x20efcc","0x297c00","0x3e06e8","0x2e7b44","0x1af157","0x2b582f","0x284ebc","0x1aef27","0x2b8ec8","0x1af19c","0x2b6200","0x2b641c","0x1aef28","0x370c","0x13ca93","0x2b6298","0x1aef74","0x147033","0x135d2b","0x4b4de0","0x219220","0x25ef84","0x2babc8","0x3290ec","0x4a6758","0x4ad153","0x23f07c","0x1b016f","0x31b914","0x1d6b74","0x234e4b","0x3824","0x5eb4","0x25b088","0x30f93c","0x21d293","0x2a54c0","0x2837e0","0x2eff2f","0x2966c4","0x2a38b8","0x6d38","0x2e716c","0x21a66c","0x29fae0","0x2318a4","0x3834","0x1b1007","0x2094a8","0x29ad04","0x29a8d0","0x26890","0x23ee08","0x198477","0x137e9b","0x2658f0","0x180307","0x4a69c4","0x1a7c1b","0x234e5c","0x1d6aff","0x1d6a34","0x2316dc","0x27e493","0x353c","0x2226a8","0x21a693","0x2a9ec0","0x447b","0x3c98","0x2963fc","0x19e74f","0x25bc73","0x287327","0x2a13a4","0x66fc","0x12c4bb","0x27cca0","0x29ced0","0x1f3daf","0x3171a8","0x29033f","0x177c7","0xc22f","0xdcaf","0x3377","0x1728","0x12b923","0x226d43","0x241778","0x2b5317","0x4b58","0x196f6b","0x2a5090","0x4504","0x2af9cb","0x268c90","0x2df54","0x281c58","0x2bf1fc","0x1910bb","0x2bf913","0x2bf678","0x285aa8","0x1a2d20","0x2921b0","0x280a4c","0x185b94","0x1f4c8","0x2b1ab4","0x29ba2f","0x3c10","0x2fa3e8","0x29a2e8","0x18c373","0x2945bc","0x29cfc7","0x29b714","0x18240b","0x29d444","0x259284","0x29a300","0x2e09a8","0x25c68c","0x4c0444","0x21eb67","0x4098","0x21f4cc","0x25925b","0x2eb2cb","0x1320","0x2930e4","0x267e94","0x1b014b","0x1d047b","0x21d167","0x28075c","0x14f8","0x1d62d0","0x26896f","0x274aa0","0x184c4c","0x2b03f0","0x2670a3","0x2a1a53","0xacdb","0x1fbef","0xad9f","0x4538","0x6ef8","0x176a4","0x26888","0x2f05c8","0x2c040f","0x2683c","0x293198","0x2bf13c","0x2a354c","0x25a39c","0x2f3e7f","0x4d80","0x236764","0x2ea78b","0x19dc4b","0x29af5b","0x1510e4","0x2b545f","0x3c40","0x2cb6ec","0x2cff53","0x38c0","0x29ed34","0x297fab","0x1f4b0","0x4a04a8","0x6120","0x2fdd77","0x2e49bf","0x1c8e64","0x1d70c8","0x17a303","0x259c04","0x2a4848","0x2f576f","0x30a8a8","0x2f49b0","0x1b4147","0x1cd5dc","0x1f3a8","0x2f1e24","0x2bf528","0x738c","0x3f94","0x1fc97f","0x1fc743","0x1c8d00","0x2f30bf","0x308780","0x29a484","0x269aeb","0x26d4c8","0x2fdc03","0x301a7c","0x295fc8","0x61eb","0x6b8c","0x25950c","0x2fa484","0x2b6320","0x2ea8a7","0x285adc","0x2e70bc","0x25a0d0","0x285d30","0x1d6940","0x2e0930","0x29301c","0x2e7170","0x265bbc","0x2e7184","0x2efbd0","0x150ac0","0x2e7783","0x2e3748","0x1c224f","0x2b1dc7","0x21f10f","0x4c0474","0x259c1c","0x2963ef","0x2a3428","0x4eb4","0x755c","0x223244","0x1c8d4f","0x2e6974","0x2b5418","0x2969b8","0x19f0eb","0x29a29c","0x29ead4","0x2e85e4","0x2f5657","0x2efe50","0x1d764f","0x7448","0x2bf4ef","0x1d6a3c","0x2ea774","0x2e688c","0x2a3894","0x2911d0","0x29f49f","0x3730","0x29cf64","0x2f9178","0x1b1183","0x1efa5c","0x1d6e97","0x1d7238","0x2a4b20","0x2ee170","0x28ae5f","0x151f84","0x2a2fdc","0x2a9eb0","0x25bbe8","0x1d44fc","0x2694b8","0x2b9240","0x21ec48","0x292110","0x2a5098","0x12c43b","0x1302ab","0x2a2000","0x281e48","0x17a547","0x2efedc","0x2e4183","0x275a08","0x2a3424","0x268a27","0x29a48c","0x1d6b5f","0x1566e3","0x156bb8","0x197e6b","0x19c474","0x280a44","0x293444","0x151454","0x7570","0x25ae5c","0x5d34","0x18fe30","0x26a08c","0x2840cc","0x13f373","0x18938f","0x2e7ae0","0x29ee13","0x2cabf4","0x2840b4","0x2f48c4","0x2e7cd4","0x1a0834","0x1fc4af","0x2f1df8","0x25a174","0x2a3b23","0x297d40","0x19edf0","0x2f00bc","0x259808","0x265e20","0x30f8c0","0x2f57d3","0x2ef3c4","0x1883f7","0x260f37","0x1f9c40","0x268930","0x2a3058","0x604c","0x2bfa53","0x2bfb04","0x7694","0x2c048b","0x213b5f","0x2a6868","0x19f29b","0x6b08","0x5ec4","0x3e02c3","0x3dee53","0x29bc37","0x2a53bb","0x2a4ad8","0x5d10","0x281d80","0x188333","0x1d260b","0x283b38","0x293128","0x2b546f","0x4ad0f8","0x29d048","0x1f16c","0x259a20","0x66f0","0x2dea98","0x281e54","0x220c93","0x19d283","0x29a0f8","0x1860af","0x21a657","0x1807c7","0x176d4","0x2ea448","0x2e6988","0x2234f0","0x2592d0","0x2b4278","0x25a600","0x285b04","0x2eefd3","0x2eec94","0x771c","0x2c3c","0x17a7a7","0x28e5d7","0x28eb53","0x1d6918","0x2264","0x2e6fd0","0x2f834c","0x2001dc","0x2cfd54","0x2eecd4","0x2f2090","0x2ea84b","0x274554","0x2b1ee7","0x2eec70","0x19ad2f","0x2e0940","0x28c870","0x2cab78","0x2aa0f0","0x62d4","0x259250","0x2bdd14","0x2baca4","0x4b30","0x6264","0x2e92b0","0x26db24","0x18cc17","0x26dd24","0x20f010","0x1ca8","0x17a337","0x29cce8","0x221b2f","0x27e5a7","0x2fa3c8","0x3e070c","0x1d0c70","0x29342c","0x2ea8a8","0x2f36a7","0x30f31c","0x2930c4","0x2b5123","0x23edbc","0x21fd24","0x287eb8","0x18a8e4","0x5f94","0x2bac8c","0x18b2f7","0x27c707","0x23691f","0x3028c0","0x1bc4","0x2e6828","0x26d448","0x198713","0x1f2290","0x29cef8","0x26d4d8","0x17edb7","0x25bbcc","0x2b20fc","0x285ab8","0x25edd7","0x2cfd23","0x267f84","0x2cfd14","0x7424","0x283ea0","0x31c083","0x31f503","0x2ef844","0x2e6fb8","0x25c11b","0x25e2fc","0x267bf4","0x27faec","0x15716f","0x288f84","0x29ebb4","0x15690b","0x2962c0","0x304354","0x2933d0","0x2fddf7","0x329744","0x1fca10","0x1f38c","0x1ec8","0x2d4e44","0x266ca3","0x25a4ac","0x6440","0x26815f","0x3d77","0x2df28","0x17fc07","0x30d53c","0x3028b8","0x21a6ac","0x6250","0x1b6bcf","0x22d7d0","0x2e71bc","0x265b1c","0x1f1c4","0x26597c","0x25c778","0x1c8d98","0x281a80","0x258a9b","0x214fb8","0x292ff0","0x7320","0x222e58","0x2a2e7c","0x1d6d10","0x2a3ac7","0x49f7b4","0x259b38","0x1318d7","0x39ac","0x2ea948","0x21f75c","0x295e70","0x411b","0x30aa77","0x21f5e4","0x1510e8","0x2b279b","0x2b412c","0x1a2a64","0x2f1880","0x2b036c","0x1d68f8","0x2921a0","0x1a6c8f","0x1a76ec","0x2f3533","0x19fc37","0x1d3bdc","0x1d70b4","0x2b370b","0x281404","0x1930","0x2595f8","0x259d38","0x285b90","0x21d248","0x2e9744","0x13f8d0","0x227c","0x63fc","0x1d6998","0x5d4c","0x280a08","0x285d28","0x2a53a7","0x5403","0x7137","0x151500","0x2801cc","0x2a16d8","0x2e7174","0x259118","0x2de943","0x448a28","0x1f91bf","0x2a2f80","0x259514","0x19ed10","0x2b6a0c","0x2f00f8","0x1d6990","0x126b03","0x2e5728","0x1c8e18","0x29a268","0x1fca0b","0x29ec2c","0x21a6bc","0x25c16c","0x148f84","0x6b64","0x4a6be0","0x29211b","0x13f0bc","0x2e0b24","0x2ef270","0x29a50c","0x2b204f","0x2904f8","0x29ceec","0x22744b","0x27cbd8","0x21f4cb","0x292f28","0x2faee4","0x2a25df","0x17abc7","0x2bec28","0x7594","0x29c7dc","0x31d838","0x13f0c0","0x29e1ec","0x156f57","0x30da0c","0x15430b","0x31b8b8","0x258fbc","0x1a16eb","0x295ff0","0x285cac","0x2f9158","0x265c24","0x30d810","0x265a30","0x2ee180","0x267efc","0x31d824","0x280770","0x2f485c","0x4bfa38","0x26d49c","0x2c8b33","0x2494","0x2962c8","0x19e614","0x6dd4","0x2ededc","0x2fa50c","0x2efee4","0x259d78","0x311dd3","0x30b937","0x4adce8","0x266797","0x29af04","0x1d7728","0x3e06f0","0x2fa6e4","0x185048","0x151123","0x2a2fac","0x31b924","0x2b42ff","0x289d38","0x1318d8","0x347c","0x25a178","0x2debf4","0x2f579c","0x29b0c0","0x17bddb","0x1b0387","0x2071b0","0x2840c8","0x283b2c","0x20efe0","0x2fa48c","0x1aef7c","0x4b90","0x297fac","0x3e0744","0x26887c","0x1a19eb","0x28ac53","0x1a7ddc","0x2934e4","0x2a3064","0x2e7b18","0x26af4","0x2a2263","0x298524","0x26683f","0x2e6894","0x2f18c4","0x21f3a0","0x2fadb4","0x2f4198","0x2f7e84","0x2a5358","0x259bdc","0x21fc6c","0x21d134","0x2e97e8","0x296054","0x31d578","0x1e9698","0x2ee2bc","0x2e7774","0x259a68","0x2681ac","0x259f98","0x1508","0x29a2f4","0x305a93","0x3e067c","0x19d06b","0x1b111b","0x31b95f","0x326b74","0x285ba8","0x387c","0x2efc68","0x4a6708","0x274bf8","0x12b5af","0x241493","0x448868","0x293100","0x2ee14c","0x2efc6c","0x2f1838","0x2eb2ab","0x4b4e50","0x2fdf3f","0x23c364","0x2e570c","0x28af2b","0x4b4f37","0x268600","0x297fbc","0x29b66c","0x43ec","0x1975e0","0x260900","0x29a314","0x29a328","0x17bd6f","0x2fd897","0x2ecc53","0x296a4c","0x27cc04","0x18ac07","0x4a67c0","0x1b7003","0x19599f","0x180a37","0x25a368","0x1265fb","0x2a4d7f","0x1fb758","0x1a0bf4","0x28fde3","0x1d6cf4","0x1a150b","0x1d7a44","0x280ef0","0x2bfd88","0x311307","0x322c8f","0x280f60","0x1d7693","0x297f7f","0x1a620f","0x2bdcfb","0x317ec0","0x29da47","0x28d293","0x2458","0x1878e8","0x25aed8","0x22bc","0x27fbbc","0x2debe8","0x2ea6b4","0x256f2c","0x2ea438","0x2961ac","0x2ba60c","0x30e464","0x1d4e3c","0x1d6390","0x2fa3a4","0x17e0","0x21f680","0x30f8d4","0x2e7190","0x29ab47","0x281eec","0x417c","0x199237","0x30fc23","0x3115df","0x1d7068","0x21f19c","0x150f24","0x2b6374","0x297c07","0x25a1b4","0x31d8ab","0x30c130","0x2840b8","0x28a51f","0x2b53cf","0x21d603","0x2d1c","0x29eaf8","0x258f78","0x25bcd0","0x29e2b3","0x2a343c","0x184a14","0x2eec80","0x189253","0x2b0397","0x235510","0x2c8be0","0x2191dc","0x265c0c","0x2f9344","0x29ec38","0x2e6814","0x265bf4","0x5f90","0x45a0","0x2f41ab","0x30f287","0x30d0a4","0x2e084c","0x2eff44","0x258f48","0x2683c4","0x31ec13","0x2ea8ec","0x2a4913","0x29b53c","0x1306b7","0x2930c0","0x1d2ab0","0x25d883","0x25d918","0x6c68","0x287ebc","0x27fcb3","0x2a01eb","0x6134","0x18a2a3","0x3dec00","0x2cfd90","0x19e647","0x2a3470","0x607c","0x19ee9f","0x4a6a0c","0x2efc58","0x1fcf90","0x13fac7","0x156d5f","0x157230","0x2838e0","0x1af5d3","0x2b73a7","0x2fd020","0x258cbb","0x2d14","0x25a378","0x2e0b4c","0x1c8d77","0x1d6b6c","0x1a22f4","0x2e7aec","0x1d7130","0x23f19c","0x3e0144","0x2bad80","0x4b2c","0x2f20e0","0x287f18","0x29b798","0x2fe4","0x18abd7","0x2ee198","0x152c73","0x238c","0x148c","0x2f0158","0x265ccf","0x29afab","0x1360","0x29ec54","0x1834","0x259840","0x1c8e38","0x4d04","0x280858","0x284ec8","0x2b65c7","0x2b9ec8","0x4b4dd0","0x1aef10","0x3ded98","0x259b0b","0x292db8","0x2a54fc","0x3df47c","0x2a3a7c","0x1322db","0x28ce14","0x259b48","0x2b4448","0x2920f8","0x1d4e8c","0x1d4f24","0x258810","0x14d4","0x1278","0x20ef68","0x2f1e14","0x30d99c","0x2b6ab0","0x2a16d7","0x3e0688","0x3ded40","0x2ae57b","0x277514","0x2af998","0x30287c","0x221b08","0x2a54d8","0x29dc","0x2e0aac","0x31809f","0x315393","0x3153af","0x25a3c4","0x1d3754","0x2b4233","0x21f168","0x281b48","0x3df48c","0x1514d8","0x2f25b0","0x1f4f0","0x2f0863","0x25892c","0x21922c","0x17a09f","0x1c24a4","0x2f1de0","0x1d63c8","0x4adcb0","0x151f53","0x2bf243","0x1f9444","0x265d40","0x23196c","0x2aa0c7","0x222be3","0x5ce8","0x29b6a4","0x21a97c","0x2be67c","0x129f17","0x1314","0x2a9eb8","0x151063","0x25b07c","0x4bfa80","0x1d2abb","0x1d0d8c","0x2effd0","0x2b2300","0xacdc","0x4adcf8","0x29c670","0x2cfcdc","0x2e0990","0x12480","0x1750","0x259967","0x2deaa0","0x302c0b","0x4a0344","0x2cfd74","0x25a1e0","0x269aec","0x1c8d97","0x265894","0x30a9b7","0x3e0190","0x297033","0x30f8c8","0x25e594","0x17a847","0x25af24","0x21fe28","0x7394","0x311313","0x2d48","0x2a2e68","0x28e54f","0x3d04","0x28c7d0","0x19275b","0x7488","0x265a3c","0x3714","0x2362b0","0x2005a4","0x2bb017","0x1759c","0x28f15b","0x2b6930","0x256f20","0x241837","0x23c3a3","0x4b4f67","0x1310","0x2933f3","0x2b41f7","0x2315b3","0x29cf1c","0x23b2cf","0x23bfab","0x287288","0x2840d8","0x1ce0","0x2e84a4","0x4a03a4","0x2c1c","0x1d770f","0x31d213","0x28fa24","0x2840bc","0x2e7178","0x297c08","0x2a3474","0x1e96d4","0x15285b","0x2e85c8","0x2f4874","0x6484","0x213c57","0x4b532f","0x2a4f80","0x222bbc","0x29a6ec","0x1f98e3","0x1a6d63","0x259a1c","0x25eeb7","0x1f36ac","0x25bb88","0x275a34","0x25bb3c","0x2a23eb","0x29643c","0x26dc30","0x297be3","0x29e4d0","0x41f0","0x296290","0x1b115c","0x29a6e0","0x2c8bf8","0x2ef284","0x19fe27","0x1a9417","0x259990","0x2e681c","0x150f0c","0x2fa1a8","0x1970a7","0x2a505c","0x3019d7","0x280f20","0x29ff57","0x26588c","0x2fdefb","0x2e785f","0x2e60bb","0x634c","0x2bf867","0x2fa480","0x31833b","0x31e370","0x1eec","0x2cb6dc","0x2837b0","0x3028a4","0x29eda0","0x310d44","0x285b1c","0x3d48","0x26881f","0x26d44c","0x152984","0x302894","0x2edfc3","0x2a357c","0x29c3a8","0x2920c4","0x18565c","0x2cb320","0x293164","0x3df45c","0x1a0bec","0x29cf6c","0x2191d4","0x265b90","0x2fa458","0x2fa6d4","0x2e07e0","0x2a5088","0x3066f0","0x2efdc8","0x2921a8","0x1550","0x2f2d53","0x30871b","0x2bfea0","0x306323","0x2a22d4","0x2f1dd0","0x4a659c","0x25b933","0x2ea730","0x2b203b","0x1c2207","0x1f220","0x265c44","0x200208","0x26db28","0x190963","0x322193","0x322c53","0x322973","0x2a3978","0x1d6bec","0x14b3c3","0x1e878c","0x2a0d4c","0x1c5bc0","0x12c0","0x2a2900","0x296c30","0x268343","0x1c10","0x1d79cb","0x289127","0x291c48","0x1d700c","0x1d4f93","0x268588","0x4404","0x2ea830","0x30f293","0x175e8","0x7418","0x322bf3","0x23f17c","0x21fcf8","0x2747bc","0x17c604","0x1f3b8","0x3720","0x2a1fe8","0x2f92d4","0x1ecf5b","0x19e570","0x4a6efc","0x269ad4","0x2e788b","0x2d51e7","0x21f74c","0x2f2b8f","0x3089e4","0x30e1c0","0x4489a4","0x29a340","0x2ba388","0x1d7134","0x2b274b","0x2b41b8","0x2a4b08","0x293120","0x26dd48","0x31d89b","0x259be8","0x29e5f8","0x1ecf98","0x189367","0x2d6c38","0x2efefc","0x1d4f84","0x1a1eb3","0x1d3950","0x6e88","0x1a2d00","0x293680","0x18816b","0x259504","0x26894","0x2fa43c","0x1f238","0x29b720","0x2f4990","0x30e4a8","0x19da43","0x2ef2b0","0x25a360","0x27fb20","0x2e7b10","0x2f9134","0x2b6a18","0x2cb0","0x2314f8","0x2963b8","0x19a977","0x265a5c","0x26d3f4","0x2b212f","0x1d7700","0x21ecef","0x38d8","0x17f46f","0x28fa9b","0x4c0468","0x1f118","0x2fa474","0x2ba370","0x2e97ac","0x280fbc","0x269ae8","0x2a2160","0x2a5094","0x258d88","0x3df2d4","0x156bab","0x1497d4","0x29aea4","0x2e97ff","0x293168","0x2fa188","0x1d6cb4","0x21f724","0x2a233b","0x1d08e4","0x216b18","0x1ecf4f","0x1ed8fb","0x1ed87c","0x1b44","0x153a18","0x19e637","0x1498d0","0x1c6c48","0x2a2524","0x2a5060","0x1a0f3f","0x2b8ee0","0x29a7b8","0x26955c","0x259970","0x1a6a28","0x259e50","0x2a4bdc","0x2cfd87","0x7754","0x2a051f","0x1f3d8","0x259be4","0x690c","0x2bf7ac","0x150a1c","0x29be73","0x25bbe0","0x29ba28","0x2b92a8","0x1d206f","0x1d2b74","0x48a0ec","0x222e7c","0x2bad88","0x21d2a0","0x2ee17c","0x2face0","0x3e0178","0x1d2fbc","0x295a80","0x19d293","0x29a0d4","0x25891f","0x30f7d8","0x31bd13","0x31f96b","0x2ef8bb","0x2f2643","0x3df6bc","0x25c0b0","0x29eb34","0x2a29bb","0x3226b8","0x268c3c","0x267dc7","0x29a2bc","0x6940","0x2592b4","0x2d000f","0x2592fc","0x1d63b0","0x2001f0","0x1a75df","0x2bd58f","0x2a2e78","0x4c14","0x18809f","0x26802c","0x29c83f","0x2904a7","0x2e7028","0x2a5544","0x33ec","0x25c6f0","0x19580f","0x2fcb88","0x25925c","0x2a5303","0x292140","0x311424","0x31d990","0x2931ec","0x25c150","0x1814","0x2a4cef","0x29a260","0x1d6b2c","0x27453c","0x1d3e67","0x25a200","0x2b36a3","0x28717b","0x281630","0x214f0b","0x26850c","0x1b8a68","0x12a8","0x1644","0x268bc8","0x4d78","0x19773b","0x1c6c1c","0x1d7004","0x2e7068","0x1ffc","0x2354f0","0x29368c","0x2934d4","0x2cac00","0x232cc0","0x150f38","0x4e84","0x258eec","0x181b23","0x265868","0x1764","0x297c04","0x2efc90","0x17dc","0x16c0","0x17ca57","0x2b03d0","0x209567","0x28adf8","0x281d9c","0x268b00","0x2e84c8","0x2a6194","0x150ee0","0x2e0a4c","0x19691b","0x29a0bc","0x25b9e0","0x4418","0x1a16ec","0x28a4a7","0x25f8d7","0x19c6db","0x2b936c","0x3df478","0x269554","0x1d7224","0x2fa454","0x2ea714","0x2a25e0","0x19fdb0","0x25a440","0x297fc0","0x30d7c8","0x19b997","0x25995c","0x2f4968","0x4cb8","0x1af264","0x15146f","0x2e9818","0x2a48c0","0x29f8ac","0x2bcf94","0x1291a7","0x2b656b","0x2b9f58","0x2bf6b8","0x1a0bd0","0x25bfaf","0x258bd0","0x17d8","0x178cd0","0x26dd03","0x269ae0","0x1d63cc","0x25b098","0x298a6c","0x2a2f5c","0x2f9068","0x274564","0x265c04","0x297f48","0x29fbcb","0x28d7b7","0x1c61c8","0x25c2bf","0x2a2660","0x200604","0x1ba0","0x1b2bef","0x289f97","0x2932f0","0x15233b","0x4a670c","0x29cfb8","0x12c4","0x2e0a40","0x4578","0x3e0210","0x3eac","0x292d80","0x2b6338","0x182000","0x29a798","0x25a1fc","0x317138","0x3428","0x1a1e13","0x293518","0x2debd0","0x1f12c","0x297d4c","0x2414","0x2963c8","0x2a4d54","0x29ee7c","0x17ec18","0x28f078","0x271e4","0x283fa0","0x3df678","0x287f08","0x30da34","0x2f98ac","0x1514e8","0x27fac4","0x29218c","0x28e28c","0x2eee00","0x1af59b","0x31ba84","0x5fa8","0x25c180","0x14cc8b","0x1cca34","0x30f948","0x3e00e4","0x2319db","0x15143f","0x1d76b4","0x2e7158","0x19c87c","0x27224","0x19a153","0x267c47","0x152080","0x2936a4","0x289767","0x31d89c","0x281d70","0x1a83c8","0x150fb8","0x26880c","0x29b71f","0x2eb42c","0x2b9338","0x15157f","0x1d3924","0x1d7214","0x2a21ef","0x1d6d08","0x1c8c","0x2aa143","0x29ed84","0x3df488","0x2a2b23","0x280854","0x1f544","0x2faed8","0x2ba8fb","0x2b47d3","0x1d4f64","0x28ef9c","0x2e09bc","0x22ec","0x29ad40","0x2bfd78","0x2e6898","0x1d63c0","0x12679f","0x151508","0x1d4e58","0x4314","0x292da4","0x317f00","0x20014b","0x184180","0x2a39c0","0x2658ec","0x2964b8","0x2effa3","0x1f244","0x1e34","0x265b38","0x31d900","0x2f1df0","0x1a169c","0x14da2b","0x1f1f7","0x1b60","0x1a70e3","0x2b8fbc","0x19c6a7","0x2a2e40","0x3e0778","0x2e09f4","0x26d4e4","0x1d7220","0x6058","0x297bf7","0x258818","0x1fb1d7","0x1fcedb","0x1f9327","0x14902b","0x2b9dfc","0x1d63d0","0x322c70","0x2f829b","0x3e0158","0x2faebc","0x234e08","0x2fad78","0x1a858","0x198fdb","0x28fbd7","0x302247","0x2e7cf4","0x2baf2b","0x2bad94","0x6c2c","0x156d23","0x4b4e58","0x2684b0","0x2ea7dc","0x292f88","0x21f5fc","0x29a36c","0x1907fb","0x2bdffc","0x21f76c","0x19edd3","0x1d3c10","0x1842ab","0x2bcfa0","0x2961c8","0x180b70","0x20efe8","0x448954","0x25af88","0x19faab","0x1dd25c","0x1fb270","0x2a22f0","0x219438","0x2b36ab","0x2870f7","0x2811bf","0x28d25b","0x2abb94","0x1fb7a3","0x1fceff","0x1f51f0","0x292d90","0x13ccfc","0x222658","0x23f174","0x3df49c","0x29e508","0x285d80","0x29fe47","0x2a0684","0x1b08ef","0x2bcee4","0x226d2f","0x32a728","0x198468","0x26c2a4","0x26840","0x292e1c","0x25c208","0x21f518","0x265a6c","0x258f04","0x21f530","0x4a04d4","0x2fa40c","0x25e618","0x2b4788","0x2a4bfb","0x2e0a7c","0x281b30","0x151137","0x25bc67","0x25d91c","0x28d2cf","0x1d3e24","0x27d6cc","0x2b628c","0x29c967","0x297e4c","0x1a7797","0x1d5627","0x1f2988","0x29be27","0x1354","0x30192f","0x12a567","0x13053b","0x1b479f","0x1bc9c0","0x29626f","0x13f8a0","0x260f63","0x1f4aef","0x24d5a0","0x1e8ba0","0x4a03b4","0x216084","0x18cf37","0x6b177","0x88b93","0x86537","0x1e5db","0x24648","0x6b79b","0x679eb","0x66c77","0x17d67","0x115f8","0x151e7","0x1849f","0x10a0f","0x111e7","0x37f57","0x321d4","0x17c88","0x1523b","0x10838","0x15203","0x18523","0x6368","0x1805f","0x31787","0x6b94","0x6bd4","0x18053","0x17b1c","0x111d7","0x1852b","0x111bf","0x10827","0x18083","0x10a4b","0x14ca0","0x37f8b","0x32118","0x184ef","0x18513","0x321b4","0x10a33","0x11194","0x32277","0x7614","0x18503","0x3214b","0x151fb","0x37f7f","0x2fb4c","0x17fa7","0x1f478","0x11180","0x17c9b","0x1526f","0x111c4","0x109fc","0x6c74","0x10a23","0x10837","0x180cc","0x17caf","0x6bb8","0x1802b","0x316c4","0x10813","0x17f77","0x6b68","0x17f8b","0x6a0c","0x111ac","0x17fcb","0x316e4","0x32110","0xac58","0x4db0","0x1525f","0x184f0","0x111b8","0x17c54","0x7714","0x111f7","0x1337f","0x3792b","0x31be7","0x7650","0x1fba7","0xf20","0x10a43","0x10814","0x124b8","0x1f2b0","0x17c9c","0x111cb","0x14cac","0x111d0","0x18478","0x184dc","0x37f00","0x3228c","0x17c90","0x6794","0x15217","0x3178c","0x1f604","0x3015f","0x30143","0x2ffc0","0x10a10","0x1f4a4","0x1cec","0x37f73","0x2ff64","0x32100","0x2fb60","0x6268","0x2ff80","0x14ccc","0x6384","0x17faf","0x10ed4","0x321e0","0x654b","0xd11b","0x14cb4","0x63cf","0x2c613","0x5e24","0x151ec","0x316f0","0x2fb78","0x378ec","0x1844c","0x6597","0xd288","0x32188","0x1529c","0x1120c","0x151fc","0x4ec0","0x15234","0x18434","0x3223f","0x638c","0x1ccc","0x18504","0x10800","0x17feb","0x51db","0xe2df","0x6bc8","0x6394","0x30153","0xd238","0xd050","0x3214c","0x66e7","0x4cac","0x668f","0xd593","0x4ed4","0x37f74","0x180f0","0x6434","0xd3fc","0x32288","0x15af4","0x10ef0","0xd0ec","0x1f490","0x2ffac","0x17f94","0x17b8c","0x1f428","0x72e4","0x10834","0x5d28","0x6e48","0x2ffb8","0x6960","0x18524","0x37f68","0x7284","0x4f94","0x18458","0x1f2f4","0x17cc0","0x300b8","0x4f88","0x37907","0x31a60","0x3165b","0x30144","0x60c8","0x6c60","0x17790","0x339c","0x2f350","0x31600","0x37f94","0x18510","0x7324","0x18518","0x7740","0x3174f","0x2c6b8","0x320f0","0xd444","0x37f64","0x10854","0x4ed8","0x37f9c","0x10820","0x773c","0x32124","0x17514","0x1f2c0","0x18440","0x4f5b","0x1a423","0x6924","0x764c","0x63cc","0xd4c0","0x69b8","0x7334","0x66c9b","0xc0f4"],"tid":5970075,"unregisterTime":13416.374542}],"pages":[],"profilerOverhead":[],"counters":[]} \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 4a88654b..052d5a33 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -89,6 +89,10 @@ struct Args { /// then ends the program #[clap(long)] pub debug: bool, + + /// Max stack depth to evaluate to + #[clap(long, short, default_value = "200")] + pub max_stack_depth: usize, } pub fn subscriber() { @@ -201,6 +205,7 @@ fn main() { }, }; let mut analyzer = Analyzer::default(); + analyzer.max_depth = args.max_stack_depth; analyzer.root = Root::RemappingsDirectory(env::current_dir().unwrap()); let (current_path, sol) = if args.path.ends_with(".sol") { diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index a007ab3a..d8d2060b 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -65,9 +65,9 @@ pub enum Node { /// The entry node in the graph Entry, /// A source unit (i.e. a source file) - SourceUnit(usize), + SourceUnit(SourceUnit), /// A subcomponent of the source unit - SourceUnitPart(usize, usize), + SourceUnitPart(SourceUnitPart), /// A contract Contract(Contract), /// A solidity-based function diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index 9f90d80c..e684e48e 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -231,23 +231,19 @@ impl Builtin { Builtin::Uint(_) => SolcRange::from(Concrete::from(U256::from(0))), Builtin::Bytes(s) => SolcRange::from(Concrete::Bytes(*s, H256::zero())), Builtin::DynamicBytes | Builtin::Array(_) | Builtin::Mapping(_, _) => { - let zero = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::zero())), - val: Default::default(), - loc: Loc::Implicit, - })); + let zero = Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::zero())), + Default::default(), + Loc::Implicit, + ))); Some(SolcRange::new(zero.clone(), zero, vec![])) } Builtin::SizedArray(s, _) => { - let sized = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })); + let sized = Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(*s)), + Default::default(), + Loc::Implicit, + ))); Some(SolcRange::new(sized.clone(), sized, vec![])) } Builtin::Rational | Builtin::Func(_, _) => None, diff --git a/crates/graph/src/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs index cbd2b5ce..0bf8987c 100644 --- a/crates/graph/src/nodes/context/context_tys.rs +++ b/crates/graph/src/nodes/context/context_tys.rs @@ -1,4 +1,4 @@ -use crate::nodes::{ContextNode, ContextVarNode, ContractNode, FunctionNode}; +use crate::nodes::{ContextNode, ContextVarNode, ContractNode, FunctionNode, StructNode}; use shared::NodeIdx; use solang_parser::pt::Loc; @@ -75,6 +75,8 @@ pub struct ContextCache { pub vars: BTreeMap, /// Visible functions from this context pub visible_funcs: Option>, + /// Visible structs from this context + pub visible_structs: Option>, /// First ancestor of this context pub first_ancestor: Option, /// Associated source of this context diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index b2f9f018..b53c7f76 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -1,9 +1,9 @@ use crate::{ - nodes::{ContextNode, ContractNode, FunctionNode, StructNode}, + nodes::{ContextNode, ContractNode, FunctionNode, StructNode, SourceUnitNode, SourceUnitPartNode}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, }; -use shared::{NodeIdx, Search}; +use shared::Search; use std::collections::{BTreeMap, BTreeSet}; impl ContextNode { @@ -32,16 +32,16 @@ impl ContextNode { pub fn maybe_associated_source( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Option { + ) -> Option { let context = self.underlying(analyzer).unwrap(); if let Some(src) = context.cache.associated_source { - Some(src) + Some(src.into()) } else if let Some(parent_ctx) = context.parent_ctx { let src = parent_ctx.maybe_associated_source(analyzer)?; self.underlying_mut(analyzer) .unwrap() .cache - .associated_source = Some(src); + .associated_source = Some(src.into()); Some(src) } else { let func = self.associated_fn(analyzer).unwrap(); @@ -53,7 +53,7 @@ impl ContextNode { pub fn associated_source_unit_part( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + ) -> Result { if let Some(sup) = self .associated_fn(analyzer)? .maybe_associated_source_unit_part(analyzer) @@ -82,7 +82,7 @@ impl ContextNode { // extend with free floating functions modifiers.extend( analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) + .search_children_depth(source.into(), &Edge::Modifier, 1, 0) .into_iter() .map(FunctionNode::from) .collect::>(), @@ -131,7 +131,7 @@ impl ContextNode { )); }; Ok(analyzer - .search_children_depth(source, &Edge::Modifier, 1, 0) + .search_children_depth(source.into(), &Edge::Modifier, 1, 0) .into_iter() .map(FunctionNode::from) .collect::>()) @@ -195,7 +195,7 @@ impl ContextNode { }; analyzer .search_children_exclude_via( - source, + source.into(), &Edge::Func, &[ Edge::Context(ContextEdge::Context), @@ -211,17 +211,27 @@ impl ContextNode { pub fn visible_structs( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Vec { + ) -> Result, GraphError> { // TODO: filter privates + if let Some(vis) = &self.underlying(analyzer)?.cache.visible_structs { + return Ok(vis.clone()); + } + let Some(source) = self.maybe_associated_source(analyzer) else { - return vec![]; + return Ok(vec![]); }; - analyzer - .search_children_exclude_via(source, &Edge::Struct, &[Edge::Func]) - .into_iter() - .map(StructNode::from) - .collect::>() + let mut structs = source.visible_structs(analyzer)?; + let contract = self.associated_contract(analyzer)?; + structs.extend( + contract.visible_structs(analyzer) + ); + + structs.sort(); + structs.dedup(); + + self.underlying_mut(analyzer)?.cache.visible_structs = Some(structs.clone()); + Ok(structs) } /// Gets the associated function for the context diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 130d3609..fe558686 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,7 +1,9 @@ +use crate::SolcRange; +use std::borrow::Cow; use crate::{ as_dot_str, nodes::{ContextNode, ContextVarNode}, - range::{elem::RangeOp, RangeEval}, + range::{Range, elem::RangeOp, RangeEval}, solvers::{ dl::{DLSolver, SolveStatus}, Atomize, SolverAtom, @@ -37,9 +39,9 @@ impl ContextNode { dep.display_name(analyzer).unwrap() ); } - let r = range.into_flattened_range(analyzer)?; + let r: Cow<'_, SolcRange> = range.flattened_range(analyzer)?; // println!("dep {} range: [{}, {}]", dep.display_name(analyzer).unwrap(), r.min, r.max); - ranges.insert(*dep, r); + ranges.insert(*dep, r.into_owned()); Ok(()) })?; @@ -85,17 +87,22 @@ impl ContextNode { dep.is_controllable(analyzer)? ); if dep.is_controllable(analyzer)? { - let range = dep.ref_range(analyzer)?.unwrap(); - let r = range.into_flattened_range(analyzer)?; - let underlying = self.underlying_mut(analyzer)?; - if !underlying.ctx_deps.contains(&dep) { + // let underlying = self.underlying_mut(analyzer)?; + if !self.underlying(analyzer)?.ctx_deps.contains(&dep) { + // dep.cache_flattened_range(analyzer)?; + let range = dep.ref_range(analyzer)?.unwrap(); + let r = range.flattened_range(analyzer)?.into_owned(); // add the atomic constraint if let Some(atom) = r.min.atomize() { + let underlying = self.underlying_mut(analyzer)?; underlying.dl_solver.add_constraints(vec![atom]); } else if let Some(atom) = r.max.atomize() { + let underlying = self.underlying_mut(analyzer)?; underlying.dl_solver.add_constraints(vec![atom]); } + let underlying = self.underlying_mut(analyzer)?; + underlying.ctx_deps.push(dep); } } diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 2901dc4f..77a157be 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -207,6 +207,13 @@ impl Context { } else { None }, + visible_structs: if fork_expr.is_some() { + parent_ctx.underlying(analyzer)?.cache.visible_structs.clone() + } else if let Some(ret_ctx) = returning_ctx { + ret_ctx.underlying(analyzer)?.cache.visible_structs.clone() + } else { + None + }, first_ancestor: if fork_expr.is_some() { parent_ctx.underlying(analyzer)?.cache.first_ancestor } else if let Some(ret_ctx) = returning_ctx { diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 7012111f..2795a135 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -113,11 +113,21 @@ impl ContextVarNode { pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if let Some(mut range) = self.range(analyzer)? { range.cache_eval(analyzer)?; + range.cache_flatten(analyzer)?; self.set_range(analyzer, range)?; } + // self.cache_flattened_range(analyzer)?; Ok(()) } + // pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + // if let Some(mut range) = self.range(analyzer)? { + // range.cache_flatten(analyzer)?; + // self.set_range(analyzer, range)?; + // } + // Ok(()) + // } + pub fn set_range( &self, analyzer: &mut impl GraphBackend, diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index e5e26462..6fc5c1d8 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -14,6 +14,7 @@ impl ContextNode { var: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { + var.cache_range(analyzer)?; let name = var.name(analyzer)?; let vars = &mut self.underlying_mut(analyzer)?.cache.vars; vars.insert(name, var); diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 0504365c..09af21b4 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{FunctionNode, StructNode, VarNode}, + nodes::{FunctionNode, StructNode, VarNode, SourceUnitNode, SourceUnitPartNode}, AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, }; use shared::{NodeIdx, Search}; @@ -62,7 +62,7 @@ impl ContractNode { ) { let src = self.associated_source(analyzer); let all_contracts = analyzer.search_children_include_via( - src, + src.into(), &Edge::Contract, &[ Edge::Import, @@ -198,6 +198,15 @@ impl ContractNode { .collect() } + pub fn visible_structs(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { + let mut structs = self.structs(analyzer); + let inherited = self.all_inherited_contracts(analyzer); + structs.extend(inherited.iter().flat_map(|c| { + c.structs(analyzer) + }).collect::>()); + structs + } + /// Gets all associated modifiers from the underlying node data for the [`Contract`] pub fn modifiers(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer @@ -207,17 +216,17 @@ impl ContractNode { .collect() } - pub fn associated_source_unit_part(&self, analyzer: &(impl GraphBackend + Search)) -> NodeIdx { + pub fn associated_source_unit_part(&self, analyzer: &(impl GraphBackend + Search)) -> SourceUnitPartNode { analyzer .search_for_ancestor(self.0.into(), &Edge::Contract) - .expect("detached contract") + .expect("detached contract").into() } - pub fn associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> NodeIdx { + pub fn associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> SourceUnitNode { let sup = self.associated_source_unit_part(analyzer); analyzer - .search_for_ancestor(sup, &Edge::Part) - .expect("detached source unit part") + .search_for_ancestor(sup.into(), &Edge::Part) + .expect("detached source unit part").into() } } diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 47ce9c9f..2c7719e7 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -1,7 +1,7 @@ use crate::{ - nodes::{ContextNode, ContractNode}, + nodes::{ContextNode, ContractNode, SourceUnitNode, SourceUnitPartNode}, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, SolcRange, - VarType, + VarType }; use shared::{NodeIdx, Search, StorageLocation}; @@ -226,14 +226,14 @@ impl FunctionNode { pub fn maybe_associated_source_unit_part( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Option { + ) -> Option { if let Some(sup) = self .underlying(analyzer) .unwrap() .cache .associated_source_unit_part { - Some(sup) + Some(sup.into()) } else { let parent = analyzer .graph() @@ -255,13 +255,13 @@ impl FunctionNode { Node::Contract(_) => { ContractNode::from(parent).associated_source_unit_part(analyzer) } - Node::SourceUnitPart(..) => parent, + Node::SourceUnitPart(..) => parent.into(), _e => return None, }; self.underlying_mut(analyzer) .unwrap() .cache - .associated_source_unit_part = Some(sup); + .associated_source_unit_part = Some(sup.into()); Some(sup) } } @@ -269,38 +269,38 @@ impl FunctionNode { pub fn associated_source( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> NodeIdx { + ) -> SourceUnitNode { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { - src + src.into() } else { let sup = self .maybe_associated_source_unit_part(analyzer) .expect("No associated source unit part"); let src = analyzer - .search_for_ancestor(sup, &Edge::Part) + .search_for_ancestor(sup.into(), &Edge::Part) .expect("detached function"); self.underlying_mut(analyzer) .unwrap() .cache .associated_source = Some(src); - src + src.into() } } pub fn maybe_associated_source( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Option { + ) -> Option { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { - Some(src) + Some(src.into()) } else { let sup = self.maybe_associated_source_unit_part(analyzer)?; - let src = analyzer.search_for_ancestor(sup, &Edge::Part)?; + let src = analyzer.search_for_ancestor(sup.into(), &Edge::Part)?; self.underlying_mut(analyzer) .unwrap() .cache .associated_source = Some(src); - Some(src) + Some(src.into()) } } diff --git a/crates/graph/src/nodes/mod.rs b/crates/graph/src/nodes/mod.rs index d4a53246..819a05b2 100644 --- a/crates/graph/src/nodes/mod.rs +++ b/crates/graph/src/nodes/mod.rs @@ -33,3 +33,9 @@ pub use builtin::*; mod context; pub use context::*; + +mod source_unit_part; +pub use source_unit_part::*; + +mod source_unit; +pub use source_unit::*; diff --git a/crates/graph/src/nodes/source_unit.rs b/crates/graph/src/nodes/source_unit.rs new file mode 100644 index 00000000..ddb330d0 --- /dev/null +++ b/crates/graph/src/nodes/source_unit.rs @@ -0,0 +1,139 @@ +use crate::{ + Node, GraphBackend, GraphError, AsDotStr, + nodes::{ + SourceUnitPartNode, + FunctionNode, + StructNode, + VarNode, + ContractNode, + }, +}; + +use shared::NodeIdx; + +#[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct SourceUnit { + pub file: usize, + pub parts: Vec, +} + +impl SourceUnit { + pub fn new(file: usize) -> Self { + Self { + file, ..Default::default() + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct SourceUnitNode(pub usize); + +impl From for NodeIdx { + fn from(val: SourceUnitNode) -> Self { + val.0.into() + } +} + +impl From for SourceUnitNode { + fn from(idx: NodeIdx) -> Self { + SourceUnitNode(idx.index()) + } +} + +impl AsDotStr for SourceUnitNode { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "SourceUnit({})", + underlying.file + ) + } +} + + +impl SourceUnitNode { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a SourceUnit, GraphError> { + match analyzer.node(*self) { + Node::SourceUnit(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find source unit part: {}", + ident.name + ))), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be SourceUnit but it was: {e:?}" + ))), + } + } + + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut impl GraphBackend, + ) -> Result<&'a mut SourceUnit, GraphError> { + match analyzer.node_mut(*self) { + Node::SourceUnit(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find source unit: {}", + ident.name + ))), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be SourceUnit but it was: {e:?}" + ))), + } + } + + pub fn parts<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.parts) + } + + pub fn visible_funcs(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut nodes = vec![]; + self.parts(analyzer)?.iter().try_for_each(|part| { + nodes.extend( + part.visible_funcs(analyzer)? + ); + Ok(()) + })?; + Ok(nodes) + } + + pub fn visible_structs(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut nodes = vec![]; + self.parts(analyzer)?.iter().try_for_each(|part| { + nodes.extend( + part.visible_structs(analyzer)? + ); + Ok(()) + })?; + Ok(nodes) + } + + pub fn visible_constants(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut nodes = vec![]; + self.parts(analyzer)?.iter().try_for_each(|part| { + nodes.extend( + part.visible_constants(analyzer)? + ); + Ok(()) + })?; + Ok(nodes) + } + + pub fn visible_contracts(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + let mut nodes = vec![]; + self.parts(analyzer)?.iter().try_for_each(|part| { + nodes.extend( + part.visible_contracts(analyzer)? + ); + Ok(()) + })?; + Ok(nodes) + } + + pub fn add_part(&self, part: SourceUnitPartNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.parts.push(part); + Ok(()) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/source_unit_part.rs b/crates/graph/src/nodes/source_unit_part.rs new file mode 100644 index 00000000..2b3fd1ef --- /dev/null +++ b/crates/graph/src/nodes/source_unit_part.rs @@ -0,0 +1,127 @@ +use crate::{ + Node, GraphBackend, GraphError, AsDotStr, + nodes::{ + FunctionNode, + StructNode, + VarNode, + ContractNode, + + }, +}; + +use shared::NodeIdx; + +#[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] +pub struct SourceUnitPart { + pub file: usize, + pub part: usize, + pub funcs: Vec, + pub structs: Vec, + pub constants: Vec, + pub contracts: Vec, +} + +impl SourceUnitPart { + pub fn new(file: usize, part: usize) -> Self { + Self { + file, part, ..Default::default() + } + } +} + +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct SourceUnitPartNode(pub usize); + +impl From for NodeIdx { + fn from(val: SourceUnitPartNode) -> Self { + val.0.into() + } +} + +impl From for SourceUnitPartNode { + fn from(idx: NodeIdx) -> Self { + SourceUnitPartNode(idx.index()) + } +} + +impl AsDotStr for SourceUnitPartNode { + fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + let underlying = self.underlying(analyzer).unwrap(); + format!( + "SourceUnitPart({}, {})", + underlying.file, + underlying.part + ) + } +} + + +impl SourceUnitPartNode { + pub fn underlying<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a SourceUnitPart, GraphError> { + match analyzer.node(*self) { + Node::SourceUnitPart(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find source unit part: {}", + ident.name + ))), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be SourceUnitPart but it was: {e:?}" + ))), + } + } + + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut impl GraphBackend, + ) -> Result<&'a mut SourceUnitPart, GraphError> { + match analyzer.node_mut(*self) { + Node::SourceUnitPart(c) => Ok(c), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find source unit part: {}", + ident.name + ))), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be SourceUnitPart but it was: {e:?}" + ))), + } + } + + pub fn visible_funcs<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.funcs) + } + + pub fn visible_structs<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.structs) + } + + pub fn visible_constants<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.constants) + } + + pub fn visible_contracts<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.contracts) + } + + pub fn add_func(&self, func: FunctionNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.funcs.push(func); + Ok(()) + } + + pub fn add_struct(&self, strukt: StructNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.structs.push(strukt); + Ok(()) + } + + pub fn add_contract(&self, contract: ContractNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.contracts.push(contract); + Ok(()) + } + + pub fn add_constant(&self, constant: VarNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.constants.push(constant); + Ok(()) + } +} \ No newline at end of file diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 19bd5c6c..78418994 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{ContextVar, ContextVarNode, ContractNode}, + nodes::{ContextVar, ContextVarNode, ContractNode, SourceUnitPartNode, SourceUnitNode}, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; @@ -89,7 +89,7 @@ impl VarNode { pub fn maybe_associated_source_unit_part( &self, analyzer: &impl GraphBackend, - ) -> Option { + ) -> Option { if let Some(con) = self.maybe_associated_contract(analyzer) { Some(con.associated_source_unit_part(analyzer)) } else { @@ -100,7 +100,7 @@ impl VarNode { .filter_map(|edge| { let node = edge.target(); match analyzer.node(node) { - Node::SourceUnitPart(..) => Some(node), + Node::SourceUnitPart(..) => Some(node.into()), _ => None, } }) @@ -112,9 +112,9 @@ impl VarNode { pub fn maybe_associated_source( &self, analyzer: &(impl GraphBackend + Search), - ) -> Option { + ) -> Option { let sup = self.maybe_associated_source_unit_part(analyzer)?; - analyzer.search_for_ancestor(sup, &Edge::Part) + analyzer.search_for_ancestor(sup.into(), &Edge::Part).map(Into::into) } pub fn name(&self, analyzer: &impl GraphBackend) -> Result { diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index da84e397..219b3b93 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -48,6 +48,12 @@ impl RangeElem for RangeConcrete { Ok(Elem::Concrete(self.clone())) } + fn is_flatten_cached(&self) -> bool { true } + + fn cache_flatten(&mut self, _: &impl GraphBackend) -> Result<(), GraphError> { + Ok(()) + } + fn range_eq(&self, other: &Self) -> bool { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => self_val == other_val, diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 39315503..c5ce6dd5 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -401,6 +401,29 @@ impl RangeElem for Elem { } } + fn cache_flatten( + &mut self, + analyzer: &impl GraphBackend, + ) -> Result<(), GraphError> { + match self { + Self::Reference(d) => d.cache_flatten(analyzer), + Self::Concrete(c) => c.cache_flatten(analyzer), + Self::Expr(expr) => expr.cache_flatten(analyzer), + Self::ConcreteDyn(d) => d.cache_flatten(analyzer), + Self::Null => Ok(()), + } + } + + fn is_flatten_cached(&self) -> bool { + match self { + Self::Reference(d) => d.is_flatten_cached(), + Self::Concrete(c) => c.is_flatten_cached(), + Self::Expr(expr) => expr.is_flatten_cached(), + Self::ConcreteDyn(d) => d.is_flatten_cached(), + Self::Null => true, + } + } + fn dependent_on(&self) -> Vec { match self { Self::Reference(d) => d.dependent_on(), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 8231d603..9527306c 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -16,6 +16,10 @@ pub trait RangeElem { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; + /// Returns whether `cache_flatten` has been called + fn is_flatten_cached(&self) -> bool; + /// Flattens an element and caches the result + fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value fn maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Maximizes the element and caches the result for quicker use later diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 2193ceb5..b322661e 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -39,6 +39,8 @@ pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, pub struct RangeExpr { pub maximized: Option>, pub minimized: Option>, + pub flattened_min: Option>>, + pub flattened_max: Option>>, pub lhs: Box>, pub op: RangeOp, pub rhs: Box>, @@ -77,6 +79,8 @@ impl RangeExpr { RangeExpr { maximized: None, minimized: None, + flattened_max: None, + flattened_min: None, lhs: Box::new(lhs), op, rhs: Box::new(rhs), @@ -99,6 +103,15 @@ impl RangeElem for RangeExpr { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + match (maximize, &self.flattened_min, &self.flattened_max) { + (true, _, Some(flat)) + | (false, Some(flat), _) => { + // println!("flatten cache hit"); + return Ok(*flat.clone()) + }, + _ => {} + } + // println!("flatten cache miss"); // println!("flattening expr: {}", Elem::Expr(self.clone())); Ok(Elem::Expr(RangeExpr::new( self.lhs.flatten(maximize, analyzer)?, @@ -107,6 +120,10 @@ impl RangeElem for RangeExpr { ))) } + fn is_flatten_cached(&self) -> bool { + self.flattened_min.is_some() && self.flattened_max.is_some() + } + fn range_ord(&self, _other: &Self) -> Option { todo!() } @@ -166,14 +183,18 @@ impl RangeElem for RangeExpr { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(simp_max) = &self.flattened_max { + return Ok(*simp_max.clone()); + } + let l = self.lhs.simplify_maximize(exclude, analyzer)?; let r = self.rhs.simplify_maximize(exclude, analyzer)?; - match collapse(l, self.op, r) { - MaybeCollapsed::Collapsed(collapsed) => collapsed - .expect_into_expr() - .simplify_exec_op(true, exclude, analyzer), + let collapsed = collapse(l, self.op, r); + match collapsed { + MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer), + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(true, exclude, analyzer) + Ok(Elem::Expr(RangeExpr::new(l, self.op, r))) } } } @@ -182,16 +203,36 @@ impl RangeElem for RangeExpr { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(simp_min) = &self.flattened_min { + return Ok(*simp_min.clone()); + } + let l = self.lhs.simplify_minimize(exclude, analyzer)?; let r = self.rhs.simplify_minimize(exclude, analyzer)?; - match collapse(l, self.op, r) { + let collapsed = collapse(l, self.op, r); + match collapsed { + MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) + Ok(Elem::Expr(RangeExpr::new(l, self.op, r))) } } } + fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + if self.flattened_max.is_none() { + let flat_max = self.flatten(true, g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + self.flattened_max = Some(Box::new(simplified_flat_max)); + } + if self.flattened_min.is_none() { + let flat_min = self.flatten(false, g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + self.flattened_min = Some(Box::new(simplified_flat_min)); + } + Ok(()) + } + fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { self.cache_exec_op(true, g)?; @@ -226,6 +267,7 @@ impl RangeElem for RangeExpr { } enum MaybeCollapsed { + Concretes(Elem, Elem), Collapsed(Elem), Not(Elem, Elem), } @@ -233,6 +275,9 @@ enum MaybeCollapsed { fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { let zero = Elem::from(Concrete::from(U256::zero())); match (l.clone(), r.clone()) { + (Elem::Concrete(_), Elem::Concrete(_)) => { + MaybeCollapsed::Concretes(l, r) + } // if we have an expression, it fundamentally must have a dynamic in it (Elem::Expr(expr), c @ Elem::Concrete(_)) => { // potentially collapsible @@ -629,6 +674,7 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone()) { collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(_, _) => unreachable!(), }, _ => MaybeCollapsed::Not(l, r), } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 4dcc397d..61fa1603 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -17,6 +17,8 @@ pub struct RangeDyn { pub minimized: Option>, /// Cached maximized value pub maximized: Option>, + pub flattened_min: Option>>, + pub flattened_max: Option>>, /// Length of the dynamic variable pub len: Elem, /// Values of the dynamic variable @@ -24,7 +26,20 @@ pub struct RangeDyn { /// Sourcecode location pub loc: Loc, } + impl RangeDyn { + pub fn new(len: Elem, val: BTreeMap, Elem>, loc: Loc) -> Self { + Self { + minimized: None, + maximized: None, + flattened_min: None, + flattened_max: None, + len, + val, + loc + } + } + /// Set the length pub fn set_len(&mut self, new_len: Elem) { self.len = new_len; @@ -104,15 +119,22 @@ impl RangeElem for RangeDyn { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + match (maximize, &self.flattened_min, &self.flattened_max) { + (true, _, Some(flat)) + | (false, Some(flat), _) => return Ok(*flat.clone()), + _ => {} + } // println!("flattening range dyn"); Ok(Elem::ConcreteDyn(Box::new(Self { minimized: None, maximized: None, + flattened_min: None, + flattened_max: None, len: self.len.flatten(maximize, analyzer)?, val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.flatten(maximize, analyzer)?); + map.insert(idx.flatten(maximize, analyzer)?, val.flatten(maximize, analyzer)?); } map }, @@ -120,6 +142,24 @@ impl RangeElem for RangeDyn { }))) } + fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + if self.flattened_max.is_none() { + let flat_max = self.flatten(true, g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + self.flattened_max = Some(Box::new(simplified_flat_max)); + } + if self.flattened_min.is_none() { + let flat_min = self.flatten(false, g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + self.flattened_min = Some(Box::new(simplified_flat_min)); + } + Ok(()) + } + + fn is_flatten_cached(&self) -> bool { + self.flattened_min.is_some() && self.flattened_max.is_some() + } + fn update_deps(&mut self, mapping: &BTreeMap) { self.len.update_deps(mapping); self.val @@ -146,19 +186,17 @@ impl RangeElem for RangeDyn { return Ok(*cached); } - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.maximize(analyzer)?, - val: { + Ok(Elem::ConcreteDyn(Box::new(Self::new( + self.len.maximize(analyzer)?, + { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert(idx, val.maximize(analyzer)?); } map }, - loc: self.loc, - }))) + self.loc, + )))) } fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { @@ -166,19 +204,17 @@ impl RangeElem for RangeDyn { return Ok(*cached); } - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.minimize(analyzer)?, - val: { + Ok(Elem::ConcreteDyn(Box::new(Self::new( + self.len.minimize(analyzer)?, + { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert(idx, val.minimize(analyzer)?); } map }, - loc: self.loc, - }))) + self.loc, + )))) } fn simplify_maximize( @@ -186,38 +222,40 @@ impl RangeElem for RangeDyn { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_maximize(exclude, analyzer)?, - val: { + if let Some(max) = &self.flattened_max { + return Ok(*max.clone()) + } + Ok(Elem::ConcreteDyn(Box::new(Self::new( + self.len.simplify_maximize(exclude, analyzer)?, + { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert(idx, val.simplify_maximize(exclude, analyzer)?); } map }, - loc: self.loc, - }))) + self.loc, + )))) } fn simplify_minimize( &self, exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - Ok(Elem::ConcreteDyn(Box::new(Self { - minimized: None, - maximized: None, - len: self.len.simplify_minimize(exclude, analyzer)?, - val: { + if let Some(min) = &self.flattened_min { + return Ok(*min.clone()) + } + Ok(Elem::ConcreteDyn(Box::new(Self::new( + self.len.simplify_minimize(exclude, analyzer)?, + { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert(idx, val.simplify_minimize(exclude, analyzer)?); } map }, - loc: self.loc, - }))) + self.loc, + )))) } fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { @@ -237,6 +275,8 @@ impl RangeElem for RangeDyn { fn uncache(&mut self) { self.minimized = None; self.maximized = None; + self.flattened_min = None; + self.flattened_max = None; } fn contains_op_set( diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 0b9fd386..3515f87d 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -22,6 +22,10 @@ pub struct Reference { pub minimized: Option>, /// Cached maximized value pub maximized: Option>, + /// Cached minimized flatten value + pub flattened_min: Option>>, + /// Cached maximized flatten value + pub flattened_max: Option>>, } impl Reference { @@ -30,6 +34,8 @@ impl Reference { idx, minimized: None, maximized: None, + flattened_min: None, + flattened_max: None, } } } @@ -94,6 +100,16 @@ impl RangeElem for Reference { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + match (maximize, &self.flattened_min, &self.flattened_max) { + (true, _, Some(flat)) + | (false, Some(flat), _) => { + // println!("flatten cache hit: {}", self.idx.index()); + return Ok(*flat.clone()) + }, + _ => {} + } + + // println!("flatten cache miss: {}", self.idx.index()); let cvar = ContextVarNode::from(self.idx); // println!("flattening reference: {} (idx_{})", cvar.display_name(analyzer)?, self.idx.index()); if cvar.is_fundamental(analyzer)? { @@ -103,17 +119,35 @@ impl RangeElem for Reference { } if maximize { cvar.range_max(analyzer)? - .unwrap() + .unwrap_or(Elem::Null) .flatten(maximize, analyzer) } else { let flattened = cvar .range_min(analyzer)? - .unwrap() + .unwrap_or(Elem::Null) .flatten(maximize, analyzer)?; Ok(flattened) } } + fn is_flatten_cached(&self) -> bool { + self.flattened_min.is_some() && self.flattened_max.is_some() + } + + fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + if self.flattened_max.is_none() { + let flat_max = self.flatten(true, g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + self.flattened_max = Some(Box::new(simplified_flat_max)); + } + if self.flattened_min.is_none() { + let flat_min = self.flatten(false, g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + self.flattened_min = Some(Box::new(simplified_flat_min)); + } + Ok(()) + } + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { @@ -171,6 +205,10 @@ impl RangeElem for Reference { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(simp_max) = &self.flattened_max { + return Ok(*simp_max.clone()); + } + let cvar = ContextVarNode::from(self.idx); let independent = cvar.is_fundamental(analyzer)?; @@ -189,6 +227,10 @@ impl RangeElem for Reference { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(simp_min) = &self.flattened_min { + return Ok(*simp_min.clone()); + } + let cvar = ContextVarNode::from(self.idx); if cvar.is_fundamental(analyzer)? { Ok(Elem::Reference(Reference::new( @@ -217,6 +259,8 @@ impl RangeElem for Reference { fn uncache(&mut self) { self.minimized = None; self.maximized = None; + self.flattened_min = None; + self.flattened_max = None; } fn contains_op_set( diff --git a/crates/graph/src/range/exec/cast.rs b/crates/graph/src/range/exec/cast.rs index dbbdd5e6..41ab5ed4 100644 --- a/crates/graph/src/range/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -41,13 +41,11 @@ impl RangeCast>> for RangeConcrete { }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(size))), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(size))), + existing, + other.loc, + )))) } ( Concrete::DynBytes(val), @@ -73,13 +71,11 @@ impl RangeCast>> for RangeConcrete { }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(val.len()))), + existing, + other.loc, + )))) } ( Concrete::String(val), @@ -105,13 +101,11 @@ impl RangeCast>> for RangeConcrete { }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(val.len()))), + existing, + other.loc, + )))) } _e => None, } diff --git a/crates/graph/src/range/exec/concat.rs b/crates/graph/src/range/exec/concat.rs index aa3ffb2f..dfc768d9 100644 --- a/crates/graph/src/range/exec/concat.rs +++ b/crates/graph/src/range/exec/concat.rs @@ -42,13 +42,11 @@ impl RangeConcat> for RangeDyn { }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(val.len()))), + existing, + other.loc, + )))) } ( Concrete::String(val), @@ -76,13 +74,11 @@ impl RangeConcat> for RangeDyn { }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(val.len()))), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(val.len()))), + existing, + other.loc, + )))) } _e => None, } @@ -120,13 +116,11 @@ impl RangeConcat> for RangeDyn { .collect::>(); existing.extend(other_vals); - Some(Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: self.len.clone() + other.len.clone(), - val: existing, - loc: other.loc, - }))) + Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + self.len.clone() + other.len.clone(), + existing, + other.loc, + )))) } (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index ef720173..22e53651 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -40,7 +40,9 @@ impl ExecOp for RangeExpr { exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - let (parts, lhs_is_conc) = self.simplify_spread(exclude, analyzer)?; + let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(exclude, analyzer)?; + let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); + let rhs_is_conc = rhs_min.maybe_concrete().is_some() && rhs_max.maybe_concrete().is_some(); if self.op == RangeOp::Cast { // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete if lhs_is_conc { @@ -56,7 +58,15 @@ impl ExecOp for RangeExpr { } } } - self.exec(parts, maximize) + let parts = (lhs_min, lhs_max, rhs_min, rhs_max); + match (lhs_is_conc, rhs_is_conc) { + (true, true) => { + self.exec(parts, maximize) + } + _ => { + Ok(Elem::Expr(self.clone())) + } + } } fn spread( @@ -84,13 +94,10 @@ impl ExecOp for RangeExpr { analyzer: &impl GraphBackend, ) -> Result< ( - ( - Elem, - Elem, - Elem, - Elem, - ), - bool, + Elem, + Elem, + Elem, + Elem, ), GraphError, > { @@ -98,8 +105,7 @@ impl ExecOp for RangeExpr { let lhs_max = self.lhs.simplify_maximize(exclude, analyzer)?; let rhs_min = self.rhs.simplify_minimize(exclude, analyzer)?; let rhs_max = self.rhs.simplify_maximize(exclude, analyzer)?; - let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); - Ok(((lhs_min, lhs_max, rhs_min, rhs_max), lhs_is_conc)) + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } fn exec( @@ -404,7 +410,7 @@ impl ExecOp for RangeExpr { .range_mul(&rhs_min) .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") + fallback(self, lhs_min, rhs_min, consts) } } } else { @@ -453,7 +459,7 @@ impl ExecOp for RangeExpr { .range_mul(&rhs_min) .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), (false, true, _, _) | (_, _, false, true) => { - panic!("unsatisfiable range") + fallback(self, lhs_min, rhs_min, consts) } } } diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index d970a133..b7bd827b 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -35,7 +35,7 @@ pub trait ExecOp { &self, exclude: &mut Vec, analyzer: &impl GraphBackend, - ) -> Result<((Elem, Elem, Elem, Elem), bool), Self::GraphError>; + ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; fn uncache_exec(&mut self); diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index c24b2de2..6178f9a8 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -1,5 +1,6 @@ use crate::{range::elem::RangeElem, GraphBackend}; use shared::NodeIdx; +use std::borrow::Cow; pub trait Range { type GraphError; @@ -64,6 +65,10 @@ pub trait Range { fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); /// Replace a potential recursion causing node index with a new index fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + /// Cache the flattened range + fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + /// Produce a flattened range or use the cached flattened range + fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone; } pub trait RangeEval>: Range { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 52bd46b5..75b0ff22 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -9,7 +9,7 @@ use shared::NodeIdx; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; -use std::collections::BTreeMap; +use std::{borrow::Cow, collections::BTreeMap}; #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct SolcRange { @@ -18,6 +18,7 @@ pub struct SolcRange { pub max: Elem, pub max_cached: Option>, pub exclusions: Vec>, + pub flattened: Option>, } impl AsDotStr for SolcRange { @@ -124,6 +125,7 @@ impl SolcRange { max, max_cached: None, exclusions, + flattened: None, } } @@ -184,13 +186,11 @@ impl SolcRange { (idx, v) }) .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(s.len()))), + let r = Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(s.len()))), val, - loc: Loc::Implicit, - })); + Loc::Implicit, + ))); Some(SolcRange::new(r.clone(), r, vec![])) } Concrete::DynBytes(b) => { @@ -205,13 +205,11 @@ impl SolcRange { (idx, v) }) .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::from(b.len()))), + let r = Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::from(b.len()))), val, - loc: Loc::Implicit, - })); + Loc::Implicit, + ))); Some(SolcRange::new(r.clone(), r, vec![])) } _e => None, @@ -319,37 +317,29 @@ impl SolcRange { | Builtin::String | Builtin::Array(_) | Builtin::Mapping(_, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::zero())), - val: Default::default(), - loc: Loc::Implicit, - })), - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(U256::MAX)), - val: Default::default(), - loc: Loc::Implicit, - })), + Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::zero())), + Default::default(), + Loc::Implicit, + ))), + Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(U256::MAX)), + Default::default(), + Loc::Implicit, + ))), vec![], )), Builtin::SizedArray(s, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })), - Elem::ConcreteDyn(Box::new(RangeDyn { - minimized: None, - maximized: None, - len: Elem::from(Concrete::from(*s)), - val: Default::default(), - loc: Loc::Implicit, - })), + Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(*s)), + Default::default(), + Loc::Implicit, + ))), + Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::from(Concrete::from(*s)), + Default::default(), + Loc::Implicit, + ))), vec![], )), _ => None, @@ -576,17 +566,22 @@ impl SolcRange { } pub fn into_flattened_range(&self, analyzer: &impl GraphBackend) -> Result { - // println!("----- into flattened range -----"); + if let Some(cached) = &self.flattened { + return Ok(*cached.clone()); + } + let flattened_min = self.range_min().flatten(false, analyzer)?; - // println!("flattened minimum: {}", flattened_min); - let simp_min = flattened_min.simplify_minimize(&mut vec![], analyzer)?; - // println!("simplified minimum: {}", simp_min); - // println!("----- min flattend -----"); + let simp_min = if !self.range_min().is_flatten_cached() { + flattened_min.simplify_minimize(&mut vec![], analyzer)? + } else { + flattened_min + }; let flattened_max = self.range_max().flatten(true, analyzer)?; - // println!("flattened maximum: {}", flattened_max); - let simp_max = flattened_max.simplify_maximize(&mut vec![], analyzer)?; - // println!("simplified maximum: {}", simp_max); - // println!("----- max flattend -----"); + let simp_max = if !self.range_max().is_flatten_cached() { + flattened_max.simplify_maximize(&mut vec![], analyzer)? + } else { + flattened_max + }; Ok(SolcRange::new(simp_min, simp_max, self.exclusions.clone())) } @@ -612,11 +607,13 @@ impl Range for SolcRange { if self.min_cached.is_none() { let min = self.range_min_mut(); min.cache_minimize(analyzer)?; + min.cache_flatten(analyzer)?; self.min_cached = Some(self.range_min().minimize(analyzer)?); } if self.max_cached.is_none() { let max = self.range_max_mut(); max.cache_maximize(analyzer)?; + max.cache_flatten(analyzer)?; self.max_cached = Some(self.range_max().maximize(analyzer)?); } Ok(()) @@ -683,6 +680,22 @@ impl Range for SolcRange { fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { self.max.filter_recursion(self_idx, new_idx); } + + fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError> { + if self.flattened.is_none() { + let flat = self.into_flattened_range(analyzer)?; + self.flattened = Some(Box::new(flat)) + } + Ok(()) + } + /// Produce a flattened range or use the cached flattened range + fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone { + if let Some(flat) = &self.flattened { + Ok(Cow::Borrowed(flat)) + } else { + Ok(Cow::Owned(self.into_flattened_range(analyzer)?)) + } + } } impl RangeEval> for SolcRange { diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 01ea3f71..f4b34b32 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -97,9 +97,9 @@ impl BruteBinSearchSolver { dep.display_name(analyzer).unwrap() ); } - let r = range.into_flattened_range(analyzer)?; + let r = range.flattened_range(analyzer)?; atomic_idxs.extend(r.dependent_on()); - ranges.insert(*dep, r); + ranges.insert(*dep, r.into_owned()); Ok(()) })?; diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index b3b5b4b7..b65df8fd 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -143,7 +143,7 @@ impl Default for Analyzer { builtin_fn_nodes: Default::default(), builtin_fn_inputs: Default::default(), expr_errs: Default::default(), - max_depth: 50, + max_depth: 200, max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), }; @@ -321,10 +321,10 @@ impl Analyzer { .push((current_path.clone(), src.to_string(), Some(file_no), None)); match solang_parser::parse(src, file_no) { Ok((source_unit, _comments)) => { - let parent = self.add_node(Node::SourceUnit(file_no)); + let parent = self.add_node(Node::SourceUnit(graph::nodes::SourceUnit::new(file_no))); self.add_edge(parent, self.entry, Edge::Source); let final_pass_part = - self.parse_source_unit(source_unit, file_no, parent, current_path); + self.parse_source_unit(source_unit, file_no, parent.into(), current_path); self.final_pass_items.push(final_pass_part); if entry { self.final_pass(); @@ -381,7 +381,7 @@ impl Analyzer { &mut self, source_unit: SourceUnit, file_no: usize, - parent: NodeIdx, + parent: SourceUnitNode, current_path: &SourcePath, ) -> FinalPassItem { let mut all_funcs = vec![]; @@ -393,13 +393,14 @@ impl Analyzer { .iter() .enumerate() .for_each(|(unit_part, source_unit_part)| { - let (_sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( + let (sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( source_unit_part, file_no, unit_part, parent, current_path, ); + parent.add_part(sup, self); all_funcs.extend(funcs); all_usings.extend(usings); all_inherits.extend(inherits); @@ -414,11 +415,11 @@ impl Analyzer { sup: &SourceUnitPart, file_no: usize, unit_part: usize, - parent: NodeIdx, + parent: SourceUnitNode, // imported: &mut Vec<(Option, String, String, usize)>, current_path: &SourcePath, ) -> ( - NodeIdx, + SourceUnitPartNode, Vec, Vec<(Using, NodeIdx)>, Vec<(ContractNode, Vec)>, @@ -426,7 +427,8 @@ impl Analyzer { ) { use SourceUnitPart::*; - let sup_node = self.add_node(Node::SourceUnitPart(file_no, unit_part)); + let sup_node = self.add_node(Node::SourceUnitPart(graph::nodes::SourceUnitPart::new(file_no, unit_part))); + let s_node = SourceUnitPartNode::from(sup_node); self.add_edge(sup_node, parent, Edge::Part); let mut func_nodes = vec![]; @@ -438,6 +440,7 @@ impl Analyzer { ContractDefinition(def) => { let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = self.parse_contract_def(def, parent); + s_node.add_contract(node, self).unwrap(); self.add_edge(node, sup_node, Edge::Contract); func_nodes.extend(funcs); usings.extend(con_usings); @@ -446,6 +449,7 @@ impl Analyzer { } StructDefinition(def) => { let node = self.parse_struct_def(def); + s_node.add_struct(node, self).unwrap(); self.add_edge(node, sup_node, Edge::Struct); } EnumDefinition(def) => { @@ -458,19 +462,24 @@ impl Analyzer { } VariableDefinition(def) => { let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); + s_node.add_constant(node, self).unwrap(); if let Some(func) = maybe_func { - func_nodes.push(self.handle_func(func, None)); + let func = self.handle_func(func, None); + func_nodes.push(func); + s_node.add_func(func, self).unwrap(); } if needs_final_pass { - vars.push((node, parent)); + vars.push((node, parent.into())); } self.add_edge(node, sup_node, Edge::Var); } FunctionDefinition(def) => { let node = self.parse_func_def(def, None); + s_node.add_func(node, self).unwrap(); func_nodes.push(node); + self.add_edge(node, sup_node, Edge::Func); } TypeDefinition(def) => { @@ -479,18 +488,19 @@ impl Analyzer { } EventDefinition(_def) => todo!(), Annotation(_anno) => todo!(), - Using(using) => usings.push((*using.clone(), parent)), + Using(using) => usings.push((*using.clone(), parent.into())), StraySemicolon(_loc) => todo!(), PragmaDirective(_, _, _) => {} ImportDirective(import) => { self.parse_import(import, current_path, parent); } } - (sup_node, func_nodes, usings, inherits, vars) + + (s_node, func_nodes, usings, inherits, vars) } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_import(&mut self, import: &Import, current_path: &SourcePath, parent: NodeIdx) { + pub fn parse_import(&mut self, import: &Import, current_path: &SourcePath, parent: SourceUnitNode) { let (import_path, remapping) = match import { Import::Plain(import_path, _) => { tracing::trace!("parse_import, path: {:?}", import_path); @@ -734,7 +744,7 @@ impl Analyzer { pub fn parse_contract_def( &mut self, contract_def: &ContractDefinition, - source: NodeIdx, + source: SourceUnitNode, ) -> ( ContractNode, Vec, @@ -761,7 +771,7 @@ impl Analyzer { let import_nodes = import_nodes.as_slice(); let (contract, unhandled_inherits) = - Contract::from_w_imports(contract_def.clone(), source, import_nodes, self); + Contract::from_w_imports(contract_def.clone(), source.into(), import_nodes, self); let inherits = contract.inherits.clone(); let con_name = contract.name.clone().unwrap().name; @@ -915,7 +925,7 @@ impl Analyzer { // looking for free floating function let funcs = match self.node(scope_node) { Node::Contract(_) => self.search_children( - ContractNode::from(scope_node).associated_source(self), + ContractNode::from(scope_node).associated_source(self).into(), &Edge::Func, ), Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), diff --git a/crates/pyrometer/tests/challenges/apron.sol b/crates/pyrometer/tests/challenges/apron.sol index c15db140..d4352d34 100644 --- a/crates/pyrometer/tests/challenges/apron.sol +++ b/crates/pyrometer/tests/challenges/apron.sol @@ -1,4 +1,8 @@ // Realistically this challenge requires `join` functionality to run in a normal time frame (15 seconds currently) + +// uint256 constant ITERS = 20; +// int256 constant ITERS2 = int(ITERS) - 1; + contract Apron { uint256 k; uint256 i; @@ -15,7 +19,7 @@ contract Apron { } function bb1_t() public { - if (i <= 99) { + if (i <= 50) { bb2(); } } @@ -23,12 +27,12 @@ contract Apron { function bb2() public { i += 1; k += 1; - if (i <= 99) { + if (i <= 50) { bb1(); } } function bb1_f() public { - require(-1 * int256(i) <= -100); + require(-1 * int256(i) <= -51); } } \ No newline at end of file diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs index a0b86381..72529f6d 100644 --- a/crates/shared/src/search.rs +++ b/crates/shared/src/search.rs @@ -220,7 +220,11 @@ where .clone() .filter_map(|edge| { if edge.weight() == edge_ty { - Some(edge.source()) + if !seen.contains(&edge.source()) { + Some(edge.source()) + } else { + None + } } else { None } @@ -231,12 +235,16 @@ where this_children.extend( edges .flat_map(|edge| { - self.search_children_exclude_via_prevent_cycle( - edge.source(), - edge_ty, - exclude_edges, - seen, - ) + if !seen.contains(&edge.source()) { + self.search_children_exclude_via_prevent_cycle( + edge.source(), + edge_ty, + exclude_edges, + seen, + ) + } else { + Default::default() + } }) .collect::>(), ); diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index a773584c..771e54e4 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -173,13 +173,11 @@ pub trait Cmp: AnalyzerBackend + Sized { rhs_cvar.display_name(self).unwrap() ); let range = { - let elem = Elem::Expr(RangeExpr { - minimized: None, - maximized: None, - lhs: Box::new(Elem::from(lhs_cvar)), + let elem = Elem::Expr(RangeExpr::new( + Elem::from(lhs_cvar), op, - rhs: Box::new(Elem::from(rhs_cvar)), - }); + Elem::from(rhs_cvar), + )); let exclusions = lhs_cvar .ref_range(self) @@ -285,13 +283,11 @@ pub trait Cmp: AnalyzerBackend + Sized { // invert if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?) { - let val = Elem::Expr(RangeExpr { - minimized: None, - maximized: None, - lhs: Box::new(lhs_range.range_min().into_owned()), - op: RangeOp::Not, - rhs: Box::new(Elem::Null), - }); + let val = Elem::Expr(RangeExpr::new( + lhs_range.range_min().into_owned(), + RangeOp::Not, + Elem::Null, + )); return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions)); } diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 029fce88..e9a417a1 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -54,7 +54,7 @@ pub trait InternalFuncCaller: if possible_funcs.is_empty() { // check structs - let structs = ctx.visible_structs(self); + let structs = ctx.visible_structs(self).into_expr_err(*loc)?; let possible_structs = structs .iter() .filter(|strukt| { diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index 80abecc6..53645a0c 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -786,7 +786,7 @@ pub trait MemberAccess: AnalyzerBackend + if let Some(source) = ctx.maybe_associated_source(self) { funcs.extend( self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { - matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source) + matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source.into()) }).map(|edge| edge.target().into()).collect::>() ); } diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index d27908ef..01fc710e 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -934,7 +934,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { tmp_cvar = Some(cvar); any_unsat |= new_var_range.unsat(self); - if any_unsat { + if any_unsat || ctx.unreachable(self).into_expr_err(loc)? { ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); } From 20868a85c757dc115a3cfe8cea06fb52529ab639 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 13:08:32 -0800 Subject: [PATCH 31/71] lint --- crates/graph/src/nodes/context/querying.rs | 8 +- crates/graph/src/nodes/context/solving.rs | 4 +- crates/graph/src/nodes/context/underlying.rs | 6 +- crates/graph/src/nodes/contract_ty.rs | 22 ++-- crates/graph/src/nodes/func_ty.rs | 2 +- crates/graph/src/nodes/source_unit.rs | 92 +++++++-------- crates/graph/src/nodes/source_unit_part.rs | 113 +++++++++++-------- crates/graph/src/nodes/var_ty.rs | 6 +- crates/graph/src/range/elem/concrete.rs | 4 +- crates/graph/src/range/elem/elem_enum.rs | 5 +- crates/graph/src/range/elem/expr.rs | 27 ++--- crates/graph/src/range/elem/map_or_array.rs | 14 ++- crates/graph/src/range/elem/reference.rs | 7 +- crates/graph/src/range/exec/exec_op.rs | 8 +- crates/graph/src/range/range_trait.rs | 7 +- crates/graph/src/range/solc_range.rs | 8 +- crates/pyrometer/src/analyzer.rs | 20 +++- crates/shared/src/search.rs | 6 +- 18 files changed, 204 insertions(+), 155 deletions(-) diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index b53c7f76..c9bea425 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -1,5 +1,7 @@ use crate::{ - nodes::{ContextNode, ContractNode, FunctionNode, StructNode, SourceUnitNode, SourceUnitPartNode}, + nodes::{ + ContextNode, ContractNode, FunctionNode, SourceUnitNode, SourceUnitPartNode, StructNode, + }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, }; @@ -223,9 +225,7 @@ impl ContextNode { let mut structs = source.visible_structs(analyzer)?; let contract = self.associated_contract(analyzer)?; - structs.extend( - contract.visible_structs(analyzer) - ); + structs.extend(contract.visible_structs(analyzer)); structs.sort(); structs.dedup(); diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index fe558686..2f47d450 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,15 +1,15 @@ use crate::SolcRange; -use std::borrow::Cow; use crate::{ as_dot_str, nodes::{ContextNode, ContextVarNode}, - range::{Range, elem::RangeOp, RangeEval}, + range::{elem::RangeOp, Range, RangeEval}, solvers::{ dl::{DLSolver, SolveStatus}, Atomize, SolverAtom, }, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; +use std::borrow::Cow; use shared::NodeIdx; diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 77a157be..eaaec14f 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -208,7 +208,11 @@ impl Context { None }, visible_structs: if fork_expr.is_some() { - parent_ctx.underlying(analyzer)?.cache.visible_structs.clone() + parent_ctx + .underlying(analyzer)? + .cache + .visible_structs + .clone() } else if let Some(ret_ctx) = returning_ctx { ret_ctx.underlying(analyzer)?.cache.visible_structs.clone() } else { diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 09af21b4..77f6dbca 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{FunctionNode, StructNode, VarNode, SourceUnitNode, SourceUnitPartNode}, + nodes::{FunctionNode, SourceUnitNode, SourceUnitPartNode, StructNode, VarNode}, AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, }; use shared::{NodeIdx, Search}; @@ -201,9 +201,12 @@ impl ContractNode { pub fn visible_structs(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { let mut structs = self.structs(analyzer); let inherited = self.all_inherited_contracts(analyzer); - structs.extend(inherited.iter().flat_map(|c| { - c.structs(analyzer) - }).collect::>()); + structs.extend( + inherited + .iter() + .flat_map(|c| c.structs(analyzer)) + .collect::>(), + ); structs } @@ -216,17 +219,22 @@ impl ContractNode { .collect() } - pub fn associated_source_unit_part(&self, analyzer: &(impl GraphBackend + Search)) -> SourceUnitPartNode { + pub fn associated_source_unit_part( + &self, + analyzer: &(impl GraphBackend + Search), + ) -> SourceUnitPartNode { analyzer .search_for_ancestor(self.0.into(), &Edge::Contract) - .expect("detached contract").into() + .expect("detached contract") + .into() } pub fn associated_source(&self, analyzer: &(impl GraphBackend + Search)) -> SourceUnitNode { let sup = self.associated_source_unit_part(analyzer); analyzer .search_for_ancestor(sup.into(), &Edge::Part) - .expect("detached source unit part").into() + .expect("detached source unit part") + .into() } } diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 2c7719e7..c5d0d8f4 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -1,7 +1,7 @@ use crate::{ nodes::{ContextNode, ContractNode, SourceUnitNode, SourceUnitPartNode}, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, SolcRange, - VarType + VarType, }; use shared::{NodeIdx, Search, StorageLocation}; diff --git a/crates/graph/src/nodes/source_unit.rs b/crates/graph/src/nodes/source_unit.rs index ddb330d0..aabc2db9 100644 --- a/crates/graph/src/nodes/source_unit.rs +++ b/crates/graph/src/nodes/source_unit.rs @@ -1,28 +1,23 @@ use crate::{ - Node, GraphBackend, GraphError, AsDotStr, - nodes::{ - SourceUnitPartNode, - FunctionNode, - StructNode, - VarNode, - ContractNode, - }, + nodes::{ContractNode, FunctionNode, SourceUnitPartNode, StructNode, VarNode}, + AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; #[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct SourceUnit { - pub file: usize, - pub parts: Vec, + pub file: usize, + pub parts: Vec, } impl SourceUnit { - pub fn new(file: usize) -> Self { - Self { - file, ..Default::default() - } - } + pub fn new(file: usize) -> Self { + Self { + file, + ..Default::default() + } + } } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -43,16 +38,12 @@ impl From for SourceUnitNode { impl AsDotStr for SourceUnitNode { fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); - format!( - "SourceUnit({})", - underlying.file - ) + format!("SourceUnit({})", underlying.file) } } - impl SourceUnitNode { - pub fn underlying<'a>( + pub fn underlying<'a>( &self, analyzer: &'a impl GraphBackend, ) -> Result<&'a SourceUnit, GraphError> { @@ -84,56 +75,67 @@ impl SourceUnitNode { } } - pub fn parts<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { + pub fn parts<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Vec, GraphError> { Ok(&self.underlying(analyzer)?.parts) } - pub fn visible_funcs(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn visible_funcs( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { let mut nodes = vec![]; self.parts(analyzer)?.iter().try_for_each(|part| { - nodes.extend( - part.visible_funcs(analyzer)? - ); + nodes.extend(part.visible_funcs(analyzer)?); Ok(()) })?; Ok(nodes) } - pub fn visible_structs(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - let mut nodes = vec![]; + pub fn visible_structs( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + let mut nodes = vec![]; self.parts(analyzer)?.iter().try_for_each(|part| { - nodes.extend( - part.visible_structs(analyzer)? - ); + nodes.extend(part.visible_structs(analyzer)?); Ok(()) })?; Ok(nodes) } - pub fn visible_constants(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - let mut nodes = vec![]; + pub fn visible_constants( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + let mut nodes = vec![]; self.parts(analyzer)?.iter().try_for_each(|part| { - nodes.extend( - part.visible_constants(analyzer)? - ); + nodes.extend(part.visible_constants(analyzer)?); Ok(()) })?; Ok(nodes) } - pub fn visible_contracts(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - let mut nodes = vec![]; + pub fn visible_contracts( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + let mut nodes = vec![]; self.parts(analyzer)?.iter().try_for_each(|part| { - nodes.extend( - part.visible_contracts(analyzer)? - ); + nodes.extend(part.visible_contracts(analyzer)?); Ok(()) })?; Ok(nodes) } - pub fn add_part(&self, part: SourceUnitPartNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.parts.push(part); - Ok(()) + pub fn add_part( + &self, + part: SourceUnitPartNode, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.parts.push(part); + Ok(()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/source_unit_part.rs b/crates/graph/src/nodes/source_unit_part.rs index 2b3fd1ef..22791787 100644 --- a/crates/graph/src/nodes/source_unit_part.rs +++ b/crates/graph/src/nodes/source_unit_part.rs @@ -1,32 +1,28 @@ use crate::{ - Node, GraphBackend, GraphError, AsDotStr, - nodes::{ - FunctionNode, - StructNode, - VarNode, - ContractNode, - - }, + nodes::{ContractNode, FunctionNode, StructNode, VarNode}, + AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; #[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct SourceUnitPart { - pub file: usize, - pub part: usize, - pub funcs: Vec, - pub structs: Vec, - pub constants: Vec, - pub contracts: Vec, + pub file: usize, + pub part: usize, + pub funcs: Vec, + pub structs: Vec, + pub constants: Vec, + pub contracts: Vec, } impl SourceUnitPart { - pub fn new(file: usize, part: usize) -> Self { - Self { - file, part, ..Default::default() - } - } + pub fn new(file: usize, part: usize) -> Self { + Self { + file, + part, + ..Default::default() + } + } } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -47,17 +43,12 @@ impl From for SourceUnitPartNode { impl AsDotStr for SourceUnitPartNode { fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { let underlying = self.underlying(analyzer).unwrap(); - format!( - "SourceUnitPart({}, {})", - underlying.file, - underlying.part - ) + format!("SourceUnitPart({}, {})", underlying.file, underlying.part) } } - impl SourceUnitPartNode { - pub fn underlying<'a>( + pub fn underlying<'a>( &self, analyzer: &'a impl GraphBackend, ) -> Result<&'a SourceUnitPart, GraphError> { @@ -89,39 +80,67 @@ impl SourceUnitPartNode { } } - pub fn visible_funcs<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { - Ok(&self.underlying(analyzer)?.funcs) + pub fn visible_funcs<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.funcs) } - pub fn visible_structs<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { - Ok(&self.underlying(analyzer)?.structs) + pub fn visible_structs<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.structs) } - pub fn visible_constants<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { - Ok(&self.underlying(analyzer)?.constants) + pub fn visible_constants<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.constants) } - pub fn visible_contracts<'a>(&self, analyzer: &'a impl GraphBackend) -> Result<&'a Vec, GraphError> { - Ok(&self.underlying(analyzer)?.contracts) + pub fn visible_contracts<'a>( + &self, + analyzer: &'a impl GraphBackend, + ) -> Result<&'a Vec, GraphError> { + Ok(&self.underlying(analyzer)?.contracts) } - pub fn add_func(&self, func: FunctionNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.funcs.push(func); - Ok(()) + pub fn add_func( + &self, + func: FunctionNode, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.funcs.push(func); + Ok(()) } - pub fn add_struct(&self, strukt: StructNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.structs.push(strukt); - Ok(()) + pub fn add_struct( + &self, + strukt: StructNode, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.structs.push(strukt); + Ok(()) } - pub fn add_contract(&self, contract: ContractNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.contracts.push(contract); - Ok(()) + pub fn add_contract( + &self, + contract: ContractNode, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.contracts.push(contract); + Ok(()) } - pub fn add_constant(&self, constant: VarNode, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.underlying_mut(analyzer)?.constants.push(constant); - Ok(()) + pub fn add_constant( + &self, + constant: VarNode, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + self.underlying_mut(analyzer)?.constants.push(constant); + Ok(()) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 78418994..6503713e 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{ContextVar, ContextVarNode, ContractNode, SourceUnitPartNode, SourceUnitNode}, + nodes::{ContextVar, ContextVarNode, ContractNode, SourceUnitNode, SourceUnitPartNode}, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; @@ -114,7 +114,9 @@ impl VarNode { analyzer: &(impl GraphBackend + Search), ) -> Option { let sup = self.maybe_associated_source_unit_part(analyzer)?; - analyzer.search_for_ancestor(sup.into(), &Edge::Part).map(Into::into) + analyzer + .search_for_ancestor(sup.into(), &Edge::Part) + .map(Into::into) } pub fn name(&self, analyzer: &impl GraphBackend) -> Result { diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 219b3b93..a1116e48 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -48,7 +48,9 @@ impl RangeElem for RangeConcrete { Ok(Elem::Concrete(self.clone())) } - fn is_flatten_cached(&self) -> bool { true } + fn is_flatten_cached(&self) -> bool { + true + } fn cache_flatten(&mut self, _: &impl GraphBackend) -> Result<(), GraphError> { Ok(()) diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index c5ce6dd5..92b3a6e1 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -401,10 +401,7 @@ impl RangeElem for Elem { } } - fn cache_flatten( - &mut self, - analyzer: &impl GraphBackend, - ) -> Result<(), GraphError> { + fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { match self { Self::Reference(d) => d.cache_flatten(analyzer), Self::Concrete(c) => c.cache_flatten(analyzer), diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index b322661e..cb651370 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -104,11 +104,10 @@ impl RangeElem for RangeExpr { analyzer: &impl GraphBackend, ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { - (true, _, Some(flat)) - | (false, Some(flat), _) => { + (true, _, Some(flat)) | (false, Some(flat), _) => { // println!("flatten cache hit"); - return Ok(*flat.clone()) - }, + return Ok(*flat.clone()); + } _ => {} } // println!("flatten cache miss"); @@ -191,11 +190,11 @@ impl RangeElem for RangeExpr { let r = self.rhs.simplify_maximize(exclude, analyzer)?; let collapsed = collapse(l, self.op, r); match collapsed { - MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer), - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => { - Ok(Elem::Expr(RangeExpr::new(l, self.op, r))) + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, self.op, r))), } } fn simplify_minimize( @@ -211,11 +210,11 @@ impl RangeElem for RangeExpr { let r = self.rhs.simplify_minimize(exclude, analyzer)?; let collapsed = collapse(l, self.op, r); match collapsed { - MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer), - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => { - Ok(Elem::Expr(RangeExpr::new(l, self.op, r))) + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, self.op, r))), } } @@ -275,9 +274,7 @@ enum MaybeCollapsed { fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { let zero = Elem::from(Concrete::from(U256::zero())); match (l.clone(), r.clone()) { - (Elem::Concrete(_), Elem::Concrete(_)) => { - MaybeCollapsed::Concretes(l, r) - } + (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), // if we have an expression, it fundamentally must have a dynamic in it (Elem::Expr(expr), c @ Elem::Concrete(_)) => { // potentially collapsible diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 61fa1603..f0d1a21c 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -36,7 +36,7 @@ impl RangeDyn { flattened_max: None, len, val, - loc + loc, } } @@ -120,8 +120,7 @@ impl RangeElem for RangeDyn { analyzer: &impl GraphBackend, ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { - (true, _, Some(flat)) - | (false, Some(flat), _) => return Ok(*flat.clone()), + (true, _, Some(flat)) | (false, Some(flat), _) => return Ok(*flat.clone()), _ => {} } // println!("flattening range dyn"); @@ -134,7 +133,10 @@ impl RangeElem for RangeDyn { val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx.flatten(maximize, analyzer)?, val.flatten(maximize, analyzer)?); + map.insert( + idx.flatten(maximize, analyzer)?, + val.flatten(maximize, analyzer)?, + ); } map }, @@ -223,7 +225,7 @@ impl RangeElem for RangeDyn { analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(max) = &self.flattened_max { - return Ok(*max.clone()) + return Ok(*max.clone()); } Ok(Elem::ConcreteDyn(Box::new(Self::new( self.len.simplify_maximize(exclude, analyzer)?, @@ -243,7 +245,7 @@ impl RangeElem for RangeDyn { analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(min) = &self.flattened_min { - return Ok(*min.clone()) + return Ok(*min.clone()); } Ok(Elem::ConcreteDyn(Box::new(Self::new( self.len.simplify_minimize(exclude, analyzer)?, diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 3515f87d..8c13a9b5 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -101,11 +101,10 @@ impl RangeElem for Reference { analyzer: &impl GraphBackend, ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { - (true, _, Some(flat)) - | (false, Some(flat), _) => { + (true, _, Some(flat)) | (false, Some(flat), _) => { // println!("flatten cache hit: {}", self.idx.index()); - return Ok(*flat.clone()) - }, + return Ok(*flat.clone()); + } _ => {} } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 22e53651..51afbd33 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -60,12 +60,8 @@ impl ExecOp for RangeExpr { } let parts = (lhs_min, lhs_max, rhs_min, rhs_max); match (lhs_is_conc, rhs_is_conc) { - (true, true) => { - self.exec(parts, maximize) - } - _ => { - Ok(Elem::Expr(self.clone())) - } + (true, true) => self.exec(parts, maximize), + _ => Ok(Elem::Expr(self.clone())), } } diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index 6178f9a8..e6c65a62 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -68,7 +68,12 @@ pub trait Range { /// Cache the flattened range fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range - fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone; + fn flattened_range<'a>( + &'a self, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError> + where + Self: Sized + Clone; } pub trait RangeEval>: Range { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 75b0ff22..c63ee8e5 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -689,7 +689,13 @@ impl Range for SolcRange { Ok(()) } /// Produce a flattened range or use the cached flattened range - fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone { + fn flattened_range<'a>( + &'a self, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError> + where + Self: Sized + Clone, + { if let Some(flat) = &self.flattened { Ok(Cow::Borrowed(flat)) } else { diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index b65df8fd..d7364081 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -321,7 +321,8 @@ impl Analyzer { .push((current_path.clone(), src.to_string(), Some(file_no), None)); match solang_parser::parse(src, file_no) { Ok((source_unit, _comments)) => { - let parent = self.add_node(Node::SourceUnit(graph::nodes::SourceUnit::new(file_no))); + let parent = + self.add_node(Node::SourceUnit(graph::nodes::SourceUnit::new(file_no))); self.add_edge(parent, self.entry, Edge::Source); let final_pass_part = self.parse_source_unit(source_unit, file_no, parent.into(), current_path); @@ -427,7 +428,9 @@ impl Analyzer { ) { use SourceUnitPart::*; - let sup_node = self.add_node(Node::SourceUnitPart(graph::nodes::SourceUnitPart::new(file_no, unit_part))); + let sup_node = self.add_node(Node::SourceUnitPart(graph::nodes::SourceUnitPart::new( + file_no, unit_part, + ))); let s_node = SourceUnitPartNode::from(sup_node); self.add_edge(sup_node, parent, Edge::Part); @@ -495,12 +498,17 @@ impl Analyzer { self.parse_import(import, current_path, parent); } } - + (s_node, func_nodes, usings, inherits, vars) } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_import(&mut self, import: &Import, current_path: &SourcePath, parent: SourceUnitNode) { + pub fn parse_import( + &mut self, + import: &Import, + current_path: &SourcePath, + parent: SourceUnitNode, + ) { let (import_path, remapping) = match import { Import::Plain(import_path, _) => { tracing::trace!("parse_import, path: {:?}", import_path); @@ -925,7 +933,9 @@ impl Analyzer { // looking for free floating function let funcs = match self.node(scope_node) { Node::Contract(_) => self.search_children( - ContractNode::from(scope_node).associated_source(self).into(), + ContractNode::from(scope_node) + .associated_source(self) + .into(), &Edge::Func, ), Node::SourceUnit(..) => self.search_children(scope_node, &Edge::Func), diff --git a/crates/shared/src/search.rs b/crates/shared/src/search.rs index 72529f6d..ea5ebb6c 100644 --- a/crates/shared/src/search.rs +++ b/crates/shared/src/search.rs @@ -221,10 +221,10 @@ where .filter_map(|edge| { if edge.weight() == edge_ty { if !seen.contains(&edge.source()) { - Some(edge.source()) + Some(edge.source()) } else { None - } + } } else { None } @@ -244,7 +244,7 @@ where ) } else { Default::default() - } + } }) .collect::>(), ); From 93557d9b7d6bd0a96f2c26e6b0a5b33d5a9b8c54 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 13:55:28 -0800 Subject: [PATCH 32/71] cleanup --- crates/cli/src/main.rs | 2 +- crates/graph/src/range/elem/expr.rs | 47 +++++++++++++++++++ crates/pyrometer/src/analyzer.rs | 2 +- .../tests/test_data/repros/issue66.sol | 2 +- crates/pyrometer/tests/test_data/viz.sol | 2 - 5 files changed, 50 insertions(+), 5 deletions(-) delete mode 100644 crates/pyrometer/tests/test_data/viz.sol diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 052d5a33..f06726a2 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -91,7 +91,7 @@ struct Args { pub debug: bool, /// Max stack depth to evaluate to - #[clap(long, short, default_value = "200")] + #[clap(long, default_value = "200")] pub max_stack_depth: usize, } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index cb651370..e6d7238d 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -273,14 +273,61 @@ enum MaybeCollapsed { fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { let zero = Elem::from(Concrete::from(U256::zero())); + let one = Elem::from(Concrete::from(U256::one())); match (l.clone(), r.clone()) { (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), + (Elem::Expr(expr), d @ Elem::Reference(_)) => { + let x = expr.lhs; + let y = expr.rhs; + let z = d; + + let x_ord_z = x.range_ord(&z); + let x_eq_z = matches!(x_ord_z, Some(std::cmp::Ordering::Equal)); + + let y_ord_z = y.range_ord(&z); + let y_eq_z = matches!(y_ord_z, Some(std::cmp::Ordering::Equal)); + + let y_eq_zero = matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | None); + let x_eq_zero = matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Equal) | None); + let y_eq_one = matches!(y.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); + let x_eq_one = matches!(x.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); + match (expr.op, op) { + (RangeOp::Sub(_), RangeOp::Eq) + | (RangeOp::Div(_), RangeOp::Eq) => { + if x_eq_z && !y_eq_zero { + // (x -|/ k) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Add(_), RangeOp::Eq) => { + if (x_eq_z && !y_eq_zero) || (y_eq_z && !x_eq_zero){ + // (x +|* k) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(l, r) + } + } + (RangeOp::Mul(_), RangeOp::Eq) => { + if (x_eq_z && !y_eq_one) || (y_eq_z && !x_eq_one){ + // (x +|* k) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(l, r) + } + } + _ => MaybeCollapsed::Not(l, r) + } + } // if we have an expression, it fundamentally must have a dynamic in it (Elem::Expr(expr), c @ Elem::Concrete(_)) => { + println!("expr, c"); // potentially collapsible let x = expr.lhs; let y = expr.rhs; let z = c; + match (expr.op, op) { (RangeOp::Sub(false), RangeOp::Min) => { // min{x - y, z} diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index d7364081..2877fed5 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -401,7 +401,7 @@ impl Analyzer { parent, current_path, ); - parent.add_part(sup, self); + parent.add_part(sup, self).unwrap(); all_funcs.extend(funcs); all_usings.extend(usings); all_inherits.extend(inherits); diff --git a/crates/pyrometer/tests/test_data/repros/issue66.sol b/crates/pyrometer/tests/test_data/repros/issue66.sol index a743f2de..c7eb5c2a 100644 --- a/crates/pyrometer/tests/test_data/repros/issue66.sol +++ b/crates/pyrometer/tests/test_data/repros/issue66.sol @@ -8,7 +8,7 @@ contract Foo { function foo() public { Struct memory data; assembly { - let x = eq(data, 0xFF) + let x := eq(data, 0xFF) } } } diff --git a/crates/pyrometer/tests/test_data/viz.sol b/crates/pyrometer/tests/test_data/viz.sol deleted file mode 100644 index 139597f9..00000000 --- a/crates/pyrometer/tests/test_data/viz.sol +++ /dev/null @@ -1,2 +0,0 @@ - - From 0d2c6259292ed34165eb1952f8dcf4b09ef29f8e Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 13:55:54 -0800 Subject: [PATCH 33/71] lint --- crates/graph/src/range/elem/expr.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index e6d7238d..39895636 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -292,8 +292,7 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed let y_eq_one = matches!(y.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); let x_eq_one = matches!(x.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); match (expr.op, op) { - (RangeOp::Sub(_), RangeOp::Eq) - | (RangeOp::Div(_), RangeOp::Eq) => { + (RangeOp::Sub(_), RangeOp::Eq) | (RangeOp::Div(_), RangeOp::Eq) => { if x_eq_z && !y_eq_zero { // (x -|/ k) == x ==> false MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) @@ -302,7 +301,7 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed } } (RangeOp::Add(_), RangeOp::Eq) => { - if (x_eq_z && !y_eq_zero) || (y_eq_z && !x_eq_zero){ + if (x_eq_z && !y_eq_zero) || (y_eq_z && !x_eq_zero) { // (x +|* k) == x ==> false MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) } else { @@ -310,14 +309,14 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed } } (RangeOp::Mul(_), RangeOp::Eq) => { - if (x_eq_z && !y_eq_one) || (y_eq_z && !x_eq_one){ + if (x_eq_z && !y_eq_one) || (y_eq_z && !x_eq_one) { // (x +|* k) == x ==> false MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) } else { MaybeCollapsed::Not(l, r) } - } - _ => MaybeCollapsed::Not(l, r) + } + _ => MaybeCollapsed::Not(l, r), } } // if we have an expression, it fundamentally must have a dynamic in it From fc4a42a3ff4351cf8e190887cd1cc8265a50aa7a Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 13:56:38 -0800 Subject: [PATCH 34/71] remove profile.json --- .gitignore | 1 + crates/cli/profile.json | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 crates/cli/profile.json diff --git a/.gitignore b/.gitignore index 9ba2a3b7..786ab108 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +**/profile.json **/target **/.DS_Store **/out diff --git a/crates/cli/profile.json b/crates/cli/profile.json deleted file mode 100644 index ee62d6b4..00000000 --- a/crates/cli/profile.json +++ /dev/null @@ -1 +0,0 @@ -{"meta":{"categories":[{"name":"Other","color":"grey","subcategories":["Other"]},{"name":"Regular","color":"blue","subcategories":["Other"]}],"debug":false,"extensions":{"baseURL":[],"id":[],"length":0,"name":[]},"interval":1.0,"preprocessedProfileVersion":44,"processType":0,"product":"cli","sampleUnits":{"eventDelay":"ms","threadCPUDelta":"µs","time":"ms"},"startTime":1702240022036.5378,"symbolicated":false,"pausedRanges":[],"version":24,"usesOnlyOneStackType":true,"doesNotUseFrameImplementation":true,"sourceCodeIsNotOnSearchfox":true,"markerSchema":[]},"libs":[{"name":"dyld","path":"/usr/lib/dyld","debugName":"dyld","debugPath":"/usr/lib/dyld","breakpadId":"EC7A3BA0F9BF3AB8A0F48622E5606B200","codeId":null,"arch":"arm64e"},{"name":"cli","path":"/Users/brockelmore/git_pkgs/pyrometer/target/release/cli","debugName":"cli","debugPath":"/Users/brockelmore/git_pkgs/pyrometer/target/release/cli","breakpadId":"7721603B0FB13E2CAA802837F3BC6C910","codeId":null,"arch":"arm64"},{"name":"libsystem_kernel.dylib","path":"/usr/lib/system/libsystem_kernel.dylib","debugName":"libsystem_kernel.dylib","debugPath":"/usr/lib/system/libsystem_kernel.dylib","breakpadId":"B7751381144230B591B9AD7BE461BEBE0","codeId":null,"arch":"arm64e"},{"name":"libsystem_platform.dylib","path":"/usr/lib/system/libsystem_platform.dylib","debugName":"libsystem_platform.dylib","debugPath":"/usr/lib/system/libsystem_platform.dylib","breakpadId":"FC8CD17B8769348C8DCD1BFED022F9E40","codeId":null,"arch":"arm64e"},{"name":"libsystem_malloc.dylib","path":"/usr/lib/system/libsystem_malloc.dylib","debugName":"libsystem_malloc.dylib","debugPath":"/usr/lib/system/libsystem_malloc.dylib","breakpadId":"901200AA10163DAA88165032588ED4600","codeId":null,"arch":"arm64e"}],"threads":[{"frameTable":{"length":5083,"address":[24799,463471,4728535,483391,395759,437291,4732935,4744855,9332,437815,1967263,4604803,4574255,4114235,4251667,4086836,4109755,4226751,13940,4107695,4140180,4105231,4176223,14084,4574115,4569707,4567119,4564555,4609267,4764,4117623,4095840,4574192,4114103,4232528,4561996,4107103,4232527,4113027,4232668,4109479,4212539,4965359,4552179,160227,158431,22123,14072,4105152,1967571,1968703,1971135,1983123,2056263,8939,9403,11647,28036,1985443,1998355,1905031,2060783,2079443,2082307,2045327,2082155,2085859,2084783,4850571,4992,2059247,2080295,2078083,2078495,2083671,2084835,2043604,1969623,2027975,2032895,24243,25592,1967683,1941371,2348775,2046743,2330475,2358163,1952691,2391463,2348011,2366779,2077199,2082179,2045731,1941635,2549787,1951059,1935875,1320983,1349711,1309059,1713167,2862955,2792547,1918207,2628444,1942491,1339367,1740271,1743311,1363955,1370951,1349839,1725211,1772739,1757732,1320903,1724491,1772783,1736095,1770463,1310723,1589631,1591607,1592455,1593335,1572211,2663767,3216163,4060288,4060191,4065124,1309819,1590287,1917987,1920863,2816935,2190143,2004807,1920795,2818939,2200088,1591535,1891639,1567691,2750491,2747463,2710479,2712103,3079155,3117436,1309335,1749015,2862987,2004664,1715055,1730235,1310407,1572895,3216120,1349575,1723003,1772079,1786735,1306255,1633739,1641923,1662571,1665387,1690379,1675807,2753267,2747211,2470048,1633607,1645763,1663619,1699175,2877127,2747127,2461091,2766175,2523035,2704955,2469551,2714739,2764535,2466839,2714187,2764911,3098971,3017079,8903,13627,16891,17176,1575791,1574091,2754791,2721048,1363455,1604991,1606775,1609747,1625211,1308875,1221747,1222787,1217371,1235679,4060343,4065140,1741263,1756383,1757371,1307243,1706335,1422771,1760599,1761479,1308515,1390807,1303895,1391491,1725163,1773915,1310511,1574907,1692155,1681135,2747435,2460659,2766299,3091735,3171788,1607467,1702979,2716343,2764255,2764351,2764443,2714688,1606495,1285059,3099007,2927660,1625411,4064956,1751639,1895767,1713863,2653899,2355555,4850611,14364,1607531,1300271,1349887,1277999,1368159,1376943,1255359,1274507,1256823,1386923,1380007,1930803,1925855,1928251,1928327,1928407,1929183,1309251,1534143,1306647,1570631,2522051,2711343,3080027,3076935,3076075,128440,1722115,1830619,1833203,1229863,2004631,2628392,1769439,4065012,2792611,2614359,2158539,2628483,128175,13324,2614387,2300439,4981848,2747823,2763051,2712855,2771719,2774187,2774267,2774296,2818995,2621879,2231136,1572723,2766235,2766540,1633695,1652507,1654095,1664187,2746515,2737863,2683003,2695483,16868,1743347,1854848,2158587,5348,1607735,1302595,1309171,1246867,1714907,157836,2653991,4848891,4876127,4850963,4979347,4847591,17828,1276915,2843695,2844043,2836359,2319103,2317808,2738331,2746971,2695315,2699611,2699899,5128,1577635,1691307,1670875,2695368,2710075,2713095,2525167,2524607,2574223,2574283,1633651,1638859,1745487,1878371,1746835,2098564,1737955,2610935,2147167,2827771,2756747,3064691,7492,1577471,1703343,2859859,2740943,2740256,1665227,1697059,2877664,2747155,2712979,2525279,2530011,128508,1644603,1217543,1228063,2748063,2762219,3060820,1248263,1250039,1250811,1315215,1385347,13904,2147371,2828227,2710367,2525235,127568,1339179,1734619,2165999,2259355,2866971,1920740,4876051,4979395,4847627,4759784,1308295,1596995,1598567,1700467,4850919,14340,1835467,1836015,2875427,2874515,2483619,2135291,157824,1607671,1267639,2711931,3080535,7456,1384647,2756363,2661695,157752,2299703,2313856,1385603,1314327,1381139,1863839,7380,2713215,2765904,2711835,3117399,3121543,3121476,1710711,1382051,3073095,3071744,2826843,2695383,2699531,2699455,2700960,1633911,1648975,1702859,2522363,2712235,2765847,1714912,2654079,13360,2792775,2300283,3092955,3171087,3209200,1716979,1307387,1877055,1617171,2683307,3269207,3031483,2948747,20063,28184,3104579,3331747,3347931,3043255,3043568,1601407,1219095,1309223,1542995,1593631,1567215,2711932,3060903,3056623,3057671,3057879,3046195,3041508,1572039,2712100,2524907,2761552,1640763,3057611,193368,127908,1593467,2753239,2710167,3079683,3121431,2459711,2472543,2644691,2645243,2637732,2521959,2524731,2739971,2730187,4935091,2317847,17799,128152,2473027,2623340,2700543,2638036,2464780,1388307,2460019,2472955,2524875,2761243,2513771,2513847,2513927,2513248,2683323,14108,1706731,2876867,2869472,2623359,2240104,1575123,2774247,127503,6627,7216,2711912,1383163,1925787,1929736,2525339,2531419,2544875,2531395,2529991,127672,3080131,127924,1588219,1308827,1615767,2663619,3214615,4063812,2644875,2645188,1248879,2711435,2768083,3095299,3017492,1625311,1309519,1594887,2741967,2699375,2698912,4064996,1624931,1308467,1390755,2752107,2699616,2459803,2464311,3079719,3122275,3121532,1633783,1638099,1655679,2522251,2774216,2466712,1670467,2710723,2722607,2719627,2722548,7420,2461187,2475943,2623388,1661991,6204,2513691,2513928,2827951,2760439,3065371,3056651,3041359,19312,1640019,1660087,1671607,128204,3084440,1722059,1729391,1789927,1805331,2519043,2767695,3112640,2772715,2644727,11492,2761575,2514724,3122155,4981824,1662427,1697635,128352,2827567,2758191,2699235,1307835,1392663,1393455,1402479,2741427,2743235,2721075,2722583,2514744,2463727,2544851,7408,2758799,2758575,3062503,3046183,3036936,2241788,1662507,2513907,5120,1544575,1546379,1547403,1549491,1381659,2464387,2240752,3086447,127936,3076056,1308731,1287607,1326111,1320003,128196,2200520,3122096,3122060,4060328,2531352,2760015,2699591,2753019,3061627,3057643,3057699,3057687,128444,3079192,1599987,2698688,2711075,2462583,2623348,1387839,2472887,2513564,1594987,2738395,2748736,1363351,1259639,1556171,6028,1741831,2078528,128496,2711171,4984,2240100,2638000,1285035,1910387,1912731,1910267,1908939,1908823,1912711,2949015,4981860,1548643,1928387,2749383,2699435,6088,1550227,1904783,1929091,1929368,2699612,1545219,1711663,2460375,2483047,2650779,2629364,3122216,2240120,2716395,2704775,3105103,7448,2464091,2482944,1920700,3098892,3086463,128124,1568419,2730960,4064960,1689287,1927591,157792,3079167,5884,1277871,1254279,1386455,2757519,2712423,2465100,1672927,2700215,2623623,2546563,2226080,2462584,1699311,2579019,2757556,1668603,2750243,3063183,3266859,3266919,3266947,4981740,2461923,2645324,2948411,3053591,3072344,2774419,6212,3122924,1668487,2751319,4981736,1363543,1561451,1780171,1549899,1672735,2513435,5804,1837511,3017603,95628,1706163,2869412,3216575,4063612,1743331,1766095,1765303,1767215,2484211,2047531,2257739,2260031,2744503,2669195,160236,4060215,4065152,2740648,17783,13916,2755691,2712424,1349787,1297939,1883463,1373859,1251947,2856587,2855823,2855804,2523143,4944,1254695,2097959,1381515,127972,1765267,2744915,25120,1366432,2825931,2672763,3063251,24768,3172039,4063500,3095335,2927944,1607267,1607955,2712195,3016688,2767416,1690979,1623619,1863819,1871399,1871132,4875680,1308371,1393943,1929071,1560283,1366991,1311976,1701859,95512,2654032,2767539,2490804,2466188,1694667,2695288,1838695,1263179,1841987,1780683,1272243,1804639,1925975,1927464,1549767,1204199,1803535,1209607,3073111,3072583,3072975,3045311,3051964,1551119,1916208,3216175,4064968,3076900,2047279,2744479,2775819,2771119,2774107,2771512,4060276,2004828,1710763,2878468,1682579,3096155,17168,1338083,2001407,2747924,1623627,1863847,1871343,128276,4065076,1576031,2766203,2460572,1770464,2260503,3057472,2714627,2773092,1780899,1711095,2664923,2672419,3009867,4850528,2877439,2625284,1227651,2665987,2672575,3271791,4065048,3093051,3166572,1688707,2699119,2699831,2700340,1723987,2469623,2475383,2513219,2486051,2645231,2472856,1749667,2187391,2653147,2476079,3090716,2200080,13928,1749699,2865755,2791715,1920596,17276,2855824,2460755,2474388,2525032,2699139,2698932,2758559,14048,3036964,1920656,3057659,128156,2313784,2463272,3061559,3266843,13344,1758115,14356,14348,3088819,3156095,2793379,2223136,2739943,2728756,3093639,3171400,3086431,2793239,2238059,4065044,2711475,2765899,2190571,160212,4060308,1833263,2119515,2816391,17755,1766771,2841659,2061419,14116,1736867,2876943,2845555,2845556,1682939,2711116,23936,1733111,1483691,2870231,2135195,2258555,2874643,2871112,2728816,1689359,2698795,5876,1320860,2751352,2839451,14324,3156112,2828203,26492,3076928,1736735,7440,2845379,2862352,1930627,1709751,1380604,3156187,4063524,1757935,2810411,2811559,2785663,2789027,2788576,2238104,3079695,3117788,1574995,2765972,2654020,4848596,2864247,2649671,2628223,25212,1218888,3266891,2741295,2771239,2771188,3106079,3077279,3027584,4850556,15740,2654059,1742351,2098600,1698895,1320783,2843611,2843767,4935135,2317887,1551087,3057252,1665267,1380000,1696839,4064852,3097791,3336827,3346883,3345051,3345247,6064,2695519,2200811,1570632,1690803,2685676,1703475,1871487,1871459,3095824,2513751,3016919,25336,1681015,2793107,4820,2698756,2700968,3057180,1689335,3261107,2826643,1696879,1248135,1537199,1540075,1542175,2877155,2733519,4850632,1633563,1643843,1653303,15452,1636939,2740535,2739896,2826423,95668,2699271,1671387,1928715,1927728,3101043,3077184,2513199,2466708,1920864,1772663,2139383,2249671,2267135,2270519,2270068,2249499,2673139,2699215,1595099,2767499,2792627,2794300,2317792,2223287,14572,1897031,1775359,2825391,2884527,2880851,15420,2766263,2773152,2469519,2704920,1226439,2845372,1665331,17000,2200100,2475780,3057236,2466807,2525919,2488528,1584255,127692,2516531,2735203,2659803,2703303,3089971,3169071,4062431,4060928,2749072,2241091,4063584,3112596,2826004,2740227,2728668,1576511,3098655,3162883,3201667,3206044,4063536,3073043,3071976,15931,188236,3122880,2767619,2719064,1758511,2197131,2822767,3212255,3076032,1680907,1378095,1928303,2700387,5360,2748576,4060395,4065052,2712203,2719672,127712,3266748,2719596,2354672,2669063,5188,2525615,4848748,2740503,2745564,4876035,160015,17884,1920648,3057515,7484,11388,2699507,5296,4759772,2513671,3086415,1928067,7452,3108819,2927891,3209404,2839339,13364,2699768,5856,2704840,2863043,2614667,2178079,2779224,3212319,3028251,3026807,13992,4065128,2119419,2816303,2771051,3096255,2976852,1690275,2685699,2704800,3266627,3266592,1358219,2843412,127988,1925923,2069056,1738191,2357175,2115296,128148,1298011,2855516,2699256,3017308,2710339,2190487,2751143,2712467,2524407,2319059,2317928,3057247,1928171,1731631,1733759,2874560,2811159,159864,4064888,5020,2711652,2200467,1920711,2624227,2205187,2682824,2793060,2699648,3079244,2713076,2206155,5812,1699347,3214699,2699356,2747519,2700980,1765904,2793076,2299888,1929776,2098588,2653243,2863495,2140507,2608436,2811347,4850884,3057220,2730119,2730055,2729844,4788,2355536,2785691,2788999,5848,2827231,1573511,1917944,3057395,2461596,2699544,1758003,17495,8140,2544867,3266803,7360,2531412,1255211,127976,2869443,4832,2863183,2622243,3119100,2810887,4060144,2649707,2719584,2728532,4850940,2761564,1930615,2704908,5220,2816991,2231224,127700,1592411,3258440,1308107,1404719,2763211,3240268,1767279,2878487,2320327,25691,27536,2832659,2835183,2835211,2835239,1925955,4060320,1654012,1920608,3027647,21435,23548,2513048,2513531,2712835,3212055,22051,11240,1572355,2730211,14332,3057208,2764632,3017256,2522223,2525148,2728576,2927671,4065028,3076856,2855747,3060324,2788967,3017279,4981872,2793172,1689591,2077323,2082059,2085839,2513228,2300332,4060176,4063875,4058735,4906124,1854871,2032103,2021383,2032759,2021371,1927472,4064900,2826063,2880683,2881975,2882051,2882907,2730156,3117159,3124908,21364,3117884,2728452,2826676,3211999,2855603,2200036,2826827,1915684,3057380,2774372,1566987,5112,1715175,2700956,1767023,2070791,3156140,3057300,2861055,3245895,3243887,3244263,3067539,3074283,3074243,2771708,2238116,3122104,2513587,2625483,2546883,2216631,14368,2624212,2789055,2788564,1703443,2683324,2531388,2880871,2880984,2774308,2710299,4060248,1927484,1766807,2578951,2662063,2513260,1920943,2624032,3108923,25204,2004796,3172075,3201059,3203456,2699291,2698944,3086460,2774188,3064791,2793627,2653311,2622288,10416,3076008,24500,3088644,3075992,1549371,2845536,4065024,2843144,2827051,2774027,2528579,2729099,3079819,3122860,2140691,2608252,23883,2774212,2695347,2700592,1605307,22139,95780,3122896,2728528,1736983,2098580,1568223,2313879,2354824,2525147,2544632,1685919,1871304,2663691,17500,2843467,2843444,2843168,3091883,3117792,2794323,1648527,1602063,3091951,3207803,1752723,3090804,2788608,2730239,2522783,2704987,2748535,2712587,1551387,1871511,1843643,24788,4632,1320708,2461540,6036,8052,1570367,1302531,2746383,2774087,16711,27076,1349631,2843388,2739700,2827459,1251619,2855620,1675395,2747971,27352,1267383,1633827,1636179,1654887,25256,2529972,1316187,1384567,2524355,2729868,3112611,3076712,2792007,2109239,2002987,2628783,2775643,1664711,2761647,2719068,1633167,1880607,1651347,2514748,2546636,4065104,2845459,1914728,13088,3112575,3076688,3057396,1392383,2854616,2354671,2835071,2834792,1928627,1927552,2740859,2730020,2525136,4848868,2523096,1700607,2877428,2461468,2531400,2761055,2691523,2518907,2711415,1589304,2460636,3075592,3088927,1702999,2861827,2879864,2672543,1384355,2683443,2800536,4981856,2767500,2712652,3093103,4063532,2871260,1920780,2645179,10476,1669479,2759675,3063907,2460131,2462332,1697595,4876036,4064932,2469504,4934988,2771684,1929152,1928231,2653331,5828,2614471,2235439,2466808,2712896,2845307,1929492,1741468,1929508,3243899,3244151,3068283,3074411,2004663,2628552,1685847,1871431,4860,1713915,2876995,2862488,2793640,1254439,2672548,3117176,2513880,2222984,2654031,4624,3057216,2523991,2728472,2462507,2711076,1306452,2486180,14352,3016736,2700708,1735559,2665340,4847680,4065108,2832644,128260,2628804,4878072,2793215,1549543,2878072,3056748,16872,3086516,2465072,3121416,2469700,2710683,3121704,3072084,2466328,1696947,2728284,4065132,2524856,1927892,4850960,2235055,2777896,2201088,3122128,3057847,3041659,19771,29252,2672868,4064688,3266699,3266935,128452,4065064,1230019,2627923,23828,4848824,3057660,2514331,2463344,1685947,1871415,2845255,2862456,3266907,2861315,2832687,2835227,2463364,26900,2200556,3122828,2004620,3076068,1896899,1385543,2731216,4064988,2699919,24752,2699640,2205119,14580,2544815,3087852,4935092,3122140,2845232,2793028,2810923,2681663,2881276,2740055,2734896,3091856,5152,3057563,2773704,2524480,3166827,4059284,3057531,3057672,2728799,2765908,1928695,1928607,2734664,2839504,2793372,3117136,3119256,23832,1929011,1929339,2637516,3057595,1391151,2874612,2627984,2695503,2698843,4847576,2748043,3079888,4876052,3122280,3103383,24832,1571775,3071903,3071967,3072100,2068864,2522607,7424,4672,1385395,2698676,2699991,2771875,2855728,3260707,3286175,3289003,4063560,3079928,2739840,1315651,1897871,2844972,3091595,17132,4065056,2712535,2317872,3216196,1540123,2872852,4848612,3017544,1697155,3098503,3201676,1349788,1693915,2485863,2486124,3117428,2654092,2767031,128180,2001099,8220,1838352,1544899,2871156,1633871,1647667,1659023,3113859,1930672,2771983,2771652,2624172,2625360,1693243,1871447,2762756,2474551,4850948,2231723,1699547,2140680,1928208,2826563,17328,2698772,1607319,1265939,2884351,5024,2741819,2686087,2490483,1568839,4876012,3062403,2729895,4064972,13112,2779167,1616256,1309067,1867411,2839471,4848920,2047647,2628632,1925819,1927639,6192,3203508,2828119,2834840,2083664,1871383,1675975,1770311,128140,3090795,3171279,3088812,2699636,2531376,2313748,2627956,2528743,608368,3156128,25275,26992,2300424,4935152,2260311,13920,4864,2514008,1767883,2098816,1381787,1914868,2855948,1719355,19808,2845300,2223251,16780,3108787,3057455,2513492,1549291,2300468,2927500,2098568,2522891,3105291,2862360,2747636,2767128,2685811,2525708,2098592,2158255,2354660,2524763,1929772,1615991,2628167,26504,2469492,3121572,1550971,2069048,2516843,4060304,2466200,3071819,3072932,1605583,4847560,2205151,4847832,1871144,2474552,1863951,2713975,16804,1306704,1871344,2827492,2721103,2722599,2719620,2761455,3266875,1927708,2313860,159884,2811495,2788516,23888,4696,1220879,1217195,2666231,1920620,3076063,3075580,2764484,2810243,2669303,2531472,2711443,2764720,2816268,8908,1692627,2299984,3206036,2628408,2712104,17480,4064772,1556211,2843696,2473028,1386559,6044,11615,29604,2546616,1769007,2060991,3076916,2513151,1380588,9256,1609767,1858747,1858455,1858388,2240592,2158371,27012,2470068,2513455,2514408,2699532,1914756,2757859,2677311,3118124,3031395,2919403,2930411,2004780,2771508,1625511,1557203,1875711,1558371,3056755,3056644,4065156,2880715,2881196,2225812,1692327,2732072,2004700,2714607,5324,11332,1781415,3053536,3117243,3124043,3043559,29628,2765832,1741796,2728432,3122908,17364,3057815,2645308,4063580,5924,3079164,1616031,14588,4058679,1558059,2546728,3104755,3043580,1672899,3079608,2226072,1606503,1858771,1858704,2461036,1914971,2318447,22103,18875,81199,6324,3122211,3124432,2462956,24775,74972,2700079,3041284,1871475,9096,1666715,3092612,2828151,2835419,2650831,2629112,2523455,2730312,1597331,10571,45884,2225120,3075568,2061383,13391,108644,2699355,6076,2623284,2623608,2475659,2480396,2740136,2645272,2869424,2524587,5164,2474279,2629288,2474027,2466956,2225488,3104403,2700515,4876072,2546500,1699147,3102699,3241292,2826887,2361063,2339684,3057767,1927496,1405455,3099071,2977511,19859,29300,2481091,2483187,2481084,2766236,1273468,25604,2513171,2485631,2486023,2514692,3071879,3072547,3045128,1314224,2522832,1925820,3269411,3289159,3043652,2761387,2690984,3046184,2531407,2540172,27088,3122288,2481072,2779255,4752,2759211,2754136,3101967,3240636,2874780,2475944,2475671,2629004,2645200,1928468,2771576,3053516,27040,2474380,1307423,1619767,2475875,2469444,3113839,3156392,2474159,2644843,2635712,2623308,3124972,1576835,2853331,2855776,3031367,3008988,1544172,2544876,1928787,1929311,3216059,4065148,2472679,2629104,160172,3057988,3079140,4063504,1572171,1928151,4065080,3037455,3037427,3037443,2465212,2635732,2463284,2826804,2540184,128044,2623652,2764836,2779300,2544835,2712068,4979348,3046171,1227759,3171315,2629248,3017524,2713995,2459995,2650807,2620579,2620607,3240288,3122100,3037416,2712804,1625711,1217859,1413455,2845000,1928875,2740660,2880887,2513892,2772107,2826615,2318867,2772687,2744803,2774328,3043235,3048940,1380076,2464172,1862704,2546436,2645136,3082327,3238919,3077507,3121584,3216536,2525064,2201096,2763556,2699556,2845212,2699576,2240736,2465675,2097699,4935299,23852,3117352,2825587,24876,1702776,2747091,2225528,3099047,3043120,3122832,2466911,2473831,9352,2636667,2636587,2635812,2514300,9180,2700295,2355300,1680947,2629343,19791,30140,3122224,3043071,193400,2762607,3087884,1551175,2473183,2513112,3117416,2320283,3244715,2747112,2475363,2514215,3048884,2700320,2682796,4065136,3076795,1863935,2635708,3157131,1625611,4848839,1928316,2225968,3080116,3266971,3037744,1204023,8152,2637724,3043107,29460,2763520,1708584,15432,1702831,2083687,2081943,2713044,2227676,2462287,2481060,2462948,2465347,2183135,2258164,2728616,2767968,1557975,1925991,2614732,7472,2227323,29688,4065112,3037008,1833399,1310795,2664051,2795204,4064908,2827315,2638032,3122088,2227184,127480,15588,2517775,3098759,1285079,1858395,3117860,2751176,4876128,3046143,3041268,3117164,2241784,2475796,3266764,2766599,2698815,2635968,2629136,1672947,3289131,3287300,1668191,2183199,24908,3090743,17396,2462968,3072080,3043223,1379907,2729328,4759880,2078019,2080319,16120,2713144,2695415,2700972,15908,3117356,2729856,2869488,3076876,2629043,28288,2861843,2494251,2614939,2175796,3076724,2638016,2827528,2240144,3079808,159996,2469792,3080039,20332,2844975,3121488,2737463,2719603,2718684,2826931,2628968,2623424,2544816,3203428,2475551,11156,2472263,13368,1312212,1925887,1928767,3076756,2069072,3089955,3170124,158364,2625331,4792,15712,1927915,2472768,2645348,27560,2677271,1954479,2813052,1721420,13300,2747991,2645336,4848632,3043623,3048900,2729740,2540192,2699692,1928011,2636647,2466792,3061519,2470000,2472784,4065072,1843735,2623452,4064844,2711340,3037152,1693171,29812,2355308,4065068,2774176,2719643,2466780,2644855,2637708,4848620,2461291,3056671,3090003,4060848,2704807,2771540,1579839,2741047,13372,3080323,2645292,2227336,1928252,2235048,2764332,2764848,2771568,1638440,2637443,1928087,1927652,2699184,2469764,3072959,15476,2729732,3086403,3057627,96156,2774192,6180,3056643,3046076,2628952,2513551,2825611,3091683,13612,2635988,2354808,8856,2466240,2517883,2513823,3121556,2623368,2740476,2225371,2774352,2466292,2690980,2494123,2649815,3017820,11376,1694751,1871327,95852,1694759,1871367,1843659,11624,2948548,2695508,1606911,2879927,2641587,26980,1568163,3266643,2737099,2688307,1916451,2546540,3102015,3079720,3117412,1568899,2644924,3076128,14420,3264951,2183116,1929720,2881955,5624,2690972,2825600,2205951,2755708,3043611,2464228,3017540,11452,1648936,2637980,3072540,1379336,2513728,2862212,3117740,11239,2703331,3075576,2637972,2225476,1929756,2650820,3043284,2666259,2462408,2762740,2881895,3102799,3077195,2461644,3057871,2464204,3048628,3057799,1668451,2715599,3016996,3087904,2719608,2225175,2225944,2260219,3057439,3041680,3057723,2765912,2722567,127844,2747472,4877308,2624044,2482964,24472,2077975,2083495,2083235,3209360,2463204,2747031,2461156,2546631,1582423,1954399,2657971,2693924,3203484,2882111,3217803,4064055,4876160,128064,2763519,4850620,2472804,3041603,28444,3079224,2574303,2574807,3046636,9244,2629360,2241080,2764788,2512980,1927616,3090163,3046896,2771580,2713188,3162596,2462972,3057596,3121487,3122168,2623260,2623604,2513872,2514060,2355304,2645392,1205471,3056608,2461400,16816,1379187,2854648,2464800,2740332,1609271,1858627,3057483,3041564,3088492,3096231,2513032,3043224,1617532,2514684,14360,2637763,4066056,2473288,2764708,2645132,2645244,2226132,3117332,6052,1558839,2860775,3046892,2645232,3071764,2623304,2178108,3009551,4947355,20040,2258152,2698864,2238028,2879867,2071640,2464388,3112599,95636,2710428,1702655,3268500,3094051,4060132,5196,1707020,2927568,3043612,1843687,128256,2238032,3121720,3117784,3009007,3259688,2463376,1639164,2700059,2650819,2620128,28260,14440,2845392,16848,2623352,4759776,1376619,2874404,2019195,2018975,2021855,2845460,2623644,2700920,2762771,3240232,3053712,2241076,2459536,2665476,1737167,2524904,2728564,17288,2841519,26940,2513607,2843143,127984,2514360,2528679,2575316,2740040,2862059,2831932,2880819,2069003,2091776,19879,29692,3046196,3091463,14468,4982328,6200,3095399,2976828,6032,3043676,1929768,2238088,2513128,2774200,9259,1669847,2816963,2472684,3260227,3285219,3078279,2861155,3137303,2970071,2976864,3112591,2761123,2739804,2855515,157804,1356659,2153580,1954551,1860000,2530056,1928991,1277011,2857716,6100,2462940,30532,1308419,2824963,2358899,3266604,4979304,13104,2764808,2731204,3122200,1929212,2624060,2525204,3057336,2735771,2747800,3209240,2474483,2467052,2712108,3265936,3156111,3209375,4063435,3079112,1252371,29872,2076984,9388,2240756,2877040,3122324,1706383,2518091,2258027,2465068,2711616,2638020,2839087,4850916,2766835,157800,3017064,2875196,3080143,1920588,1843612,2472664,7736,2760736,2459516,1685819,30032,1929344,1928812,3088900,2528659,193420,1615719,1582647,4065212,2728516,2843819,3266787,3266564,1573975,3240128,3104384,3017016,2753195,1920716,19364,1914727,2513876,1255163,2544844,1696607,2730971,3122856,2700432,2948539,30116,1902840,20344,30552,5264,1306519,2843120,2472976,19240,2463400,14124,2474528,127944,3090752,3084468,2513952,2473000,2622395,2545963,2223504,1570603,1548931,3048944,2619540,3204191,3195172,5888,5052,3087896,2838676,4065096,1579283,2258188,1696443,2731092,2855764,1251908,2764872,1305319,2857872,3203476,3122092,1548731,2799688,2225108,3122844,2225184,1713539,1311095,2765816,2772808,1557703,1858723,1696747,3132152,3017088,3057516,2519299,2540527,1568184,1691887,2513008,1920664,15884,4060544,2764820,128284,3076676,2464792,3091808,1308792,2728468,2206179,14612,26952,3169404,2712412,3103419,3209543,4064672,2712004,3041676,2740035,2462424,2728800,2226064,3117388,2860967,2231208,2729855,3060788,4065040,2623360,2525531,2771783,2711876,2033667,2710564,1366372,1928184,3264995,4065216,3048920,1696991,2466035,2722572,2869464,1871288,2699956,2225592,2467356,3122460,2641600,3060840,3209228,2517039,2540555,2472788,2514728,1320984,2698820,2774136,1311055,1931459,2658208,2828267,1915912,1843751,2699971,27620,2225440,3243868,1668991,2774388,1928356,2624036,1871424,2206084,2711836,1600480,3089004,3056656,2472748,2474404,3046172,1790319,1797611,2665395,3056640,2762556,3076044,2843591,5960,4063920,2712452,4064824,3048632,2700924,2645312,1706244,1672671,2700976,95784,2004808,3206024,2654008,2524023,3037056,3103436,2645320,2777695,2699811,5936,10456,19804,2710056,1306531,4491616,2712800,4063544,2360807,3270368,2514740,17640,3112604,2514736,28004,26828,95944,46199,5711,5964,3088756,2240724,2224367,3043756,2645220,2529332,3207944,2827167,2614779,2777612,2472880,2225300,1607031,2844611,2855836,3122256,2241064,3122116,3266668,2524472,1798039,2473055,4060876,2463764,2235131,17400,2635728,3121444,1858711,3285383,3122300,3046156,1550783,4877268,2183152,2529304,2746204,2621811,2764236,2845224,3117223,1226363,4847612,3053512,2200012,2513836,1348460,2461124,1843767,1309023,3136731,3235599,16388,4064976,2628984,2623396,16644,3053472,2573616,3113647,4952,3053552,2614736,3122268,3122872,2637744,3171320,2225448,2474344,2715612,2711448,13392,2523992,2739904,1320795,4491772,2097647,2453287,2607928,2629287,6072,2465411,2178784,2512976,2158540,2718720,4065000,3046212,1765719,2840623,2641596,1765159,2854600,1765788,2843136,2843676,1765160,14092,1297043,2843288,1765236,1339443,1269035,4935136,2200096,2486148,2862024,3313900,4876120,4903251,2355324,1769839,3258644,1928052,2313803,14372,24244,2470024,3209532,2216595,2774208,2635744,3079983,2713284,2767032,27960,3043692,2205292,2751200,2300068,14388,1773575,2135208,2731268,2730192,157840,2354696,1672311,1277595,2513136,1573639,4876740,1735707,2313820,1927935,1927732,2299612,2614419,13628,2238120,2205331,2793152,17531,15512,2712572,1697615,2473075,2650919,2757540,26364,1230011,2608288,2739920,2047407,3240360,2687807,96199,49711,56495,13175,5928,1227043,2256195,2365304,2839319,19288,1666923,2773136,17668,2816459,2526352,188244,2628696,2879996,1642683,2881811,2881144,2644648,1715488,2695600,2624076,1596308,128200,2824884,2734639,15376,3122152,2728680,1622899,2704828,2740167,2733844,1582091,2741316,2462340,2728704,3017128,2475660,4981828,2222951,16536,2225356,2462299,3060427,4896,2699492,2522772,1769803,1901691,2216295,2623324,5368,1925840,2525551,2575008,1592396,2819056,2519203,2759251,44251,130031,44447,17720,28408,95908,157832,3081672,2884623,157756,2699672,2879804,2766156,2466716,3096191,19840,2320228,3057547,1694795,2731867,1380580,2839647,15424,2930412,2948947,14528,2747700,2719659,128176,4850856,24864,3136887,3033535,1871460,1929416,1549059,2464772,2771016,3102575,3188904,3099056,1786183,1889756,127912,3087908,2880808,29580,16276,2083199,2082627,1871104,3092671,3180416,2729092,2530027,2544840,3136515,3152508,2711496,25067,27532,2462988,3122308,2843424,3057831,2644700,3043516,2466000,2645296,1927488,3017008,2699292,3043696,2513852,3043716,3079120,1379008,3045251,3028808,1843791,2825671,2224399,4981876,2464796,2712559,2765864,20148,30044,2241092,1871183,3041652,2839576,2714040,1700075,2728604,2747092,3048932,3102295,3079760,1930831,29768,2880751,1927740,3057524,3041420,2766996,2691536,2749599,14128,2740068,3117432,1773955,2030172,1928855,1929784,2771744,3072368,2666079,1384324,2764764,2793136,2472936,1918204,2528440,2855488,2223176,2695440,2773144,1229883,1245867,2760704,2629192,1549639,3079900,3031427,2578952,2765860,2525735,2729100,1928031,1402595,1403832,1670763,1688692,2624068,2700356,1381460,30064,2469468,23860,1637936,2531468,2638028,1307507,1610639,3046112,2747923,2927604,2638004,3098820,3046612,1706036,2081967,3087864,2466164,2767651,2719040,1699312,3080380,2463752,2514464,3209408,3102675,3077060,1606647,2494263,2071616,2525488,2764888,24652,2882131,2882308,30356,2884747,2177887,2779240,1700507,27400,24260,4063939,4058707,2735159,2773947,2771672,23824,2628992,1606451,1910283,2636600,2699560,2839663,4903160,2740296,127340,2464288,26352,3009176,2629204,2231443,1692291,2728184,1597615,2205271,1574855,95956,3056712,3041672,2241776,2462416,2835064,2467328,2644740,3076051,3075220,30492,11324,1550247,2680279,2681683,1927448,8804,3043280,3113804,2097628,2948436,3075284,3088528,3057739,2573652,2825959,3075184,1682735,3017024,2672752,2927480,2793712,25300,2462288,2874644,2862244,19248,25188,3052208,2546468,1625111,2546980,2158608,7336,1549111,2739432,2235183,2614695,3122120,4065036,1903728,2700332,3057832,3094183,3207964,2699460,2838819,2354620,2227492,2653880,1616100,24468,2862220,1618679,2606855,2320671,3156160,7108,3041320,2544712,1672979,2040464,2739960,2544856,1568183,2472908,2826492,2644664,2485719,2948387,2523012,2948372,29732,2637472,3260547,3273987,3078212,3043256,2474267,2482940,2522100,2620140,1405295,2658180,2747316,1403147,2712256,3162964,2700240,3137015,3315524,2083344,127884,7880,2969156,2518179,2466988,25664,2523487,15735,188200,1571847,3200316,3156152,2205356,25168,1797071,2283472,3043772,2513692,127428,2513276,2475896,1871256,2628224,2460315,2183096,2699248,29472,2240088,2764412,1928464,2767559,4847540,2464568,1251543,14764,3057992,2226012,2711152,16667,3189367,2225636,1380584,2828187,2834732,1714788,3086464,2818924,1927416,2695584,1731727,1734380,3093811,1702967,1915868,1929396,2832139,2626564,6448,2463224,2465080,2644880,2216520,3053380,1308880,8828,25596,1927576,23884,2624008,2645288,2773927,21507,28983,1381632,2621900,2758360,3043700,2461976,3008835,4491816,2068927,2764672,2462996,1699088,2845196,3080440,1927568,1207043,3036968,1871384,2728552,2083339,2747436,2205372,2474348,1347460,27492,4877280,2695451,1306812,3017508,3076720,2729228,2826319,2688248,2739948,2257995,2608088,2225355,2699048,3124964,2762207,1551303,2878504,30100,2738140,3266616,1306816,2744812,1404759,3201548,1393419,3258552,2461628,1709803,2711536,2645164,3117400,2513956,3201040,2513456,3072384,2522876,3266596,2623344,3098716,4979256,2544796,2919219,9364,2712264,1697300,28116,3071708,3122444,3079908,2465144,3218899,3193143,4906216,2516887,2731780,1931048,4065008,3122916,1593416,1380643,2764716,3258660,2835199,2661688,1251544,13436,2466168,3009524,3102620,2732224,1555931,1770375,2126256,2638024,2636588,2158560,3122316,1765244,19344,2719660,4065092,2525308,1710571,2665555,1736156,2700516,2764900,3046168,158452,2761315,2721060,2517055,3041428,3086532,2225056,3124660,3096984,3112580,2773848,2464732,2227308,2216244,3053544,2711636,3265912,2004632,3072700,3045236,2464360,2523564,2465688,5384,2728692,3168915,4064892,1691755,1773851,3258719,3304308,2644904,14460,3079272,4876040,2575352,1226159,2364563,4491368,2699520,3072332,3079276,3086392,3060395,4935248,3137343,2343780,3036940,2666283,4935479,2524672,2719676,2733676,17388,1668576,2492672,2728724,2728744,1555823,3135639,3066963,2714188,2608132,1616903,4876224,1798147,1661343,1575479,2466664,1205755,2772351,2078552,1706996,2686435,1928436,1709323,1931844,2625264,2882952,3216135,3288207,2625376,1930899,2719615,1729039,2874619,3243712,2742855,2675347,9304,1603816,2469592,8892,2620348,3009512,3057332,2453292,3056696,2711980,2860556,3204196,1920572,1926032,3122084,6112,2225792,3209428,3043728,2730823,2629356,16764,1675831,3210275,3216863,1929320,2224540,1380132,2843508,2718727,2466228,3266731,3195184,2638008,2663711,2839503,2217475,11548,2747128,2461560,2473168,2745011,2765884,1591828,3075200,1610323,2818967,2315536,2919392,2200028,2513932,3117892,2747448,3041300,2513908,24464,17824,3097003,3207815,3199140,3016780,3080004,2461512,2524100,3271699,3057900,2771219,2733372,1246903,2699456,1911472,2480259,2480408,27752,2653884,2620595,2753003,24884,1614499,4058112,2948496,1697351,2765936,24700,1699487,4876812,3079256,2084752,1309383,1404255,1405488,2636000,1766867,2847655,3133472,2460859,11540,2466680,3017548,1871223,1928044,1712884,3046124,1929520,2355612,4063556,2862464,19244,3088608,6324,2653976,2733976,12260,1616855,3072408,1387635,9100,5260,3080536,2514127,2731947,4960,2747476,6196,2463808,1871416,19716,2623576,2641608,2844103,2858696,4935120,1765136,4058520,2464523,2698680,2774268,4060284,2767484,1254107,2674196,2464584,2835528,2695416,1920652,1920804,2459664,5332,4728,2158440,3087892,3201436,2845360,2758359,4064904,4058432,2811259,2585876,2816408,3156092,2235144,2774232,10716,3017388,3244191,3232659,3232687,2466756,1914708,2834995,2224488,2628424,4060300,1381592,3089840,128240,3082339,2459948,2200108,1548447,1844388,3087840,1926088,4906160,1384275,2880067,2069572,2514240,2300268,2793671,2239459,23784,2733732,2206076,2877052,1220375,4884,2793144,1380451,2470012,4979328,1911483,1904012,3080144,2827008,44252,4906232,2737776,2948316,3017104,74880,5968,2464103,3009184,3157003,4850500,2948468,2466272,2530028,1871255,2513044,3189175,4063632,2715699,3209416,2483604,1550407,2469668,2227752,29588,3216147,11592,2764392,2680143,15620,2672592,1648475,29832,2513468,14100,2319024,2098596,2863127,95644,2683227,2844976,2453280,2365495,2343843,4935527,4880,2700275,2834935,2299315,2739996,2339535,2342827,2650760,2638040,7392,3048612,4850596,11292,1931023,3265043,2685476,2638012,3043704,2718728,2765940,2004692,1386587,3048904,3098740,25732,2178135,4936495,2772864,2239420,2729708,2070755,1731939,2464284,2485943,2045612,2472840,2578996,2472764,2761707,2712636,2546736,2718691,2745552,16880,2712208,1773916,2729696,2919416,3076740,1703463,1741847,2464144,3041308,1380108,3121576,1667239,2773084,3152343,2625312,2752343,2513036,3137275,3045471,3039419,25420,2881639,3122304,3244859,3269488,7916,2930396,2635696,3156132,2747808,3214660,2644764,15688,2525215,2544716,1386884,3156116,3071939,2766204,2737064,2695364,1594972,2929440,2699620,4060252,1706988,2740076,2200020,2513808,3122264,3122900,3016672,2773128,3172080,3079624,2695592,5456,3091795,3180315,2883232,3171107,2761428,3087824,4875676,2472243,3057456,2826299,1843719,127520,2513988,2097672,2546472,1640803,3285395,3288147,3287411,2767224,1928172,1356739,2000780,2755916,1858496,4800,2763008,2714672,2523971,7184,1931723,2658599,2694216,1929228,1920915,2524552,17412,3057712,3207827,95720,29720,3288051,2355580,2227448,2574268,1558020,127928,14112,2760680,3117780,2019163,1697136,4878076,2530004,3045515,2970087,2225996,3091343,3181028,3203520,4491684,2728768,2859912,1929524,2828107,2834872,2771720,2699552,2547016,3266715,2464744,2745848,2019224,1610599,2976824,3079932,1920900,1711795,1915216,28296,1715456,2700928,1605995,2462980,157844,3122236,127544,2733856,3099024,3204264,1694275,3076784,2466656,2620192,3046160,3117364,2845208,11440,2299128,2712504,1681783,2513500,2544628,2826543,1931008,2223343,14552,1569903,2685595,4981864,127256,3122292,2859888,3053484,2625468,2530024,2761056,2773140,2461064,4059860,1403819,1349588,2731684,3053567,2699624,3121544,1928372,2225956,2761531,1902820,2190104,2019151,2021627,2021500,6980,1391128,1697335,1349840,1862728,2762020,2773088,1707839,2854624,2729912,2528604,2464112,1731112,2465360,2771932,2948487,30548,2753823,127960,2464740,26892,2881452,1378844,2735731,2472928,2734632,2855592,1908847,1911668,4759788,2240124,2862472,2216608,3072380,3124448,4063608,1912764,2710144,1692307,2728148,2459935,3209176,3259667,3275115,3078331,3089987,4060860,2474160,2747188,2763195,3286712,2526268,2522567,2728636,26944,2462388,2949135,2462460,1926064,2097648,1734111,2872719,2764408,19476,1605791,2523180,2738239,2688167,3043368,2774340,13292,2475760,1660943,3132296,2462300,2773763,2695488,3216420,3266960,2699756,2474320,6164,2772207,2728544,1927980,2573628,1916519,2466304,2832035,2650491,2627120,2182923,2524428,1804904,4776,5700,2526152,19832,1668923,1862684,1929220,3043432,8188,2315504,2700940,2700500,2927616,2305216,1380152,20100,2461420,1579811,2513000,5988,2718724,3079312,6108,5824,1559127,2819024,2135399,2665976,2629020,2525952,3048648,2777492,1380064,3017292,1665307,2728124,2472416,17432,1709804,2663591,2488535,1689307,2855788,4060280,2528596,1929764,3122260,3057428,2762208,1703344,2466880,2719680,3200968,1685911,2464092,3098984,19640,1765988,1381487,3053592,2771136,2750636,2871188,1216935,2844011,2858840,2881208,1706960,2473903,2460624,6104,1543376,2546947,2530016,1926092,2470040,2722412,2764636,3117160,2573668,2513924,2719560,2751435,2676663,1860040,2474687,2762336,2098692,7072,1780719,2662295,2700016,1385275,4876044,2740152,4804,3017280,17784,4063760,16044,2698624,2843448,1581056,2729880,2466300,3240248,13352,1711635,2700568,3009488,127276,2719052,9236,2712520,2772308,2748028,1567768,2683000,160228,2637728,4060792,2653960,3201588,3119276,1381608,2620100,2695564,2679436,3075584,1766811,3259012,24488,2474368,1363083,1886772,3209544,4063460,2300379,1381439,1930932,3043672,1689724,160292,1679699,2522183,1384576,2700964,2660199,3266716,2628976,1737672,1380280,2525196,2733855,3060780,2855736,1381759,1915172,1929748,2761199,1928456,7308,2793795,2747780,4060296,2763555,2623572,128324,3124952,2861307,2836435,1920868,2682780,3017148,8940,2731328,2882936,3041432,1926080,1206175,1381640,1920600,17172,2698660,3243776,2097483,1589632,2767296,2513132,2712760,3080099,127556,7732,2513720,3266816,3087856,1709724,1366571,127479,7008,1732835,2854844,1689255,2764352,4065144,3017204,2544868,1929760,24664,2718711,2459672,2077143,2084571,2069287,1347627,2858492,1926096,3288176,3113627,4063576,3124924,2313736,3124600,108632,1675227,2685911,3154503,3046644,2862891,2862484,27692,1404195,4935256,2524336,3057628,2699144,2225660,2728812,1640443,2875388,2226028,1699283,1915920,1589931,2871200,2712008,1575792,2158568,4491604,2469768,1702571,1954396,2077296,2761456,2200632,2832043,2650359,2625983,2675291,2800532,2078627,2084607,2052592,2698640,1297660,2238040,2355572,4060316,2745608,2645376,2752071,2754180,1771759,2871012,2256175,3319592,1672296,2540196,157760,2698780,2474504,2225432,2513516,2461444,2225456,4850900,3122188,2483736,2836360,2771963,3017340,2628400,1380663,2473063,2480412,2675407,1916452,2610892,2843276,2738535,2719308,1734551,1922599,2042248,2735655,4948,3152175,1221991,1246523,1787807,1821120,2712175,1308832,2494307,2050799,2413984,2001824,4850612,2187396,1625911,438647,560019,550199,124379,149064,440219,424427,420983,97639,71160,86503,99487,68111,70119,229207,205268,97416,86587,67640,86531,99619,25448,98399,202631,27540,27604,98387,97052,70103,99627,70079,67623,98435,68171,85152,229259,205080,99567,99603,205236,68147,70036,205431,30228,99587,205131,86523,229247,195404,98215,128120,70016,97435,86639,70084,68092,27764,68131,67639,98508,97455,27576,98347,202436,67603,98167,27496,98187,27148,70060,98251,202468,205072,44120,19888,86623,99568,70072,97364,30484,70135,78719,227627,203751,30288,129959,3872,68163,67604,74936,127664,97436,70091,85164,70096,99448,99548,229120,205452,97424,26516,86551,202636,128516,196959,196931,196544,68112,128164,7404,229235,196452,205056,195424,25192,196480,85196,25476,98223,69332,205280,25931,53531,85172,25551,181779,24100,86508,202480,195448,227564,99404,26007,53896,205192,86684,70156,86524,20160,86580,99380,205375,25484,7372,99588,67584,98283,20955,58079,27592,25492,196947,53816,53328,205132,26343,19628,26255,54675,20180,229236,98544,25652,54268,205448,88820,69360,53484,128144,196524,98196,97164,128040,29412,67636,23848,28232,196536,26976,99620,229224,29316,20372,99416,127732,97472,196792,20360,227591,203360,202331,196932,24776,27744,96144,13212,193360,202240,229268,99600,29476,99608,30528,202575,181944,205040,54340,229220,67668,20184,229276,67616,30524,205092,95508,127680,99392,20315,107555,26916,30284,25548,54464,27064,29492,421019,49396],"inlineDepth":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"category":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"subcategory":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"func":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082],"nativeSymbol":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"innerWindowID":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"implementation":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"line":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"column":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"optimizations":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"funcTable":{"length":5083,"name":[1,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,2125,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086],"isJS":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"relevantForJS":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"resource":[0,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,3,1,1,1,1,3,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,4,3,1,1,1,1,1,1,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,3,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,4,4,1,1,4,4,1,4,1,1,1,1,4,1,1,1,1,3,1,4,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,1,4,4,1,1,4,1,1,4,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,4,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,3,3,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,4,4,4,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,4,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,2,2,2,1,1,1,4,4,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,4,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,4,1,3,4,1,1,1,4,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,4,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,4,1,4,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,4,4,4,1,1,1,4,1,3,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,3,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,4,1,1,1,1,1,1,1,1,4,1,1,4,4,4,4,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1,1,1,1,1,1,1,1,4,1,1,1,1,3,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,4,4,4,2,2,1,1,1,1,4,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,3,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,4,4,2,4,4,4,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,3,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,4,1,4,4,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,4,1,4,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,1,4,4,1,1,1,4,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,3,1,1,1,1,1,1,1,1,4,1,1,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,1,4,1,1,4,1,3,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,4,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,4,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,3,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,4,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1,4,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,3,1,4,1,4,1,1,1,1,1,1,3,1,1,1,4,1,4,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,4,4,1,1,1,1,1,4,4,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,4,4,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,4,1,1,1,1,1,4,1,1,1,1,4,1,1,1,1,4,1,4,1,1,1,1,4,4,1,1,1,1,4,1,1,1,1,4,4,3,1,1,4,4,1,1,1,1,1,1,1,1,1,4,1,1,4,1,1,1,1,4,4,1,1,1,1,4,1,1,4,1,1,1,4,4,1,4,4,4,1,1,1,1,1,4,4,1,1,1,1,4,1,1,1,4,4,1,1,1,4,4,4,4,1,4,4,1,4,4,4,4,4,1,1,4,4,1,1,1,4,4,1,1,1,4,4,1,4,4,1,4,1,1,4,4,1,4,1,1,4,1,1,1,1,4,4,4,3,4,1,1,1,4,1,4,1,4,1,4,1,1,4,1,1,4,1,4,4,1,4,4,4,4,4,4,4,4,1,4],"fileName":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"lineNumber":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"columnNumber":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]},"markers":{"length":0,"category":[],"data":[],"endTime":[],"name":[],"phase":[],"startTime":[]},"name":"GeckoMain","nativeSymbols":{"length":0,"address":[],"functionSize":[],"libIndex":[],"name":[]},"pausedRanges":[],"pid":70383,"processName":"cli","processShutdownTime":13416.374542,"processStartupTime":380.192208,"processType":"default","registerTime":380.192208,"resourceTable":{"length":5,"lib":[0,1,2,3,4],"name":[0,2,10,21,48],"host":[null,null,null,null,null],"type":[1,1,1,1,1]},"samples":{"length":12956,"stack":[8,15,18,20,23,29,31,32,34,35,38,40,48,49,58,70,79,84,93,102,114,127,150,161,176,187,199,222,237,266,276,290,343,365,385,395,421,484,526,537,573,590,616,644,674,714,743,763,797,824,836,843,856,883,931,949,963,974,979,986,1000,1025,1032,1048,1059,1068,1088,1098,1157,1168,1177,1182,1224,1269,1277,1311,1323,1328,1332,1339,1354,1377,1409,1459,1491,1518,1552,1594,1623,1650,1665,1683,1697,1710,1720,1737,1746,1757,1774,1811,1819,1832,1844,1852,1858,1862,1889,1915,1920,1947,1959,1983,1993,2007,2022,2032,2049,2065,2074,2088,2102,2116,2126,2144,2152,2174,2204,2241,2275,2301,2331,2346,2359,2380,2412,2427,2458,2484,2493,2544,2577,2601,2632,2684,2693,2709,2735,2763,2781,2798,2811,2832,2859,2894,2931,2975,3002,3024,3060,3089,3105,3117,3135,3160,3176,3189,3213,3224,3268,3307,3342,3368,3390,3394,3420,3444,3468,3487,3498,3519,3540,3566,3604,3626,3653,3680,3712,3721,3726,3743,3749,3756,3780,3801,3807,3838,3855,3900,3905,3978,3999,4043,4094,4117,4145,4230,4245,4258,4272,4299,4306,4309,4319,4336,4345,4359,4376,4388,4395,4401,4413,4437,4443,4453,4455,4468,4481,4493,4505,4519,4523,4532,4543,4580,4625,4636,4668,4685,4689,4700,4708,4744,4748,4824,4844,4893,4909,4944,4981,5006,5022,5034,5045,5087,5099,5109,5117,5131,5151,5164,5173,5183,5192,5211,5216,5225,5251,5323,5333,5355,5375,5381,5389,5396,5404,5408,5417,5425,5438,5443,5451,5461,5464,5472,5493,5504,5507,5509,5520,5534,5538,5553,5557,5558,5570,5586,5588,5645,5653,5664,5674,5683,5688,5695,5696,5702,5705,5711,5720,5730,5742,5748,5758,5771,5778,5786,5796,5805,5814,5820,5825,5831,5842,5854,5856,5858,5860,5862,5868,5870,5874,5890,5898,5899,5913,5915,5917,5919,5922,5928,5937,5946,6005,6025,6072,6111,6150,6221,6234,6242,6256,6276,6284,6297,6306,6316,6372,6383,6407,6415,6420,6435,6443,6447,6459,6474,6483,6496,6508,6522,6532,6564,6609,6619,6632,6652,6694,6711,6719,6741,6746,6752,6764,6789,6800,6812,6817,6821,6832,6838,6868,6877,6896,6962,6974,6993,7004,7014,7031,7037,7054,7059,7064,7083,7097,7125,7126,7132,7142,7146,7154,7171,7177,7184,7219,7230,7240,7255,7267,7272,7301,7307,7311,7332,7358,7365,7379,7393,7399,7401,7411,7420,7431,7442,7465,7474,7476,7494,7515,7518,7530,7542,7551,7559,7566,7576,7605,7611,7620,7628,7638,7665,7675,7681,7693,7700,7706,7715,7731,7735,7742,7753,7755,7764,7775,7781,7801,7802,7810,7823,7828,7838,7844,7846,7853,7857,7867,7875,7878,7894,7903,8003,8010,8014,8021,8033,8042,8054,8061,8068,8081,8086,8090,8099,8101,8104,8105,8112,8122,8129,8131,8139,8140,8152,8159,8167,8169,8190,8191,8193,8201,8208,8227,8231,8243,8246,8258,8259,8276,8277,8280,7240,8290,8291,8298,8301,8305,8320,8325,8336,8337,8339,8340,8344,8364,8372,8375,8385,8387,8403,8414,8421,8427,8438,8448,8449,8462,8473,8477,8485,8496,8522,8526,8536,8538,8541,8548,8564,8568,8578,8582,8584,8591,8594,8599,8617,8621,8632,8636,8640,8649,8652,8662,8685,8702,8705,8719,8730,8732,8748,8758,8762,8765,8766,8771,8782,8787,8797,8808,8816,8831,8839,8844,8852,8862,8874,8892,8902,8909,8918,8930,8936,8946,8954,8958,8967,8972,8993,8999,9006,9015,9016,9021,9022,9063,9068,9076,9077,9083,9089,9095,9100,9103,9112,9113,9114,9116,9125,9132,9146,9147,9149,9150,9151,9170,9175,9182,9185,9188,9190,9192,9193,9197,9206,9212,9224,9243,9255,9188,9265,9273,9274,9291,9302,9304,9306,9323,9334,9355,9365,9367,9374,9396,9399,9413,9414,9424,9434,9438,9448,9460,9469,9474,9478,9490,9495,9496,9498,9503,9516,9533,9546,9188,9551,9556,9565,9577,9582,9594,9602,9604,9606,9634,9638,9639,9648,9113,9670,9682,9686,9691,9692,9710,9711,9734,9744,9751,9760,9766,9767,9769,9771,9774,9077,9781,9193,9782,9788,9793,9796,9810,9836,9844,9846,7311,9862,9863,9865,9867,9876,9887,9892,9900,9905,9906,9911,9914,9926,9956,9958,9961,9962,9971,9767,9972,9976,9987,9992,10009,10023,10026,10029,10033,10036,10038,10046,10057,10064,10069,10075,10095,10103,10105,10110,10112,8766,8101,10114,10118,10122,10128,7240,10134,10144,10169,10251,10263,10273,10277,10286,10289,10295,10308,10310,10317,10318,10323,10339,10355,10356,10368,10371,10376,10381,10383,10384,10390,10404,10417,10425,10438,7742,10458,10473,9193,10498,10530,10601,10616,10657,10690,10702,10749,10756,10820,10840,10854,10906,10930,10944,10953,10969,10979,10993,11016,11020,11091,11102,11111,11127,11138,11156,11175,11184,11191,11192,11194,11198,11205,11212,11222,8766,11228,11230,11239,11241,11251,11265,7240,11272,11276,11288,11291,11296,11309,11315,11316,11323,11324,11333,11344,11349,11356,11370,11382,11397,11436,11444,11454,11463,11468,11471,11473,11477,11483,11486,11500,11503,11511,11516,5211,11523,11528,11486,11540,11547,11554,11567,11570,11590,11608,11623,11633,11644,11654,11662,11670,11673,11674,11678,11682,11689,11695,11702,11707,11717,11726,11728,11730,11733,11735,11737,11743,11749,9962,11755,7240,11756,11818,11826,7240,5586,7240,11830,11892,11898,11908,11919,11937,11945,11948,11966,11967,11970,11980,11991,11993,12003,12008,12015,12041,12048,12049,12051,12057,12059,12068,12072,12074,12076,12083,12091,12094,12095,12102,12108,12114,12120,12125,7240,12127,12134,12140,12149,12160,12162,12163,12165,12170,12172,12173,12176,12180,12184,12188,12207,12216,12220,12227,12231,12240,12246,12254,12255,12260,12262,12264,12265,12275,12276,12277,12285,12294,12295,12297,12299,12302,8473,12321,12323,12324,12331,12336,12337,12347,5538,12348,12362,12369,12378,12382,12383,12392,12394,12403,12404,12405,12415,12419,12431,12433,12438,12445,12455,12460,12465,12467,12474,12475,12478,12485,12492,12508,12517,12522,12528,8473,12530,12540,12543,12545,12551,12561,12567,12568,12574,12575,12262,12577,12583,4689,12588,12589,12605,12609,12613,12618,12622,12627,12634,12639,12651,12658,12659,12670,12672,12678,12679,12684,12694,12698,12706,12711,12715,12716,12719,12730,12745,12265,12763,12766,12768,12787,12788,12794,12798,12804,12810,12818,12827,12831,12836,12847,12855,12860,12861,12871,12874,12886,12887,12888,12889,12896,12903,12149,12914,12921,12923,12927,12935,12942,12949,7240,12956,12957,12964,12969,12972,12976,12979,12984,12993,12994,13006,13012,7240,13021,13023,13025,13035,13039,13044,13060,13065,13072,13078,13087,13093,7240,13104,13106,13111,13114,13115,13118,13122,13128,13131,13136,13139,13148,12265,13157,13158,13162,13172,13182,13194,13290,13323,10263,13385,13419,13444,13467,13517,13525,13571,13573,13585,13634,13664,13678,13713,13761,13767,13814,13865,13879,13890,13910,13915,13947,13975,13979,13999,14000,14011,14068,14083,14110,14112,14123,14174,14178,14195,14236,14274,14286,14289,14294,14295,14309,14325,14348,14358,14385,14402,14421,14440,14485,14518,14534,14564,14615,14639,14651,14661,14676,14681,14696,14701,14726,14749,14752,14753,14769,14812,14856,14869,14882,14907,14909,14922,14924,14964,14975,15003,15016,15041,15050,15100,15143,15164,15190,15229,15271,15277,15308,15335,15344,15362,15383,15407,15418,15453,15475,15497,15499,15509,15418,15527,15543,15545,15558,15577,15592,15603,15603,15619,15650,15685,15717,15750,15789,15805,15808,15811,15818,15825,15834,15846,15856,15874,15901,15917,15931,15950,15968,15973,15978,16000,16015,16025,16027,16030,16044,16062,16080,16094,16113,16117,16118,16120,16126,16134,16137,16149,16165,16186,16195,16197,16207,16219,16229,16245,16248,16252,16263,16274,16279,16292,16304,16308,16312,16320,16322,16323,16339,16348,16362,16363,16383,16398,16418,16423,16426,16428,16442,16363,16449,16452,16459,16472,16485,16494,16515,16524,16539,16274,16551,16553,16569,16577,16579,16588,16589,16605,16607,16621,16630,16701,16702,16719,16721,16731,16732,16735,16363,16740,16761,16768,16779,16783,16791,16801,16803,16814,16819,16824,16842,16852,16858,16871,16881,16903,16906,16927,16363,16931,16938,16945,16952,16956,16960,16969,16972,16974,16979,16993,17003,17004,17012,17013,17025,16363,17034,17035,17043,16779,17045,17046,17052,17057,17064,17066,17077,17084,17123,17127,17137,17148,17159,17161,17173,17175,17181,17183,17189,17202,17204,17215,17217,17224,17225,16363,17237,17251,17260,17266,17273,17284,17293,17302,17312,17328,17347,17351,17359,17368,17371,17379,17389,17398,17404,16363,17413,17426,17430,17434,17435,17446,17456,17458,17469,17204,17473,17483,17485,17541,17578,17629,17676,17706,17840,17861,17896,17978,17984,17992,18010,18036,18042,18052,18061,18068,18091,18101,18117,18132,18140,18202,18227,18237,18263,18266,18278,18292,18305,18309,18325,18343,18359,18368,18384,18402,18415,18431,18440,18457,18470,18475,18498,18503,18532,18568,18576,18582,18598,18604,18606,18620,18626,18645,18655,18668,18674,18686,18693,18704,18711,18718,18719,18721,18735,18751,18792,18795,18809,18829,18858,18889,18903,18922,18932,18943,18949,18964,18976,18989,18994,19001,19012,19024,19031,19036,19043,19060,19071,19079,19087,19099,19107,19119,19124,19134,19152,19158,19162,19177,19186,19199,19221,19238,19247,19260,19275,19279,19290,19292,19304,19317,19333,19340,19353,19364,19380,19384,19388,19405,19416,19423,19438,19455,19464,19477,19488,19498,19505,19509,19513,19522,19527,19537,19561,19565,19581,19584,19592,19598,19611,19620,19622,19626,19632,19636,19645,19653,19667,19672,19686,19692,19702,19710,19714,19717,19725,19728,19731,19738,19745,19753,19758,19763,19769,19782,19792,19809,19812,19828,19829,19840,19853,19858,19863,19875,19882,19887,19896,19900,19905,19906,19916,19922,19926,19930,19938,19954,19959,19970,19981,19994,20005,20011,20023,20027,20041,20047,20057,20066,20076,20087,20098,20106,20111,20115,20126,20135,20157,20162,20165,20180,20182,20183,20188,20209,20222,20229,20244,20245,20255,20275,20281,20287,20293,20319,20325,20330,20349,20352,20356,20369,20382,20463,20468,20471,20477,20488,20497,20507,20528,20533,20543,20571,20580,20592,20605,20611,20620,20623,20626,20628,20639,20655,20659,19199,20662,20672,20681,20690,20704,20706,20714,20725,20734,20737,20741,20745,20753,20758,20761,20786,20794,20800,20808,20813,20819,20835,20839,20844,20858,20863,20870,20880,20892,20901,20905,20915,20919,20927,20941,20943,20952,20963,20978,20984,20991,21004,21014,21020,21021,21023,21036,21040,21051,21067,21078,21088,21092,21099,21103,21104,21110,21119,21124,21125,21133,21134,21140,21152,21157,21158,21165,21166,21170,21172,21178,21185,21192,21206,21215,21216,21225,21227,21231,21236,21244,21250,21253,21256,21258,21261,21272,21275,21320,21323,21345,21353,21357,21377,21388,21393,21407,21421,21429,21432,21441,21444,21445,21451,21467,21471,21477,21485,21502,21511,21522,21537,21543,21553,21566,21567,21573,21583,21588,21592,21596,21599,21617,21623,21634,21643,21652,21663,21675,21688,21696,21698,21706,21719,21721,21729,21739,21760,21763,17578,21764,21776,19981,21789,21800,21806,21819,21822,21827,21830,21837,21844,21854,21856,21868,21874,21875,21879,21885,21894,21902,21911,21920,21929,21944,21949,21956,21961,21974,21980,21986,21989,22000,22005,22010,22020,22029,22040,22117,22137,22146,22150,22159,22168,22170,22180,22188,22190,22194,22201,22209,22212,22216,22227,22235,22242,22254,22263,22264,22266,22276,22277,22285,22300,22321,22327,22328,22336,22340,22348,22353,22356,22359,22384,22399,22406,22411,22418,22422,22424,22429,22431,22434,22438,22443,22447,22453,22462,22465,22480,22486,22498,22501,22506,22516,22527,22534,22539,22547,22557,22559,22570,22580,22581,22584,22594,22600,22604,22615,22631,22635,22646,22651,22653,22665,22672,22681,22684,22688,22693,22702,22712,17578,22716,22719,22725,22737,22742,22745,22749,22760,22765,22776,22787,22791,22796,22808,22818,22822,22827,22832,22840,22846,22852,22867,22873,22880,22894,22902,22912,22918,22924,18994,22932,22934,22937,22941,22954,22961,22969,22973,22982,22995,22999,23005,23009,23016,23020,23036,23043,23050,23055,23062,23109,23113,23121,23122,23128,23146,23160,23171,23181,23186,23191,23199,23207,23212,23218,23237,23243,23250,23254,23256,23257,23261,23264,23268,23271,23272,23278,23281,23285,23294,23303,23307,23309,23318,23319,23324,23332,23337,23346,23353,23367,23378,23382,23392,23393,23399,23408,23411,23415,23416,23419,23420,23427,23432,23439,23452,23455,23464,18440,23470,23481,19906,23489,23496,23503,23508,23513,23516,23522,23532,23570,23571,23574,23585,23591,23595,23604,23605,23619,23622,23626,23628,23638,23641,23642,23651,23673,23710,23713,23716,23724,23734,23744,23751,23763,23775,23783,23790,23791,23801,23791,23802,23809,23814,23824,23827,23836,23852,23875,23878,23890,23895,23896,23902,23906,23907,23910,23919,23933,23937,23943,23949,23960,23962,23978,23987,23992,24005,24112,24118,24123,24130,24133,24138,24143,24147,24151,24161,24172,24182,24189,24198,24202,24206,24216,24230,24235,24236,24243,24245,24249,24255,24267,23050,24270,24274,24280,24286,24296,24300,24310,24316,24328,24335,24343,24355,19906,24356,24362,24368,24380,24387,24391,24398,24406,24410,24415,24418,24425,24429,24439,24453,24470,24472,24477,24489,24499,24502,24509,24519,24522,24526,24532,24538,24544,19199,24554,24556,24561,24573,24586,24591,24601,24613,21567,24623,24630,24640,24644,24648,24656,24662,24666,24675,24685,24690,24697,24707,24720,24722,24733,24740,24749,24755,24771,24772,24776,24783,24791,24795,24801,24813,24817,24820,24825,24826,24827,24832,24841,24845,24849,24853,24869,24871,24875,24884,24899,24904,24906,24915,24923,24925,24942,24948,24953,24963,24967,24972,24977,24990,24997,24998,25000,25002,25008,25015,25025,25032,25036,25045,25057,25058,25060,25063,25064,25065,25073,25091,25100,25102,25104,25109,25116,25121,25125,17578,25130,25134,20963,25146,25152,25153,25166,25175,25183,25188,25191,25193,25195,25204,25211,25214,25217,25222,25226,25237,25247,25253,25263,25267,25275,24236,25282,25291,25300,25307,25318,25322,25323,25326,19199,25340,25346,25348,25359,25365,25367,25368,25376,25382,25383,25390,25404,25412,25418,25419,25423,25426,25431,25437,25501,25509,25528,25536,25541,25548,25555,25562,25568,25585,25590,25593,25597,25614,25621,25626,25631,25646,25647,25651,25663,25666,25670,25677,22539,25678,25686,25700,25701,25703,25709,25716,25728,25738,25746,25755,25759,25765,25772,25774,25778,25781,25782,25785,25790,25801,25804,25805,25816,25819,25823,25832,24300,25841,25850,25857,25864,25867,25881,25892,25894,25898,25905,25907,25914,25921,25928,25932,25945,25952,24915,25959,25961,25973,25986,25993,25996,26003,26009,26011,26015,26026,26028,26030,26042,26046,26050,26061,26068,26079,26083,26088,26090,26098,26106,26110,26120,26125,26129,26137,26144,26150,26156,26158,26163,26164,26174,26177,26183,26194,26205,26206,26209,26222,26225,26228,26241,26245,26254,26259,26265,26289,26291,26296,26302,24439,26310,26314,26321,26322,26343,26345,26352,26354,26360,26364,26371,26383,26390,26392,26393,26401,26410,26413,26419,26426,26432,26438,26450,26452,26460,26462,26480,26486,26487,26492,26498,26501,26393,26512,26515,26524,26532,26539,26545,26548,26555,26556,26557,26564,26573,26584,26589,26599,26601,26606,26615,26619,26626,26630,26633,26641,26642,26646,26651,26652,26659,26662,26664,26668,26675,26679,26689,26695,26708,26712,26720,26731,26739,26745,26750,26763,26776,26779,26780,26790,26794,26795,26807,26814,26844,26851,26861,26868,26870,26877,26889,26893,26895,26910,26917,26921,26931,26940,26943,26948,26953,26961,26966,26977,26978,26982,26988,26993,27000,27008,27012,27021,27022,27025,27032,27044,27045,27054,27061,27063,27066,27068,27074,27078,27079,27087,27095,27100,27101,27103,27108,27114,27120,27121,27123,27128,27138,27143,27148,27150,27165,27176,25647,27182,27186,27192,27203,27208,27213,27216,27242,27246,27250,27252,27258,27259,27263,17578,27267,27275,27278,27285,27293,27300,27305,27307,27322,27333,27342,27368,27369,27371,27379,27387,27395,27397,27404,27408,25237,27416,27430,27433,27445,27455,27461,27462,27469,27473,27475,27476,27499,27500,27502,27507,27512,27517,27519,27525,27539,27540,27544,27547,27550,27551,27553,27564,27566,27568,27578,27580,27584,27585,27592,27600,27609,27617,27623,27624,27630,27639,25104,25782,27643,21567,27644,27647,27649,27658,27660,27671,27676,27689,27697,27703,27708,27715,27716,27724,27731,27733,27739,27744,27750,27752,27766,27767,27768,27776,26174,27784,27789,27804,27822,27824,27832,27841,27852,23791,27857,25065,27866,27871,27933,18266,27936,27937,27941,27949,27957,27963,27975,27983,27989,27997,28003,26487,28012,28019,28023,28028,28040,28042,28048,28054,28088,28092,25647,28098,28110,28115,28126,28132,28137,28138,28139,28149,28158,28159,28163,28169,28187,28191,28193,28200,28208,28209,28214,28220,28222,28227,28239,28242,28253,28263,28270,28275,28282,28291,28300,28341,28344,28353,28368,28375,28377,28384,28391,28394,27462,28409,28430,28438,28440,28446,28454,28455,28458,28466,28475,28480,28482,28488,26393,28503,28507,28514,28515,28523,28529,27462,18266,28534,23791,28535,28538,28546,28555,28559,23416,28567,28570,28576,28579,28582,28587,28599,28601,28608,28621,28629,28636,28638,28646,28650,28656,28660,28667,28668,28670,28671,28690,23791,28700,28707,17578,28711,28721,28725,28726,28732,28743,28752,28761,28766,28780,21567,27462,28781,28788,23791,28793,28795,28804,28811,28814,28818,28819,28829,28833,28835,25359,28839,28843,28845,28846,28854,28858,28860,28866,28877,28885,28889,28898,28904,28905,28911,28919,28926,28935,28944,28953,28957,27462,21567,28968,28971,28976,28977,28981,28992,28997,29004,29011,29021,29024,29028,29029,24915,29033,29041,29043,29055,29062,29066,29070,29081,29086,29088,29089,29093,29101,29106,29107,23791,29109,29117,29118,29121,17578,29130,29132,25647,29138,29149,29150,29152,29156,29157,29160,21567,29166,29172,29173,29181,29185,29189,29193,29194,29196,29198,29203,29219,29223,29234,29242,29247,29254,29256,29259,27462,29263,29277,29280,29281,29286,29288,29290,29296,29297,29299,29304,29308,29311,29330,29344,29352,29356,29366,29373,29380,29388,29389,23791,29391,21134,29402,29417,29418,29420,29427,29499,29504,29513,29519,29524,29535,29550,29554,29561,29572,29573,29575,29587,29596,29602,29606,29610,29619,29620,29624,26393,29628,29631,29637,25237,29640,29651,29652,29657,29662,29664,29670,29673,29674,29677,29686,29695,29702,29712,29715,29721,29730,19906,29731,29733,29738,17578,29740,29743,29748,29754,29759,29760,29767,29777,21567,29779,29783,29789,29790,29793,29796,27462,29803,29807,29811,29814,29817,29823,27176,29831,29841,29854,29861,21567,29869,29870,29874,29883,29895,29899,29902,29903,29907,23791,29909,19199,29917,29926,29929,25359,29938,29940,29941,29951,29955,29957,29964,29977,29981,29983,29987,30004,30010,30011,30012,30014,30020,30024,30036,30041,30048,30052,30061,21567,30062,30065,30072,30144,30148,30154,23791,30160,30171,30179,30181,30182,30185,30187,30188,21567,30199,30202,30204,30210,30220,30244,30249,30252,30266,30267,30269,30281,30285,30297,30300,30310,30312,30317,30319,23420,30322,30324,30330,30338,30347,30351,30360,30367,30369,30372,30380,30386,25237,30391,30392,30393,21567,30396,30397,30401,30410,30421,30427,30429,30433,30443,30450,30452,30458,30460,30467,30477,30484,30494,27462,30498,30507,30508,30515,30518,30520,30521,30523,30586,30588,30593,30602,30612,30618,30621,30625,30632,30640,30644,30647,30653,30665,30674,30682,30683,30689,30698,30706,30714,30719,30726,30734,28926,30743,19981,30745,30750,25065,30756,23791,30757,21567,30760,20919,30768,30774,30784,30787,30791,30794,30797,30813,25237,30815,30818,30819,30827,30838,30849,27462,30859,30867,30873,30879,30888,30896,21567,30897,17578,30898,30901,30908,30916,30921,30924,30930,30941,30945,30954,30959,30963,23050,30967,30972,30979,30983,30985,30995,31003,31009,31013,31014,31015,31019,31028,31035,27462,31045,31047,31055,21567,31059,31064,31066,31072,31077,31086,31096,31105,19981,31109,31110,31114,31121,31125,31129,31131,31137,31138,31145,31149,31150,31151,31157,31159,31166,31171,31175,31192,31202,31205,31211,31215,31218,31219,31224,31230,31235,31244,31250,31259,31260,26393,24915,31264,31267,31271,31279,31283,31287,31291,31292,31296,31305,31310,31317,31323,31324,31331,31346,31347,31350,31356,31357,31370,31377,31389,31400,31407,21567,31415,31416,26652,31425,31429,31433,31435,31439,31449,31455,31457,31463,31469,31471,31482,31484,31489,31494,31496,31499,31506,31515,31524,31525,31539,31548,31551,31555,31559,31568,31577,31580,31584,31590,26174,31593,31608,31610,31618,31629,27462,31632,31640,31645,31649,31652,31661,31668,31669,31673,31683,31684,31702,31703,31706,30995,31707,31708,31715,31721,31729,31733,31744,31745,31752,31759,31764,31772,31773,31776,31781,31795,31801,31803,31806,31809,31811,31813,25237,31827,31845,31850,31851,31859,31864,31871,31879,31883,23791,31886,31887,31895,31896,31899,31901,31356,31904,31910,31911,31921,31929,25993,31934,31942,23791,31944,31945,31954,31960,31965,31968,31973,31988,25805,31993,19199,32001,31096,32011,19981,32019,32020,32021,32030,32036,32040,32041,32049,32054,27462,21567,32058,21567,32061,32065,32071,32079,25647,32088,32093,27462,32097,32103,21567,32109,32112,32122,32127,32128,32136,32142,32145,32152,32159,32167,32170,25647,32181,32191,27462,32197,32202,32204,32208,32212,32213,32221,32223,32235,32240,32243,32245,32252,32255,32258,32264,32270,32277,32286,32291,32302,21567,32306,32310,32320,32329,32332,32341,32350,32354,26393,27404,32361,32373,32376,32381,32383,32384,32391,32397,32399,32402,32409,32412,32415,32418,32431,32432,32433,32436,32440,32443,32445,32450,32458,32463,22559,32466,32469,32474,32476,32488,23791,32493,32494,32497,32501,32508,32510,32514,32522,25647,32528,32532,27462,32535,32539,32540,32541,32552,32555,32657,32659,32667,32673,32674,32680,32684,32693,32696,32704,25647,32716,32727,32730,23791,32734,32745,32746,32747,32749,32750,21134,32751,32757,32759,32764,32771,30995,32781,25237,32789,32794,32796,32797,32803,32809,32810,32812,32823,23791,32825,32826,32830,32837,32859,32862,32867,32871,32879,32881,32892,32898,32904,32911,32919,32921,32922,32928,23791,32931,32935,32937,32943,32948,32952,32955,32960,32971,32983,32991,32994,32995,33005,33006,33011,33013,33027,33034,33044,23050,33047,33048,33054,33057,33061,33062,33070,33075,25237,33080,33082,33086,33088,33095,33102,33172,33173,33187,33189,33192,33196,33197,33206,33209,33212,33213,33222,33226,33230,33231,33241,33244,33245,33247,33258,23791,33262,33265,33275,33290,33296,33301,33306,33314,33318,33321,33322,33326,27176,33336,33343,33359,33361,23791,33365,33370,33373,33377,33391,33392,33394,33395,33403,33404,33409,19199,33411,33417,25647,33418,33427,33432,33437,26487,33447,33453,33456,33457,33463,23791,33464,33465,33471,33472,33474,19199,33477,33483,25647,33484,33486,33489,27462,33498,33501,33512,33516,33521,33532,33542,27462,33545,33555,33557,33558,33567,33574,33578,33580,33592,33601,33603,33610,33617,33621,33631,33633,33650,33655,33663,33664,33670,33679,29152,33682,33687,33800,33863,33936,34024,34131,34188,34215,34283,34348,34433,34537,34611,34710,34804,34924,35009,35083,35194,35286,35402,35494,35578,35720,35784,35901,36026,36035,36052,36092,36129,36159,36195,36215,36256,36277,36308,36336,36345,36362,36369,36371,36395,36404,36420,36436,36447,36459,36465,36476,36486,36504,36513,36519,36523,36538,36549,36568,36581,36586,36621,36643,36670,36693,36714,36741,36749,36751,36761,36795,36804,36811,36825,36834,36842,36856,36867,36873,36880,36900,36915,36925,36948,37002,37017,37023,37037,37064,37082,37101,37112,37125,37131,37143,37150,37161,37170,36751,37177,37186,36751,37189,37198,37205,37219,37223,37225,37243,37254,37256,37265,37272,37292,37295,37298,37308,37322,37331,37339,37341,37345,37358,37369,37379,37381,37390,37397,37404,37415,37423,37430,36670,37432,37443,37450,37454,37465,37470,37479,37481,37482,37494,37507,37518,37522,37531,37535,37537,37544,37545,37548,37549,37561,37567,37574,37583,37584,37612,37613,37617,37465,37623,37549,37627,37634,37637,37652,37658,37661,37678,37703,37725,37731,37735,37479,37744,37748,37763,37777,37778,37782,37784,37256,37790,37792,37812,37814,37818,37833,37834,37835,37843,37848,37866,37875,37879,37888,37902,37915,37933,37944,37955,37965,37966,37972,37977,37978,37990,37479,37991,38002,38015,38030,36670,37358,38035,38041,38044,37345,38048,38056,38061,38067,38080,38094,38096,36670,38110,38119,37549,38129,38145,38153,38154,38157,38165,38170,38174,38178,38190,38195,38200,38212,38213,38220,38223,38224,38234,38238,38239,37358,38249,38258,38262,38267,38282,38284,38292,38293,38296,38299,38304,38305,38310,38314,37465,38322,38323,38324,38329,38330,38336,37358,38344,38353,37479,38362,38363,38370,38468,38501,38517,38542,38559,38611,38650,38671,38703,38732,38766,38797,38831,38842,38843,38854,38873,38886,38897,38910,38934,38947,38960,38972,38986,39011,39029,39043,39068,39083,39094,39114,39137,39149,38766,39159,39170,39195,39208,39221,39226,39229,39235,39245,39254,39265,39276,39302,39323,39324,39333,39351,39360,39362,39386,38854,39404,39333,38766,39406,39411,39414,39429,39444,39464,39484,39495,39511,39523,39534,39541,39551,39568,39578,39587,39603,39616,38897,39619,39636,39649,39655,39667,39679,39688,39704,39710,39719,39724,38766,38854,39733,39733,39739,39746,39754,39764,39771,39772,39784,39797,39810,39811,39824,39828,39834,39854,39869,39875,39888,39903,39913,39936,39952,39957,39959,39966,39972,39982,39992,40004,40014,40021,40024,40035,40044,40055,40074,40092,40107,40113,40120,40122,40138,40146,40154,40165,40171,40173,40252,40258,40262,40280,40288,40295,40309,40321,40334,40340,40350,40363,40374,40380,38766,40390,40394,40400,38766,40404,40418,40429,40434,40439,40449,40455,40485,40504,40516,40518,40523,40535,40544,40550,40557,40569,40575,40587,40603,40612,40634,40643,40650,40656,40664,40671,40684,40692,40697,40702,40712,40722,40736,40739,40743,40753,40757,40760,40768,40792,40799,38766,40807,40820,40822,40825,40831,40842,40849,38897,40857,40870,40874,40976,40985,40989,40998,41012,41019,41041,41046,40122,41048,41066,41071,41078,41083,41093,41098,41099,41110,41129,41140,41146,41147,41158,40055,41170,41183,41185,41202,41208,41218,41227,41238,41244,41252,41266,41276,41284,41293,41303,41318,41324,41328,41330,41336,41341,41351,41358,41362,41367,41377,38766,41379,41383,41394,41395,41397,41410,41414,41425,41426,41434,41441,41473,41478,41492,41505,41512,41518,41526,41543,41551,38766,41560,41575,41583,41589,41592,41605,41140,41610,41685,41699,41707,41711,41147,38986,41719,41725,41736,41742,41755,41760,41769,41784,41795,41796,41803,41812,41817,41822,41830,41840,38854,41848,41855,40753,41857,41863,41870,41890,41904,41910,41918,41927,41936,41940,41946,41954,41959,41973,38766,41981,41992,41998,42008,42017,42025,42037,42041,42053,42062,42072,42079,42085,42087,42091,42097,42099,42104,42110,42115,42126,42134,42147,42153,42166,42175,42181,42186,42198,42211,42226,42234,42236,38854,42239,41140,42243,42246,42255,42264,42272,42279,42290,42303,42305,42312,40544,42325,42331,42348,42357,42369,42371,42385,42398,42414,42418,42500,42501,42510,42516,42522,42528,42543,41140,42547,42556,41147,42560,40055,42568,42575,42587,42597,42605,42616,42623,39811,42628,42641,42645,38854,42648,42649,42653,42658,42666,42677,42684,42695,42701,42708,42718,42727,42730,42733,42742,42748,42755,42768,42779,38854,42783,42789,42827,42831,42833,42838,42839,42851,42864,42865,42867,42874,42879,41140,42891,42895,42898,42903,42917,41140,42923,42929,42937,42944,42954,42962,42963,42974,42977,42992,40092,42994,43001,43010,43011,43013,43020,43035,43038,43041,43042,43047,43055,43063,43068,38766,43073,43086,43096,43145,43148,43150,43153,43168,43174,40092,43180,43193,43206,43207,43217,43230,43239,43240,43246,43257,43259,43266,43274,43277,43284,43288,43296,43302,43305,43317,43325,43334,39043,43342,43357,43363,43366,43380,43390,43402,43413,43420,43425,43428,43447,43451,43453,43462,43473,43481,43489,43490,43499,43501,43506,43513,38766,43517,43526,43538,38854,43539,43543,43548,43554,43562,43571,43577,43586,43602,43609,43613,43617,43621,43631,43637,43642,43651,43663,43668,43672,41140,43673,43679,43688,43691,43692,43695,43705,43715,43722,43727,38986,43736,43747,43751,43764,43778,43784,43786,43795,43798,43803,43804,43814,43821,43825,43837,43844,43848,43851,43854,43859,43868,43872,43880,43901,43907,43923,43937,43947,43953,43959,43965,43967,43968,38766,43977,43982,41140,43992,43999,44001,44009,44013,44019,44027,44029,40753,44034,44039,39043,44050,44052,44061,44068,44080,44087,44092,44096,44103,44109,44111,44116,44128,44130,44139,44141,42839,44152,44164,44166,44172,44186,44196,38766,44211,44221,44227,44231,44232,44235,44243,38766,44249,44269,44324,44326,44332,44339,44348,44355,44376,44382,44391,44405,44409,44418,44428,44434,44444,44448,44456,44460,44467,44474,44489,44513,44518,42839,44527,41351,40092,44538,44546,44547,44553,44562,44567,44578,44581,44595,44598,44601,44602,44612,44620,39811,44622,44628,44632,44637,44643,44644,44665,44679,44688,44693,44700,44705,44712,44721,44727,44738,44750,38854,44757,38854,44767,42658,44772,44781,38986,44787,44790,44796,44804,44815,44817,44824,44832,44835,44840,44846,44854,44860,44861,44867,44871,39811,44873,44877,44882,44891,44896,44901,44912,44923,44925,44934,44944,44948,44961,44967,44970,44973,44985,38897,44989,44994,44999,45016,45022,45029,45033,45044,45049,45059,45068,45069,45071,45075,41140,45078,45085,45103,45108,43011,45110,45120,41140,45123,45128,38986,45138,45140,45157,45167,45173,45184,45188,41140,45200,45215,45221,45222,45229,45233,45235,45242,45250,45261,45273,45278,45283,45292,45302,45306,45314,45325,45333,45338,45341,41140,45344,45345,45357,45361,38897,45365,45378,45389,45393,45404,42839,45412,45413,45430,40092,44538,45443,45446,41140,45453,45457,45458,45463,45470,45473,45480,45483,45493,45501,45514,45519,42166,38986,45522,45535,40092,45537,45548,45559,45567,39333,45580,41140,45587,45591,45598,45612,45616,45618,45625,45632,45639,45662,45665,45673,45674,45679,45689,45690,45697,45714,45721,45725,45738,45742,45748,45751,45752,45757,45761,45763,45776,45782,45785,45789,45796,45803,45814,45817,45824,45829,45832,45833,45839,45842,45848,45851,45866,45873,38897,45880,45881,45999,46000,46003,46004,46008,46020,46100,40092,46110,46120,46121,46127,46132,46135,46141,41140,46152,46159,46164,38843,46165,46175,46193,46210,46217,46226,40753,46230,46235,46243,46250,46254,46256,46264,46279,46284,46290,46299,46307,46316,46317,46321,41140,46331,46334,46340,46342,46345,46346,46353,46358,46359,46364,46370,46375,46389,46391,42649,46395,46401,46411,41140,38897,46414,46420,46433,38854,46435,46439,46444,46445,46448,46450,46459,46475,46480,46484,46492,46511,46521,46528,46534,46535,46540,46546,46547,38766,46552,46560,46568,46577,46583,46584,46600,46608,43631,46612,46623,46637,46639,46640,46645,46651,41140,46656,46662,46668,46675,41140,46679,46686,38854,46698,39739,46701,46709,46722,42839,46728,46730,46739,40092,46757,46760,46769,46771,46774,46775,46806,41426,46814,41140,46815,46825,46838,46839,38854,46842,46845,46848,46852,46872,38986,46878,46892,46897,46907,46923,46924,46926,46942,41140,46943,41140,46947,46954,46961,46962,46967,46983,46986,46990,41147,47002,47010,47027,47038,47044,47047,47057,47061,47062,47067,47068,47070,41140,47074,47075,47078,47083,47087,47092,47094,47097,47107,47113,47121,47129,47136,47150,47160,47171,38854,47198,47201,47208,47211,47223,47225,47228,47229,47234,47241,47255,47261,47266,47269,47274,47285,47295,47301,47305,47311,47321,47326,47330,47336,47340,47347,47354,47358,47366,47371,38766,47373,47375,41140,47377,47378,47383,47384,47395,47398,47412,47425,47433,47436,47438,41140,47444,41140,47455,47459,47470,47475,47476,47488,47489,47497,47499,47500,47504,47511,47517,47519,47533,47543,47551,47559,47569,47572,47576,47585,47590,47596,47602,47610,47612,47616,47622,47625,47629,47637,47644,40092,47654,47664,38766,47665,47670,47672,47676,47679,47688,47693,47698,47704,39811,47707,47708,47710,47713,47718,47723,47727,47728,47740,47745,47751,47752,47757,47760,47761,47772,47779,47792,47803,47810,47811,47816,47818,47829,47831,47835,44781,47844,47847,41351,40092,47851,47854,47860,47861,47870,47880,47885,41140,47888,47892,47899,47906,47909,47910,47920,47923,47927,47931,47932,40753,47934,47941,39043,47946,47962,47970,47981,47983,38854,47990,38854,47994,47995,47999,41140,48005,48016,48022,48030,42839,48040,48046,48051,48052,48058,48066,38766,48073,48077,48081,38766,48082,48087,48088,48097,48128,48134,48144,48176,48180,48186,48192,48204,48248,48253,48269,48274,48277,48287,48293,48300,38766,48310,48314,48319,48324,48332,48336,48337,48338,44781,38986,48341,48352,43631,39043,48362,48378,48387,48393,48395,48400,48401,48409,48417,39739,48422,48431,48433,48436,48443,48448,48450,44781,48453,48458,48464,48468,48475,48489,48490,48491,48504,48505,48508,48514,48526,48535,48541,48543,48549,48563,48568,48591,48596,42839,48608,41351,40092,42867,48620,48632,48634,48645,48684,48685,38766,48694,48705,48712,48713,48717,48723,39333,48725,48736,48744,48748,43631,48750,48756,48770,48773,48777,48792,42658,38766,47665,48799,48800,48803,48806,48807,48812,48823,48826,48831,48835,48842,48848,48860,48863,48864,48877,48880,40122,48882,48893,41140,48895,48897,48907,48916,48927,40122,48935,48943,48948,48952,48953,48959,48968,48981,40092,48983,48998,38766,49000,49012,49013,49015,49020,49026,49033,49039,49046,49058,49059,49070,49076,39811,49080,44781,49089,38986,49091,49093,43631,49103,49108,49116,49119,49121,49127,49129,49133,38854,49137,49142,49144,49145,49155,49164,45016,49171,42839,48040,41351,49182,49183,49192,49203,38766,49208,49216,41140,43692,49217,49221,49222,38897,38766,49229,49232,49235,49242,49249,49251,49255,43631,49256,49265,49271,49272,49281,41140,49283,49286,49292,49296,44861,38766,49345,49356,49358,49362,49366,48040,49372,49376,49383,49393,49400,49412,49421,38766,49422,49429,49432,49433,49434,49440,49458,49463,49467,49474,49483,49489,49490,49496,49501,49503,49505,49506,49513,49523,49524,49532,49540,42658,38766,46547,49556,49558,49568,41426,49575,49576,49585,49588,49592,49598,49605,49614,49619,49624,49634,39324,49640,49647,49648,49651,49652,49656,41140,49657,49662,49667,49672,49673,49676,49753,49796,49846,49856,44538,49866,49871,49874,49887,49890,49897,49901,49909,49927,49935,49942,49948,49957,49965,49970,49972,49977,49997,49999,50003,50006,50015,50022,50026,50033,50043,50047,50048,50050,50054,41426,50057,50063,50065,50072,50076,50085,50087,40753,50089,43631,50098,50102,50113,50118,50119,50126,50127,38766,50129,50139,50160,41426,50166,50171,50172,50176,50177,50180,50186,50192,50194,50195,50204,50213,50214,50216,50219,41140,50221,50223,50225,50227,38897,38766,50234,50237,50241,50244,42839,50248,50253,50258,50260,50267,50272,38766,50275,50281,50288,38766,50289,50292,50303,50311,50314,50326,50328,50341,50344,50356,50359,50446,43631,50456,50464,50465,50470,50474,41140,50475,50477,50485,41140,50490,50494,50504,50509,50522,50524,42839,48040,41351,40092,50525,50532,50537,50539,50545,50550,50553,50558,50566,50580,50583,50584,50588,50591,50592,50598,50605,46226,50610,50615,50616,40092,50617,50626,50633,50637,50648,50657,38854,50662,39811,50666,50667,50672,50675,50677,50682,50691,50693,50698,50706,50713,50717,50723,50727,50733,50739,50742,50752,50762,50768,50769,50776,50792,50793,38897,38854,50796,50798,50802,44781,38986,40055,50811,50814,50819,50826,50827,50829,50846,50849,50855,50859,50864,50868,50875,50878,38854,50885,50889,50891,50893,50900,50911,50912,50913,50925,50927,50940,50954,50962,50969,50978,50980,50986,50987,50993,41140,50994,50995,51005,51007,51011,51019,51020,40753,51025,51037,51044,51054,51069,51075,38766,51087,51089,51090,51097,51101,51107,51118,41140,51124,51130,51134,51135,51140,41140,51141,51143,51144,42839,51157,51163,51167,51173,51177,51182,51183,51191,51206,51210,51213,51221,51222,39811,51227,51230,51236,51240,51244,51250,51251,51253,51259,51266,51278,51284,51291,51295,51300,51308,51314,51321,51328,51340,51349,51353,51354,38766,51369,51379,38854,51381,51384,40044,51387,51397,51399,51405,51407,40122,51408,51415,41140,51417,41140,51421,51430,51432,40122,51440,51450,51460,51462,51464,40753,51470,43631,39043,51476,51484,51496,42649,51500,51502,51512,51516,51517,51525,41140,38897,38766,51529,51535,51548,51550,42839,48040,51551,51558,39043,51560,51575,51583,51585,43526,51595,39810,51607,51613,49119,51615,51628,51637,51639,51644,51653,51660,51671,38854,51682,51683,40044,51687,51695,43631,51704,51716,51722,51728,51731,51739,51752,51755,51759,51764,51771,51778,51782,51793,51801,51808,51811,51820,51823,51824,51830,51834,51840,51845,51852,51862,51866,51869,51871,51876,51887,51890,40122,41140,51902,51914,51946,51951,42839,48040,51551,51952,51957,51965,51975,51978,38766,51983,51986,51993,51994,51999,52000,52003,46334,52010,52011,52015,52022,52023,52027,52028,42839,52029,52033,52037,44538,52047,52049,52053,38854,52066,52070,52074,52078,52084,52087,52091,52092,38766,52095,52101,41140,52105,52111,52114,46226,52122,52126,52132,52138,52144,52156,52169,52174,52181,52182,45069,52189,52201,41140,38897,52208,52212,52227,52233,52235,52242,52247,52250,52254,52256,52266,52275,52280,52283,52291,52293,52294,46165,52304,52317,52329,52332,52340,52358,52361,52372,52404,52407,52415,52424,52436,52439,52444,52453,52464,52466,52472,52482,52483,41099,52486,52491,52493,52501,52509,52516,41140,52519,52524,52530,52534,52541,43631,52548,52553,52554,52562,52565,52575,52624,52626,52635,52642,52653,52656,52658,41140,52667,39739,52671,52677,52681,52687,52692,52699,44538,52712,52713,38766,52718,52732,52734,52736,52741,52743,42649,38766,52746,52753,52759,52764,52766,52771,52774,52781,40044,52784,40055,52797,44166,39043,52809,52812,50289,52813,52823,52824,52829,52831,41140,52837,39739,52840,52846,52857,52860,52861,52864,52865,40044,52867,52870,52879,49183,52883,52885,52888,52898,52941,52945,52947,52950,52955,38854,38766,52961,52966,41140,52972,52974,52983,52987,52990,52997,53002,53013,53021,53023,38766,53029,53036,53040,53043,53054,53058,53061,38897,53063,53073,53078,53085,44781,40044,53089,53096,53101,53113,53115,53116,53120,53127,53128,53135,53146,53156,53162,53163,38897,38854,53178,53179,53181,44781,53185,53186,53195,43631,53200,53203,53212,53213,46547,53222,53223,38766,43073,53233,53234,53236,53238,38854,53245,53247,53249,53253,41147,53263,38986,53266,53284,53294,53302,53308,53323,38766,53324,53325,53330,53335,53337,53341,53345,53347,53348,41140,53350,53357,53365,53368,53369,53376,53382,45413,40092,53390,53403,53406,38766,53418,53422,53429,43692,53438,53448,38854,53449,53451,53459,41140,53462,53464,53466,53472,53479,43631,53487,53494,53495,41140,53498,53505,53517,53518,53528,53533,38854,53537,53538,53546,53548,53549,53550,53553,53559,40055,53567,53573,53576,53587,53588,53590,53594,53595,53600,53595,53604,53608,53615,40702,53619,53631,53636,53637,53639,53641,40055,53646,53652,53663,53675,40122,53676,53686,53691,53695,53698,53705,53722,53725,53734,53739,53742,53747,53753,53762,53765,53772,38986,40055,53781,53782,53785,53799,53803,53806,53807,53809,53810,53816,53818,45742,53825,53833,53837,38897,53838,53843,53852,53854,53856,53859,42839,53862,53865,53867,39043,53875,53889,53893,38854,53901,53909,53910,53914,53922,53928,53930,38766,41140,53932,53933,53935,53938,53947,53952,53957,53968,53969,53975,53988,38766,53990,54001,54002,54003,41140,54014,54022,54028,54030,54038,54045,54048,54050,44781,40044,54053,54062,54071,44538,54083,54088,54093,54099,54106,54117,54119,54120,41140,54124,54128,54129,54136,54140,54148,54158,54160,54161,54169,54170,54176,54187,54188,54196,54200,54203,54206,54207,54213,54220,38843,54226,54234,54239,54245,54246,54253,54264,54303,54306,42839,54314,54317,54323,54324,54331,54345,54357,54361,54366,54367,54380,54381,54383,54385,54386,54396,54402,54408,54412,54421,54424,54436,54441,54443,40753,54446,54447,54460,54469,54477,38766,54480,54492,54493,54495,54501,54503,54511,54517,54520,50827,54525,54526,54527,54533,54540,52028,54549,54553,41351,40092,54557,54567,54583,54586,54587,54598,54601,54602,38854,54617,54621,54623,53595,54631,54636,54650,54652,42839,54663,54668,43631,54675,54684,54686,54691,38766,54694,54703,54710,54712,54719,54731,54733,54740,54742,41140,54747,54751,39739,54755,54760,54782,54788,54792,54793,39043,54798,54804,54805,54807,54814,54815,38766,54817,54826,49217,54833,54837,54844,54857,54861,54865,54868,40753,54873,54876,40092,54881,54883,38766,41140,54892,54898,47665,54907,53595,54912,54922,54926,54926,54927,54998,38897,55002,55007,55013,55024,55026,55030,55033,40044,55034,55042,55050,42867,55054,55060,38766,55063,55070,55075,55077,55078,55084,55085,55087,41140,55094,55095,55098,55101,42839,55107,55113,55115,55121,55133,55140,55141,43668,55149,55158,55163,55173,55175,55181,55185,46547,55190,55191,55194,41140,55197,55198,55202,55213,41351,42865,55219,55228,55232,55238,55243,55248,38854,55250,55257,55260,41140,55261,55267,55275,55277,38854,55282,55285,55289,40055,55296,55300,55307,55316,55329,55341,55345,55349,55352,55361,55377,40122,55385,55393,42649,38766,55398,55399,41140,55402,55405,55412,55413,41351,55470,55474,55483,55487,55495,55498,38854,55505,55509,55514,55516,55519,55525,55530,55532,55534,55536,55537,55545,55547,55550,55555,55559,42839,55563,55568,55575,43631,55580,55590,55594,55595,38854,55598,55600,55601,55602,55608,55611,38897,55612,55618,55622,38854,55626,55631,55632,40055,55643,55644,55652,55653,55654,41140,55668,55677,55680,50827,55686,55692,38854,55693,55695,55698,55718,55720,55728,41147,40044,55730,55735,55743,44538,55754,55759,55761,55762,55770,55776,55777,55780,55785,55787,55788,55796,55800,55808,55810,55815,55936,56029,56053,56141,56150,56203,56255,56311,56346,56451,56509,56516,56578,56630,56734,56813,56887,56934,57041,57083,57175,57246,57319,57391,57470,57541,57657,57744,57837,57925,58000,58017,58044,58082,58114,58130,58151,58199,58222,58233,58259,58289,58325,58337,58366,58392,58222,58406,58419,58433,58436,58457,58479,58491,58502,58259,58531,58544,58556,58571,58579,58586,58591,58617,58648,58683,58715,58754,58771,58791,58800,58812,58815,58831,58859,58868,58887,58902,58913,58924,58955,58966,58982,58995,59009,59012,59028,59033,59038,59051,59068,59079,59093,59097,58924,59104,59127,59137,59140,59146,59153,59155,59158,59168,59170,59179,59195,59205,59219,59225,59227,59229,59230,59239,59254,59260,59267,59272,59179,59285,59304,59311,59321,59327,59336,59347,59432,59439,59449,59472,59474,59476,59494,59507,59514,59527,58715,59535,59554,59556,59570,59581,59599,59605,59607,59618,59622,59626,58924,59630,59643,59647,59651,59655,59657,59660,59661,59674,59689,59693,59710,59718,59731,59776,59782,59783,59799,59808,59808,59820,59828,59835,59851,59854,59158,59179,59868,59873,59891,59902,59915,59920,59158,59925,59938,59945,59953,59958,59960,59966,59976,59986,60002,58715,60013,60022,59179,60028,60030,60041,60043,59179,60052,60055,60061,60076,60095,60115,60125,59179,60136,60144,60156,60173,59158,60185,60191,60194,60198,60209,60219,60239,60250,60260,60264,60266,60275,60276,60278,60286,60288,60290,60292,60295,60310,60315,60322,60324,60333,60346,60355,60357,60372,60378,60387,60388,60391,60392,60397,59195,60415,60416,60422,60440,59158,60453,60456,60466,60470,60473,60474,60485,59179,60486,60492,60503,60506,60528,60537,60538,60541,60542,59179,60548,59158,60553,60563,60568,60569,60577,60013,60580,59158,60584,60585,60589,60598,60599,60603,60605,59179,60621,60625,58715,60013,60629,59179,60641,60648,60650,60652,60654,60662,60599,60663,60747,60755,60784,60784,60819,60851,60875,60902,60939,60974,60989,61016,61042,61082,61112,61130,61141,61154,61170,61183,61195,61206,61218,61224,61230,61242,61263,61275,61336,61350,61365,61388,61392,61400,61429,61447,61461,61474,61486,61491,61497,61206,61524,61549,61552,61558,61568,61577,61590,61598,61602,61618,61631,61643,61663,61670,61681,60939,61705,61710,61711,61732,61743,61755,61766,61778,61795,61801,61804,61206,61817,61834,61854,61868,61879,61885,61897,61910,61916,61944,61950,61956,61968,61974,61980,61989,61993,61998,62008,62020,62031,62037,62052,62059,62064,62073,62074,62084,62088,62094,62102,62117,62120,62127,62135,62144,62145,62161,62163,62191,62197,62201,62202,62212,62219,62232,62239,62250,62265,62278,61910,62282,62290,62309,62314,61154,62317,62322,62330,61206,62340,62348,62352,62031,62354,62366,62381,61154,62409,60784,62434,62442,60902,61910,62447,62455,62467,62483,62489,62495,62501,62515,62523,62537,62544,62553,61154,62202,62558,62569,62575,62584,62585,61879,62588,62598,62606,62617,62625,62639,62640,62652,62661,62669,62202,62673,62681,62683,62684,62693,62697,62707,62711,62718,62727,62744,62763,62773,60902,61910,62784,62813,62824,62830,62834,61206,62839,62841,62854,62871,62877,62890,62895,62909,62911,62920,62932,62943,62954,62974,62977,63001,63011,63016,62202,63021,63030,61154,63040,63042,63046,63061,61154,62202,63067,63081,63083,63088,63097,60819,62954,63109,60902,63112,63120,63127,63136,63142,63152,63163,63166,63173,63190,63197,63203,63210,63220,63229,63332,63339,63343,61643,63345,63350,63354,63365,63379,63392,63396,63403,63414,63427,63432,63436,62202,63439,63447,63469,61154,62031,63472,63474,63488,63493,63501,63514,63522,63523,63538,63550,63563,63573,63579,63587,63596,63609,63620,63633,63638,63658,63663,63669,63674,63686,63695,63712,63716,63727,63731,63742,63750,63756,63763,63777,63787,63789,63797,63808,63812,63819,63826,63833,63841,63847,63856,62202,63865,63875,61154,63880,63887,63889,62278,61910,63897,63915,63919,63921,63926,63934,63937,63946,63948,63958,63961,63968,63975,63976,64083,64088,64097,64108,64117,64122,64140,64154,64160,64166,64181,64182,64189,64196,64201,64210,61042,64217,64232,64239,64245,64246,64257,64261,64286,64288,64289,64298,64310,60902,60939,64314,64323,62202,64327,64329,64333,64338,64351,64351,64354,64368,64371,64372,64380,64391,64393,64401,64407,64417,64426,61643,64428,64434,64445,64455,64467,64471,64477,64490,64494,64496,61206,64508,64523,64534,64535,62163,64539,62575,64540,64547,64556,64563,64574,64577,64578,64581,64587,64591,64597,64604,64609,64616,64618,64626,64636,61206,64642,64647,64651,64658,64666,64667,64669,64677,64689,64706,61910,64713,64721,64739,64742,64753,64768,64773,62202,64778,64789,64790,64792,64794,64802,64807,64808,64811,60784,64828,64832,64844,64852,64864,64877,64881,64885,64897,64913,64918,64920,64926,64939,64948,64952,62031,64955,64966,64971,64977,64986,60784,62763,64998,65012,65016,60939,65021,65028,62202,65031,65046,65049,62202,65053,65065,65067,65176,65178,65186,65201,65207,65209,65216,62763,65221,65240,65243,65250,65258,65259,65263,65270,65279,65284,65292,65294,65300,61206,65306,65312,65320,61711,65326,65331,62575,65361,65362,65373,65379,62278,65381,65385,65391,65402,65405,61154,65416,65424,65427,62684,65435,65442,65444,65453,65463,65471,65478,65488,61868,61879,65497,65509,65513,65517,65537,65553,65566,65567,65572,65587,65590,65593,62911,65606,65618,65630,62031,65638,65639,62575,65642,61868,60819,65647,65650,60902,65657,65667,65673,62202,65682,65691,61154,62202,65693,65699,61206,65708,65713,65722,65730,65731,65739,65760,62763,65766,60902,61910,65774,65786,65795,65800,65802,65803,65326,65804,65805,65815,62575,65820,65827,65828,65838,65839,65848,60784,65854,65861,60902,61910,65910,65922,65929,65930,65938,65944,65953,65804,65962,65963,65693,65968,65977,65983,65989,65995,65998,66011,66020,62954,66028,66029,66038,66045,66053,66064,66072,66077,66083,66095,66101,66104,66106,66128,66130,66133,62202,66144,66152,66157,66162,66168,62763,66171,66179,61910,66180,66197,66203,66209,66214,62575,66223,62202,66237,66245,61154,66252,61206,66271,66280,66286,66291,60784,66297,62763,66308,66316,62954,66335,60902,60939,66344,66346,66353,66361,66371,66374,66376,66379,66382,66383,65804,66386,66392,66397,66401,66405,66410,61643,66417,66423,66425,66436,66450,66458,66468,66477,66481,66484,66493,66502,66508,65693,66513,66520,66527,66537,66540,66557,61868,60819,66562,66572,60902,66573,66586,66588,66594,66604,66607,66619,66621,61154,66637,66639,66641,62202,66652,66660,66669,60784,61879,66677,66678,66683,66684,66692,66700,66702,66703,61154,66705,66714,61206,66721,66725,61154,66732,66738,66746,62031,65804,66769,66780,66781,66783,66785,66787,62954,66790,66795,60939,66804,66808,66813,66815,66822,66828,66834,61154,66843,66844,66851,62202,66862,66873,61154,66877,66900,61643,66906,66909,66910,66918,66928,66938,66943,66955,61206,66958,66960,66969,66977,66984,61206,67020,67025,67029,67035,65802,67042,60784,67052,67062,60902,67069,67077,67085,62202,67088,67095,67099,67106,62202,67117,67130,67138,67146,67149,67164,66540,67182,61868,60819,67189,67204,67221,67225,67235,67241,67245,67248,67259,67263,67271,67275,67283,67288,67297,61154,62202,62684,67303,67313,67329,61868,67335,67337,67342,67353,67357,67360,67379,67386,62911,61154,67395,67397,67399,61206,67413,67417,67422,62031,67429,67435,67444,67472,67473,61879,67478,67485,61910,67496,67503,67509,67510,67513,67520,67530,65567,67539,67545,67553,67555,67560,62202,67572,67577,67583,67584,67596,67597,67605,67611,67612,67618,67625,67636,67642,67649,61206,67657,62202,67670,67679,61154,62202,67682,67685,67694,67701,67705,67711,61643,67718,67725,67734,67746,67755,67762,67765,61154,67774,67785,67786,62202,67795,67804,61154,62202,62684,67813,67829,67838,64986,67839,67872,62278,67874,67879,67894,67898,67906,67907,67913,61206,67917,67924,67930,67933,67935,62202,67939,67946,67961,67982,67984,67997,68014,68015,68028,68034,68037,68048,68064,68077,68082,61206,68089,68095,68107,68116,68118,68123,62575,68125,62031,68131,68134,68136,68158,68161,68162,68166,62278,61910,68174,68187,68188,68191,61154,68199,68231,68234,62202,68246,68257,68261,68264,68265,68270,68277,68285,68297,68299,60784,68304,68311,60902,68314,68322,68327,68330,68332,68337,61206,68341,68344,68347,68351,68352,68356,68360,68372,68375,68379,68380,61879,68381,62278,61910,67612,68392,68400,62202,68403,68409,68415,68424,65804,68530,68545,68548,62031,68553,68555,68561,68572,61154,68576,68582,68604,68608,60902,61910,68615,68627,62202,68631,68633,62575,68643,65804,68649,68660,68664,68665,62202,68666,68680,61206,68685,68686,68692,68695,68700,68707,61910,68713,68724,68728,68732,68743,68754,62911,68759,61804,68768,68775,68782,68793,68800,68806,62202,68811,68822,65567,68826,68827,62763,68842,68852,68854,68861,68871,65259,61206,68874,68882,68884,68891,61154,68893,68894,68897,62202,68901,68913,62163,68918,60784,68919,68920,68927,68934,68943,68952,68957,68960,68965,68972,61154,62202,68981,68987,68990,68997,62684,69008,61042,69012,69025,69034,61154,69039,60784,69053,69063,60902,61910,69078,69090,69098,61206,69102,69114,69126,69127,69136,69145,69146,69152,62202,69167,69176,62163,69182,62074,69187,69190,69199,69200,69205,69208,69211,69216,69227,69240,69252,62684,69259,62202,69265,69275,61154,62202,61206,69281,69287,69292,69301,61879,69305,62088,69306,69311,69318,69325,69328,69329,69331,69338,61206,69346,62202,69353,69359,61206,62031,69365,62145,69413,69418,69422,69423,69425,69428,69429,61910,69434,69440,69452,69457,62202,69458,69464,69469,69471,61804,62684,69475,69486,69493,69494,69495,69509,61206,69519,67473,60819,69523,69527,61910,69532,69535,69542,69548,69559,69565,61206,69572,62202,69580,69587,61154,69594,61206,69600,69607,69613,69618,69620,61643,69627,69632,69642,69654,69662,69671,69674,69676,69684,61206,69691,69694,69700,69710,69715,62202,69718,69725,69733,69749,64986,69750,69756,62278,69764,67612,69773,69787,69792,69798,69815,69817,69821,69822,69826,69836,69841,69842,69847,69857,69863,62163,69869,69881,62763,69885,69890,69894,69898,69913,69926,69927,61206,69932,69937,65567,69942,61206,69947,69960,62145,69963,69965,69971,69979,69982,69983,69984,62074,69992,69999,60902,70006,70007,70011,70020,70025,70033,70042,61154,62202,70043,70045,70052,70058,62202,70059,70062,70070,70077,70087,64986,70088,70098,70106,70112,67612,70119,70130,70148,70149,70151,61206,70156,70163,70169,70175,70177,62202,70186,70195,70198,70206,64986,70224,70227,62278,70231,67612,70235,70243,62202,61206,70252,70269,70270,70272,65567,70289,61206,70291,70297,70308,70309,70315,70317,70326,70333,62074,70338,70339,60902,61910,70343,70351,62640,61206,70355,70361,70364,70369,61154,70379,70384,62031,70385,70389,70396,70399,70405,70414,70423,62954,70437,60902,70441,70457,70468,70472,61042,61154,70478,70479,70483,70490,61206,70508,70521,70533,62575,70535,70537,62202,70545,70550,70554,70561,70562,60819,70566,70669,61910,70676,70680,70686,70689,61154,70693,70694,70698,62911,70703,70706,70710,62202,70711,70718,70720,70725,70735,70738,61643,64428,60902,70751,70769,70775,70784,61206,70794,70806,62145,70813,70816,70821,70923,70933,70942,62202,70947,70956,70967,70968,64986,61879,70979,62278,70980,66684,70990,70997,71000,62145,71004,71007,71011,71013,71021,71031,61154,71035,71037,71041,71044,71048,71050,71052,60784,71056,62954,71059,71060,71061,71070,71074,71082,71083,71087,71089,71091,71092,61206,71099,71106,71123,62031,71129,71134,61206,71140,67473,60819,71147,71161,71163,71169,71175,71176,71184,62145,71195,71199,71200,61206,71202,71210,71213,62031,71214,71219,71223,71296,61868,60819,71303,71310,71321,67612,71326,71337,71348,71356,71413,71416,71418,71424,71429,71441,71448,71450,71451,71465,61206,71467,71470,61154,71475,61206,71478,61868,61879,71486,62278,71491,67612,71496,71601,71608,71609,71620,71632,71641,71649,71654,71658,71660,71661,71664,71668,71684,71688,71693,71695,71699,62954,71708,71714,71718,61910,71724,71732,71737,61206,71745,71755,71764,64182,71772,71774,71777,71783,62202,71792,71803,61154,71812,60784,71817,71821,71828,71829,71832,71837,71839,71841,71843,71849,71851,71859,71860,71865,62911,71870,71879,61154,71887,71894,71903,71919,71925,62585,71932,61643,71938,71942,61910,71954,71955,69458,71957,71959,71968,71973,71978,71979,71992,61206,62031,71994,72002,72010,72011,72013,72041,72045,62954,72053,72064,60939,72073,72077,62640,72078,72082,72083,63042,61206,72084,72091,72096,62202,72101,72104,72109,72114,72117,72123,72126,61879,72127,72129,60902,60902,72139,72145,72150,72152,62145,72158,72159,68665,72163,72166,72173,72175,62202,61206,72179,72192,72197,72201,60784,72213,72214,72220,72226,72240,72242,72245,72246,72247,72253,72255,72264,72266,72267,72269,72286,72287,72296,62202,72304,72309,61154,72314,72316,72322,62954,72335,60902,72342,72361,72369,72370,72372,72373,72374,72375,61206,72387,72399,72411,72412,64088,72415,72424,72496,64986,72502,61643,72507,60902,67874,72517,72529,72534,72538,72543,72551,61154,62202,72552,72556,72561,61206,72566,72569,72570,72585,61206,72592,72597,60819,72605,72611,72614,72620,72624,72636,72639,72644,72650,72652,72654,62202,72665,72674,72677,72685,72691,65804,72695,72697,72699,72710,61868,61879,72715,62278,72718,72724,72732,72739,72749,62684,72751,72761,72767,72769,72771,61154,72776,72777,62031,72783,72791,72800,72803,72804,72805,72811,72817,72821,72823,60939,72828,72829,62202,72835,72836,72837,72843,61206,72847,72852,72853,62202,61206,72864,72868,72873,72878,72886,72887,72887,72894,72895,72901,72902,60939,72914,72925,72929,72939,62684,72954,72960,72963,72968,72972,72981,61206,62031,72988,61154,72991,72993,73002,73003,60784,62763,73012,73021,73026,60939,73094,73097,62202,73100,73103,73104,73105,61206,73111,73113,73118,65804,62202,73123,73134,73138,73142,73153,73163,62954,73176,60902,73182,73188,73193,73195,69965,73196,73201,73206,73215,61206,73218,73224,65804,65804,73225,73234,73241,73248,73254,69423,73260,73273,73276,73283,73292,73300,73306,61950,73311,61154,73313,61206,73315,62202,73322,73330,73333,73336,73342,73351,73361,73362,73367,73370,73371,73373,73378,73393,60902,73399,73409,73417,73428,73432,73433,73435,62202,73438,73444,73448,73455,62202,73456,73458,73469,73474,73475,73484,73495,73504,60902,73506,73508,73516,73520,61042,73524,73532,73534,61711,73535,73538,73542,73547,61042,61206,73551,73563,73573,61154,73574,60784,62763,73577,73586,73589,73597,73605,73606,73608,73615,73618,73620,73105,61206,73626,73632,73633,62202,61206,73635,73642,73660,69984,73668,61643,73670,60902,61910,73673,73683,73688,61206,73694,73703,73709,70272,62163,73722,73724,73728,73736,73744,62031,73745,73754,73755,73759,73761,73763,61643,73769,73776,61910,66910,73782,73787,73795,69458,61154,73805,73822,61206,73830,73839,73847,73855,61206,62031,71839,61154,73857,73859,73861,73862,61879,73866,62278,73868,67612,73879,73885,62202,73892,73895,66540,73907,73909,73911,73914,73923,73932,73939,73940,62202,73942,73949,62163,73950,60784,62763,73958,73970,73972,60939,74012,74016,62202,74019,74020,74024,74027,62911,74035,74039,61154,74045,62202,74057,74064,74067,74069,70414,60819,74076,74079,74083,74087,74097,74103,74108,74113,74120,74125,74172,74178,73105,74183,74194,74209,61154,74218,74226,74231,74237,61154,74240,60784,62763,74248,74257,74259,60939,74263,74275,65804,61154,74277,61206,74283,62202,74285,74290,74291,74296,62202,74304,74308,74311,74312,70735,74318,74327,74333,74336,74352,74358,74364,74376,62202,62684,74384,74392,74403,74408,61206,74415,74419,62163,74425,74428,62031,65804,74430,74437,74444,74445,74455,61879,74459,74460,61910,67612,74471,74476,74478,74485,74497,74506,74513,74514,74521,74532,74535,74548,74549,74556,74563,74564,74567,69423,61879,74570,62278,61910,67612,74577,74587,74595,74598,61950,62202,74606,74617,62575,62163,62202,61206,74621,74629,66383,74630,74635,74641,74647,74650,74657,74666,74672,74676,60784,74678,74684,74698,74700,74707,74708,74710,62911,74716,74730,74731,74732,61206,68403,61154,74742,74743,74746,74747,61154,74758,74760,74772,74776,74778,74787,60819,62763,74789,62954,64428,74795,60902,61910,74803,60902,74804,61910,60939,74814,68188,62202,74820,61206,74829,74835,62684,62163,74843,62202,69458,61154,74853,61206,74856,74857,74859,74865,66540,74884,64986,60784,74886,74903,74908,74910,60939,74917,74922,62202,61154,74928,74933,74937,74947,74948,74949,74955,74959,62145,74963,62202,61154,74972,74984,74987,74989,74993,74994,60784,74996,75001,62954,75011,60902,75012,75024,75036,75047,75054,75062,75064,61154,75069,75076,75083,75088,75093,75096,75105,62202,75111,75115,61206,75119,75120,75125,75134,75136,75140,75151,75158,75161,75163,75168,61804,75174,75177,75180,62575,75181,75183,69458,61154,75192,75199,75200,75203,75204,61154,75210,75217,75219,75223,75227,60784,75236,75240,75247,75248,75253,75257,75267,75269,75276,66619,75282,75292,61206,75294,75299,61206,75300,75314,75318,62202,61206,75334,75346,75347,64669,60784,75351,75356,75360,75361,75367,75377,75382,75390,62202,61206,75399,75407,67907,75409,61206,75414,75419,75431,62684,75437,75441,65567,75447,75448,75454,75458,75464,75468,62278,75474,67612,75483,75490,75492,75493,75499,61206,75501,75504,75508,75515,61154,75525,75526,75535,75541,61154,75543,60784,62763,75547,75559,75564,75570,75577,75580,62202,75587,75592,75599,75603,75611,61154,75623,75631,75633,61206,61206,75637,75648,75650,62202,75656,75657,75661,75668,61206,61154,75673,75676,60784,75685,75688,75697,62278,60902,75700,61910,75704,75717,75725,62202,61206,75736,75744,75747,75752,75759,75760,75767,75777,75784,75789,61206,75792,75801,75805,75807,75808,75817,62954,75822,75829,75830,75836,75843,75846,75850,75856,75868,75876,61154,75880,75881,75889,75894,75899,62031,75903,75910,64790,75937,61868,61879,75946,75947,75951,75952,75956,75961,75970,62202,75972,75979,75981,61206,75983,75988,75991,61154,75994,76000,76004,62031,76013,61206,76020,76032,76043,76049,76054,76058,76060,61879,76063,62278,76071,67612,76087,76095,65804,76103,76110,62202,76115,76127,76129,61154,76130,62202,61206,76134,76138,61154,62314,62202,76141,76145,61154,76150,76157,60819,76160,62278,76168,76172,76176,76188,62202,76189,76196,76198,76199,62640,62911,76209,76214,61154,76215,76221,76226,76237,61154,76242,76246,62074,76255,76256,62278,76259,76266,76269,76273,76282,65804,76287,63638,76291,61206,76292,76293,75181,76294,61206,62031,76297,61154,76302,76306,76311,76320,61879,61643,76326,76327,60902,61910,76333,76337,76343,76346,62163,76425,62575,76434,76438,76449,76452,76455,74955,61206,76459,62031,76463,76464,61154,76478,76490,62684,61154,76496,76503,60784,61879,61879,76509,61643,76510,76519,76520,76525,76526,76534,76548,76555,76565,76568,76614,64790,76619,76622,76627,74020,76635,76639,76642,76646,76658,73755,76664,76669,76678,76680,76687,76689,61910,76696,76706,76714,76717,62911,76723,76727,61154,62202,76730,76740,62575,76763,62031,76764,76775,76784,61206,76798,61868,69750,76801,62278,76806,76809,76815,76822,62202,76826,76834,76838,76839,76840,76850,76856,76858,76860,76866,76868,76871,76876,76881,76885,76890,76896,76909,76914,76917,76925,76927,76930,76937,76942,76953,76958,76963,61154,76972,61206,76974,76975,76979,76990,76992,77003,66540,77007,77010,77021,61643,77023,77027,61910,77036,77044,77045,61206,77054,77069,77074,77078,73138,77086,75526,77090,77092,77093,77097,77104,77106,61868,61879,77112,62278,77120,77121,67612,77133,68188,77141,77146,77147,77150,77153,77156,77159,77171,77171,77183,77187,62684,77191,77198,61206,77200,77211,77214,77215,77216,77223,62954,77232,77238,77249,77255,77264,77265,61154,77270,77272,77273,77275,77283,77289,61154,77290,77291,77299,77306,61154,77317,77318,77325,77330,77337,61910,67612,77346,77347,62202,67149,77349,77352,77358,77366,62202,61206,77382,77396,77400,62202,61206,77405,77411,77420,77424,60784,77426,77431,62278,77439,77440,77449,77456,77463,61206,77466,77469,77472,77476,67907,77478,61206,77488,77494,77495,77506,61206,77524,62585,77529,61643,77533,60902,61910,77535,77540,77542,62202,77547,77551,77560,61206,77564,62202,77567,77574,77575,62202,77578,77584,77589,77596,77599,77601,60784,60819,77606,77607,77615,60902,60939,77629,77634,77637,61154,77646,65805,77650,77654,77656,77660,77664,62031,77665,61154,77673,77680,61854,69984,60784,77685,76510,77702,77713,77714,77718,77741,77751,77758,69458,62202,77763,77776,61154,62202,61206,77786,77795,77797,77798,61206,77801,77811,77813,64986,77814,62763,77817,77826,77827,60939,77835,77842,62640,77843,77854,77856,77857,61711,77864,77873,77874,62031,77878,61154,77891,62911,77899,61868,77908,61643,77915,60902,77920,60902,61910,77922,77929,76215,61206,77931,77939,77942,77946,77947,77953,77955,77961,77962,61206,77969,77974,77978,77983,60784,62763,62954,77985,77986,77991,78008,68188,78090,78091,78096,78110,78112,62202,78113,78118,78123,78132,62202,64790,78139,78143,78144,78148,78151,78158,78159,61643,64428,78170,61910,78176,78186,78187,62202,78192,78196,67907,78197,78199,78208,78216,78217,78219,78224,61154,78237,78241,61206,78242,78244,78253,78264,78266,78278,78282,60902,78288,78293,78297,62202,78298,78304,78305,78311,78314,78316,78322,78327,78332,62202,61206,78338,78341,78346,62684,78348,78350,61879,78353,78360,78361,61910,78371,78374,78378,61206,78386,78399,78400,78404,78406,61154,78415,61206,78418,78419,61206,78426,78438,61206,78444,64669,70414,61879,78454,78461,78469,61910,67612,78470,78475,64182,78480,78486,78495,78498,78499,78500,61154,78516,78522,61206,78527,78531,78534,62031,65804,78537,78543,78548,78549,78551,78557,69984,78566,78576,78578,78584,78592,78593,61910,78602,60939,78611,78614,78615,62202,62202,61154,78630,78633,78635,78636,78637,62911,78644,78651,61206,61154,78652,65804,61154,78654,66540,78656,78658,62585,60784,60819,78665,78667,60902,78676,78678,78692,62120,62202,78695,78706,78717,61206,78722,78723,78733,78740,78748,78754,78757,78758,62031,78759,67907,78768,61206,78781,64986,60784,78788,78795,78799,61910,78807,78809,78818,78823,78831,78845,78855,61154,62202,78856,78862,78869,78871,78873,62684,78874,78878,78881,78883,60784,68919,78892,78896,60902,78900,78905,78906,78909,78913,78917,78922,78939,78941,78942,62202,78948,78958,61206,61154,62031,78959,78965,78975,78984,78985,78993,78994,60784,79000,62954,79005,79016,79018,79024,79029,79031,79032,79036,79041,79050,79051,79052,79064,62911,79072,62031,79075,79080,73755,79083,64986,79088,61643,79092,79103,60902,79109,79117,61950,79118,79124,79125,79133,79135,79140,69965,61154,79148,61206,62031,79151,79152,79156,62911,79176,61868,79181,79182,79187,60902,79190,60939,79201,79205,79206,79209,79228,79233,79238,72246,61154,79239,64790,79243,62031,61206,79256,79264,79270,79274,79289,60819,79293,62278,79294,61910,79301,79306,79307,76130,62202,79316,79318,73206,79319,61206,79321,79326,61154,74747,62202,79327,79329,79332,79337,79339,79342,73373,79350,67874,67612,79364,79374,62202,79379,79382,79393,79395,79398,79400,79402,79418,79421,62684,79427,62202,79430,79432,79438,61206,79439,79442,62074,79445,79450,79456,79457,79465,79468,60939,79487,79489,79493,61154,79503,73535,61461,62202,79507,79509,79513,79517,64182,61154,79522,61206,79525,79531,61879,61643,79538,74804,79539,79544,79550,79551,79552,79553,79554,61206,79557,61042,79558,79559,79560,62031,79568,79570,79573,79576,61206,79579,64986,79595,79600,79604,79611,60902,79612,79614,79621,79625,61154,79633,61206,79641,61711,79643,79647,61206,62031,79557,79648,79660,79661,79679,79680,79686,79692,79695,79701,60902,79702,79713,79720,79722,74067,79725,79728,79736,79737,62163,79743,79748,61206,79756,62202,79768,79776,79784,79789,79790,79797,66781,79799,79801,61879,79807,79808,79809,61910,79811,79812,79814,62202,79815,79822,78144,79828,61206,79831,79843,61154,79848,79851,79860,79867,79870,79872,79876,79879,79886,79892,61910,66425,79898,79909,79910,79920,79929,79930,79931,79932,62911,79934,79937,79943,61154,63042,62202,79948,79953,67545,79955,79957,79960,79962,79971,61910,67612,79979,79986,62202,61206,79989,79992,79999,80006,80009,80015,73755,80017,80020,61206,80022,80027,80029,80031,60784,62763,80036,80039,60902,80040,80042,62120,80043,80044,80053,80058,61206,80060,80063,80071,80079,61042,62202,80080,80084,80106,62684,80112,80114,80116,80121,80127,80132,80134,80134,80137,62763,80143,62278,60902,64160,79612,80147,80155,80157,62202,62202,80162,80166,80167,80169,62202,80170,80171,80172,62031,80175,62669,80190,80192,80207,64986,60784,62763,62954,80218,80226,80231,80235,80241,80250,80254,80264,80276,80281,61206,62145,61804,62202,61154,80290,66540,80292,61711,62911,80303,80312,80317,80319,60784,80324,63523,80334,80341,80344,80351,80357,80358,80363,61154,80374,61206,61154,80375,62202,61154,80377,62575,80379,80385,62202,80386,80392,80399,62911,61206,62163,80403,80543,80588,80638,80677,80701,80790,80798,80838,80883,80934,80965,80984,81025,81041,81138,81177,81231,81283,81357,81457,81509,81575,81623,81667,81744,81821,81915,81955,82045,82054,82095,82112,82151,82196,82265,82295,82351,82440,82514,82567,82636,82722,82829,82922,82994,82995,83006,83006,83033,83068,83094,83137,83156,83190,83222,83233,83254,83259,83288,83314,83328,83340,83357,83376,83398,83409,83420,83425,83433,83446,83409,83449,83462,83503,83532,83584,83599,83636,83668,83701,83723,83760,83779,83790,83800,83813,83830,83839,83849,83855,83866,83760,83877,83790,83879,83890,83941,83960,83992,84008,84030,84075,84095,84125,84149,84154,84165,84177,84189,84207,84209,84218,84240,84257,84278,84287,84314,84338,84347,84354,84358,84368,84388,84401,84406,84411,84417,84418,84420,84423,84425,84430,84431,84433,84418,84435,84436,84441,84436,84418,84445,84418,84447,84453,84457,84463,84433,84469,84472,84478,84479,84483,84486,84489,84493,84457,84494,84496,84494,84497,84506,84418,84508,84509,84512,84494,84514,84523,84530,84531,84538,84514,84539,84540,84541,84545,84551,84562,84563,84564,84566,84567,84445,84568,84436,84418,84433,84572,84574,84575,84576,84418,84578,84580,84581,84582,84568,84583,84584,84586,84590,84494,84592,84418,84436,84593,84601,84604,84617,84619,84620,84621,84622,84436,84418,84623,84626,84627,84633,84634,84418,84469,84568,84433,84635,84636,84637,84638,84494,84639,84641,84418,84433,84418,84647,84531,84592,84648,84649,84494,84651,84436,84661,84690,84418,84695,84494,84494,84698,84418,84699,84700,84494,84418,84701,84568,84433,84702,84494,84436,84700,84494,84703,84494,84568,84436,84704,84705,84706,84592,84714,84715,84719,84433,84722,84726,84436,84730,84734,84436,84736,84740,84592,84748,84749,84750,84703,84756,84762,84763,84765,84766,84768,84769,84773,84592,84774,84780,84783,84786,84494,84592,84494,84436,84568,84787,84789,84793,84797,84798,84799,84418,84801,84805,84807,84494,84418,84418,84436,84808,84494,84494,84812,84819,84820,84821,84823,84824,84740,84730,84828,84830,84831,84833,84839,84418,84842,84843,84844,84494,84497,84436,84858,84497,84859,84861,84862,84864,84865,84867,84494,84417,84873,84494,84497,84719,84874,84494,84494,84875,84876,84433,84704,84877,84879,84700,84494,84880,84418,84884,84885,84568,84436,84886,84892,84494,84592,84436,84893,84894,84494,84494,84508,84436,84895,84483,84897,84899,84900,84901,84902,84903,84904,84906,84915,84916,84917,84919,84921,84925,84494,84578,84494,84497,84926,84418,84494,84884,84927,84436,84494,84433,84497,84928,84436,84418,84932,84934,84418,84768,84936,84494,84937,84494,84494,84938,84436,84939,84941,84730,84942,84946,84950,84951,84954,84955,84568,84957,84962,84963,84969,84457,84972,84436,84418,84418,84976,84983,84985,84989,84494,84494,84957,84991,84726,84992,85002,85003,84433,85007,84469,85015,84463,85016,84436,85017,85021,85024,85026,84469,84436,84436,84719,84494,84578,85032,84418,84494,84469,85033,85035,85037,85041,85043,84496,84496,84820,84821,84436,84436,85050,85053,85055,84494,84497,84497,85058,84991,85059,84820,85063,85064,84483,84494,84514,85066,85067,85071,84483,84514,85073,85076,85077,84494,85078,85082,84972,85085,85090,84805,85092,85093,84436,85095,85043,85043,85097,84463,84726,84821,85098,84457,85100,85101,85102,85103,84531,85104,85108,84514,85112,85114,84469,84494,84722,85115,85116,85117,84469,85120,85122,85007,85126,84576,84812,85127,85128,85129,85131,85095,84436,85132,84925,84436,84568,84417,84436,85136,85137,84483,84453,85104,84497,84496,84469,84436,85144,85147,85151,84768,85152,84821,85153,85154,85158,85159,85163,84864,85170,84514,85172,85174,84899,84768,84508,84445,84445,85175,85176,84568,84641,85181,85182,85186,84859,85189,85191,85192,85026,85197,85210,85211,84496,85212,84494,85213,85214,85215,85216,85217,85218,84820,85050,85221,85224,85225,85228,85235,84418,85241,85241,85243,84568,85248,85249,85254,85255,85258,85259,85260,84700,84805,85263,85265,85266,84976,85267,84469,85270,85272,85280,85282,84494,84494,85285,85286,84453,85288,84436,85290,84494,85292,85294,85296,84895,84469,84469,85299,84730,85300,85301,85302,85097,85303,85303,85306,85307,85312,85314,84950,85315,85317,84578,84483,85318,85319,84812,85322,84433,84821,84436,84494,84472,85323,85104,84576,84946,85329,85224,84453,85331,85332,85333,85336,85337,85348,85349,85353,84463,84496,85355,85360,84969,85104,85361,85361,85363,85364,85367,84418,85368,85373,85374,84584,85378,84430,85379,84972,85381,85385,84934,84730,85392,84972,85395,84864,85397,85398,84469,85399,85401,85409,85411,85412,85021,85413,85414,84436,84867,84472,85066,85066,85415,84436,85416,85418,85419,85425,85428,84469,85432,85433,84489,84463,85436,84895,85441,85443,85445,85449,85450,85452,84436,84463,84436,84972,84418,85453,84497,84592,84453,85053,85454,85066,84730,85456,85457,85458,85463,85464,85465,84578,85467,85469,84833,85470,85476,85482,84494,85483,85490,85491,84469,85493,85494,84514,85147,85499,85502,85503,84423,84494,84946,85504,84821,84453,85483,84494,85221,85511,84433,85513,84436,84895,84494,85517,85520,84436,85521,85526,85248,85527,85419,85528,84496,85530,85535,85537,85538,85539,85540,85544,85546,84469,85547,84989,85445,84433,85549,85554,84497,85555,85097,84457,84494,85453,85453,85557,85558,84494,84494,85538,85561,84496,84469,84497,84463,85562,84436,84831,84972,85563,84578,84592,84859,84821,85565,85566,85572,85108,85577,84483,84972,84497,85578,84820,85580,84541,84805,85581,85585,84906,85586,85587,85097,84531,85591,85592,85599,85604,85608,85612,85613,85614,85336,85617,84463,85026,85591,85619,85562,84469,85620,84479,85622,85623,84950,84821,85627,85629,85630,84494,84445,84496,84937,85631,84884,85634,84972,84578,85635,84433,85639,84568,84531,84436,85450,84417,85640,84436,85397,85026,85641,84496,85645,84972,84514,85147,85650,85654,84469,85656,85657,85659,85661,85021,84568,85662,85381,84494,85663,85667,85668,85670,85674,84805,84494,85675,85677,85681,84592,85661,85401,85175,85685,85686,84722,85687,85688,84793,84950,85690,84756,85691,84884,85695,85696,85697,85699,84453,84436,85701,84469,85704,84463,84875,85706,84494,85707,85619,85708,85712,84472,85530,84895,85716,84457,85717,84821,85718,85367,85719,85433,85720,85721,85662,85722,85381,85723,85724,85725,85726,85727,85728,85248,85731,85733,85734,84436,85735,85736,85737,84494,85307,84722,85740,85741,84899,85742,85744,85745,85746,85747,84463,85748,85558,84463,85761,84895,84494,84469,85765,85769,85772,85773,84568,85774,85775,85783,84497,85784,84436,84483,84445,84430,85318,84568,84805,84884,85476,85024,85785,84514,85786,84906,84989,85787,84453,84991,85670,84983,84417,85147,85791,85221,85591,85792,85793,85797,84592,85798,85800,85802,84457,84457,85805,85221,85806,85807,84730,85808,85809,85812,85813,84568,85826,85827,85828,84730,84457,85830,85832,85695,85842,85355,84592,85530,85708,85843,85849,85850,85851,84972,85852,84821,85855,85857,85859,85860,85221,85861,85043,85863,84494,84436,84436,84821,84417,84433,85147,85864,85041,85865,85731,85866,85041,85868,85872,85108,85873,84494,84496,85875,85876,85877,85879,84635,84531,85108,85661,85880,84494,85221,85095,84497,85411,84436,85017,84950,85092,84821,85886,84418,85888,85889,84418,85893,84483,85894,85895,84436,85104,85896,85899,84457,85097,84463,85147,84793,85900,85147,84469,85806,85905,84508,85908,85912,84418,85913,84469,85740,85415,85558,85916,85411,85917,85765,84483,85670,84494,85919,84436,84497,84453,85740,85920,84436,84433,84494,85921,84925,85294,84418,85397,85922,84453,84453,84514,84989,85923,84453,85924,85147,84483,84418,84497,84469,85926,85147,84514,85927,85214,84494,84483,84820,84423,85932,84418,85939,85941,84541,84592,84820,84859,85591,85942,84483,85950,85951,85952,85411,84494,84463,84592,85953,85954,84514,84453,85955,84768,84418,85956,85957,85191,85797,85960,85964,84578,85769,84494,85965,85967,85968,84879,84722,84514,85972,85974,85979,85981,85983,84418,85987,84989,85765,84469,84586,84469,85401,85217,85476,85290,86000,84494,84436,84433,84592,84436,85224,85021,86003,86004,85708,85367,85432,84496,86005,86010,84494,86011,84621,86012,85530,86013,86014,86018,86019,84989,84494,86023,85290,84486,86026,86027,86028,86033,84494,84436,86037,84989,85097,84463,84575,85893,86038,86045,86046,85661,84821,84893,84436,84578,84494,86047,84951,84453,84545,84578,86048,86050,84496,86051,84469,84469,84469,84418,86053,86054,85385,86059,85591,84812,86064,84483,86071,85272,85530,86075,86076,86077,86078,84592,86079,85147,86037,84592,86081,84436,84494,86088,86089,84700,85175,85614,84972,84972,86094,86095,85385,86096,84592,86097,86098,84496,86099,84436,84494,86100,86101,84453,86105,84494,86106,85102,84821,86107,84436,84564,84418,86110,86115,84418,86117,84578,85097,84463,85058,84469,86118,84489,84950,86120,86123,86124,84730,84463,85215,84497,86126,84508,84494,85677,86127,85413,85432,86129,86132,86133,84641,85415,86134,86135,85661,85097,86136,84989,86142,85432,86143,84436,86144,85095,84463,84722,86145,84531,85363,85221,84592,84496,86149,86150,84494,85007,84756,84899,86152,85972,84545,86005,86153,84592,86165,86169,84494,86172,84418,86173,86174,86175,84494,84592,85189,85224,86178,86180,84494,84494,85614,84433,84497,84895,84494,85701,86184,86185,85612,86186,86188,84568,86194,84486,85591,84436,85385,84436,86195,84494,85337,86196,86197,84496,85097,85299,84496,86198,86199,86203,84463,84884,86204,84514,86208,86107,84469,85085,85137,86209,84494,86214,85731,84592,84586,86216,84867,86217,84541,84812,86219,84463,86220,86231,86232,84469,86234,84906,86235,84483,85735,86237,86241,85225,86242,85095,84722,86246,84469,86247,84991,86248,84989,86252,85147,86253,84494,86255,85800,85708,84417,84576,84514,84433,84545,86256,86257,84592,84972,86258,86259,84453,85181,84463,85381,86260,85681,84957,85299,86261,85667,86270,86271,84496,85381,84418,85411,86275,84457,86279,84494,85591,86280,86281,85097,85476,86282,84989,84568,84497,85101,84774,84463,84418,86286,84719,86287,86288,84821,86294,86295,84730,86296,86297,84926,84812,84514,84497,84730,86298,86301,86302,85806,84436,86305,84453,84457,86306,84436,85832,86307,86013,85381,84436,86308,84494,86309,84989,84769,86310,84494,85554,84899,85483,86312,84592,84494,85221,86316,84483,86317,85299,84453,86318,86319,86320,84514,86321,84514,84494,86324,84531,84508,86326,86331,84592,84719,84483,85731,86332,86333,84469,84436,85191,84821,84497,86334,84895,86337,86341,84568,85832,84436,86342,84483,86348,84722,86349,84436,86350,84820,85097,86358,85785,85913,84497,85224,84497,86362,85092,85147,86363,86364,85147,84436,86365,86367,85620,84494,84821,85972,86368,84514,84457,86372,84950,86287,84821,85591,86373,84494,85147,86374,85102,84483,85017,84820,84469,84859,85483,84514,84436,84494,84494,86375,84592,85677,86286,84494,86377,86379,85562,84418,85591,84494,84494,85807,84483,84497,86380,86381,84576,84433,86382,84469,86383,84494,86385,84436,85191,86387,84418,86388,86208,84514,84494,84641,84469,84508,86390,86037,84453,85221,84463,86392,86404,86405,86412,86208,86413,86414,85294,86350,86415,86416,86417,84494,84514,84895,86421,84483,85032,84514,85367,84769,86425,86426,84494,84989,86427,86429,85483,86431,84568,86432,86436,85026,85294,86004,84494,84436,86441,84494,84469,86442,86444,86445,84483,86446,86449,84436,85908,84457,86450,84494,84436,86385,85254,86452,86453,86457,84472,85097,86460,84463,86100,85299,84469,84496,84972,84418,85685,84722,86461,86462,86463,86464,84418,84722,86465,84453,86466,84453,86467,84972,85397,86473,85147,86474,86475,86477,84494,84514,86478,85097,86479,86449,84494,86487,84545,84496,86488,84494,86493,84972,84722,84497,85662,85294,86494,86497,84991,84469,84989,85381,85221,86498,86499,84592,86003,85893,86501,84483,86037,84906,86479,84592,86502,85591,86504,86505,84719,84875,86506,86507,86508,86509,86513,84418,85381,86515,86517,84805,86518,86286,85191,86522,85097,86523,84472,86527,86532,84469,86534,86535,84479,86537,86538,86541,86545,85097,84820,86546,84989,85224,84989,84972,86548,84820,85411,84578,86549,86550,84463,86551,86552,84508,85037,84592,86553,84494,85667,86556,86557,84423,84875,86552,86561,86037,86563,86564,84568,84763,86565,84862,84463,86286,85411,85381,86566,86568,86574,86576],"time":[380.999167,383.703167,384.888042,385.904167,386.900667,387.898333,388.899917,389.905583,390.903125,391.903667,392.908417,393.916167,394.909292,395.900125,396.918583,397.891292,398.897917,399.901292,400.914583,401.896333,402.916208,403.875583,404.902875,405.895417,406.92,407.894167,408.913875,409.915292,410.908375,411.899792,412.894125,413.921667,414.904708,415.8985,416.913,417.909667,418.915375,419.910333,420.898958,421.908542,422.920833,423.913417,424.907708,425.916625,426.9105,427.916083,428.907958,429.9095,430.920208,431.911875,432.912042,433.920375,434.907875,435.927792,436.915917,437.887917,438.927917,439.8735,440.931958,441.851167,442.935542,443.913167,444.91475,445.918917,446.921542,447.909333,448.92475,449.740042,450.966958,451.897833,452.926,453.917375,454.919667,455.910208,456.916167,457.924,458.918,459.921667,460.922167,461.926417,462.920708,463.940792,464.928792,465.929875,466.92975,467.933458,468.937417,469.932333,470.938667,471.931167,472.931292,473.939042,474.931583,475.934,476.93375,477.93725,478.937792,479.935208,480.934208,481.942375,482.905333,483.9465,484.93825,485.934458,486.941375,487.9325,488.94375,489.9325,490.93775,491.941167,492.9125,493.918708,494.935167,495.936542,496.939917,497.935542,498.94225,499.938833,500.942833,501.934542,502.937958,503.94325,504.935042,505.941042,506.936208,507.917417,508.94875,509.935917,510.935833,511.942625,512.941083,513.944083,514.938333,515.946833,516.935542,517.944792,518.942958,519.943583,520.938875,521.943833,522.925792,523.919958,524.945125,525.944958,526.936333,527.942792,528.943042,529.942833,530.939917,531.947792,532.944042,533.939708,534.9475,535.918625,536.947875,537.946208,538.946083,539.941083,540.948,541.941417,542.943458,543.941958,544.942958,545.945125,546.943292,547.949,548.941167,549.941625,550.942333,551.943833,552.940292,553.94425,554.949458,555.955667,556.947458,557.923958,558.928958,559.95325,560.9475,561.944083,562.950083,563.94975,564.944125,565.911375,566.960292,567.939125,568.954917,569.950375,570.951958,571.949167,572.950125,573.948917,574.949875,575.944208,576.954208,577.95225,578.950042,579.948292,580.949833,581.951083,582.949292,583.943,584.950708,585.946083,586.920208,587.9535,588.948625,589.949208,590.947917,591.948333,592.949042,593.948875,594.948917,595.947708,596.9495,597.948083,598.950042,599.947708,600.952208,601.94575,602.952667,603.951667,604.948333,605.951333,606.957292,607.955,608.948208,609.951333,610.950792,611.954375,612.949042,613.953042,614.947458,615.951958,616.947667,617.952625,618.953625,619.950208,620.957875,621.956875,622.955458,623.957875,624.951417,625.954917,626.948958,627.958417,628.956125,629.950625,630.953125,631.952875,632.95825,633.959875,634.951125,635.954917,636.958708,637.954958,638.95875,639.952917,640.959667,641.956333,642.95425,643.953,644.957333,645.952417,646.956917,647.953583,648.961917,649.960125,650.952417,651.958167,652.958208,653.955833,654.9615,655.959792,656.95625,657.958292,658.958458,659.954583,660.958042,661.953917,662.962583,663.955625,664.957458,665.959833,666.95575,667.955583,668.956542,669.960875,670.956,671.965,672.961917,673.937875,674.962458,675.961208,676.960083,677.95,678.954583,679.960333,680.954583,681.961542,682.966333,683.9525,684.962917,685.960708,686.95925,687.962292,688.961833,689.960875,690.963375,691.957458,692.966958,693.957625,694.968208,695.956958,696.95975,697.967542,698.962292,699.964208,700.960958,701.960708,702.962583,703.943042,704.96725,705.947333,706.966583,707.939667,708.975,709.960333,710.965375,711.960625,712.964167,713.966292,714.962417,715.960125,716.968375,717.95975,718.965125,719.963625,720.964208,721.962542,722.964375,723.963958,724.966375,725.960833,726.964292,727.963333,728.963083,729.963,730.960125,731.964542,732.964333,733.96525,734.942125,735.969542,736.96275,737.963,738.963875,739.966125,740.965625,741.956292,742.938,743.944458,744.973792,745.965083,746.967417,747.966292,748.972,749.966917,750.971875,751.963708,752.972,753.967125,754.966167,755.965292,756.970667,757.96525,758.968667,759.967833,760.968625,761.975208,762.966708,763.969542,764.968958,765.973458,766.971042,767.967917,768.966417,769.974167,770.968208,771.971875,772.97275,773.965792,774.957958,775.968292,776.946542,777.980375,778.952083,779.952042,780.976917,781.97275,782.970792,783.970208,784.973917,785.972458,786.969458,787.970458,788.968208,789.973,790.947958,791.976542,792.794333,794.019125,794.916042,795.981708,796.968042,797.980875,798.971708,799.9715,800.972,801.978375,802.97475,803.9715,804.976375,805.975,806.97825,807.971625,808.973625,809.976333,810.97975,811.972375,812.97425,813.974583,814.976875,815.973667,816.972125,817.974292,818.974833,819.982208,820.976167,821.977,822.981375,823.97975,824.973458,825.97725,826.973792,827.981083,828.978583,829.982,830.979042,831.980792,832.978708,833.981208,834.97675,835.977625,836.98225,837.974625,838.98375,839.977792,840.982667,841.982083,842.979667,843.97725,844.980958,845.977458,846.984125,847.977667,848.95725,849.992708,850.979667,851.955917,852.987042,853.9805,854.983583,855.978875,856.987292,857.980292,858.98125,859.979875,860.98,861.98575,862.985083,863.986125,864.97775,865.98775,866.984292,867.982958,868.984333,869.987833,870.979,871.982292,872.98475,873.98425,874.979125,875.983833,876.98375,877.983,878.989,879.9845,880.98825,881.987625,882.981833,883.986667,884.982,885.984458,886.989875,887.984792,888.982,889.985042,890.985,891.990208,892.979833,893.990375,894.989833,895.987625,896.991458,897.985375,898.984333,899.984708,900.985417,901.988625,902.99125,903.990125,904.983167,905.992333,906.990875,907.984625,908.988333,909.988792,910.984958,911.99125,912.979208,913.991917,914.98725,915.993125,916.986792,917.987208,918.990667,919.99275,920.989875,921.990292,922.991208,923.991583,924.985292,925.994042,926.98975,927.969208,928.969917,929.968208,930.986375,931.993917,932.987708,933.985375,934.992667,935.989,936.989958,937.993917,938.99325,939.988833,940.9895,941.998583,942.986458,944.000042,944.991042,945.98575,946.998375,947.987375,948.995375,949.988583,950.9975,951.987583,952.994458,953.992583,954.994042,955.988667,956.995042,957.988083,958.994792,959.992458,960.9915,961.996542,962.996833,963.989208,965.001333,965.993875,966.99725,967.996583,968.99125,969.996083,970.996042,971.991458,972.997958,973.99325,974.997792,975.992375,977.000333,977.990042,978.994708,979.992125,980.99375,981.993208,982.993417,983.99275,984.993125,985.993625,986.993333,988.001083,988.990375,990.002458,990.994417,991.99375,992.994542,994.000583,994.999958,995.99625,996.997625,997.99525,998.998417,999.994042,1000.997417,1001.999292,1002.997125,1003.994958,1004.996333,1005.9995,1006.973792,1008.015792,1008.990833,1009.976708,1011.001792,1012.001708,1012.99975,1013.997833,1015.005375,1016.016042,1017.000083,1017.995333,1019.002,1019.997875,1020.995875,1022.005167,1023.003292,1024.002417,1024.998292,1026.002958,1026.997875,1028.004083,1028.998708,1030.002833,1031.00425,1032.004625,1032.997792,1034.005292,1035.000542,1036.000417,1037.005125,1038.005333,1039.005708,1040.008042,1041.003375,1041.9985,1043.004042,1044.001167,1045.005667,1046.00425,1047.00625,1048.004,1049.002292,1050.003042,1051.000833,1052.002333,1053.01025,1053.9965,1055.008875,1056.007042,1057.006708,1058.001667,1059.001583,1060.004792,1061.002833,1062.00525,1063.00725,1064.000708,1065.011833,1066.007708,1067.003,1068.004583,1069.005958,1070.003667,1071.0085,1071.988958,1073.006625,1073.9855,1075.028583,1075.999875,1077.003375,1078.0075,1079.008125,1080.009,1081.003917,1082.011958,1083.004375,1084.006125,1085.0055,1086.005958,1087.005792,1088.00925,1089.004333,1090.012458,1091.002208,1092.008583,1093.008542,1094.006208,1095.01325,1096.009958,1097.006375,1098.009958,1099.009458,1100.007458,1101.00425,1102.008833,1103.009125,1104.0105,1105.008333,1106.007708,1107.011875,1108.007292,1109.01275,1109.986333,1111.0165,1112.007417,1113.00875,1114.01625,1115.013542,1116.00925,1117.009125,1118.017417,1119.024833,1120.004917,1121.01125,1122.008292,1123.010833,1124.011208,1125.010667,1126.0105,1127.011708,1128.011625,1129.009333,1130.010583,1131.010917,1132.009792,1133.009958,1134.012458,1135.011542,1136.012,1137.010125,1138.01275,1139.010417,1140.009958,1140.991375,1142.029042,1143.0085,1143.9905,1145.016958,1146.022208,1147.01125,1148.01275,1149.013167,1150.01275,1151.017375,1152.011958,1153.020875,1154.014708,1155.014583,1156.012333,1157.021583,1158.009792,1159.012875,1160.016958,1161.018917,1162.019292,1163.01625,1164.015833,1165.013875,1166.014042,1167.022542,1168.011125,1169.025208,1170.013958,1171.017583,1172.0125,1173.02625,1174.017417,1175.020875,1176.020083,1177.02075,1178.021583,1179.015833,1180.015125,1181.015833,1182.021792,1183.016583,1184.01725,1185.019417,1186.016042,1187.016042,1188.020292,1189.022417,1190.01825,1191.020083,1192.017042,1193.013833,1194.023292,1195.022083,1196.015792,1197.016667,1198.01625,1199.02375,1200.017333,1201.01675,1202.014708,1203.017875,1204.017625,1205.024625,1206.014125,1207.022875,1207.995958,1209.046458,1210.009,1211.00125,1212.02225,1213.003583,1214.026833,1215.018875,1216.021042,1217.014833,1218.024208,1219.016875,1220.026292,1221.019083,1222.0205,1223.020083,1224.021125,1225.020667,1226.028125,1227.017792,1228.023792,1229.02075,1230.022167,1231.024833,1232.023333,1233.027,1234.020042,1235.026167,1236.023917,1237.023292,1238.020042,1239.0215,1240.023167,1241.028583,1242.025542,1243.021708,1244.023333,1245.026083,1246.0295,1247.028417,1248.020458,1249.026917,1250.025542,1251.02325,1252.023583,1253.022875,1254.030417,1255.024333,1256.028083,1257.02875,1258.026292,1259.025792,1260.0255,1261.029542,1262.0235,1263.033667,1264.021833,1265.027958,1266.02925,1267.031083,1268.023125,1269.029292,1270.030042,1271.028458,1272.030167,1273.023792,1274.028458,1275.027125,1276.0265,1277.033167,1278.023708,1279.003667,1280.043458,1280.999917,1282.029833,1283.030792,1284.025792,1285.031792,1286.025542,1287.02875,1288.031292,1289.025833,1290.029,1291.029625,1292.027583,1293.029167,1294.030042,1295.033792,1296.025542,1297.028042,1298.032458,1299.03275,1300.03025,1301.034042,1302.026375,1303.0325,1304.028458,1305.029083,1306.033875,1307.033875,1308.025667,1309.029958,1310.029208,1311.030542,1312.029042,1313.03025,1314.034083,1315.029208,1316.0355,1317.030375,1318.034667,1319.030625,1320.033917,1321.028167,1322.039792,1323.027875,1324.032667,1325.034417,1326.031125,1327.038833,1328.037417,1329.029625,1330.0315,1331.030917,1332.03975,1333.03175,1334.0355,1335.037583,1336.032083,1337.032875,1338.039208,1339.030917,1340.0355,1341.039875,1342.032375,1343.040625,1344.032333,1345.039208,1346.016625,1347.05625,1348.025875,1349.055583,1350.028125,1351.037583,1352.039,1353.0395,1354.041667,1355.036583,1356.035125,1357.038958,1358.037625,1359.034667,1360.0335,1361.038792,1362.035333,1363.037542,1364.035042,1365.036667,1366.036583,1367.026708,1368.035708,1369.031417,1370.035583,1371.043792,1372.033833,1373.041,1374.040583,1375.0355,1376.035667,1377.037333,1378.041875,1379.037208,1380.039458,1381.039833,1382.040542,1383.037583,1384.042208,1385.036417,1386.043375,1387.037125,1388.038792,1389.04325,1390.03975,1391.037875,1392.038958,1393.041875,1394.037458,1395.043417,1396.039958,1397.0435,1398.037542,1399.047708,1400.038083,1401.019542,1402.061667,1403.03975,1404.042208,1405.0415,1406.044833,1407.045875,1408.037333,1409.042417,1410.042,1411.048458,1412.039042,1413.048167,1414.043083,1415.042,1416.040292,1417.045458,1418.04075,1419.049375,1420.044417,1421.040708,1422.040417,1423.052917,1424.043042,1425.042375,1426.048708,1427.041292,1428.044417,1429.046,1430.045208,1431.047083,1432.04625,1433.042167,1434.049667,1435.042875,1436.044458,1437.044917,1438.055208,1439.047792,1440.044875,1441.044333,1442.050583,1443.042333,1444.044042,1445.050958,1446.049583,1447.043833,1448.019083,1449.057125,1450.045667,1451.046417,1452.046375,1453.050875,1454.014875,1455.059458,1456.04225,1457.05575,1458.044125,1459.049583,1460.051542,1461.047042,1462.0495,1463.048417,1464.054625,1465.050417,1466.0495,1467.047875,1468.051208,1469.048542,1470.04975,1471.054417,1472.050708,1473.045625,1474.050708,1475.051333,1476.025833,1477.073792,1478.044583,1479.031042,1480.053042,1481.054875,1482.054375,1483.048375,1484.051667,1485.049917,1486.054583,1487.051792,1488.050208,1489.0475,1490.052083,1491.049917,1492.053625,1493.053458,1494.048708,1495.056458,1496.052833,1497.048542,1498.056917,1499.054292,1500.052792,1501.054625,1502.050167,1503.05425,1504.053875,1505.051083,1506.059,1507.054542,1508.052125,1509.058208,1510.050292,1511.059958,1512.048875,1513.052667,1514.060333,1515.055375,1516.057042,1517.052083,1518.053042,1519.058042,1520.055,1521.053792,1522.060208,1523.048417,1524.056458,1525.056292,1526.052042,1527.059292,1528.052917,1529.053625,1530.055625,1531.053,1532.054917,1533.055,1534.053083,1535.056792,1536.054542,1537.056083,1538.056917,1539.055,1540.055917,1541.056625,1542.053917,1543.03275,1544.050042,1545.052667,1546.054917,1547.055208,1548.058917,1549.054208,1550.055625,1551.057208,1552.0595,1553.063042,1554.052167,1555.066833,1556.059208,1557.060542,1558.057292,1559.066708,1560.059708,1561.063792,1562.0615,1563.061792,1564.057292,1565.06525,1566.063625,1567.065833,1568.058667,1569.06375,1570.062292,1571.062875,1572.059542,1573.069333,1574.064167,1575.065208,1576.064708,1577.059708,1578.068667,1579.061167,1580.065458,1581.061542,1582.070792,1583.06775,1584.062,1585.063958,1586.063208,1587.058833,1587.997833,1589.082083,1590.062417,1591.06525,1592.065167,1593.062083,1594.076,1595.062125,1596.070458,1597.061125,1598.066875,1599.070083,1600.067167,1601.06425,1602.070125,1603.069583,1604.063042,1605.073833,1606.068333,1607.066458,1608.06325,1609.065708,1610.071792,1611.080875,1612.064708,1613.079833,1614.063125,1615.068542,1616.074125,1617.065417,1618.068625,1619.065083,1620.070125,1621.068917,1622.06725,1623.07175,1624.07,1625.072083,1626.06825,1627.068833,1628.043792,1629.072792,1630.073042,1631.0745,1632.07575,1633.066958,1634.075792,1635.064417,1636.073292,1637.068458,1638.069917,1639.072583,1640.067875,1641.068667,1642.072583,1643.069875,1644.077625,1645.074333,1646.067625,1647.078792,1648.069125,1649.070375,1650.076375,1651.0695,1652.071917,1653.073417,1654.077125,1655.075792,1656.070542,1657.077042,1658.076667,1659.07125,1660.07275,1661.074375,1662.074375,1663.072625,1664.071792,1665.073667,1666.075417,1667.075833,1668.048583,1669.055833,1670.072583,1671.073125,1672.081125,1673.073042,1674.075875,1675.050167,1676.06775,1677.061042,1678.098625,1679.070417,1680.05825,1681.080208,1682.08225,1683.07375,1684.065792,1685.081208,1686.077917,1687.083542,1688.074958,1689.083583,1690.0785,1691.080583,1692.076417,1693.073333,1694.083208,1695.08225,1696.081375,1697.075667,1698.086708,1699.081292,1700.085125,1701.079542,1702.07525,1703.080875,1704.084667,1705.079,1706.086042,1707.085083,1708.084458,1709.076167,1710.088458,1711.078083,1712.085,1713.079208,1714.087208,1715.085583,1716.08075,1717.048792,1718.091167,1719.084208,1720.087792,1721.080125,1722.084083,1723.08075,1724.086417,1725.084458,1726.086875,1727.08475,1728.084833,1729.0815,1730.08725,1731.078,1732.089083,1733.083542,1734.088708,1735.081292,1736.085375,1737.079875,1738.085417,1739.086542,1740.083875,1741.082667,1742.089042,1743.081875,1744.064208,1745.103917,1746.076208,1747.09975,1748.080833,1749.087208,1750.089042,1751.089083,1752.082625,1753.089458,1754.090625,1755.084292,1756.084167,1757.088167,1758.084167,1759.09,1760.086083,1761.085583,1762.087125,1763.087708,1764.084542,1765.084833,1766.089542,1767.082917,1768.084417,1769.085125,1770.09,1771.089792,1772.089208,1773.084792,1774.087958,1775.09225,1776.085125,1777.085958,1778.093083,1779.0855,1780.088875,1781.093458,1782.092,1783.092125,1784.087,1785.088417,1786.093458,1787.087375,1788.089375,1789.091875,1790.088458,1791.096667,1792.086125,1793.089792,1794.093292,1795.095,1796.087958,1797.091417,1798.092833,1799.089958,1800.09375,1801.088417,1802.092417,1803.072042,1804.11375,1805.080875,1806.091625,1807.094708,1808.094042,1809.08975,1810.095833,1811.097708,1812.08925,1813.091958,1814.0915,1815.091333,1816.091167,1817.097208,1818.095333,1819.091708,1820.091708,1821.090875,1822.091083,1823.092667,1824.096458,1825.08975,1826.098208,1827.094125,1828.094833,1829.095875,1830.089917,1831.095583,1832.098625,1833.091208,1834.100292,1835.090542,1836.095625,1837.094875,1838.092167,1839.099375,1840.092,1841.093542,1842.093208,1843.100583,1844.093625,1845.097792,1846.091458,1847.098208,1848.095083,1849.102833,1850.096625,1851.100708,1852.09425,1853.102,1854.092,1855.102833,1856.0705,1857.103958,1858.092375,1859.088167,1860.098542,1861.097458,1862.094,1863.099625,1864.092875,1865.097833,1866.101,1867.092208,1868.097333,1869.099417,1870.099458,1871.103042,1872.094833,1873.102833,1874.100583,1875.095583,1876.096542,1877.104083,1878.0965,1879.103458,1880.093875,1881.102542,1882.09625,1883.104083,1884.096958,1885.103375,1886.102958,1887.105125,1888.097083,1889.10125,1890.101875,1891.104167,1892.0995,1893.1025,1894.098708,1895.105875,1896.094875,1897.107833,1898.099333,1899.099542,1900.098833,1901.101292,1902.104917,1903.101292,1904.101125,1905.105083,1906.099,1907.1055,1908.099708,1909.103875,1910.099083,1911.106583,1912.098125,1913.104542,1914.10375,1915.104333,1916.101958,1917.102917,1918.103458,1919.1045,1920.108417,1921.10325,1922.106292,1923.105,1924.100167,1925.104625,1926.101583,1927.10675,1928.104417,1929.101042,1930.10375,1931.104083,1932.105375,1933.101417,1934.109333,1935.107125,1936.1035,1937.103167,1938.111208,1939.108708,1940.103625,1941.104792,1942.111917,1943.114667,1944.103708,1945.109583,1946.107,1947.103958,1948.112583,1949.1055,1950.110458,1951.11125,1952.107167,1953.103708,1954.112042,1955.107042,1956.107625,1957.099542,1958.113375,1959.109375,1960.107917,1961.107375,1962.107333,1963.111208,1964.113167,1965.1035,1966.111708,1967.109333,1968.111875,1969.1035,1970.113,1971.10825,1972.112167,1973.111708,1974.108667,1975.111333,1976.104708,1977.113542,1978.111125,1979.106042,1980.112083,1981.107042,1982.114708,1983.111125,1984.112458,1985.106917,1986.115292,1987.110083,1988.111625,1989.111875,1990.109292,1991.109375,1992.111083,1993.10825,1994.107958,1995.087958,1996.092083,1997.000042,1998.116208,1999.104792,2000.098208,2001.092042,2002.10825,2003.1135,2004.108958,2005.111667,2006.112083,2007.113458,2008.110792,2009.110875,2010.111208,2011.113917,2012.112625,2013.111542,2014.115,2015.110042,2016.119083,2017.111958,2018.092667,2019.0945,2020.11875,2021.112917,2022.113167,2023.117125,2024.112833,2025.115208,2026.119833,2027.115125,2028.119333,2029.117208,2030.110875,2031.119417,2032.115292,2033.118292,2034.117417,2035.1175,2036.113292,2037.12,2038.112583,2039.122,2040.117708,2041.118208,2042.118583,2043.118625,2044.114583,2045.11725,2046.112708,2047.120833,2048.115958,2049.1185,2050.117667,2051.118417,2052.1195,2053.120708,2054.114083,2055.121958,2056.123625,2057.122542,2058.121333,2059.119083,2060.121792,2061.117375,2062.116792,2063.120583,2064.116875,2065.119917,2066.115375,2067.119375,2068.11825,2069.116167,2070.119833,2071.120292,2072.117375,2073.123667,2074.119708,2075.117583,2076.120708,2077.123583,2078.123542,2079.120333,2080.118375,2081.119875,2082.124042,2083.117083,2084.12375,2085.119333,2086.125,2087.121833,2088.124708,2089.12325,2090.123458,2091.117833,2092.12875,2093.117583,2094.121167,2095.123958,2096.126167,2097.116708,2098.123792,2099.120708,2100.1235,2101.126417,2102.124667,2103.12425,2104.122958,2105.121417,2106.123917,2107.126292,2108.11125,2109.130833,2110.122375,2111.125,2112.120375,2113.146417,2114.095917,2115.132083,2116.121542,2117.1235,2118.1215,2119.124,2120.123208,2121.12575,2122.128375,2123.121833,2124.104083,2125.105417,2126.129792,2127.12375,2128.123542,2129.124708,2130.125417,2131.12175,2132.125292,2133.12425,2134.124125,2135.12325,2136.125292,2137.125667,2138.124542,2139.124583,2140.124417,2141.124083,2142.105208,2143.148,2144.119917,2145.122333,2146.127292,2147.128667,2148.125167,2149.125583,2150.127125,2151.127167,2152.132667,2153.131083,2154.129375,2155.126083,2156.128458,2157.1315,2158.124917,2159.131667,2160.126708,2161.134458,2162.125458,2163.128375,2164.114958,2165.134,2166.127,2167.076,2168.144083,2169.125042,2170.133125,2171.128208,2172.134125,2173.128667,2174.130125,2175.131708,2176.128,2177.133,2178.134542,2179.128667,2180.133167,2181.126375,2182.136875,2183.126667,2184.128292,2185.132042,2186.130375,2187.133208,2188.134292,2189.128792,2190.1315,2191.136042,2192.128875,2193.131625,2194.132208,2195.134042,2196.147583,2197.1275,2198.1325,2199.133083,2200.132875,2201.130375,2202.136875,2203.135292,2204.129583,2205.13375,2206.132333,2207.136292,2208.131375,2209.112958,2210.1555,2211.107375,2212.157458,2213.129292,2214.134542,2215.135292,2216.131417,2217.133917,2218.131792,2219.132083,2220.132792,2221.135792,2222.134708,2223.133458,2224.132917,2225.135625,2226.133417,2227.132958,2228.137,2229.134333,2230.136875,2231.13775,2232.134375,2233.135583,2234.1365,2235.137917,2236.136875,2237.134667,2238.135208,2239.141417,2240.123917,2241.125458,2242.12375,2243.132958,2244.143708,2245.141167,2246.139458,2247.140583,2248.140375,2249.148042,2250.1375,2251.1395,2252.121375,2253.149833,2254.115917,2255.167458,2256.108875,2257.151458,2258.14675,2259.143917,2260.143917,2261.144708,2262.141417,2263.151292,2264.143833,2265.14975,2266.143375,2267.152167,2268.142625,2269.162667,2270.11475,2271.160042,2272.145458,2273.122542,2274.155458,2275.156375,2276.136125,2277.09525,2278.1355,2279.120917,2280.144708,2281.150083,2282.151458,2283.145917,2284.153083,2285.14475,2286.154375,2287.151167,2288.143667,2289.146,2290.150083,2291.145708,2292.1485,2293.1435,2294.160625,2295.124792,2296.153833,2297.144583,2298.159333,2299.143625,2300.152708,2301.152625,2302.149042,2303.149208,2304.147542,2305.150083,2306.147542,2307.150625,2308.150417,2309.15325,2310.147625,2311.1545,2312.1475,2313.147125,2314.1545,2315.149542,2316.155458,2317.15,2318.149292,2319.153917,2320.149875,2321.150958,2322.151208,2323.147125,2324.152042,2325.155292,2326.148417,2327.155333,2328.155125,2329.153292,2330.155583,2331.148667,2332.156167,2333.152875,2334.152208,2335.159833,2336.153208,2337.153583,2338.15475,2339.154833,2340.154542,2341.155458,2342.151625,2343.159208,2344.15225,2345.158708,2346.158,2347.15775,2348.159292,2349.151833,2350.155833,2351.153542,2352.1575,2353.161958,2354.161208,2355.155417,2356.158833,2357.158375,2358.151458,2359.162708,2360.156417,2361.156083,2362.156708,2363.155833,2364.154958,2365.155,2366.145917,2367.160208,2368.145708,2369.145417,2370.158542,2371.155625,2372.139125,2373.142208,2374.163042,2375.153792,2376.154917,2377.160667,2378.159667,2379.155,2380.16425,2381.15825,2382.162667,2383.155417,2384.161792,2385.162042,2386.162958,2387.159375,2388.159333,2389.163292,2390.161875,2391.163417,2392.155708,2393.157833,2394.160792,2395.157375,2396.157542,2397.165792,2398.158167,2399.164667,2400.156417,2401.152417,2402.160083,2403.161917,2404.160792,2405.165875,2406.16275,2407.164,2408.160083,2409.160833,2410.143583,2411.169,2412.140208,2413.187708,2414.130792,2415.159042,2416.160458,2417.161042,2418.166333,2419.182958,2420.156125,2421.158792,2422.163958,2423.164042,2424.168958,2425.160875,2426.170458,2427.159875,2428.169083,2429.159667,2430.164292,2431.167458,2432.1645,2433.164292,2434.169625,2435.15975,2436.170833,2437.160417,2438.164958,2439.163208,2440.17025,2441.162333,2442.168917,2443.163625,2444.165375,2445.166917,2446.163042,2447.17075,2448.162542,2449.169583,2450.1635,2451.169125,2452.167542,2453.164167,2454.17325,2455.170917,2456.162542,2457.170542,2458.173625,2459.163583,2460.167333,2461.168583,2462.168083,2463.166208,2464.170125,2465.167375,2466.171917,2467.167417,2468.167042,2469.169208,2470.165833,2471.175042,2472.166083,2473.173333,2474.173708,2475.167167,2476.175958,2477.167875,2478.167917,2479.171,2480.165167,2481.174458,2482.167833,2483.14925,2484.177958,2485.164958,2486.173667,2487.169458,2488.173958,2489.167167,2490.17,2491.171958,2492.16825,2493.16925,2494.179583,2495.171083,2496.168458,2497.172625,2498.16925,2499.175667,2500.171292,2501.170708,2502.169417,2503.173,2504.173458,2505.168542,2506.176083,2507.170708,2508.176375,2509.167667,2510.172,2511.181583,2512.173792,2513.170583,2514.172333,2515.174833,2516.173083,2517.1695,2518.172208,2519.173125,2520.173417,2521.172292,2522.172792,2523.171458,2524.17775,2525.170542,2526.173625,2527.174833,2528.176083,2529.172958,2530.179625,2531.170833,2532.1785,2533.1695,2534.174125,2535.173542,2536.178917,2537.173333,2538.178042,2539.172958,2540.178542,2541.158833,2542.183,2543.154167,2544.179708,2545.176583,2546.176875,2547.158375,2548.186958,2549.170583,2550.176125,2551.173458,2552.182542,2553.179,2554.175375,2555.175833,2556.179958,2557.174542,2558.177958,2559.177042,2560.175958,2561.176208,2562.1775,2563.177667,2564.178167,2565.178958,2566.178708,2567.174667,2568.176167,2569.178583,2570.178333,2571.176708,2572.177833,2573.178417,2574.177792,2575.178208,2576.178208,2577.180125,2578.178042,2579.179542,2580.179417,2581.18525,2582.184292,2583.179458,2584.18475,2585.180083,2586.183125,2587.178792,2588.183917,2589.18775,2590.179875,2591.184125,2592.179333,2593.163708,2594.173875,2595.185125,2596.183667,2597.181167,2598.182167,2599.18675,2600.181917,2601.185,2602.189167,2603.184083,2604.187125,2605.181292,2606.187,2607.183958,2608.187,2609.182542,2610.166333,2611.165958,2612.167125,2613.18725,2614.161375,2615.184667,2616.196458,2617.183417,2618.191292,2619.187833,2620.162,2621.18275,2622.18375,2623.184125,2624.187625,2625.188625,2626.163667,2627.188917,2628.185375,2629.188417,2630.187833,2631.193208,2632.186292,2633.188083,2634.194125,2635.187292,2636.192875,2637.187583,2638.193667,2639.192542,2640.186792,2641.187917,2642.19075,2643.185417,2644.174958,2645.190417,2646.187208,2647.192833,2648.189333,2649.192917,2650.189583,2651.188833,2652.191542,2653.194375,2654.188417,2655.194583,2656.187625,2657.191167,2658.194208,2659.187792,2660.193083,2661.190958,2662.1915,2663.195375,2664.188208,2665.197417,2666.193625,2667.188417,2668.173458,2669.171333,2670.191708,2671.199708,2672.193125,2673.196,2674.19675,2675.18875,2676.192625,2677.191667,2678.19075,2679.1825,2680.191125,2681.170208,2682.196,2683.182917,2684.184792,2685.154417,2686.208125,2687.192167,2688.199667,2689.191917,2690.197958,2691.204167,2692.207917,2693.171333,2694.191667,2695.174958,2696.192292,2697.1945,2698.202917,2699.197125,2700.203458,2701.19075,2702.183792,2703.203333,2704.195667,2705.1945,2706.195417,2707.200417,2708.200375,2709.19725,2710.195042,2711.200125,2712.195167,2713.196667,2714.203875,2715.200458,2716.197625,2717.1985,2718.199125,2719.180875,2720.180042,2721.202792,2722.199875,2723.197042,2724.203667,2725.201375,2726.196875,2727.199833,2728.200417,2729.198958,2730.198292,2731.198125,2732.2005,2733.197833,2734.20225,2735.200417,2736.2005,2737.2045,2738.206667,2739.200333,2740.205208,2741.210417,2742.202625,2743.210792,2744.177125,2745.213917,2746.200167,2747.210583,2748.200083,2749.204167,2750.204458,2751.20425,2752.200833,2753.20525,2754.201417,2755.206667,2756.202792,2757.203708,2758.205083,2759.203583,2760.204917,2761.210708,2762.209083,2763.200042,2764.206292,2765.204917,2766.208542,2767.207958,2768.208875,2769.212208,2770.18325,2771.209,2772.205042,2773.203417,2774.211958,2775.203208,2776.210125,2777.201375,2778.210792,2779.208083,2780.210083,2781.204167,2782.205875,2783.210458,2784.211125,2785.204458,2786.20975,2787.203833,2788.21525,2789.209333,2790.210792,2791.206417,2792.210333,2793.203917,2794.2115,2795.207208,2796.216125,2797.205208,2798.214792,2799.211292,2800.21075,2801.212708,2802.212542,2803.207958,2804.209125,2805.209375,2806.213875,2807.208333,2808.210667,2809.214833,2810.21575,2811.207958,2812.215083,2813.20875,2814.214833,2815.215458,2816.212,2817.207208,2818.211375,2819.211375,2820.211667,2821.206083,2822.213542,2823.20875,2824.208958,2825.210042,2826.211083,2827.207958,2828.212792,2829.2165,2830.212417,2831.216083,2832.210375,2833.215292,2834.209833,2835.214542,2836.215708,2837.208625,2838.214542,2839.217833,2840.18925,2841.231292,2842.209958,2843.192625,2844.195333,2845.21825,2846.210583,2847.21725,2848.213,2849.215833,2850.215458,2851.213958,2852.215333,2853.217458,2854.218333,2855.2115,2856.212208,2857.208167,2858.193333,2859.2185,2860.212833,2861.216958,2862.21325,2863.215125,2864.221583,2865.217917,2866.21925,2867.214667,2868.222875,2869.21525,2870.214208,2871.218542,2872.213125,2873.218208,2874.222417,2875.215417,2876.218583,2877.218167,2878.219417,2879.212417,2880.2195,2881.217708,2882.219208,2883.217167,2884.21825,2885.219,2886.218708,2887.214708,2888.226792,2889.213208,2890.225375,2891.214917,2892.220708,2893.218125,2894.219583,2895.219792,2896.215917,2897.223208,2898.216417,2899.220042,2900.217208,2901.218417,2902.219833,2903.22125,2904.217708,2905.221417,2906.222792,2907.196833,2908.239375,2909.213208,2910.223208,2911.2145,2912.225917,2913.220042,2914.218083,2915.225625,2916.212625,2917.2225,2918.132625,2919.242292,2920.215917,2921.223875,2922.224875,2923.224958,2924.223167,2925.21725,2926.220375,2927.222083,2928.226958,2929.222958,2930.22525,2931.221042,2932.223458,2933.221,2934.228375,2935.228708,2936.222833,2937.229583,2938.2305,2939.224208,2940.231125,2941.222917,2942.223375,2943.230875,2944.222458,2945.228167,2946.226042,2947.231042,2948.22475,2949.226208,2950.229083,2951.223125,2952.232792,2953.223917,2954.231917,2955.224875,2956.232167,2957.225042,2958.227625,2959.2295,2960.231708,2961.22475,2962.229458,2963.229583,2964.225833,2965.225458,2966.229,2967.2285,2968.227958,2969.222292,2970.211,2971.226583,2972.2325,2973.223958,2974.233208,2975.236042,2976.226292,2977.229,2978.231417,2979.227625,2980.235292,2981.227875,2982.229375,2983.227833,2984.234083,2985.227542,2986.228792,2987.228167,2988.235208,2989.2315,2990.231083,2991.23575,2992.227667,2993.237167,2994.213458,2995.213583,2996.232708,2997.23325,2998.228833,2999.233542,3000.232125,3001.2335,3002.232458,3003.234958,3004.226,3005.23825,3006.226833,3007.236042,3008.228292,3009.233167,3010.237292,3011.234167,3012.236583,3013.233208,3014.227917,3015.237,3016.226417,3017.213042,3018.239667,3019.216458,3020.243042,3021.233833,3022.23775,3023.238,3024.237042,3025.239333,3026.233167,3027.238083,3028.239708,3029.237,3030.231417,3031.239333,3032.237,3033.234833,3034.238667,3035.234833,3036.234208,3037.238375,3038.2395,3039.239167,3040.235333,3041.234417,3042.234417,3043.240667,3044.220167,3045.24,3046.234917,3047.218708,3048.25525,3049.239917,3050.24875,3051.22875,3052.228875,3053.243333,3054.214542,3055.243292,3056.235375,3057.235333,3058.232208,3059.237833,3060.243375,3061.235208,3062.241167,3063.241417,3064.241125,3065.240667,3066.236375,3067.2375,3068.237833,3069.215042,3070.245792,3071.240292,3072.237208,3073.238833,3074.238792,3075.2375,3076.245792,3077.235417,3078.242792,3079.223,3080.222167,3081.24425,3082.240167,3083.241667,3084.246208,3085.24125,3086.243,3087.238792,3088.245417,3089.237875,3090.247083,3091.236625,3092.246292,3093.239125,3094.254,3095.242542,3096.240708,3097.247583,3098.244625,3099.244792,3100.241208,3101.243625,3102.241375,3103.245833,3104.238792,3105.244458,3106.241875,3107.247625,3108.247375,3109.247792,3110.241708,3111.241542,3112.24375,3113.244958,3114.247375,3115.244917,3116.249792,3117.244625,3118.242458,3119.251,3120.242958,3121.222,3122.228125,3123.225208,3124.243042,3125.22225,3126.256583,3127.224542,3128.249,3129.234625,3130.227958,3131.248542,3132.245667,3133.242917,3134.246125,3135.246125,3136.246875,3137.246292,3138.247333,3139.2465,3140.244792,3141.245042,3142.247167,3143.247083,3144.246958,3145.244125,3146.249083,3147.246542,3148.251792,3149.245417,3150.247542,3151.24425,3152.249208,3153.247083,3154.24925,3155.248375,3156.248542,3157.248583,3158.246917,3159.248583,3160.248125,3161.247708,3162.255375,3163.247625,3164.253083,3165.243458,3166.249917,3167.250333,3168.249875,3169.249792,3170.256042,3171.250125,3172.2545,3173.249625,3174.251042,3175.251292,3176.25,3177.25,3178.252208,3179.248583,3180.250708,3181.227917,3182.261083,3183.226833,3184.241083,3185.251917,3186.252333,3187.250458,3188.252792,3189.249292,3190.252625,3191.253917,3192.25125,3193.254,3194.252958,3195.249583,3196.232292,3197.257792,3198.227958,3199.237667,3200.241625,3201.23325,3202.240792,3203.25775,3204.233875,3205.259208,3206.2515,3207.2545,3208.256292,3209.257167,3210.252958,3211.256208,3212.257083,3213.255792,3214.253958,3215.259167,3216.236333,3217.265417,3218.254542,3219.257833,3220.264125,3221.241,3222.236583,3223.242667,3224.266125,3225.259333,3226.258208,3227.260208,3228.260875,3229.262208,3230.2495,3231.263875,3232.259667,3233.261958,3234.261958,3235.24625,3236.244083,3237.269125,3238.23425,3239.250917,3240.25625,3241.239542,3242.268083,3243.261792,3244.264958,3245.265292,3246.265875,3247.266458,3248.264875,3249.269417,3250.248958,3251.252667,3252.275375,3253.2665,3254.271125,3255.267125,3256.270542,3257.269542,3258.244417,3259.254333,3260.251917,3261.251458,3262.277,3263.246,3264.253667,3265.273083,3266.272417,3267.283042,3268.273583,3269.158,3270.292,3271.120042,3272.284667,3273.093458,3274.295458,3275.071208,3276.294708,3277.236042,3278.284333,3279.25225,3280.262875,3281.251917,3282.263875,3283.253458,3284.289917,3285.269208,3286.281208,3287.27675,3288.283917,3289.277458,3290.277542,3291.246417,3292.285708,3293.257167,3294.265333,3295.286333,3296.276625,3297.283583,3298.280333,3299.267042,3300.2845,3301.279792,3302.284708,3303.278292,3304.283167,3305.281292,3306.260625,3307.265375,3308.282083,3309.283542,3310.282208,3311.282375,3312.284542,3313.283542,3314.284708,3315.265083,3316.264667,3317.2685,3318.279458,3319.255,3320.276667,3321.294,3322.3,3323.282083,3324.268292,3325.287042,3326.287958,3327.266708,3328.295542,3329.266208,3330.285958,3331.288125,3332.289458,3333.287583,3334.292833,3335.27375,3336.273542,3337.269958,3338.26725,3339.282417,3340.277958,3341.271417,3342.2975,3343.292333,3344.269042,3345.281333,3346.182792,3347.323583,3348.263833,3349.296583,3350.285292,3351.280167,3352.305292,3353.295,3354.302208,3355.280833,3356.294458,3357.300583,3358.29225,3359.299125,3360.284958,3361.306583,3362.2955,3363.302167,3364.301792,3365.278375,3366.306375,3367.300125,3368.301333,3369.294,3370.316708,3371.309625,3372.297583,3373.298375,3374.28025,3375.30675,3376.301292,3377.304792,3378.304042,3379.302042,3380.301458,3381.303667,3382.3025,3383.304417,3384.298,3385.304542,3386.315917,3387.269042,3388.311375,3389.275042,3390.310875,3391.316792,3392.298958,3393.283667,3394.295333,3395.317917,3396.313125,3397.302208,3398.283417,3399.314375,3400.279417,3401.278042,3402.291375,3403.286,3404.298667,3405.285667,3406.295417,3407.292625,3408.290958,3409.290042,3410.287125,3411.251333,3412.300167,3413.303625,3414.2875,3415.310542,3416.309,3417.284167,3418.327125,3419.317708,3420.291,3421.286125,3422.316875,3423.323625,3424.312667,3425.312708,3426.308583,3427.296042,3428.320125,3429.312042,3430.311958,3431.310125,3432.299292,3433.317833,3434.306583,3435.319292,3436.289167,3437.2965,3438.321167,3439.305667,3440.305292,3441.293333,3442.301375,3443.288417,3444.304417,3445.161417,3446.33475,3447.315875,3448.1665,3449.325542,3450.299125,3451.302542,3452.296042,3453.305208,3454.226667,3455.321625,3456.2915,3457.303833,3458.290042,3459.306667,3460.295125,3461.30975,3462.302917,3463.307,3464.312083,3465.204,3466.339625,3467.292917,3468.303042,3469.326125,3470.298708,3471.1785,3472.286167,3473.307,3474.300375,3475.337417,3476.337792,3477.337375,3478.325333,3479.340125,3480.322083,3481.328375,3482.323333,3483.326875,3484.327458,3485.325542,3486.333833,3487.335,3488.328375,3489.328833,3490.33125,3491.328583,3492.33025,3493.329,3494.324042,3495.332333,3496.323833,3497.326542,3498.326167,3499.334542,3500.304833,3501.334125,3502.329958,3503.315167,3504.330125,3505.305958,3506.311542,3507.334958,3508.330208,3509.328833,3510.325583,3511.332542,3512.327792,3513.326542,3514.337,3515.329417,3516.327375,3517.337417,3518.308917,3519.340375,3520.330333,3521.330958,3522.304,3523.349625,3524.326917,3525.334875,3526.32925,3527.330333,3528.331667,3529.334042,3530.329917,3531.330667,3532.335958,3533.331958,3534.331917,3535.3345,3536.337875,3537.328208,3538.341667,3539.328958,3540.337375,3541.332875,3542.339625,3543.340708,3544.331417,3545.337458,3546.338458,3547.331167,3548.318958,3549.314042,3550.3145,3551.338458,3552.3355,3553.332042,3554.337125,3555.336458,3556.339167,3557.339167,3558.33725,3559.334417,3560.336417,3561.339875,3562.331375,3563.333542,3564.341542,3565.336125,3566.336833,3567.338042,3568.335583,3569.337,3570.33775,3571.313917,3572.346417,3573.311292,3574.341417,3575.337042,3576.333667,3577.33725,3578.338625,3579.345167,3580.341375,3581.334875,3582.339833,3583.341083,3584.343333,3585.343208,3586.344333,3587.3335,3588.346292,3589.335917,3590.343292,3591.336958,3592.339292,3593.343958,3594.338417,3595.341875,3596.344458,3597.344292,3598.340042,3599.341958,3600.343833,3601.339917,3602.3435,3603.339708,3604.346625,3605.342417,3606.3445,3607.341792,3608.344875,3609.336167,3610.344833,3611.34425,3612.343833,3613.337458,3614.349083,3615.345125,3616.341333,3617.338542,3618.347833,3619.324125,3620.323417,3621.350375,3622.343333,3623.343292,3624.34275,3625.343083,3626.322667,3627.322958,3628.34675,3629.345083,3630.345375,3631.345208,3632.348375,3633.341333,3634.344333,3635.348042,3636.343792,3637.34875,3638.346208,3639.347167,3640.347625,3641.34475,3642.352917,3643.340458,3644.3475,3645.347125,3646.352,3647.344208,3648.355667,3649.320042,3650.356542,3651.342458,3652.350833,3653.349042,3654.348583,3655.349,3656.347042,3657.348,3658.345625,3659.351208,3660.350042,3661.347667,3662.345917,3663.353292,3664.344917,3665.351542,3666.353208,3667.346667,3668.353083,3669.345917,3670.353167,3671.348292,3672.354917,3673.348958,3674.327375,3675.334292,3676.345417,3677.355167,3678.348,3679.357042,3680.347833,3681.350042,3682.324708,3683.354833,3684.34975,3685.350083,3686.356167,3687.352375,3688.351375,3689.355458,3690.34875,3691.355583,3692.355708,3693.355542,3694.348958,3695.358,3696.34675,3697.355417,3698.357292,3699.353333,3700.35825,3701.327333,3702.337,3703.361417,3704.355417,3705.354125,3706.357583,3707.354292,3708.351125,3709.332042,3710.36475,3711.330292,3712.376083,3713.342958,3714.336417,3715.337417,3716.366542,3717.352792,3718.351375,3719.355292,3720.35675,3721.358,3722.35625,3723.362083,3724.352167,3725.356083,3726.353083,3727.360292,3728.356375,3729.358042,3730.353042,3731.355375,3732.357125,3733.35375,3734.353875,3735.357625,3736.358542,3737.35575,3738.360208,3739.358125,3740.36075,3741.356125,3742.356042,3743.358833,3744.356,3745.355708,3746.356375,3747.358167,3748.36775,3749.355875,3750.368083,3751.34975,3752.336417,3753.36325,3754.341833,3755.345125,3756.361167,3757.363,3758.35775,3759.365333,3760.367708,3761.359333,3762.365708,3763.361417,3764.361875,3765.367583,3766.36525,3767.368042,3768.363417,3769.361167,3770.364167,3771.3615,3772.363792,3773.364083,3774.36525,3775.360292,3776.366667,3777.36325,3778.36475,3779.365125,3780.364875,3781.362167,3782.366083,3783.353792,3784.370083,3785.366917,3786.339792,3787.267292,3788.3385,3789.368167,3790.334292,3791.347375,3792.34725,3793.34175,3794.360417,3795.352542,3796.368375,3797.363375,3798.370458,3799.360958,3800.366542,3801.364625,3802.3665,3803.364292,3804.36425,3805.363458,3806.358208,3807.345583,3808.368125,3809.366167,3810.365333,3811.365417,3812.345792,3813.352417,3814.343208,3815.345917,3816.34825,3817.352333,3818.351208,3819.369583,3820.373542,3821.371625,3822.375208,3823.372333,3824.375625,3825.365667,3826.3745,3827.37025,3828.373417,3829.37325,3830.371667,3831.375583,3832.37475,3833.370583,3834.369917,3835.369917,3836.372708,3837.366375,3838.368792,3839.376792,3840.350875,3841.3535,3842.389792,3843.369792,3844.37725,3845.371125,3846.349583,3847.379792,3848.373,3849.376792,3850.375208,3851.37525,3852.373583,3853.375583,3854.370917,3855.374083,3856.372167,3857.380792,3858.37,3859.376792,3860.376417,3861.38125,3862.371792,3863.377458,3864.376792,3865.378708,3866.37675,3867.384208,3868.3745,3869.38025,3870.379,3871.38175,3872.374833,3873.382958,3874.376875,3875.376,3876.380042,3877.3765,3878.38175,3879.377875,3880.374958,3881.380792,3882.377708,3883.3815,3884.38125,3885.377958,3886.386917,3887.376792,3888.386333,3889.37875,3890.376417,3891.380417,3892.38225,3893.374417,3894.381417,3895.382583,3896.376917,3897.381917,3898.377292,3899.380292,3900.378792,3901.380375,3902.385042,3903.383125,3904.386375,3905.386875,3906.382708,3907.385958,3908.387208,3909.379875,3910.383708,3911.38075,3912.386083,3913.37825,3914.38575,3915.385667,3916.380958,3917.3825,3918.38025,3919.382875,3920.383875,3921.384125,3922.380667,3923.37325,3924.3835,3925.388375,3926.384792,3927.388667,3928.390208,3929.3895,3930.3825,3931.390542,3932.386292,3933.38575,3934.382708,3935.386292,3936.387083,3937.384,3938.385375,3939.3865,3940.386,3941.389792,3942.380667,3943.388833,3944.384875,3945.392042,3946.383625,3947.393583,3948.38275,3949.387958,3950.389417,3951.389583,3952.385083,3953.394583,3954.384875,3955.391958,3956.387125,3957.392042,3958.383833,3959.39375,3960.387083,3961.39375,3962.385958,3963.393042,3964.392708,3965.387708,3966.384958,3967.39525,3968.385292,3969.3895,3970.394833,3971.393708,3972.3895,3973.373792,3974.397083,3975.391833,3976.364125,3977.371167,3978.394458,3979.387667,3980.390083,3981.397958,3982.387833,3983.396167,3984.390542,3985.389958,3986.393417,3987.392958,3988.396917,3989.390583,3990.392042,3991.39375,3992.395708,3993.389958,3994.388042,3995.398708,3996.393208,3997.392292,3998.382208,3999.399292,4000.394,4001.392083,4002.392583,4003.394917,4004.398042,4005.394167,4006.39625,4007.3905,4008.397875,4009.3945,4010.397833,4011.3935,4012.396333,4013.391458,4014.393917,4015.395958,4016.400167,4017.389,4018.392583,4019.3925,4020.390958,4021.39775,4022.398083,4023.381458,4024.40125,4025.374042,4026.310917,4027.384125,4028.374375,4029.377708,4030.39975,4031.405,4032.396875,4033.397042,4034.395208,4035.401917,4036.401042,4037.395958,4038.4005,4039.394,4040.40325,4041.39425,4042.362458,4043.404458,4044.396542,4045.396292,4046.394625,4047.397542,4048.377417,4049.406333,4050.391333,4051.378375,4052.381208,4053.404,4054.396833,4055.40425,4056.403708,4057.397583,4058.4025,4059.398167,4060.400125,4061.406042,4062.394292,4063.405458,4064.396542,4065.40075,4066.399708,4067.398833,4068.401917,4069.401333,4070.400958,4071.399708,4072.400708,4073.380542,4074.411292,4075.40225,4076.404083,4077.401,4078.406875,4079.401875,4080.403333,4081.398917,4082.405083,4083.400792,4084.406542,4085.398583,4086.402625,4087.416583,4088.397625,4089.404083,4090.406542,4091.406292,4092.398042,4093.400583,4094.404708,4095.382292,4096.404917,4097.401667,4098.39725,4099.382958,4100.391417,4101.383417,4102.387458,4103.407333,4104.393208,4105.386292,4106.399375,4107.309417,4108.411667,4109.41325,4110.382,4111.410458,4112.35975,4113.364875,4114.417708,4115.372958,4116.400917,4117.411583,4118.380417,4119.406583,4120.405292,4121.403833,4122.386,4123.395875,4124.418542,4125.405583,4126.404292,4127.410333,4128.411083,4129.409542,4130.412875,4131.406,4132.412167,4133.405333,4134.406833,4135.405,4136.39175,4137.410667,4138.384333,4139.412083,4140.407375,4141.412083,4142.41075,4143.408625,4144.386083,4145.414333,4146.382333,4147.388667,4148.393792,4149.393458,4150.412333,4151.408375,4152.409542,4153.411667,4154.408667,4155.412667,4156.409708,4157.414,4158.408917,4159.413125,4160.409042,4161.413208,4162.416667,4163.418208,4164.416875,4165.416125,4166.410833,4167.407167,4168.41275,4169.418875,4170.415667,4171.4105,4172.42025,4173.413583,4174.416667,4175.417292,4176.410542,4177.423542,4178.41725,4179.421958,4180.410708,4181.418792,4182.414458,4183.421292,4184.418417,4185.414333,4186.418,4187.419417,4188.412208,4189.41975,4190.412583,4191.416083,4192.412917,4193.4195,4194.41825,4195.418125,4196.421292,4197.420417,4198.414083,4199.42325,4200.413875,4201.419042,4202.418417,4203.422333,4204.419042,4205.415333,4206.414625,4207.393542,4208.254917,4209.417208,4210.415667,4211.378125,4212.399708,4213.352667,4214.395708,4215.409333,4216.40675,4217.268208,4218.410667,4219.394917,4220.387292,4221.423417,4222.375542,4223.396708,4224.398875,4225.404042,4226.376833,4227.427375,4228.350458,4229.34925,4230.437458,4231.416083,4232.425417,4233.419417,4234.427458,4235.423042,4236.419917,4237.4225,4238.424708,4239.423,4240.425958,4241.429167,4242.42925,4243.424625,4244.428458,4245.43425,4246.417708,4247.42925,4248.420458,4249.4295,4250.419875,4251.424167,4252.422917,4253.420417,4254.424333,4255.424458,4256.425458,4257.422917,4258.423417,4259.428292,4260.42925,4261.429042,4262.423958,4263.427792,4264.423,4265.426875,4266.411333,4267.434583,4268.401375,4269.438417,4270.4215,4271.428125,4272.402542,4273.430917,4274.422917,4275.427667,4276.424583,4277.424833,4278.427042,4279.427,4280.427708,4281.425667,4282.42575,4283.427083,4284.425917,4285.433,4286.426625,4287.4315,4288.431208,4289.432625,4290.431667,4291.425083,4292.431875,4293.432333,4294.431333,4295.428583,4296.434208,4297.426333,4298.431042,4299.43325,4300.427958,4301.430458,4302.428458,4303.4305,4304.426833,4305.426292,4306.42825,4307.4275,4308.43075,4309.429625,4310.429333,4311.435167,4312.426458,4313.430208,4314.424792,4315.429667,4316.413917,4317.40225,4318.424833,4319.420417,4320.433333,4321.430542,4322.425125,4323.403542,4324.37725,4325.44175,4326.429917,4327.437458,4328.404583,4329.433375,4330.433708,4331.436333,4332.435667,4333.427375,4334.4365,4335.41725,4336.445,4337.43425,4338.436708,4339.432792,4340.437708,4341.435375,4342.433375,4343.410292,4344.446625,4345.432542,4346.433,4347.436833,4348.4335,4349.439917,4350.433167,4351.437958,4352.431542,4353.436208,4354.432583,4355.441083,4356.43675,4357.436375,4358.434583,4359.435,4360.434708,4361.438417,4362.43725,4363.4335,4364.436125,4365.436667,4366.434417,4367.439208,4368.416,4369.42825,4370.43525,4371.414292,4372.441167,4373.438792,4374.435958,4375.437,4376.435833,4377.455292,4378.409417,4379.444,4380.43625,4381.436792,4382.437958,4383.4395,4384.437667,4385.43925,4386.440333,4387.438958,4388.4405,4389.437375,4390.439375,4391.439417,4392.437667,4393.441458,4394.439875,4395.441667,4396.438292,4397.441125,4398.438875,4399.440958,4400.439875,4401.440125,4402.443083,4403.441,4404.447583,4405.438875,4406.417292,4407.458083,4408.43525,4409.42,4410.428083,4411.421208,4412.444792,4413.441333,4414.441,4415.446708,4416.439958,4417.446542,4418.440208,4419.443875,4420.442833,4421.443458,4422.442708,4423.447625,4424.442583,4425.445,4426.449083,4427.441625,4428.448,4429.44125,4430.444167,4431.446292,4432.4495,4433.446458,4434.442625,4435.443333,4436.449625,4437.442042,4438.446042,4439.44875,4440.450708,4441.443542,4442.44975,4443.449875,4444.448708,4445.441042,4446.447125,4447.44975,4448.270083,4449.493083,4450.432708,4451.448083,4452.449333,4453.446667,4454.777125,4456.045083,4456.956042,4457.994917,4458.990875,4459.974958,4460.9695,4462.000167,4462.976458,4463.996417,4464.918958,4466.013917,4466.985,4467.97,4468.999708,4469.997167,4470.997958,4471.994083,4473.0,4473.998708,4474.998917,4475.991542,4476.996583,4477.996917,4478.994875,4479.994833,4480.970583,4482.006292,4482.990958,4484.004167,4484.993583,4485.996917,4487.0,4487.998917,4488.996542,4489.997208,4491.001667,4491.999833,4492.997375,4493.9965,4494.999208,4495.9965,4496.996875,4497.995083,4499.0065,4499.994,4500.999083,4501.998417,4503.001125,4503.997375,4504.997792,4505.996708,4507.002667,4508.002667,4508.994042,4509.999458,4510.999042,4511.999833,4512.99525,4513.999792,4514.999625,4515.999708,4516.998167,4517.999375,4519.000083,4519.999708,4520.9955,4522.001792,4522.998875,4524.0015,4525.000667,4526.001875,4527.008708,4527.999792,4529.0035,4530.005042,4531.001583,4532.005833,4532.99625,4534.007625,4535.005542,4535.999875,4537.0045,4538.005125,4539.001458,4540.002583,4541.00575,4542.009,4543.005583,4544.007875,4545.00725,4546.007417,4546.999542,4548.009917,4549.000875,4550.003833,4550.999958,4552.008375,4553.001375,4554.003583,4555.005417,4556.002,4557.008292,4558.006792,4559.008917,4560.008875,4561.00925,4562.005792,4563.004208,4564.009958,4565.002792,4566.008958,4567.019792,4567.977708,4569.023583,4569.999167,4571.007667,4572.000125,4573.004042,4574.011417,4575.006458,4576.002917,4577.003583,4578.010042,4579.009125,4580.002833,4581.009292,4582.00775,4583.00425,4584.00625,4585.008625,4586.006583,4587.006167,4588.004125,4589.008875,4590.006458,4590.984708,4591.844333,4593.092583,4594.044792,4595.062625,4596.053208,4597.033208,4598.060083,4599.04375,4600.063042,4601.052875,4602.058833,4603.040167,4604.068458,4605.060125,4606.062917,4607.06425,4608.058167,4609.060042,4610.065375,4611.060542,4612.060708,4613.059167,4614.061292,4615.047708,4616.042583,4617.065333,4618.061417,4619.060792,4620.045542,4621.043583,4622.043625,4623.063958,4624.043542,4625.068917,4626.067542,4627.062375,4628.061708,4629.063417,4630.06275,4631.062875,4632.06425,4633.065667,4634.060875,4635.063083,4636.064292,4637.065458,4638.064375,4639.065583,4640.041417,4641.0715,4642.063458,4643.06525,4644.065583,4645.07075,4646.06675,4647.069125,4648.066125,4649.068625,4650.066333,4651.062958,4652.071708,4653.049417,4654.056375,4655.067792,4656.059333,4657.085917,4658.071792,4658.892625,4660.069833,4661.044208,4662.055708,4663.047542,4664.050667,4665.087333,4666.076458,4667.044292,4668.056917,4669.050125,4670.042125,4671.068833,4672.021417,4673.034167,4674.06,4675.044208,4676.078458,4677.046792,4678.080917,4679.002875,4680.070375,4681.071292,4682.077208,4683.069875,4684.081708,4685.0625,4686.075375,4687.077458,4688.074083,4689.073333,4690.085625,4691.073375,4692.085958,4693.074042,4694.078333,4695.07675,4696.081875,4697.075958,4698.0805,4699.088875,4700.0855,4701.055,4702.078125,4703.083292,4704.071833,4705.079583,4706.050208,4707.082917,4708.073958,4709.078375,4710.082,4711.076833,4712.077167,4713.074042,4714.08725,4715.0885,4716.082583,4717.0815,4718.078708,4719.08075,4720.076417,4721.083875,4722.076083,4723.076542,4724.082042,4725.082083,4726.077958,4727.086208,4728.08325,4729.078583,4730.083792,4731.077167,4732.086042,4733.079208,4734.083708,4735.080792,4736.080583,4737.081667,4738.078958,4739.08725,4740.089917,4741.084042,4742.079,4743.087417,4744.08175,4745.085667,4746.079833,4747.059792,4748.063917,4749.0835,4750.065583,4751.070917,4752.059375,4753.103458,4754.078792,4755.080708,4756.057083,4756.932667,4758.093917,4759.079542,4759.919625,4761.080333,4761.942708,4762.989167,4764.086542,4765.090375,4766.085917,4767.084458,4768.091417,4769.082583,4770.088083,4771.081708,4772.086625,4773.084458,4774.065833,4775.070333,4776.08925,4777.08525,4778.087292,4779.083375,4780.091875,4781.082875,4782.093333,4783.0855,4784.089625,4785.084958,4786.087375,4787.087125,4788.108917,4789.087292,4790.087833,4791.09375,4792.084542,4793.086125,4794.092458,4795.086792,4796.089083,4797.098,4798.093125,4799.091125,4800.085792,4801.089667,4802.091417,4803.092458,4804.086875,4805.089583,4806.088667,4807.095625,4808.088208,4809.089917,4810.092,4811.088458,4812.093625,4813.087125,4814.0875,4815.09125,4816.093958,4817.095,4818.069792,4819.111333,4820.085667,4821.07225,4822.092542,4823.0975,4824.088875,4825.092625,4826.088667,4827.095417,4828.095125,4829.089833,4830.091292,4831.094583,4832.096042,4833.090667,4834.097375,4835.087458,4836.095167,4837.0925,4838.094667,4839.089875,4840.090958,4841.0905,4842.092042,4843.092208,4844.09475,4845.091292,4846.095417,4847.093667,4848.094375,4849.09775,4850.093458,4851.095167,4852.098917,4853.098833,4854.090375,4855.09575,4856.0935,4857.076875,4858.048,4859.020958,4860.083208,4860.978208,4862.058667,4863.094542,4863.911042,4865.126042,4866.056583,4867.088167,4868.086792,4869.062,4870.106792,4871.098167,4872.097583,4873.078708,4874.116333,4875.09575,4876.083375,4877.100917,4878.094125,4879.105292,4880.042083,4881.112458,4882.099583,4883.100167,4884.099375,4885.101042,4886.098292,4887.105458,4888.092708,4889.105292,4890.097708,4891.10175,4892.099583,4893.101833,4894.097958,4895.106292,4896.101667,4897.099708,4898.10575,4899.101083,4900.100375,4901.102917,4902.101625,4903.100708,4904.103292,4905.098,4906.106042,4907.099417,4908.106583,4909.101833,4910.101125,4911.110375,4912.099583,4913.108417,4914.10225,4915.102833,4916.103333,4917.106,4918.099583,4919.109,4920.1035,4921.102958,4922.104042,4923.105375,4924.108417,4925.105417,4926.099417,4927.110625,4928.107375,4929.1005,4930.109042,4931.102292,4932.110208,4933.100708,4934.104833,4935.106667,4936.107708,4937.107042,4938.112417,4939.102042,4940.1065,4941.108375,4942.111042,4943.107833,4944.104958,4945.111,4946.110625,4947.093792,4948.110167,4949.08525,4950.107958,4951.088083,4952.111625,4953.106,4954.114542,4955.105958,4956.10875,4957.006167,4958.111542,4959.1045,4960.092708,4961.082542,4962.094667,4963.081958,4964.09325,4965.106292,4966.106125,4967.111583,4968.089917,4969.102375,4970.060833,4971.083458,4972.120042,4973.104917,4974.112667,4975.120208,4976.08125,4977.094167,4978.082292,4979.119708,4980.108583,4981.117042,4982.112042,4983.108,4984.1115,4985.114792,4986.150125,4987.10425,4988.116292,4989.113792,4990.109458,4991.114125,4992.114167,4993.110167,4994.112917,4995.115042,4996.108167,4997.11875,4998.101958,4999.121833,5000.107792,5001.112625,5002.116083,5003.142208,5004.110958,5005.114417,5006.085333,5007.121542,5008.113208,5009.122417,5010.120042,5011.112792,5012.1155,5013.118667,5014.118292,5015.117583,5016.111167,5017.117667,5018.091,5019.099417,5020.122833,5021.111875,5022.097,5023.119292,5024.13025,5025.1115,5026.11475,5027.11625,5028.115917,5029.115667,5030.1155,5031.11725,5032.117417,5033.11775,5034.115125,5035.118125,5036.101833,5037.103917,5037.944292,5039.123083,5040.108292,5041.090708,5042.078917,5043.103,5044.120917,5045.122042,5046.116083,5047.118292,5048.119208,5049.124542,5050.11475,5051.097917,5052.106708,5053.130833,5054.1165,5055.128083,5056.118875,5057.121042,5058.117417,5059.121375,5060.121375,5061.123125,5062.119042,5063.122,5064.120083,5065.118917,5066.120458,5067.122708,5068.122458,5069.123792,5070.120417,5071.122958,5072.122542,5073.123917,5074.12275,5075.121667,5076.12075,5077.121167,5078.119417,5079.1235,5080.121625,5081.122042,5082.100042,5083.143708,5084.118042,5085.118,5086.123208,5087.125208,5088.123625,5089.123417,5090.122042,5091.124292,5092.129042,5093.1245,5094.124833,5095.128125,5096.123583,5097.134208,5098.097,5098.96375,5100.163125,5101.104458,5101.969292,5103.213292,5104.1575,5105.177042,5106.162042,5107.045708,5108.173417,5109.172833,5110.101458,5111.194083,5112.172875,5113.171917,5114.181208,5115.160917,5116.170875,5117.178125,5118.202583,5119.2015,5120.17225,5121.195792,5122.194042,5123.197875,5124.194583,5125.197083,5126.190167,5127.190958,5128.19575,5129.188667,5130.200083,5131.191458,5132.198958,5133.192208,5134.198792,5135.195292,5136.196917,5137.173625,5138.213292,5139.191333,5140.19525,5141.190958,5142.171958,5143.182667,5144.203875,5145.190292,5146.195708,5147.193792,5148.194125,5149.198,5150.194375,5151.201333,5152.193542,5153.198042,5154.19525,5155.201208,5156.199208,5157.214958,5158.166917,5159.207375,5160.196833,5161.199208,5162.195083,5163.197708,5164.198625,5165.197167,5166.176542,5167.202417,5168.195667,5169.1985,5170.1955,5171.200417,5172.197167,5173.199042,5174.197375,5175.198875,5176.198917,5177.198875,5178.197667,5179.198292,5180.202333,5181.199083,5182.199333,5183.179167,5184.183333,5185.182,5186.186792,5187.204792,5188.203292,5189.2005,5190.200583,5191.207583,5192.199333,5193.198292,5194.202542,5195.202417,5196.154958,5197.206875,5198.180125,5199.191667,5200.206333,5201.189292,5202.207125,5203.195458,5204.183333,5205.095625,5206.208542,5207.175458,5208.202292,5209.179125,5210.201,5211.202167,5212.20275,5213.203458,5214.203333,5215.198875,5216.204375,5217.204125,5218.200958,5219.206875,5220.202292,5221.201875,5222.205,5223.205917,5224.20725,5225.204917,5226.203958,5227.206083,5228.203708,5229.203833,5230.206083,5231.204792,5232.206,5233.208667,5234.207167,5235.207,5236.213583,5237.203792,5238.209333,5239.209958,5240.206708,5241.215292,5242.213125,5243.205125,5244.207958,5245.210958,5246.198333,5247.195833,5248.14125,5249.198417,5250.20525,5251.176917,5252.193292,5253.1895,5254.212917,5255.205542,5256.210125,5257.207125,5258.212208,5259.215,5260.215917,5261.216083,5262.208458,5263.211042,5264.211667,5265.2105,5266.216417,5267.200375,5268.212958,5269.208583,5270.210625,5271.192583,5272.205375,5273.215667,5274.201792,5275.2145,5276.213292,5277.210167,5278.211125,5279.212667,5280.210333,5281.210667,5282.211875,5283.212583,5284.213458,5285.212833,5286.218875,5287.209833,5288.212667,5289.21,5290.213167,5291.215167,5292.218125,5293.2125,5294.214792,5295.214167,5296.21425,5297.217042,5298.211292,5299.173917,5300.224542,5301.209792,5302.212833,5303.219958,5304.215417,5305.219833,5306.216792,5307.217958,5308.215875,5309.215167,5310.211833,5311.220375,5312.212958,5313.178875,5314.225458,5315.212542,5316.215667,5317.218417,5318.21875,5319.217375,5320.2155,5321.221167,5322.217042,5323.216667,5324.224083,5325.218917,5326.219833,5327.223583,5328.220292,5329.216292,5330.224583,5331.217208,5332.222333,5333.217167,5334.2185,5335.222542,5336.21725,5337.220833,5338.198417,5339.221375,5340.217458,5341.070625,5342.254083,5343.173667,5344.169708,5345.1685,5346.214125,5347.192125,5348.111333,5349.228458,5350.091083,5351.124583,5352.209,5353.055208,5354.264,5355.181125,5356.227917,5357.222125,5358.219875,5359.222125,5360.220833,5361.22375,5362.220042,5363.222292,5364.220417,5365.22125,5366.220542,5367.222792,5368.193,5369.213,5370.210292,5371.219583,5372.200792,5373.218125,5374.228458,5375.221833,5376.220375,5377.226292,5378.222375,5379.222917,5380.225583,5381.220333,5382.229625,5383.22075,5384.224583,5385.226083,5386.229875,5387.225208,5388.228708,5389.225792,5390.231708,5391.2235,5392.229208,5393.2275,5394.225125,5395.222208,5396.224542,5397.226208,5398.222667,5399.228292,5400.223583,5401.233042,5402.223583,5403.227083,5404.226,5405.226375,5406.229333,5407.228833,5408.229208,5409.225375,5410.233542,5411.232083,5412.228333,5413.224667,5414.203708,5415.233125,5416.22925,5417.224875,5418.228042,5419.200875,5420.200125,5421.235917,5422.052125,5423.256125,5424.202833,5425.211667,5426.21325,5427.062708,5428.242917,5429.219042,5430.229958,5431.229458,5432.230583,5433.229917,5434.230333,5435.228,5436.231708,5437.226083,5438.227042,5439.231708,5440.230708,5441.228875,5442.232,5443.228167,5444.230958,5445.215958,5446.232625,5447.207458,5448.214167,5449.224792,5450.23325,5451.228292,5452.233667,5453.229625,5454.2385,5455.232125,5456.232667,5457.233292,5458.212958,5459.211542,5460.241458,5461.09425,5462.248167,5463.202083,5464.245542,5465.220708,5466.223292,5467.253667,5468.207958,5469.242292,5470.251708,5471.213125,5472.257792,5473.203625,5474.229333,5475.221375,5476.272042,5477.201583,5478.260458,5479.205667,5480.227542,5481.265583,5482.203167,5483.223875,5484.22125,5485.212875,5486.241833,5487.240208,5488.215208,5489.216583,5490.245667,5491.235125,5492.244917,5493.239042,5494.243833,5495.242208,5496.243708,5497.241667,5498.245333,5499.243083,5500.242583,5501.238042,5502.24525,5503.220458,5504.245667,5505.239875,5506.235167,5507.227333,5508.255667,5509.216542,5510.248708,5511.246667,5512.252417,5513.214375,5514.258042,5515.234083,5516.231292,5517.256,5518.249417,5519.248042,5520.232208,5521.262125,5522.22925,5523.234958,5524.16475,5525.262958,5526.119792,5527.280917,5528.226208,5529.260708,5530.237417,5531.252042,5532.230583,5533.220083,5534.166583,5535.229917,5536.257542,5537.253083,5538.256958,5539.259167,5540.250625,5541.25275,5542.259625,5543.259417,5544.2665,5545.254667,5546.258208,5547.253708,5548.261875,5549.257625,5550.235583,5551.259333,5552.251167,5553.257833,5554.253333,5555.2545,5556.257,5557.256292,5558.25625,5559.25975,5560.262375,5561.259083,5562.232958,5563.261,5564.257458,5565.266458,5566.23525,5567.268125,5568.25525,5569.242625,5570.264708,5571.258292,5572.26,5573.25775,5574.265958,5575.256167,5576.263458,5577.259417,5578.26575,5579.25775,5580.265667,5581.26375,5582.266125,5583.25275,5584.2665,5585.237458,5586.246292,5587.245833,5588.26775,5589.269,5590.265667,5591.272708,5592.262667,5593.259542,5594.264208,5595.2635,5596.261375,5597.266208,5598.260875,5599.2625,5600.252042,5601.241708,5602.127417,5603.365833,5604.318792,5605.308708,5606.347667,5607.559917,5608.37425,5609.585542,5610.540542,5611.515292,5612.457292,5613.568,5614.537625,5615.5685,5616.567375,5617.560667,5618.570708,5619.564375,5620.568667,5621.561667,5622.565375,5623.564542,5624.574458,5625.562917,5626.567458,5627.5505,5628.566042,5629.547375,5630.582833,5631.568333,5632.543458,5633.552417,5634.549417,5635.547292,5636.573875,5637.566875,5638.568,5639.566125,5640.5675,5641.566333,5642.56425,5643.567083,5644.567417,5645.570708,5646.573167,5647.573208,5648.576833,5649.562292,5650.568333,5651.565667,5652.549875,5653.549583,5654.572458,5655.572292,5656.56475,5657.572792,5658.571583,5659.566333,5660.570708,5661.569042,5662.569125,5663.568542,5664.569417,5665.573,5666.573375,5667.548375,5668.554458,5669.573833,5670.568375,5671.570333,5672.5715,5673.572917,5674.576792,5675.571167,5676.577333,5677.567542,5678.57675,5679.579458,5680.570417,5681.575417,5682.571125,5683.57125,5684.579167,5685.573917,5686.576042,5687.568625,5688.575917,5689.577417,5690.577875,5691.569958,5692.576,5693.570625,5694.581583,5695.575458,5696.57425,5697.578792,5698.585125,5699.562125,5700.562875,5701.558958,5702.559417,5703.562875,5704.580167,5705.567667,5706.578917,5707.578125,5708.578292,5709.580375,5710.57425,5711.3895,5712.615625,5713.533042,5714.568875,5715.548292,5716.563417,5717.466625,5718.586458,5719.56875,5720.547958,5721.591125,5722.574583,5723.58725,5724.577,5725.581292,5726.58825,5727.585167,5728.579333,5729.586333,5730.582958,5731.582667,5732.591708,5733.578833,5734.584292,5735.5835,5736.57625,5737.576333,5738.586583,5739.583917,5740.587833,5741.578792,5742.586083,5743.584042,5744.591667,5745.582292,5746.584167,5747.588042,5748.589958,5749.583125,5750.583625,5751.584167,5752.588,5753.582875,5754.584875,5755.584333,5756.58275,5757.592708,5758.582125,5759.590875,5760.582917,5761.588958,5762.588917,5763.5815,5764.568958,5765.591083,5766.585833,5767.586333,5768.586875,5769.58825,5770.592708,5771.585125,5772.593708,5773.590625,5774.591,5775.589458,5776.587083,5777.5935,5778.593,5779.5825,5780.594167,5781.5835,5782.563792,5783.592083,5784.59225,5785.59375,5786.592875,5787.587208,5788.5975,5789.591917,5790.58825,5791.592125,5792.5875,5793.596542,5794.593333,5795.584458,5796.59775,5797.584833,5798.591208,5799.58925,5800.595333,5801.593625,5802.59375,5803.587208,5804.597292,5805.586,5806.598708,5807.595875,5808.597083,5809.589292,5810.5985,5811.592375,5812.598208,5813.586875,5814.591042,5815.590542,5816.591083,5817.531917,5818.564542,5819.563375,5820.535625,5821.578375,5822.571333,5823.57225,5824.576458,5825.468083,5826.5835,5827.586083,5828.548125,5829.61225,5830.593583,5831.602042,5832.597917,5833.598958,5834.593208,5835.598542,5836.598458,5837.600417,5838.598417,5839.592833,5840.597083,5841.599167,5842.59275,5843.595625,5844.599583,5845.603208,5846.593292,5847.593833,5848.5955,5849.594708,5850.596958,5851.597708,5852.603792,5853.594708,5854.596458,5855.60025,5856.599042,5857.601458,5858.592708,5859.59825,5860.599708,5861.598375,5862.593542,5863.599625,5864.594917,5865.597042,5866.602,5867.597458,5868.600417,5869.598542,5870.596417,5871.599583,5872.597333,5873.59975,5874.597958,5875.599083,5876.601583,5877.592542,5878.599625,5879.600667,5880.596542,5881.598625,5882.599625,5883.600167,5884.599833,5885.597125,5886.602333,5887.576167,5888.609167,5889.598,5890.601083,5891.595792,5892.59975,5893.599875,5894.602125,5895.60575,5896.597583,5897.60325,5898.601125,5899.6,5900.600125,5901.606333,5902.604708,5903.599583,5904.578833,5905.607125,5906.601958,5907.612125,5908.598417,5909.602583,5910.602458,5911.611875,5912.600667,5913.609542,5914.600833,5915.591958,5916.612958,5917.600042,5918.6075,5919.605833,5920.606083,5921.610125,5922.608542,5923.610333,5924.613208,5925.606,5926.582125,5927.478583,5928.69875,5929.643542,5930.686917,5931.673958,5932.648792,5933.674667,5934.669458,5935.612,5936.686375,5937.5445,5938.715833,5939.641083,5940.688917,5941.668292,5942.681833,5943.67325,5944.706792,5945.701417,5946.691167,5947.695,5948.701917,5949.696375,5950.6955,5951.690208,5952.6965,5953.713125,5954.69275,5955.696125,5956.714,5957.690042,5958.692917,5959.70225,5960.698333,5961.701542,5962.696917,5963.703208,5964.702958,5965.698917,5966.697375,5967.697542,5968.695542,5969.704167,5970.69875,5971.696875,5972.703458,5973.701708,5974.700792,5975.694,5976.703542,5977.704667,5978.7045,5979.696833,5980.705083,5981.707,5982.702667,5983.702458,5984.705292,5985.682542,5986.70725,5987.701917,5988.701667,5989.698167,5990.702375,5991.695917,5992.702708,5993.705708,5994.706208,5995.70475,5996.704625,5997.702625,5998.701708,5999.698583,6000.700917,6001.70025,6002.704667,6003.702958,6004.666167,6005.706833,6006.630042,6007.646375,6008.658208,6009.638333,6010.581917,6011.606333,6012.69625,6013.676417,6014.701292,6015.7055,6016.709125,6017.710667,6018.703542,6019.706167,6020.705917,6021.708125,6022.705875,6023.707375,6024.704125,6025.710333,6026.7105,6027.705083,6028.705333,6029.705208,6030.708875,6031.713125,6032.687792,6033.712792,6034.708958,6035.704542,6036.712958,6037.709458,6038.708083,6039.705958,6040.717875,6041.704542,6042.7155,6043.70325,6044.715167,6045.705833,6046.711875,6047.710417,6048.710083,6049.715583,6050.712542,6051.712458,6052.711375,6053.71,6054.718083,6055.70675,6056.709458,6057.715708,6058.7115,6059.709542,6060.711792,6061.710167,6062.713292,6063.716542,6064.710667,6065.710417,6066.716458,6067.712833,6068.711583,6069.714167,6070.711708,6071.710875,6072.7185,6073.71425,6074.717458,6075.712917,6076.714917,6077.715292,6078.7145,6079.716292,6080.717917,6081.707583,6082.710667,6083.711458,6084.713625,6085.710708,6086.715625,6087.712042,6088.719333,6089.716833,6090.709792,6091.716083,6092.7185,6093.712875,6094.716,6095.7165,6096.715875,6097.717042,6098.718333,6099.720167,6100.718,6101.716833,6102.713833,6103.717917,6104.715333,6105.716208,6106.551292,6107.756,6108.704333,6110.192708,6111.44525,6112.376083,6113.421667,6114.408,6115.412875,6116.408167,6117.414042,6118.412958,6119.403042,6120.412,6121.410833,6122.41375,6123.428625,6124.371458,6125.421667,6126.405125,6127.415792,6128.410292,6129.415542,6130.405917,6131.416292,6132.415583,6133.411667,6134.406708,6135.411458,6136.415667,6137.406167,6138.412375,6139.408083,6140.409333,6141.410333,6142.411917,6143.410625,6144.412292,6145.411792,6146.414,6147.417625,6148.41925,6149.389375,6150.426792,6151.40325,6152.430792,6153.409625,6154.412083,6155.410792,6156.41025,6157.415083,6158.409208,6159.413667,6160.412708,6161.414958,6162.4105,6163.416083,6164.418542,6165.415917,6166.411958,6167.415125,6168.414042,6169.412625,6170.417,6171.412917,6172.412333,6173.417208,6174.412333,6175.420875,6176.409792,6177.417167,6178.414667,6179.420208,6180.422167,6181.411042,6182.420833,6183.413875,6184.415,6185.417,6186.41275,6187.423167,6188.415083,6189.4175,6190.418375,6191.421208,6192.413958,6193.421708,6194.416833,6195.423375,6196.418458,6197.415208,6198.417583,6199.418792,6200.416625,6201.424708,6202.413042,6203.281833,6205.425792,6206.675292,6207.560833,6208.631292,6209.531667,6210.639458,6211.855417,6212.820917,6213.835833,6215.05975,6216.298792,6217.250542,6218.158708,6219.260292,6220.286958,6221.255833,6222.2795,6223.25025,6224.285042,6225.2735,6226.275792,6227.272708,6228.279625,6229.275,6230.277167,6231.27925,6232.284542,6233.274458,6234.281833,6235.273958,6236.2795,6237.286583,6238.279875,6239.27925,6240.280583,6241.275708,6242.282708,6243.27475,6244.278708,6245.280417,6246.282333,6247.27475,6248.276083,6249.281083,6250.282208,6251.275375,6252.283333,6253.27875,6254.27775,6255.284542,6256.276833,6257.281292,6258.277167,6259.280875,6260.279792,6261.280833,6262.278542,6263.282,6264.278875,6265.283625,6266.275542,6267.279875,6268.28275,6269.280458,6270.2855,6271.282542,6272.285875,6273.2805,6274.280083,6275.280833,6276.280917,6277.280833,6278.280292,6279.284917,6280.281417,6281.28475,6282.28175,6283.281333,6284.284583,6285.2805,6286.28025,6287.283792,6288.27975,6289.279833,6290.2805,6291.281458,6292.280208,6293.282375,6294.282917,6295.283042,6296.279667,6297.283708,6298.284208,6299.283458,6300.283208,6301.279208,6302.285208,6303.283333,6304.286708,6305.283667,6306.274208,6307.281542,6308.256125,6309.261375,6310.203792,6311.309042,6312.251833,6313.25375,6314.268,6315.272708,6316.283125,6317.268167,6318.103042,6319.11525,6320.267917,6321.254667,6322.158167,6323.102083,6324.305875,6325.256792,6326.273542,6327.258167,6328.295042,6329.294667,6330.2905,6331.288375,6332.292958,6333.291708,6334.291042,6335.292042,6336.292875,6337.292875,6338.2925,6339.292792,6340.292083,6341.293667,6342.293958,6343.294875,6344.297792,6345.294542,6346.299875,6347.295125,6348.27475,6349.305792,6350.297083,6351.293583,6352.297,6353.302792,6354.295042,6355.295458,6356.297625,6357.296917,6358.297,6359.29975,6360.294333,6361.30075,6362.297083,6363.29475,6364.295625,6365.295875,6366.29775,6367.297208,6368.299083,6369.284917,6370.274125,6371.281917,6372.311375,6373.27525,6374.30625,6375.301792,6376.304375,6377.296625,6378.306708,6379.295708,6380.307167,6381.302333,6382.300708,6383.306625,6384.299042,6385.299875,6386.304583,6387.305208,6388.298167,6389.306875,6390.278125,6391.304875,6392.299417,6393.302667,6394.302167,6395.304875,6396.298417,6397.306417,6398.302375,6399.304875,6400.299292,6401.301,6402.305417,6403.301,6404.309,6405.300083,6406.302667,6407.306667,6408.299,6409.303917,6410.310208,6411.308,6412.308708,6413.3005,6414.303375,6415.308958,6416.303083,6417.284125,6418.283792,6419.277792,6420.284167,6421.311125,6422.312667,6423.2785,6424.107958,6425.191792,6426.314333,6427.347167,6428.419792,6429.401375,6430.411375,6431.30425,6432.387667,6433.360125,6434.392208,6435.421292,6436.413292,6437.395917,6438.41275,6439.406917,6440.420417,6441.409,6442.414833,6443.403625,6444.413375,6445.4075,6446.411167,6447.410208,6448.41025,6449.415042,6450.413167,6451.405917,6452.417167,6453.413583,6454.413375,6455.414917,6456.412083,6457.4095,6458.418833,6459.405708,6460.417125,6461.415458,6462.412917,6463.411,6464.4125,6465.411875,6466.410042,6467.411167,6468.41475,6469.4105,6470.412083,6471.411292,6472.4115,6473.408375,6474.414333,6475.410417,6476.412667,6477.411542,6478.415667,6479.412667,6480.411083,6481.412292,6482.4125,6483.41525,6484.413917,6485.41375,6486.41425,6487.414708,6488.413125,6489.431417,6490.368667,6491.408792,6492.391042,6493.41425,6494.401375,6495.402583,6496.394542,6497.41075,6498.421,6499.418292,6500.420292,6501.417875,6502.391542,6503.420583,6504.39175,6505.235417,6506.440208,6507.407625,6508.420875,6509.416833,6510.433458,6511.41225,6512.32425,6513.425875,6514.391625,6515.391417,6516.394042,6517.43975,6518.34725,6519.404917,6520.397,6521.395125,6522.278125,6523.421833,6524.4185,6525.420833,6526.423917,6527.423833,6528.425083,6529.420333,6530.428083,6531.423625,6532.428875,6533.420083,6534.425542,6535.419417,6536.428583,6537.420583,6538.426792,6539.420917,6540.4285,6541.421208,6542.424083,6543.42675,6544.423417,6545.417167,6546.428083,6547.42275,6548.427208,6549.424292,6550.424583,6551.422125,6552.403625,6553.432083,6554.426458,6555.401583,6556.425375,6557.429208,6558.412875,6559.432542,6560.434625,6561.425875,6562.424167,6563.427458,6564.4305,6565.429042,6566.423208,6567.424125,6568.429375,6569.432292,6570.426583,6571.423708,6572.428208,6573.425833,6574.428083,6575.428792,6576.429542,6577.428458,6578.431292,6579.426417,6580.432125,6581.426292,6582.427917,6583.431667,6584.424833,6585.429,6586.430833,6587.428042,6588.431375,6589.432958,6590.429042,6591.428125,6592.43,6593.426,6594.439333,6595.424042,6596.436417,6597.427208,6598.430458,6599.435667,6600.428708,6601.428667,6602.434292,6603.43275,6604.435167,6605.428042,6606.428667,6607.435125,6608.427292,6609.429083,6610.429292,6611.435875,6612.429917,6613.432375,6614.435792,6615.430583,6616.434542,6617.431625,6618.435333,6619.435542,6620.429792,6621.433,6622.437083,6623.42375,6624.439292,6625.430667,6626.430292,6627.413333,6628.442083,6629.420625,6630.439417,6631.429458,6632.438917,6633.432125,6634.413,6635.412,6636.529583,6637.568958,6638.637125,6639.647542,6640.67475,6641.789958,6642.77075,6643.751083,6644.786083,6645.654667,6646.729458,6647.76975,6648.768667,6649.793042,6650.782542,6651.787958,6652.784875,6653.790583,6654.784917,6655.788417,6656.785833,6657.790833,6658.781875,6659.788958,6660.788833,6661.787125,6662.783833,6663.789125,6664.788958,6665.788625,6666.786667,6667.786667,6668.787792,6669.764208,6670.792333,6671.792875,6672.778208,6673.793042,6674.776875,6675.793667,6676.791042,6677.768417,6678.769792,6679.790208,6680.787833,6681.789875,6682.79,6683.787625,6684.788333,6685.792708,6686.788375,6687.796292,6688.786458,6689.793,6690.792417,6691.795875,6692.801583,6693.764708,6694.798333,6695.787875,6696.791083,6697.793042,6698.79525,6699.79,6700.792958,6701.791375,6702.791667,6703.796542,6704.789917,6705.79075,6706.798083,6707.794375,6708.795208,6709.795083,6710.795625,6711.797417,6712.790125,6713.800292,6714.789,6715.796875,6716.790583,6717.794833,6718.789708,6719.798917,6720.791333,6721.794208,6722.791875,6723.799458,6724.796542,6725.792292,6726.793,6727.791917,6728.795958,6729.800958,6730.798583,6731.794167,6732.801542,6733.7985,6734.794875,6735.795125,6736.801875,6737.794625,6738.801375,6739.79425,6740.80125,6741.795,6742.802333,6743.792542,6744.797333,6745.798333,6746.772875,6747.617333,6748.642375,6749.801625,6750.693167,6751.772208,6752.802292,6753.711125,6754.785417,6755.808292,6756.7815,6757.772458,6758.663833,6759.809042,6760.775125,6761.636542,6762.807958,6763.777208,6764.780292,6765.802792,6766.798583,6767.799958,6768.801083,6769.80375,6770.80075,6771.804917,6772.802625,6773.799542,6774.80425,6775.810333,6776.800125,6777.805083,6778.8005,6779.807667,6780.800625,6781.807625,6782.796667,6783.79975,6784.799667,6785.805,6786.798917,6787.80675,6788.801,6789.799958,6790.806667,6791.799125,6792.809,6793.801542,6794.809708,6795.798875,6796.807417,6797.801583,6798.811167,6799.801208,6800.81325,6801.799083,6802.810958,6803.799417,6804.804542,6805.804333,6806.805208,6807.807542,6808.805333,6809.808333,6810.804875,6811.807958,6812.807667,6813.8045,6814.805125,6815.807292,6816.807958,6817.810333,6818.808833,6819.811917,6820.808792,6821.803375,6822.812708,6823.807583,6824.807042,6825.806875,6826.806583,6827.80625,6828.80825,6829.804458,6830.808583,6831.806083,6832.810333,6833.80375,6834.812417,6835.803208,6836.81525,6837.802542,6838.811792,6839.80425,6840.814417,6841.810417,6842.813292,6843.812333,6844.813417,6845.802375,6846.808583,6847.805792,6848.814125,6849.812125,6850.805875,6851.807875,6852.808167,6853.806417,6854.808708,6855.8085,6856.810042,6857.807167,6858.814,6859.810125,6860.805792,6861.812917,6862.808083,6863.810625,6864.813208,6865.815375,6866.808792,6867.810958,6868.787375,6869.707792,6870.598875,6871.662958,6872.742667,6873.8305,6874.759625,6875.76175,6876.79625,6877.798083,6878.789083,6879.794667,6880.685,6881.742167,6882.801,6883.784833,6884.80925,6885.817917,6886.820667,6887.815833,6888.824083,6889.820167,6890.818542,6891.818625,6892.817208,6893.824625,6894.815625,6895.821792,6896.816625,6897.821875,6898.815125,6899.818458,6900.818208,6901.817333,6902.81775,6903.818,6904.840375,6905.818958,6906.818917,6907.81575,6908.820583,6909.822458,6910.821125,6911.822125,6912.823208,6913.824708,6914.822875,6915.824542,6916.823667,6917.818875,6918.82625,6919.820458,6920.822708,6921.826083,6922.8245,6923.821708,6924.824792,6925.821167,6926.820542,6927.824375,6928.82375,6929.820083,6930.828583,6931.822417,6932.826125,6933.820667,6934.827042,6935.818625,6936.828167,6937.821,6938.825083,6939.818792,6940.82325,6941.821833,6942.828292,6943.821208,6944.819208,6945.822917,6946.827792,6947.8235,6948.801625,6949.805833,6950.82625,6951.82425,6952.825708,6953.829125,6954.824375,6955.826375,6956.824083,6957.831833,6958.825625,6959.827708,6960.825583,6961.829042,6962.8035,6963.80825,6964.836667,6965.827333,6966.831292,6967.822625,6968.832208,6969.82775,6970.828792,6971.82475,6972.826458,6973.830958,6974.804625,6975.831292,6976.826083,6977.831458,6978.82725,6979.829042,6980.824292,6982.107708,6983.356542,6984.229042,6985.24675,6986.514208,6987.340333,6988.475958,6989.337458,6990.438458,6991.442875,6992.408833,6993.433958,6994.438542,6995.461333,6996.467917,6997.460792,6998.46475,6999.46025,7000.463333,7001.44825,7002.446083,7003.471833,7004.464167,7005.472708,7006.464708,7007.4685,7008.475083,7009.462792,7010.474708,7011.468667,7012.469083,7013.470917,7014.470458,7015.468458,7016.470417,7017.46825,7018.465292,7019.448542,7020.451,7021.472875,7022.476167,7023.46725,7024.468958,7025.477292,7026.472792,7027.466958,7028.474667,7029.474083,7030.469417,7031.474958,7032.472417,7033.467958,7034.475292,7035.471042,7036.468125,7037.47025,7038.478458,7039.474625,7040.474333,7041.475083,7042.468167,7043.475375,7044.4705,7045.47125,7046.472042,7047.4765,7048.475875,7049.477167,7050.480792,7051.44525,7052.452542,7053.455792,7054.472583,7055.47525,7056.475958,7057.475583,7058.472583,7059.47025,7060.482625,7061.469583,7062.475417,7063.479917,7064.473,7065.476708,7066.476042,7067.472042,7068.476625,7069.477375,7070.482792,7071.4785,7072.468833,7073.45825,7074.478125,7075.475208,7076.48075,7077.477042,7078.4745,7079.476042,7080.477333,7081.476333,7082.482375,7083.478375,7084.478333,7085.474375,7086.477417,7087.478708,7088.478292,7089.476583,7090.47975,7091.474208,7092.48325,7093.466792,7094.458083,7095.484542,7096.477417,7097.479708,7098.476375,7099.477792,7100.481083,7101.473167,7102.445333,7103.457208,7104.476958,7105.466625,7106.315208,7107.383083,7108.496417,7109.429917,7110.6805,7111.6045,7112.482542,7113.66,7114.613125,7115.628208,7116.625375,7117.627125,7118.633083,7119.650667,7120.650208,7121.646833,7122.6435,7123.647375,7124.650667,7125.649458,7126.651167,7127.644375,7128.648833,7129.654333,7130.644708,7131.646208,7132.651292,7133.649833,7134.644792,7135.651708,7136.64975,7137.6515,7138.650542,7139.650042,7140.6555,7141.654667,7142.647667,7143.654375,7144.647625,7145.649167,7146.6445,7147.628917,7148.63225,7149.652625,7150.6545,7151.649875,7152.648583,7153.653333,7154.64575,7155.653792,7156.647667,7157.654042,7158.649583,7159.657417,7160.653958,7161.651792,7162.651958,7163.651458,7164.656417,7165.652667,7166.648375,7167.658958,7168.6505,7169.651917,7170.649917,7171.655167,7172.655542,7173.649458,7174.653667,7175.653042,7176.653083,7177.6585,7178.649167,7179.660875,7180.657083,7181.652458,7182.655958,7183.653375,7184.659833,7185.660292,7186.658,7187.659333,7188.65375,7189.658625,7190.651375,7191.658583,7192.652792,7193.659833,7194.657667,7195.660208,7196.650917,7197.65825,7198.659417,7199.658083,7200.65975,7201.657708,7202.654125,7203.660917,7204.655125,7205.651375,7206.656833,7207.661625,7208.6535,7209.663708,7210.656708,7211.662208,7212.663042,7213.650292,7214.633792,7215.618875,7216.60825,7217.6155,7218.560292,7219.654083,7220.45025,7221.697417,7222.625292,7223.652,7224.5485,7225.675333,7226.6675,7227.610083,7228.67725,7229.647583,7230.668375,7231.664542,7232.668833,7233.66825,7234.665958,7235.668792,7236.674042,7237.6675,7238.674958,7239.663792,7240.674458,7241.67,7242.672083,7243.670375,7244.674083,7245.66425,7246.666583,7247.670583,7248.677292,7249.665792,7250.667292,7251.670083,7252.670292,7253.6745,7254.665917,7255.669125,7256.670625,7257.669667,7258.670625,7259.673625,7260.675083,7261.665958,7262.670958,7263.667542,7264.676208,7265.668042,7266.67225,7267.668542,7268.67525,7269.674917,7270.671083,7271.675625,7272.673833,7273.67575,7274.667333,7275.672458,7276.676833,7277.671542,7278.678292,7279.673083,7280.671125,7281.67675,7282.675458,7283.6705,7284.677042,7285.651167,7286.674458,7287.651958,7288.654375,7289.676792,7290.6685,7291.673167,7292.673417,7293.678583,7294.671417,7295.675917,7296.675667,7297.680542,7298.673792,7299.671208,7300.677625,7301.677417,7302.67175,7303.675083,7304.671583,7305.604083,7306.670875,7307.571958,7308.676292,7309.629583,7310.687375,7311.647917,7312.654625,7313.651542,7314.65425,7315.686042,7316.65875,7317.646917,7318.980875,7320.21875,7321.040083,7322.21675,7323.008458,7324.22325,7325.164,7325.987042,7327.258625,7328.182292,7329.179667,7330.175333,7331.216417,7332.197458,7333.201,7334.207875,7335.195333,7336.208375,7337.199875,7338.207958,7339.196917,7340.205667,7341.203625,7342.208333,7343.208167,7344.202958,7345.205083,7346.206125,7347.203917,7348.209625,7349.210708,7350.205292,7351.20725,7352.211125,7353.204333,7354.212083,7355.205042,7356.213667,7357.203458,7358.21275,7359.206625,7360.211125,7361.204375,7362.212208,7363.204208,7364.210625,7365.211167,7366.208667,7367.206042,7368.207708,7369.206875,7370.205833,7371.207333,7372.202417,7373.203417,7374.207083,7375.207333,7376.212917,7377.204333,7378.178,7379.214,7380.207167,7381.20825,7382.215667,7383.205792,7384.217833,7385.183125,7386.196458,7387.210125,7388.21125,7389.210125,7390.213375,7391.209708,7392.209458,7393.206875,7394.211208,7395.2115,7396.208125,7397.213375,7398.214125,7399.211292,7400.21025,7401.21225,7402.217542,7403.211292,7404.218917,7405.212917,7406.217208,7407.214875,7408.213458,7409.213792,7410.210875,7411.216375,7412.214375,7413.214375,7414.217375,7415.217417,7416.212125,7417.210958,7418.216333,7419.209417,7420.216375,7421.210333,7422.213417,7423.217917,7424.218208,7425.21275,7426.218917,7427.212833,7428.221583,7429.206208,7430.220625,7431.212167,7432.215875,7433.213333,7434.222042,7435.212542,7436.2175,7437.211875,7438.213292,7439.218333,7440.217583,7441.215792,7442.218625,7443.216542,7444.215042,7445.217875,7446.215083,7447.221583,7448.212875,7449.216292,7450.221458,7451.213542,7452.214583,7453.218292,7454.214833,7455.219875,7456.213958,7457.216958,7458.2215,7459.194083,7460.233292,7461.216583,7462.194375,7463.199125,7464.197917,7465.221917,7466.214542,7467.221708,7468.219417,7469.196208,7472.549458,7473.800333,7474.752917,7475.596083,7476.778792,7477.755792,7478.729875,7479.604792,7480.668458,7481.695417,7482.616167,7483.6265,7484.770625,7485.739417,7486.773542,7487.768417,7488.765417,7489.769125,7490.771708,7491.762583,7492.774833,7493.762708,7494.768708,7495.767292,7496.767417,7497.76775,7498.773167,7499.767875,7500.775042,7501.766708,7502.775625,7503.769917,7504.772208,7505.765583,7506.770167,7507.769125,7508.771167,7509.77225,7510.773,7511.76875,7512.768833,7513.775875,7514.766167,7515.773583,7516.769583,7517.768,7518.772542,7519.771625,7520.772417,7521.776875,7522.765833,7523.779333,7524.773208,7525.77275,7526.770583,7527.772125,7528.776333,7529.752583,7530.781792,7531.769417,7532.775417,7533.748417,7534.773083,7535.7745,7536.776958,7537.7725,7538.767667,7539.751708,7540.753708,7541.772917,7542.784125,7543.775917,7544.779833,7545.78075,7546.791167,7547.7725,7548.752,7549.757,7550.75675,7551.758417,7552.758333,7553.75575,7554.763958,7555.757167,7556.758375,7557.758333,7558.758167,7559.759,7560.76075,7561.763583,7562.760792,7563.759875,7564.763375,7565.763875,7566.760542,7567.763167,7568.763542,7569.781583,7570.777625,7571.77225,7572.783833,7573.779375,7574.788208,7575.775125,7576.787292,7577.776542,7578.778583,7579.7805,7580.780042,7581.7805,7582.779292,7583.781792,7584.777833,7585.779125,7586.7805,7587.779917,7588.779125,7589.780458,7590.779792,7591.782875,7592.783958,7593.756458,7594.786125,7595.778458,7596.779417,7597.78125,7598.780292,7599.782917,7600.7815,7601.780708,7602.778875,7603.78925,7604.789333,7605.780333,7606.785833,7607.7915,7608.785625,7609.78875,7610.783292,7611.785083,7612.7905,7613.781917,7614.784458,7615.781542,7616.789083,7617.786667,7618.784417,7619.782042,7620.784167,7621.7845,7622.783583,7623.79025,7624.788875,7625.782958,7626.787167,7627.784625,7628.787292,7629.783583,7630.784417,7631.786708,7632.760917,7634.00375,7635.271958,7636.204208,7637.222083,7638.217458,7639.218292,7640.126333,7641.182917,7642.064583,7643.230542,7644.086667,7645.24925,7646.173292,7647.210083,7648.221417,7649.218375,7650.226,7651.219458,7652.223083,7653.218208,7654.223417,7655.220292,7656.218542,7657.22125,7658.223875,7659.226583,7660.224542,7661.226625,7662.226,7663.230125,7664.220042,7665.227708,7666.228625,7667.193417,7668.223875,7669.212708,7670.221083,7671.227667,7672.221417,7673.231292,7674.226625,7675.22275,7676.230667,7677.222792,7678.227667,7679.230792,7680.223542,7681.203125,7682.233125,7683.223,7684.207208,7685.209083,7686.205125,7687.232875,7688.202542,7689.208833,7690.229958,7691.226542,7692.229125,7693.2255,7694.220708,7695.233,7696.231125,7697.224792,7698.225625,7699.230125,7700.227792,7701.2075,7702.211917,7703.23725,7704.229333,7705.227458,7706.237875,7707.227708,7708.236333,7709.228875,7710.235417,7711.232917,7712.230542,7713.231583,7714.230417,7715.2335,7716.227833,7717.235667,7718.232958,7719.213542,7720.237333,7721.227417,7722.235833,7723.229333,7724.235208,7725.231292,7726.229958,7727.239583,7728.2375,7729.2295,7730.23575,7731.235125,7732.234167,7733.227458,7734.249667,7735.203833,7736.241917,7737.23025,7738.238875,7739.230458,7740.239583,7741.234167,7742.2335,7743.240125,7744.213333,7745.215958,7746.2415,7747.231375,7748.235208,7749.201708,7750.217542,7751.083542,7752.32675,7753.143417,7754.306917,7755.263917,7756.161625,7757.297125,7758.282458,7759.289375,7760.249833,7761.278792,7762.2805,7763.30475,7764.303292,7765.303458,7766.299,7767.304292,7768.299958,7769.301,7770.297917,7771.304542,7772.3105,7773.303583,7774.305417,7775.30675,7776.29975,7777.30325,7778.3065,7779.300917,7780.304708,7781.302958,7782.304167,7783.299958,7784.303542,7785.300542,7786.30275,7787.3005,7788.284375,7789.285542,7790.309458,7791.301792,7792.299583,7793.28025,7794.305958,7795.304375,7796.307125,7797.305542,7798.30425,7799.283083,7800.327875,7801.302292,7802.284292,7803.310083,7804.287333,7805.306458,7806.304333,7807.30525,7808.310042,7809.30225,7810.309333,7811.310583,7812.303417,7813.310042,7814.306583,7815.313417,7816.304917,7817.307708,7818.312167,7819.308167,7820.306417,7821.30725,7822.301708,7823.306375,7824.308458,7825.305833,7826.308542,7827.30475,7828.31175,7829.303542,7830.315333,7831.310583,7832.312583,7833.309042,7834.313667,7835.305167,7836.312042,7837.307833,7838.312,7839.312542,7840.315125,7841.308417,7842.314042,7843.311,7844.312125,7845.311375,7846.309292,7847.31225,7848.308708,7849.3125,7850.309208,7851.309875,7852.313208,7853.312208,7854.313625,7855.316083,7856.308125,7857.309333,7858.310042,7859.314417,7860.312542,7861.317917,7862.316875,7863.315375,7864.288,7865.295667,7866.216917,7867.198167,7868.271125,7869.126542,7870.305542,7871.307208,7872.346958,7873.274583,7874.245333,7875.346333,7876.343042,7877.33625,7878.310917,7879.321667,7880.342,7881.342583,7882.345208,7883.344958,7884.348542,7885.343167,7886.351958,7887.346292,7888.343917,7889.343,7890.348917,7891.33975,7892.347042,7893.342292,7894.345167,7895.341208,7896.344458,7897.348667,7898.344583,7899.345583,7900.34225,7901.347042,7902.350458,7903.354875,7904.340208,7905.345542,7906.351417,7907.3525,7908.350417,7909.345292,7910.344042,7911.35175,7912.351958,7913.3465,7914.351083,7915.35425,7916.351333,7917.348708,7918.34725,7919.356417,7920.34775,7921.34825,7922.349667,7923.326833,7924.356875,7925.328375,7926.33125,7927.365958,7928.324,7929.358375,7930.348708,7931.351542,7932.356125,7933.354833,7934.353208,7935.357958,7936.353125,7937.353417,7938.350042,7939.357708,7940.353958,7941.353958,7942.353625,7943.358875,7944.353958,7945.355042,7946.356083,7947.354375,7948.3635,7949.351625,7950.356542,7951.358,7952.354333,7953.35975,7954.354083,7955.35225,7956.361542,7957.357167,7958.352875,7959.356833,7960.3535,7961.358833,7962.352458,7963.357708,7964.360167,7965.360458,7966.351667,7967.362458,7968.353792,7969.354417,7970.361458,7971.35125,7972.361042,7973.366208,7974.361125,7975.355708,7976.354958,7977.357042,7978.364333,7979.357333,7980.36275,7981.355833,7982.359583,7983.354292,7984.346708,7985.506333,7986.748125,7988.030917,7989.300833,7990.109,7991.205583,7992.229042,7993.243708,7994.223667,7995.184292,7996.228042,7997.159583,7998.275208,7999.246833,8000.255,8001.232667,8002.254417,8003.231542,8004.229917,8005.255958,8006.247458,8007.2525,8008.246292,8009.244833,8010.2565,8011.251375,8012.255125,8013.244125,8014.248042,8015.254,8016.261333,8017.255458,8018.248708,8019.258458,8020.251875,8021.259333,8022.249083,8023.254625,8024.252708,8025.252042,8026.255417,8027.249583,8028.251292,8029.251375,8030.258583,8031.254667,8032.250542,8033.240667,8034.237417,8035.254875,8036.25725,8037.249167,8038.262542,8039.2515,8040.256167,8041.252,8042.2555,8043.254417,8044.236458,8045.258333,8046.257125,8047.25775,8048.252875,8049.257667,8050.256958,8051.251708,8052.259125,8053.252042,8054.253458,8055.261083,8056.254875,8057.263083,8058.257542,8059.258667,8060.261,8061.262375,8062.253292,8063.262917,8064.254125,8065.260125,8066.237458,8067.238583,8068.246125,8069.262417,8070.237708,8071.258458,8072.26625,8073.254667,8074.258,8075.25625,8076.257792,8077.258542,8078.258208,8079.257292,8080.256208,8081.25725,8082.260833,8083.265708,8084.253667,8085.261625,8086.26175,8087.267167,8088.26375,8089.264667,8090.261208,8091.263958,8092.261667,8093.261417,8094.237042,8095.263875,8096.258917,8097.263083,8098.265917,8099.237167,8100.267417,8101.267167,8102.2685,8103.2625,8104.27,8105.262958,8106.266708,8107.266208,8108.265458,8109.261833,8110.264375,8111.268625,8112.26475,8113.265958,8114.239667,8116.6825,8117.871083,8118.740458,8119.922417,8120.856,8121.758125,8122.757875,8123.901583,8124.857917,8125.872417,8126.889833,8127.874708,8128.90125,8129.90125,8130.894458,8131.901417,8132.875167,8133.907708,8134.899125,8135.885375,8136.908708,8137.903542,8138.898292,8139.903,8140.902792,8141.897792,8142.90175,8143.89925,8144.902583,8145.903167,8146.90175,8147.902458,8148.90075,8149.9025,8150.881083,8151.882042,8152.9055,8153.905417,8154.901,8155.9035,8156.903667,8157.908625,8158.907042,8159.901417,8160.889208,8161.909208,8162.900625,8163.900333,8164.793375,8165.932292,8166.892792,8167.904375,8168.906875,8169.90625,8170.90475,8171.903792,8172.907417,8173.905375,8174.907542,8175.903917,8176.882,8177.8885,8178.901833,8179.906125,8180.912333,8181.904958,8182.914083,8183.910083,8184.909583,8185.898042,8186.911875,8187.903042,8188.911375,8189.904583,8190.909667,8191.907125,8192.906958,8193.912458,8194.906125,8195.912125,8196.913125,8197.904333,8198.911042,8199.903333,8200.906292,8201.91025,8202.912208,8203.908125,8204.911167,8205.908708,8206.9105,8207.913542,8208.905583,8209.908208,8210.90825,8211.905167,8212.915125,8213.907,8214.916125,8215.912042,8216.909917,8217.913458,8218.9095,8219.909375,8220.911917,8221.908042,8222.913333,8223.916167,8224.908625,8225.9205,8226.910042,8227.915958,8228.909625,8229.915208,8230.9075,8231.912417,8232.917875,8233.892042,8234.9155,8235.890167,8236.901958,8237.918958,8238.909458,8239.915125,8240.913208,8241.916833,8242.891083,8244.019958,8245.21675,8246.156625,8247.237625,8248.127708,8249.219042,8250.205625,8251.214542,8252.219375,8253.210708,8254.21775,8255.209125,8256.226125,8257.215167,8258.214708,8259.246125,8260.2345,8261.23975,8262.238208,8263.241583,8264.235167,8265.238583,8266.244292,8267.23525,8268.244375,8269.240417,8270.242417,8271.246083,8272.243833,8273.235208,8274.244333,8275.234833,8276.241917,8277.236292,8278.239,8279.238583,8280.238833,8281.23975,8282.244208,8283.240083,8284.239542,8285.237542,8286.240708,8287.246083,8288.244458,8289.24125,8290.239,8291.243167,8292.244333,8293.246875,8294.244917,8295.246208,8296.241458,8297.240167,8298.241417,8299.246792,8300.245375,8301.241792,8302.244833,8303.24675,8304.240167,8305.242708,8306.243542,8307.240125,8308.241583,8309.243208,8310.239958,8311.245,8312.242833,8313.248375,8314.247542,8315.245,8316.242917,8317.243917,8318.252125,8319.246583,8320.2445,8321.243208,8322.245542,8323.246333,8324.244083,8325.249708,8326.242292,8327.2425,8328.245125,8329.251542,8330.246542,8331.248958,8332.244167,8333.250083,8334.245083,8335.24525,8336.249292,8337.244583,8338.24675,8339.252792,8340.250208,8341.249333,8342.253042,8343.250083,8344.245583,8345.250083,8346.254667,8347.244208,8348.248792,8349.251875,8350.248625,8351.25375,8352.245375,8353.250458,8354.254417,8355.247625,8356.255333,8357.248583,8358.253042,8359.244958,8360.248167,8361.249625,8362.069875,8363.214208,8364.255375,8365.277583,8366.270292,8367.234583,8368.296917,8369.26075,8370.269333,8371.26225,8372.110667,8373.082417,8374.209292,8375.30375,8376.279042,8377.288042,8378.291958,8379.285458,8380.289708,8381.285958,8382.289333,8383.292333,8384.282167,8385.289208,8386.293708,8387.283958,8388.298333,8389.287917,8390.294917,8391.285625,8392.299208,8393.285125,8394.29425,8395.28625,8396.296375,8397.285458,8398.289208,8399.29525,8400.290458,8401.288667,8402.279208,8403.274292,8404.300208,8405.28925,8406.286875,8407.295875,8408.289875,8409.299792,8410.290167,8411.297875,8412.288,8413.290875,8414.296625,8415.289208,8416.291833,8417.2885,8418.298083,8419.290292,8420.294875,8421.293125,8422.295625,8423.291542,8424.292,8425.2975,8426.299625,8427.289167,8428.300917,8429.289583,8430.2995,8431.291917,8432.301625,8433.293875,8434.299167,8435.29625,8436.294333,8437.298458,8438.29125,8439.29725,8440.295667,8441.293875,8442.298542,8443.298333,8444.299583,8445.298875,8446.293167,8447.299167,8448.292583,8449.297875,8450.300792,8451.297333,8452.301083,8453.301667,8454.296625,8455.302292,8456.300458,8457.296917,8458.30075,8459.295417,8460.301208,8461.302208,8462.30025,8463.301083,8464.29475,8465.308375,8466.297583,8467.306167,8468.297917,8469.299583,8470.30425,8471.306708,8472.308125,8473.302333,8474.305125,8475.306667,8476.300417,8477.304917,8478.295917,8479.301708,8480.269125,8481.296208,8482.294625,8483.282833,8484.296875,8485.290833,8486.147417,8487.342708,8488.269958,8489.3185,8490.302167,8491.306333,8492.302375,8493.307875,8494.301333,8495.307625,8496.310208,8497.304375,8498.306083,8499.313333,8500.310167,8501.3055,8502.308333,8503.3125,8504.3105,8505.305042,8506.30575,8507.310583,8508.312,8509.307583,8510.314417,8511.314375,8512.313333,8513.306792,8514.317167,8515.312042,8516.316042,8517.31175,8518.31725,8519.309375,8520.317458,8521.309833,8522.319,8523.309875,8524.317,8525.316958,8526.313958,8527.317042,8528.314667,8529.309917,8530.318875,8531.310917,8532.31875,8533.313542,8534.31275,8535.319292,8536.316333,8537.312917,8538.31475,8539.317083,8540.318708,8541.308417,8542.31375,8543.315625,8544.317333,8545.312125,8546.29375,8547.323292,8548.312333,8549.31775,8550.311083,8551.313042,8552.314542,8553.315542,8554.316083,8555.313042,8556.318833,8557.321417,8558.321042,8559.32275,8560.321417,8561.329875,8562.323958,8563.326458,8564.327042,8565.3225,8566.331625,8567.325625,8568.329708,8569.324542,8570.326875,8571.329708,8572.322417,8573.320917,8574.329417,8575.326292,8576.32675,8577.323625,8578.332917,8579.326417,8580.329792,8581.319292,8582.332875,8583.32075,8584.334125,8585.325333,8586.323583,8587.327792,8588.2925,8589.340542,8590.32025,8591.304417,8592.337625,8593.322333,8594.3315,8595.331875,8596.305792,8597.3065,8598.307333,8599.289083,8600.263042,8601.255875,8602.306625,8603.287333,8604.340625,8605.1775,8606.304708,8607.340542,8608.329458,8609.308375,8610.3135,8611.32725,8612.336292,8613.32725,8614.332333,8615.338333,8616.3295,8617.338083,8618.333292,8619.33325,8620.337042,8621.337292,8622.329417,8623.334667,8624.331417,8625.3355,8626.327583,8627.336958,8628.337167,8629.323458,8630.339375,8631.337,8632.343,8633.330625,8634.341125,8635.329833,8636.342333,8637.339292,8638.339417,8639.340375,8640.338875,8641.3375,8642.340333,8643.334,8644.336333,8645.347375,8646.333458,8647.342333,8648.33625,8649.315167,8650.342167,8651.334625,8652.335833,8653.336792,8654.334583,8655.339292,8656.334167,8657.337792,8658.340167,8659.338083,8660.344333,8661.340458,8662.342667,8663.340417,8664.339583,8665.341292,8666.35575,8667.343375,8668.335542,8669.342417,8670.339,8671.342208,8672.341042,8673.335417,8674.319917,8675.344875,8676.343792,8677.338,8678.344667,8679.343417,8680.33775,8681.346625,8682.346125,8683.342917,8684.341917,8685.346167,8686.341458,8687.342667,8688.344333,8689.342083,8690.345542,8691.346042,8692.343792,8693.349458,8694.341042,8695.351208,8696.34225,8697.341917,8698.341708,8699.345875,8700.318792,8701.345417,8702.341,8703.350458,8704.343625,8705.292542,8706.354708,8707.33925,8708.2775,8709.208875,8710.378875,8711.335542,8712.323375,8713.292875,8714.369375,8715.305167,8716.331042,8717.35775,8718.346917,8719.347083,8720.350167,8721.34425,8722.353167,8723.356417,8724.330208,8725.3545,8726.34725,8727.351333,8728.352625,8729.34425,8730.357042,8731.349458,8732.351042,8733.343375,8734.352875,8735.345625,8736.351625,8737.346583,8738.347625,8739.349167,8740.351833,8741.351083,8742.349375,8743.354083,8744.34875,8745.350625,8746.350667,8747.356208,8748.359542,8749.347958,8750.348083,8751.358333,8752.3505,8753.357167,8754.349708,8755.354292,8756.3555,8757.354375,8758.349917,8759.352542,8760.356458,8761.355667,8762.347542,8763.330417,8764.356708,8765.350833,8766.351083,8767.346917,8768.332167,8769.337417,8770.366833,8771.345083,8772.338333,8773.333083,8774.360167,8775.329792,8776.35875,8777.35725,8778.356333,8779.356542,8780.35775,8781.359208,8782.359042,8783.358458,8784.352208,8785.355292,8786.361208,8787.3545,8788.35475,8789.359625,8790.357375,8791.355792,8792.353917,8793.361583,8794.356958,8795.358417,8796.352542,8797.333583,8798.373958,8799.351,8800.373375,8801.349583,8802.34025,8803.360208,8804.355292,8805.355125,8806.356292,8807.357667,8808.357375,8809.355708,8810.355875,8811.35625,8812.359292,8813.356667,8814.359125,8815.361958,8816.356792,8817.359042,8818.359208,8819.36625,8820.353458,8821.360125,8822.358417,8823.362333,8824.361167,8825.3605,8826.3585,8827.356333,8828.281542,8829.291083,8830.237542,8831.367375,8832.333167,8833.338333,8834.282625,8835.220667,8836.338125,8837.348083,8838.330375,8839.343167,8840.36225,8841.357208,8842.367625,8843.361375,8844.364458,8845.369375,8846.370625,8847.365458,8848.366292,8849.370833,8850.363208,8851.362917,8852.367875,8853.361208,8854.342583,8855.39425,8856.358667,8857.360458,8858.366792,8859.362875,8860.364458,8861.366583,8862.365833,8863.362625,8864.364333,8865.36475,8866.370333,8867.365583,8868.369833,8869.372958,8870.36725,8871.370583,8872.365792,8873.388958,8874.342083,8875.374125,8876.372,8877.363417,8878.371458,8879.3745,8880.364708,8881.374542,8882.373667,8883.36725,8884.376292,8885.366958,8886.368292,8887.370792,8888.370083,8889.369958,8890.368958,8891.367125,8892.37175,8893.373708,8894.37225,8895.376042,8896.366542,8897.371542,8898.374458,8899.373208,8900.372042,8901.382583,8902.36775,8903.381375,8904.371708,8905.37625,8906.377417,8907.378667,8908.375,8909.376917,8910.380042,8911.375208,8912.381208,8913.346625,8914.382833,8915.37575,8916.381917,8917.381833,8918.374417,8919.384125,8920.374042,8921.378458,8922.376125,8923.37675,8924.377583,8925.380917,8926.375542,8927.382333,8928.374833,8929.380125,8930.376833,8931.375958,8932.378792,8933.378583,8934.384042,8935.374,8936.377458,8937.382708,8938.378958,8939.378542,8940.382917,8941.379917,8942.378,8943.382667,8944.378083,8945.380583,8946.385,8947.382875,8948.382625,8949.377125,8950.379292,8951.34475,8952.339583,8953.225042,8954.396625,8955.360542,8956.358917,8957.36275,8958.355,8959.227417,8960.394,8961.357333,8962.390792,8963.382625,8964.387625,8965.38175,8966.3805,8967.385333,8968.388042,8969.385417,8970.380375,8971.381417,8972.391292,8973.376208,8974.390958,8975.383458,8976.36475,8977.369542,8978.392083,8979.3845,8980.388833,8981.387083,8982.390458,8983.388292,8984.38625,8985.384417,8986.385,8987.385542,8988.393208,8989.382917,8990.391,8991.390208,8992.362792,8993.397833,8994.387625,8995.383333,8996.368875,8997.390417,8998.379875,8999.3825,9000.368333,9001.367833,9002.393833,9003.395792,9004.3925,9005.385833,9006.385,9007.388417,9008.390083,9009.38925,9010.38975,9011.391333,9012.395292,9013.392708,9014.387167,9015.393,9016.396833,9017.388167,9018.393875,9019.390875,9020.393083,9021.387583,9022.396083,9023.380083,9024.393542,9025.395958,9026.38975,9027.367833,9028.376583,9029.400167,9030.387875,9031.394458,9032.395208,9033.392042,9034.399958,9035.39275,9036.393167,9037.398042,9038.397875,9039.393833,9040.392542,9041.397667,9042.398583,9043.390625,9044.399542,9045.39575,9046.39675,9047.398292,9048.377542,9049.403458,9050.392458,9051.394375,9052.3945,9053.403917,9054.391083,9055.400833,9056.4,9057.395,9058.404542,9059.390375,9060.404375,9061.394792,9062.374042,9063.239583,9064.270083,9065.4085,9066.309083,9067.417417,9068.277542,9069.410875,9070.231042,9071.41925,9072.365292,9073.37825,9074.37575,9075.300375,9076.393,9077.390917,9078.375333,9079.382375,9080.384375,9081.393917,9082.371958,9083.407667,9084.399542,9085.402125,9086.3945,9087.403667,9088.401958,9089.405167,9090.404583,9091.402042,9092.405375,9093.397292,9094.400333,9095.406708,9096.400458,9097.401792,9098.388458,9099.401333,9100.403458,9101.404708,9102.401375,9103.408417,9104.397333,9105.407125,9106.408458,9107.403917,9108.388292,9109.407083,9110.404667,9111.398208,9112.409667,9113.392375,9114.387,9115.410583,9116.400833,9117.406042,9118.401958,9119.405708,9120.4055,9121.401167,9122.406583,9123.381917,9124.414375,9125.404833,9126.408375,9127.406417,9128.414458,9129.40575,9130.409833,9131.406917,9132.406,9133.4045,9134.405958,9135.404417,9136.406667,9137.408542,9138.406667,9139.406833,9140.407208,9141.409917,9142.411708,9143.411125,9144.408417,9145.416458,9146.404333,9147.414833,9148.386458,9149.422583,9150.405625,9151.394833,9152.413792,9153.382667,9154.395042,9155.386208,9156.412958,9157.418333,9158.406375,9159.414042,9160.408875,9161.413708,9162.409083,9163.410125,9164.411083,9165.410792,9166.416708,9167.413042,9168.41125,9169.410417,9170.409833,9171.417625,9172.4255,9173.407833,9174.417542,9175.417042,9176.417333,9177.411208,9178.419667,9179.411542,9180.415792,9181.389,9182.396583,9183.416917,9184.417583,9185.412708,9186.416042,9187.413667,9188.419708,9189.414833,9190.414125,9191.41725,9192.419417,9193.413875,9194.41575,9195.4125,9196.418375,9197.412167,9198.391167,9199.374833,9200.372208,9201.376125,9202.337917,9203.408542,9204.354917,9205.406167,9206.40225,9207.364417,9208.401083,9209.421708,9210.391292,9211.414,9212.238042,9213.654833,9214.900125,9215.856208,9216.874042,9217.84925,9218.869875,9219.875625,9220.871667,9221.875917,9222.866458,9223.8805,9224.870333,9225.875542,9226.871208,9227.872458,9228.871833,9229.86975,9230.871833,9231.870042,9232.868167,9233.871083,9234.8845,9235.867167,9236.871833,9237.87275,9238.872583,9239.848542,9240.877583,9241.878958,9242.871792,9243.87375,9244.880333,9245.867125,9246.875792,9247.8775,9248.878292,9249.874375,9250.872125,9251.876375,9252.872792,9253.881458,9254.871625,9255.872417,9256.879,9257.879958,9258.872833,9259.87325,9260.875417,9261.880292,9262.878125,9263.87525,9264.874417,9265.875917,9266.875625,9267.875208,9268.873792,9269.876625,9270.876417,9271.876958,9272.877917,9273.874958,9274.876792,9275.8755,9276.877417,9277.877167,9278.875833,9279.876458,9280.878,9281.877042,9282.877625,9283.878833,9284.874583,9285.878833,9286.876417,9287.879917,9288.87625,9289.879167,9290.881208,9291.872917,9292.884667,9293.876125,9294.884875,9295.87825,9296.880333,9297.886708,9298.885542,9299.880708,9300.860167,9301.894125,9302.877125,9303.898667,9304.876292,9305.862542,9306.864917,9307.888458,9308.878875,9309.882417,9310.883625,9311.880167,9312.883375,9313.888125,9314.882333,9315.880333,9316.890375,9317.88125,9318.887833,9319.889083,9320.886208,9321.883083,9322.889792,9323.883833,9324.884042,9325.887917,9326.884042,9327.890958,9328.883542,9329.88675,9330.890292,9331.886542,9332.885542,9333.89025,9334.885042,9335.88675,9336.828958,9338.048,9338.980292,9340.059667,9340.845417,9341.961083,9343.060333,9344.03975,9345.046708,9345.991917,9347.038167,9348.028167,9349.053708,9350.06525,9351.066792,9352.058958,9353.067917,9354.066792,9355.060083,9356.06375,9357.062417,9358.062542,9359.061083,9360.061917,9361.062917,9362.064083,9363.062708,9364.065875,9365.062667,9366.066167,9367.065333,9368.068792,9369.061625,9370.065583,9371.0625,9372.063333,9373.071375,9374.050292,9375.051042,9376.069125,9377.061667,9378.063875,9379.066917,9380.063375,9381.044125,9382.06975,9383.063375,9384.066,9385.068208,9386.069042,9387.067833,9388.069542,9389.067792,9390.070042,9391.072958,9392.070958,9393.073708,9394.06375,9395.070583,9396.067292,9397.067792,9398.066833,9399.069625,9400.071375,9401.068167,9402.0755,9403.07025,9404.074792,9405.067625,9406.066917,9407.073083,9408.072333,9409.068667,9410.072917,9411.070833,9412.069125,9413.074625,9414.073,9415.048583,9416.096417,9417.042167,9418.058792,9419.076917,9420.083208,9421.066708,9422.076167,9423.076125,9424.070958,9425.076292,9426.072542,9427.072417,9428.075375,9429.072875,9430.077417,9431.078458,9432.070917,9433.07775,9434.073708,9435.072042,9436.074458,9437.072625,9438.082042,9439.076208,9440.085875,9441.075458,9442.076417,9443.06975,9444.072167,9445.058208,9446.043917,9447.604,9448.787917,9449.678333,9450.818375,9451.798208,9452.794542,9453.816083,9454.8175,9455.798375,9456.718167,9457.84675,9458.791833,9459.8055,9460.824458,9461.821667,9462.830708,9463.820042,9464.823542,9465.827708,9466.815625,9467.824125,9468.817208,9469.822042,9470.821292,9471.827708,9472.820708,9473.827292,9474.818375,9475.827167,9476.826917,9477.82725,9478.819833,9479.801958,9480.824333,9481.828292,9482.80675,9483.805792,9484.830667,9485.822833,9486.82525,9487.826583,9488.822042,9489.825375,9490.830333,9491.824292,9492.827542,9493.828208,9494.824458,9495.822083,9496.832,9497.826417,9498.827583,9499.826542,9500.829958,9501.82425,9502.833625,9503.824708,9504.833583,9505.829167,9506.830542,9507.822708,9508.833042,9509.826833,9510.827667,9511.834,9512.835208,9513.830208,9514.826333,9515.828458,9516.834042,9517.830292,9518.8275,9519.83075,9520.833125,9521.827208,9522.829375,9523.830792,9524.836625,9525.824708,9526.83425,9527.831167,9528.834708,9529.834667,9530.832875,9531.83575,9532.83375,9533.827792,9534.831833,9535.831333,9536.836333,9537.829875,9538.8305,9539.828125,9540.833833,9541.834458,9542.826542,9543.834542,9544.837125,9545.833542,9546.830875,9547.832958,9548.833542,9549.834125,9550.829,9551.83525,9552.836833,9553.836583,9554.838792,9555.833833,9556.831458,9557.837542,9558.835625,9559.83825,9560.831375,9561.833042,9562.835958,9563.838833,9564.828875,9565.837292,9566.834792,9567.839792,9568.832625,9569.839917,9570.833333,9571.839625,9572.838875,9573.813083,9574.787708,9575.802542,9577.210875,9578.478583,9579.36325,9580.401333,9581.4075,9582.304208,9583.436667,9584.389583,9585.43675,9586.404333,9587.261417,9588.445792,9589.395958,9590.435958,9591.423458,9592.4305,9593.430042,9594.426292,9595.433458,9596.427708,9597.43725,9598.427583,9599.432792,9600.426542,9601.429583,9602.42925,9603.436583,9604.431958,9605.432708,9606.431708,9607.431875,9608.431,9609.431708,9610.433083,9611.431,9612.432167,9613.4355,9614.43,9615.435417,9616.4315,9617.431417,9618.433375,9619.431083,9620.43775,9621.433167,9622.43425,9623.425792,9624.440583,9625.431792,9626.442375,9627.433333,9628.437417,9629.429875,9630.435833,9631.443292,9632.439125,9633.431625,9634.439375,9635.432,9636.43675,9637.432167,9638.438125,9639.436,9640.44125,9641.430958,9642.439625,9643.432333,9644.43975,9645.43725,9646.433208,9647.441375,9648.432083,9649.439333,9650.438625,9651.433083,9652.441333,9653.441167,9654.435708,9655.442,9656.441833,9657.439125,9658.441083,9659.432292,9660.435292,9661.434583,9662.439625,9663.442333,9664.432375,9665.437292,9666.445042,9667.438375,9668.442958,9669.440583,9670.441458,9671.441167,9672.438375,9673.4425,9674.439625,9675.439708,9676.438833,9677.445208,9678.445917,9679.453,9680.439917,9681.440792,9682.4495,9683.443125,9684.440333,9685.444042,9686.438833,9687.444792,9688.437792,9689.4465,9690.437917,9691.447042,9692.444833,9693.443708,9694.441375,9695.41875,9696.443625,9697.444708,9698.440792,9699.445667,9700.44025,9701.447,9702.417958,9703.433,9704.420792,9705.2865,9706.484167,9707.401042,9708.399167,9709.298917,9710.4165,9711.441292,9712.298375,9713.45025,9714.418583,9715.410042,9716.424083,9717.445708,9718.443375,9719.445333,9720.454,9721.442458,9722.45375,9723.445208,9724.451958,9725.442875,9726.45625,9727.441833,9728.455458,9729.449583,9730.448375,9731.447042,9732.453,9733.443708,9734.454333,9735.44875,9736.450792,9737.446083,9738.452625,9739.442292,9740.455833,9741.441125,9742.452917,9743.45275,9744.447583,9745.455208,9746.445542,9747.449667,9748.449833,9749.448083,9750.448042,9751.453708,9752.449292,9753.456042,9754.450833,9755.45025,9756.45275,9757.449333,9758.452042,9759.449167,9760.447958,9761.45125,9762.451083,9763.447208,9764.4525,9765.448667,9766.449917,9767.453208,9768.427458,9769.474167,9770.420417,9771.472083,9772.447875,9773.434125,9774.456167,9775.427708,9776.453542,9777.413292,9778.464583,9779.462375,9780.453708,9781.453042,9782.45625,9783.454958,9784.456208,9785.451833,9786.459208,9787.450125,9788.469792,9789.453083,9790.457125,9791.456042,9792.451833,9793.459708,9794.453542,9795.454875,9796.455833,9797.453208,9798.456583,9799.457292,9800.455208,9801.460583,9802.459167,9803.457958,9804.463875,9805.452917,9806.465042,9807.458,9808.454333,9809.435333,9810.445375,9811.454333,9812.459083,9813.456958,9814.457333,9815.4665,9816.460917,9817.461708,9818.4555,9819.459667,9820.458708,9821.457042,9822.459125,9823.438125,9824.368167,9825.376667,9826.475583,9827.399958,9828.324583,9829.465292,9830.456,9831.4495,9832.310708,9833.494,9834.434708,9835.450833,9836.353375,9837.467583,9838.433958,9839.464,9840.358792,9841.482875,9842.455083,9843.464292,9844.462792,9845.463,9846.46125,9847.464958,9848.461042,9849.461875,9850.461917,9851.466333,9852.462667,9853.464292,9854.462667,9855.464958,9856.463292,9857.464542,9858.462667,9859.463708,9860.465458,9861.462083,9862.461792,9863.464125,9864.462292,9865.466,9866.461125,9867.466792,9868.466375,9869.465167,9870.466083,9871.465375,9872.465208,9873.466833,9874.466917,9875.467583,9876.467625,9877.467,9878.466917,9879.466417,9880.467292,9881.465292,9882.465417,9883.465167,9884.4675,9885.469458,9886.468208,9887.468208,9888.455958,9889.473583,9890.470375,9891.469667,9892.471458,9893.467583,9894.470833,9895.474375,9896.45,9897.473917,9898.484625,9899.475458,9900.470375,9901.471917,9902.328875,9903.354583,9904.481,9905.421625,9906.48625,9907.475417,9908.468292,9909.471875,9910.469333,9911.472625,9912.472333,9913.476042,9914.493042,9915.444375,9916.478,9917.470208,9918.43725,9919.336958,9920.508417,9921.462208,9922.477208,9923.464417,9924.464625,9925.452333,9926.455167,9927.47375,9928.441792,9929.290833,9930.470583,9931.474875,9932.451917,9933.485958,9934.481042,9935.477667,9936.459417,9937.484583,9938.488417,9939.482167,9940.481042,9941.492667,9942.485917,9943.487458,9944.45925,9945.485167,9946.491875,9947.484125,9948.464458,9949.465708,9950.482542,9951.489167,9952.486375,9953.461542,9954.482542,9955.486083,9956.48825,9957.4855,9958.484542,9959.46625,9960.492917,9961.486458,9962.488583,9963.461,9964.495208,9965.487958,9966.478167,9967.491042,9968.486375,9969.486958,9970.485083,9971.488292,9972.487458,9973.487125,9974.474458,9975.470125,9976.478417,9977.46725,9978.473042,9979.499708,9980.48825,9981.4685,9982.475875,9983.405708,9984.487042,9985.467,9986.506417,9987.458167,9988.341792,9989.426208,9990.366458,9991.362042,9992.4945,9993.439958,9994.377792,9995.406375,9996.485792,9997.471417,9998.493875,9999.494,10000.498292,10001.493792,10002.492833,10003.500042,10004.493875,10005.50175,10006.491667,10007.502333,10008.496042,10009.499333,10010.503083,10011.497083,10012.500167,10013.496417,10014.474917,10015.504667,10016.49625,10017.474083,10018.482292,10019.515708,10020.495333,10021.484708,10022.507667,10023.500917,10024.503625,10025.497667,10026.499292,10027.499667,10028.484042,10029.499875,10030.507958,10031.49925,10032.506667,10033.504167,10034.497042,10035.51125,10036.504333,10037.499458,10038.507208,10039.503542,10040.505708,10041.502125,10042.500667,10043.481917,10044.505167,10045.503583,10046.501792,10047.504875,10048.507708,10049.511708,10050.481167,10051.505667,10052.51,10053.502,10054.469167,10055.509833,10056.377208,10057.503917,10058.487583,10059.408417,10060.506,10061.478625,10062.482875,10063.481125,10064.46475,10065.498667,10066.508167,10067.486083,10068.529958,10069.504083,10070.514042,10071.485875,10072.495833,10073.489958,10074.512167,10075.512917,10076.50975,10077.518083,10078.505833,10079.513083,10080.50975,10081.492125,10082.495958,10083.489292,10084.515917,10085.511292,10086.519458,10087.516542,10088.519667,10089.494083,10090.496042,10091.524292,10092.521083,10093.51075,10094.520458,10095.514,10096.522167,10097.513292,10098.519,10099.517208,10100.519792,10101.517375,10102.52625,10103.498125,10104.519667,10105.523583,10106.516417,10107.522,10108.521458,10109.516292,10110.521042,10111.519958,10112.518042,10113.522167,10114.522833,10115.521167,10116.52225,10117.51375,10118.525625,10119.517167,10120.51975,10121.520708,10122.520042,10123.499625,10124.522208,10125.520417,10126.521958,10127.531417,10128.521583,10129.52175,10130.518875,10131.522042,10132.521458,10133.526292,10134.519167,10135.496917,10136.617208,10137.863417,10138.794,10139.825333,10140.794333,10141.805875,10142.783333,10143.8155,10144.708917,10145.834,10146.665708,10147.87125,10148.801083,10149.839625,10150.829542,10151.838583,10152.833833,10153.837083,10154.84125,10155.813833,10156.708792,10157.878375,10158.7555,10159.865958,10160.824875,10161.84275,10162.843,10163.813083,10164.830208,10165.81725,10166.843833,10167.845667,10168.838792,10169.84925,10170.84375,10171.842292,10172.842583,10173.852417,10174.787833,10175.859417,10176.81375,10177.855042,10178.843958,10179.846583,10180.849125,10181.846875,10182.848625,10183.842667,10184.849208,10185.825208,10186.851667,10187.842208,10188.852917,10189.848125,10190.846333,10191.8475,10192.856083,10193.844667,10194.828083,10195.831083,10196.852917,10197.843833,10198.85175,10199.846583,10200.848083,10201.847833,10202.845917,10203.845875,10204.846708,10205.852958,10206.841292,10207.8475,10208.856875,10209.853375,10210.834917,10211.857333,10212.850375,10213.84925,10214.849167,10215.850458,10216.846,10217.850708,10218.83325,10219.837792,10220.85225,10221.848667,10222.855792,10223.854417,10224.853875,10225.851125,10226.75,10227.847042,10228.825042,10229.861125,10230.838417,10231.708083,10232.878667,10233.845167,10234.832542,10235.771583,10236.698167,10237.873542,10238.829542,10239.83925,10240.859458,10241.862958,10242.852833,10243.860958,10244.860042,10245.857417,10246.833083,10247.852917,10248.862292,10249.865708,10250.829292,10251.842375,10252.862125,10253.8265,10254.8445,10255.866875,10256.770167,10257.847708,10258.868167,10259.857917,10260.876417,10261.862583,10262.840917,10263.868167,10264.862,10265.841042,10266.866708,10267.839292,10268.873167,10269.864542,10270.861708,10271.865667,10272.85875,10273.864667,10274.868292,10275.865667,10276.866625,10277.851458,10278.840083,10279.871542,10280.865125,10281.844167,10282.862625,10283.864542,10284.865583,10285.874833,10286.865625,10287.865208,10288.862667,10289.867417,10290.869667,10291.867333,10292.873667,10293.848833,10294.869875,10295.84325,10296.8695,10297.85275,10298.857833,10299.868833,10300.868833,10301.865708,10302.87475,10303.871583,10304.865792,10305.848458,10306.687083,10307.917625,10308.862375,10309.870208,10310.876458,10311.86675,10312.87275,10313.874042,10314.867833,10315.869083,10316.874958,10317.868,10318.876375,10319.877167,10320.8755,10321.87325,10322.865167,10323.878833,10324.874,10325.869,10326.692875,10327.92075,10328.859583,10329.854625,10330.819917,10331.692167,10332.916,10333.843583,10334.75425,10335.83575,10336.815958,10337.850042,10338.745917,10339.881458,10340.850875,10341.858542,10342.822125,10343.876292,10344.83825,10345.859208,10346.88775,10347.875875,10348.881167,10349.862375,10350.856792,10351.860083,10352.883208,10353.865,10354.884083,10355.886292,10356.853708,10357.879958,10358.887083,10359.891375,10360.882167,10361.88325,10362.88875,10363.877,10364.885917,10365.883875,10366.887083,10367.882167,10368.884958,10369.883,10370.885958,10371.883667,10372.888667,10373.89875,10374.886167,10375.880833,10376.890542,10377.884375,10378.885875,10379.889042,10380.865083,10381.901,10382.890917,10383.861333,10384.890125,10385.884708,10386.86775,10387.868458,10388.897167,10389.87525,10390.895458,10391.87125,10392.9035,10393.887417,10394.892542,10395.888542,10396.886708,10397.893125,10398.89575,10399.886292,10400.894958,10401.891417,10402.89325,10403.896333,10404.894167,10405.893583,10406.896917,10407.878875,10408.893083,10409.894667,10410.894958,10411.891792,10412.893542,10413.894958,10414.894583,10415.895667,10416.889167,10417.895,10418.889167,10419.89725,10420.894,10421.894667,10422.892542,10423.8985,10424.889333,10425.89525,10426.890042,10427.896833,10428.893917,10429.898,10430.897667,10431.897417,10432.886792,10433.899625,10434.892292,10435.894958,10436.895375,10437.900042,10438.899042,10439.898667,10440.899167,10441.895625,10442.894792,10443.897917,10444.897333,10445.901042,10446.901375,10447.892292,10448.8985,10449.903167,10450.894875,10451.9025,10452.897208,10453.903542,10454.903375,10455.899083,10456.901042,10457.895958,10458.895542,10459.903125,10460.898375,10461.900167,10462.900958,10463.901833,10464.895333,10465.902042,10466.893458,10467.908125,10468.894417,10469.905167,10470.898542,10471.904667,10472.897375,10473.907125,10474.906208,10475.877375,10476.862,10477.90275,10479.018042,10480.128292,10481.114958,10482.060167,10483.005667,10484.14175,10485.080125,10485.97175,10487.134917,10488.102542,10488.974792,10490.081125,10491.00475,10492.251917,10493.201833,10494.225125,10495.225958,10496.222917,10497.217083,10498.223583,10499.223167,10500.218958,10501.221917,10502.221167,10503.221958,10504.222167,10505.227042,10506.220167,10507.227917,10508.219083,10509.225917,10510.222625,10511.226375,10512.223542,10513.220792,10514.225667,10515.22425,10516.222042,10517.223333,10518.230833,10519.22375,10520.228833,10521.221042,10522.229042,10523.220375,10524.232042,10525.217625,10526.233542,10527.224708,10528.227167,10529.227333,10530.228125,10531.22375,10532.229667,10533.225583,10534.2285,10535.227125,10536.226542,10537.227833,10538.226875,10539.225792,10540.228458,10541.229583,10542.228667,10543.228583,10544.226833,10545.230625,10546.227,10547.22625,10548.234083,10549.224292,10550.234583,10551.233167,10552.211083,10553.21625,10554.242625,10555.218208,10556.2395,10557.23475,10558.236708,10559.232417,10560.237542,10561.233958,10562.235917,10563.233417,10564.238583,10565.235208,10566.238333,10567.233833,10568.239583,10569.23575,10570.238375,10571.231417,10572.242125,10573.229292,10574.243083,10575.24075,10576.234333,10577.236208,10578.2425,10579.23425,10580.238833,10581.237083,10582.218167,10583.258458,10584.222375,10585.222708,10586.245083,10587.234542,10588.243125,10589.235708,10590.242833,10591.23375,10592.238917,10593.175125,10594.256667,10595.213167,10596.243917,10597.157875,10598.206208,10599.246708,10600.200583,10601.080958,10602.23975,10603.203417,10604.077667,10605.275417,10606.230375,10607.245958,10608.23975,10609.239542,10610.239917,10611.2405,10612.247917,10613.241042,10614.242667,10615.241125,10616.243625,10617.244,10618.249125,10619.23675,10620.245292,10621.2175,10622.250583,10623.246917,10624.245542,10625.225792,10626.248583,10627.245958,10628.235542,10629.224167,10630.226917,10631.254208,10632.243167,10633.227458,10634.25275,10635.2465,10636.248042,10637.252167,10638.246083,10639.252667,10640.248833,10641.251,10642.247667,10643.252625,10644.253625,10645.247833,10646.254458,10647.247917,10648.249042,10649.250792,10650.253125,10651.251625,10652.248667,10653.255958,10654.243,10655.258333,10656.246292,10657.247708,10658.254958,10659.251958,10660.2535,10661.249375,10662.248625,10663.256958,10664.253458,10665.250375,10666.235958,10667.256667,10668.25675,10669.264208,10670.254833,10671.252,10672.253167,10673.25075,10674.258958,10675.248083,10676.257042,10677.254625,10678.257708,10679.254083,10680.258667,10681.252833,10682.253625,10683.25,10684.255958,10685.252625,10686.257667,10687.252458,10688.255667,10689.252042,10690.258375,10691.249583,10692.232708,10693.246708,10694.234583,10695.243208,10696.257917,10697.254208,10698.259167,10699.263833,10700.263208,10701.251125,10702.2565,10703.260208,10704.258417,10705.252875,10706.25425,10707.251708,10708.253667,10709.094833,10710.29375,10711.087417,10712.303167,10713.249208,10714.267667,10715.25425,10716.256625,10717.255917,10718.264875,10719.258083,10720.238125,10721.239667,10722.244,10723.262333,10724.265583,10725.257833,10726.266542,10727.257,10728.265125,10729.257417,10730.264375,10731.236458,10732.275208,10733.250417,10734.269542,10735.261042,10736.266542,10737.260667,10738.263333,10739.147625,10740.254917,10741.154833,10742.2875,10743.239208,10744.250833,10745.226333,10746.171542,10747.282875,10748.066208,10749.287875,10750.198167,10751.261958,10752.255625,10753.243708,10754.249042,10755.273167,10756.265333,10757.267458,10758.260417,10759.272042,10760.263208,10761.26375,10762.263625,10763.265833,10764.280333,10765.25825,10766.256833,10767.26525,10768.263875,10769.264083,10770.266458,10771.265833,10772.26325,10773.266208,10774.264125,10775.268667,10776.264833,10777.270417,10778.26825,10779.266333,10780.265625,10781.265208,10782.268333,10783.26425,10784.266792,10785.266958,10786.270625,10787.264333,10788.271667,10789.2795,10790.265417,10791.272917,10792.268625,10793.267792,10794.26975,10795.274083,10796.255625,10797.252042,10798.247667,10799.250333,10800.263375,10801.253208,10802.262875,10803.251917,10804.251625,10805.257833,10806.275875,10807.277125,10808.277125,10809.276417,10810.279083,10811.278667,10812.2755,10813.276583,10814.275167,10815.276917,10816.281625,10817.280583,10818.282708,10819.283167,10820.276167,10821.277833,10822.287792,10823.282958,10824.281417,10825.281542,10826.270333,10827.27275,10828.220875,10829.163208,10830.315875,10831.295667,10832.467667,10833.500417,10834.735042,10835.524,10836.775917,10837.699625,10838.723458,10839.722,10840.733167,10841.724625,10842.702042,10843.718375,10844.747083,10845.720875,10846.732708,10847.746417,10848.753833,10849.741083,10850.743833,10851.73,10852.751792,10853.722917,10854.755667,10855.744542,10856.74425,10857.75075,10858.748458,10859.752792,10860.727625,10861.765125,10862.748292,10863.754,10864.754917,10865.750792,10866.756917,10867.757625,10868.756042,10869.757,10870.751083,10871.754167,10872.758458,10873.755125,10874.752625,10875.749417,10876.756875,10877.729792,10878.762667,10879.750625,10880.731125,10881.740208,10882.765917,10883.731917,10884.763875,10885.748458,10886.7335,10887.738417,10888.759833,10889.755292,10890.764083,10891.751792,10892.761042,10893.761833,10894.757083,10895.761292,10896.751083,10897.737917,10898.738917,10899.754708,10900.760375,10901.761833,10902.759,10903.754542,10904.764958,10905.762583,10906.757917,10907.7575,10908.763875,10909.756667,10910.76575,10911.763125,10912.758542,10913.760667,10914.764417,10915.765167,10916.760792,10917.762458,10918.766167,10919.764042,10920.766042,10921.768625,10922.76375,10923.760458,10924.769208,10925.7605,10926.759625,10927.759917,10928.767417,10929.761625,10930.764792,10931.76125,10932.762458,10933.760958,10934.740417,10935.767167,10936.775583,10937.761708,10938.745292,10939.74325,10940.719917,10941.748667,10942.736833,10943.722833,10944.761125,10945.597292,10946.7725,10947.612208,10948.806667,10949.754667,10950.766583,10951.769458,10952.768375,10953.767375,10954.768125,10955.763667,10956.767667,10957.766042,10958.769875,10959.767167,10960.770042,10961.772375,10962.774125,10963.765083,10964.7735,10965.775458,10966.768125,10967.771167,10968.770958,10969.774125,10970.774167,10971.77525,10972.768917,10973.775083,10974.774583,10975.770167,10976.771125,10977.750042,10978.74525,10979.774,10980.751542,10981.773542,10982.761333,10983.77075,10984.770125,10985.779417,10986.768542,10987.768417,10988.771083,10989.777042,10990.772458,10991.776042,10992.775042,10993.776958,10994.771333,10995.774792,10996.77575,10997.776583,10998.773708,10999.774125,11000.77525,11001.77525,11002.758333,11003.754,11004.775125,11005.777542,11006.758292,11007.782292,11008.769583,11009.779333,11010.77025,11011.781333,11012.778667,11013.774667,11014.783417,11015.776417,11016.787583,11017.754167,11018.761333,11019.776708,11020.786042,11021.777667,11022.783042,11023.762167,11024.76325,11025.773417,11026.781667,11027.783208,11028.7755,11029.78575,11030.782375,11031.779583,11032.789167,11033.781083,11034.788125,11035.781958,11036.788583,11037.787833,11038.780875,11039.789583,11040.787708,11041.787625,11042.78125,11043.784125,11044.785958,11045.788458,11046.781917,11047.792042,11048.787708,11049.78925,11050.781417,11051.787792,11052.788,11053.788625,11054.782208,11055.771125,11056.788083,11057.782542,11058.769917,11059.7875,11060.619458,11061.629792,11062.597667,11063.658875,11064.635917,11065.799125,11066.678208,11067.743667,11068.622917,11069.814833,11070.659625,11071.809792,11072.780333,11073.790667,11074.773292,11075.76975,11076.774458,11077.767792,11078.791667,11079.78475,11080.789708,11081.793167,11082.783458,11083.79,11084.794625,11085.7855,11086.788833,11087.796042,11088.790167,11089.795917,11090.788875,11091.789833,11092.795208,11093.792833,11094.79,11095.797417,11096.790917,11097.797083,11098.7965,11099.795375,11100.800042,11101.78975,11102.800125,11103.789125,11104.79475,11105.795792,11106.7925,11107.770375,11108.804,11109.792792,11110.790083,11111.796875,11112.793583,11113.800667,11114.788125,11115.795042,11116.7985,11117.795875,11118.792292,11119.796,11120.795083,11121.798333,11122.80025,11123.795125,11124.798333,11125.791375,11126.804542,11127.79075,11128.798833,11129.80375,11130.793583,11131.79375,11132.798375,11133.795833,11134.796583,11135.796542,11136.803333,11137.800667,11138.803208,11139.790833,11140.77525,11141.8175,11142.788583,11143.79225,11144.802792,11145.796,11146.78175,11147.800833,11148.778792,11149.80275,11150.795958,11151.800292,11152.797583,11153.804,11154.796,11155.795917,11156.806042,11157.799167,11158.804333,11159.798625,11160.800708,11161.759958,11162.808542,11163.796792,11164.740292,11165.797542,11166.61325,11167.844,11168.647708,11169.830042,11170.791833,11171.798417,11172.778958,11173.807667,11174.798917,11175.801667,11176.799917,11177.804875,11178.804,11179.799125,11180.808667,11181.799833,11182.804333,11183.8085,11184.806208,11185.806333,11186.806667,11187.79775,11188.810917,11189.807333,11190.806417,11191.80425,11192.802458,11193.810167,11194.8075,11195.801667,11196.80275,11197.802708,11198.809667,11199.802125,11200.803167,11201.811208,11202.809542,11203.805083,11204.792375,11205.788125,11206.808417,11207.784,11208.80275,11209.81375,11210.808667,11211.802542,11212.811958,11213.806208,11214.809167,11215.814042,11216.803458,11217.808417,11218.805167,11219.813917,11220.813083,11221.809542,11222.813042,11223.811875,11224.805792,11225.810458,11226.811333,11227.815875,11228.808667,11229.807292,11230.810875,11231.812125,11232.806708,11233.809208,11234.810667,11235.810167,11236.809583,11237.807625,11238.808958,11239.8095,11240.807083,11241.808875,11242.811,11243.810167,11244.809542,11245.811708,11246.809583,11247.809958,11248.809875,11249.814667,11250.812458,11251.811375,11252.809958,11253.812375,11254.813167,11255.809167,11256.8115,11257.814333,11258.818542,11259.796208,11260.814083,11261.798417,11262.8265,11263.793083,11264.828958,11265.805542,11266.817875,11267.812958,11268.791375,11269.691958,11270.846042,11271.806625,11272.795958,11273.798667,11274.822,11275.814917,11276.729292,11277.819875,11278.807083,11280.082083,11281.354125,11282.265125,11283.098333,11284.358958,11285.25025,11286.285125,11287.298833,11288.295875,11289.27675,11290.280333,11291.276375,11292.280458,11293.315208,11294.292917,11295.275958,11296.305542,11297.304458,11298.301958,11299.299,11300.306542,11301.297375,11302.299875,11303.304875,11304.298833,11305.301917,11306.306792,11307.30675,11308.3,11309.301083,11310.302708,11311.301083,11312.299333,11313.299417,11314.301042,11315.300625,11316.301458,11317.302167,11318.303708,11319.302208,11320.299375,11321.308333,11322.315667,11323.303625,11324.313,11325.309167,11326.28675,11327.288583,11328.313083,11329.306375,11330.312167,11331.307833,11332.312958,11333.304042,11334.308667,11335.316208,11336.311167,11337.310833,11338.315333,11339.311,11340.319292,11341.320167,11342.301958,11343.2895,11344.309958,11345.309,11346.295333,11347.314542,11348.311125,11349.315875,11350.314,11351.312875,11352.316042,11353.286583,11354.319583,11355.3305,11356.303875,11357.316125,11358.297833,11359.298958,11360.33425,11361.145333,11362.264458,11363.290625,11364.305583,11365.289375,11366.192583,11367.206625,11368.180625,11369.213542,11370.29875,11371.231208,11372.320625,11373.2855,11374.268125,11375.302583,11376.241708,11377.31025,11378.329125,11379.276583,11380.311917,11381.216792,11382.347375,11383.313167,11384.326625,11385.319083,11386.330917,11387.311542,11388.325958,11389.322833,11390.329417,11391.324,11392.309375,11393.192167,11394.337542,11395.264667,11396.275625,11397.317083,11398.301208,11399.326625,11400.195167,11401.336458,11402.315917,11403.186292,11404.214917,11405.326,11406.293292,11407.336292,11408.299708,11409.307083,11410.332833,11411.320542,11412.33,11413.329792,11414.311792,11415.335833,11416.327417,11417.327958,11418.3305,11419.345292,11420.326958,11421.304375,11422.330583,11423.324708,11424.331167,11425.326958,11426.3305,11427.32725,11428.331833,11429.331083,11430.327958,11431.339875,11432.330833,11433.334042,11434.329125,11435.338,11436.332,11437.334042,11438.336417,11439.330708,11440.330292,11441.340958,11442.332,11443.329667,11444.340458,11445.33525,11446.332875,11447.335375,11448.333125,11449.333458,11450.339458,11451.328375,11452.33875,11453.335292,11454.338,11455.333167,11456.331958,11457.333,11458.338542,11459.332625,11460.340417,11461.334708,11462.334167,11463.332583,11464.335542,11465.338417,11466.338708,11467.33525,11468.341875,11469.338917,11470.335333,11471.33575,11472.338542,11473.334833,11474.340708,11475.33475,11476.34325,11477.336708,11478.342375,11479.338917,11480.335083,11481.338167,11482.341333,11483.339333,11484.336333,11485.339208,11486.339,11487.340125,11488.338333,11489.3285,11490.34575,11491.33825,11492.343458,11493.34425,11494.323417,11495.267583,11496.199208,11497.160833,11498.172958,11499.240583,11500.207167,11501.190708,11502.27325,11503.191042,11504.362417,11505.299167,11506.332208,11507.185875,11508.357333,11509.20925,11510.353333,11511.161042,11512.389333,11513.243292,11514.306708,11515.148292,11516.220042,11517.364375,11518.346875,11519.349667,11520.3515,11521.340125,11522.327,11523.349208,11524.355583,11525.343042,11526.348583,11527.344,11528.345958,11529.346167,11530.348583,11531.348,11532.350125,11533.345542,11534.346583,11535.349292,11536.352792,11537.335833,11538.351917,11539.3455,11540.344708,11541.34625,11542.351208,11543.196167,11544.367375,11545.147292,11546.227083,11547.354125,11548.337542,11549.189583,11550.230458,11551.351,11552.211625,11553.292542,11554.351167,11555.350583,11556.354125,11557.34025,11558.356958,11559.352167,11560.354917,11561.353542,11562.356917,11563.348958,11564.357667,11565.354542,11566.3545,11567.35675,11568.356417,11569.36175,11570.352458,11571.351125,11572.35975,11573.349833,11574.358542,11575.351042,11576.357375,11577.355042,11578.35525,11579.353958,11580.35425,11581.348792,11582.228167,11583.368542,11584.312542,11585.343292,11586.297917,11587.345125,11588.284292,11589.346917,11590.334542,11591.338125,11592.317167,11593.231542,11594.252125,11595.156458,11596.397208,11597.346167,11598.362458,11599.352458,11600.357917,11601.355,11602.36325,11603.35825,11604.358083,11605.359625,11606.355,11607.363375,11608.353125,11609.358833,11610.356625,11611.362667,11612.360333,11613.35825,11614.355542,11615.359083,11616.36225,11617.356875,11618.36675,11619.362458,11620.363625,11621.361042,11622.359083,11623.360667,11624.364083,11625.361458,11626.229792,11627.212,11628.215708,11629.198708,11630.396792,11631.232792,11632.2465,11633.243042,11634.174208,11635.372625,11636.17375,11637.201458,11638.369833,11639.332792,11640.197792,11641.274417,11642.24475,11643.382042,11644.358625,11645.364875,11646.363125,11647.363292,11648.360542,11649.3625,11650.362917,11651.364625,11652.365208,11653.367167,11654.361125,11655.361708,11656.365375,11657.368333,11658.36575,11659.362042,11660.366667,11661.365208,11662.367583,11663.360583,11664.369458,11665.365375,11666.373167,11667.365292,11668.365375,11669.362333,11670.36525,11671.364333,11672.367167,11673.364708,11674.350625,11675.175208,11676.201375,11677.307417,11678.3385,11679.368458,11680.271667,11681.361042,11682.266833,11683.383625,11684.336125,11685.268,11686.366667,11687.466667,11688.494542,11689.484125,11690.486667,11691.488125,11692.490542,11693.485958,11694.492792,11695.490625,11696.484167,11697.485708,11698.487333,11699.488,11700.494917,11701.484708,11702.4905,11703.492292,11704.484458,11705.490083,11706.489167,11707.487708,11708.493417,11709.489292,11710.498917,11711.485042,11712.495958,11713.490542,11714.491625,11715.488292,11716.49,11717.310458,11718.5025,11719.349375,11720.497375,11721.287583,11722.509583,11723.416542,11724.303958,11725.523125,11726.454542,11727.470958,11728.458167,11729.477417,11730.493792,11731.476917,11732.34425,11733.532958,11734.463083,11735.500083,11736.488417,11737.491125,11738.497875,11739.486958,11740.493417,11741.49425,11742.491708,11743.495667,11744.493083,11745.495417,11746.491042,11747.4925,11748.500083,11749.491125,11750.496708,11751.489583,11752.495125,11753.492083,11754.472167,11755.503167,11756.48175,11757.502375,11758.490458,11759.500542,11760.493708,11761.496792,11762.492833,11763.407958,11764.320583,11765.464458,11766.349792,11767.507708,11768.323917,11769.388833,11770.397042,11771.5015,11772.326083,11773.336958,11774.316542,11775.521875,11776.327417,11777.535833,11778.424,11779.40325,11780.461625,11781.505417,11782.496875,11783.496958,11784.494542,11785.500917,11786.499125,11787.497958,11788.499417,11789.498917,11790.497417,11791.504958,11792.494875,11793.505375,11794.497875,11795.498542,11796.500625,11797.497208,11798.500667,11799.505167,11800.496167,11801.503167,11802.49825,11803.502917,11804.497875,11805.504,11806.506458,11807.498542,11808.477083,11809.340292,11810.451042,11811.4805,11812.369667,11813.474,11814.335,11815.397708,11816.308208,11817.356042,11818.533167,11819.962458,11821.209583,11822.164708,11823.043875,11824.189333,11825.176417,11826.1815,11827.184667,11828.185458,11829.183083,11830.179708,11831.192583,11832.179417,11833.179625,11834.18825,11835.181708,11836.187917,11837.184833,11838.187042,11839.185208,11840.184708,11841.182125,11842.188625,11843.182,11844.18425,11845.188042,11846.180875,11847.185458,11848.180292,11849.185417,11850.159208,11851.177792,11852.044167,11853.209,11855.902667,11856.973917,11857.952667,11859.15275,11860.130917,11861.065792,11862.112208,11864.949167,11866.229833,11867.140333,11868.181125,11869.163083,11870.148917,11871.171208,11872.175125,11873.165208,11874.183583,11875.164583,11876.17075,11877.166542,11878.171792,11879.168958,11880.17875,11881.162208,11882.169792,11883.175833,11884.1675,11885.16725,11886.172083,11887.171,11888.168042,11889.1675,11890.170875,11891.020458,11892.198625,11893.114667,11894.083292,11895.2455,11896.267917,11897.159875,11898.327542,11899.611583,11901.757167,11903.016208,11903.828542,11904.995667,11905.954792,11906.965292,11907.977,11908.973208,11909.972917,11910.974625,11911.975292,11912.979042,11913.975375,11914.975083,11915.977208,11916.979333,11917.97525,11918.980542,11919.976542,11920.978458,11921.976125,11922.976125,11923.986292,11924.977375,11925.977917,11926.977667,11927.955875,11928.988583,11929.974208,11930.994083,11936.69,11941.1685,11942.196458,11943.41525,11944.360667,11945.376,11946.378792,11947.372375,11948.374667,11949.387917,11950.386333,11951.387,11952.390333,11953.386083,11954.386667,11955.387458,11956.387125,11957.38975,11958.387167,11959.388792,11960.387375,11961.388458,11962.387958,11963.389333,11964.387417,11965.388,11966.388083,11967.39,11968.3875,11969.255292,11970.265542,11971.203583,11972.313875,11973.377083,11974.596875,11978.252375,11979.417958,11980.328375,11981.4785,11983.049583,11984.299375,11985.238917,11986.273208,11987.267167,11988.268208,11989.265625,11990.26775,11991.271583,11992.265,11993.26725,11994.250458,11995.250042,11996.268417,11997.266917,11998.268875,11999.272333,12000.267292,12001.274167,12002.26675,12003.271208,12004.270208,12005.27425,12006.266125,12007.248708,12008.275208,12009.271792,12010.271375,12011.253958,12017.891292,12022.590417,12023.846792,12024.783667,12025.801375,12026.795583,12027.797542,12028.7905,12029.793625,12030.796375,12031.8135,12032.806333,12033.812,12034.808208,12035.812292,12036.8125,12037.80925,12038.810458,12039.815208,12040.809917,12041.810208,12042.808333,12043.811125,12044.813417,12045.816667,12046.809958,12047.808542,12048.810042,12049.819792,12050.786333,12051.811083,12052.803875,12053.818542,12054.811625,12055.813708,12056.664625,12057.816542,12058.760333,12059.803375,12060.718708,12062.055667,12063.506667,12064.639292,12065.720583,12066.628833,12067.69225,12068.967458,12069.897,12070.916167,12071.892208,12072.916375,12073.908625,12074.914625,12075.909625,12076.914583,12077.909333,12078.914333,12079.907,12080.913708,12081.911167,12082.911708,12083.911625,12084.909792,12085.923917,12086.912417,12087.915583,12088.911917,12089.915458,12090.91725,12091.910458,12092.9165,12093.911583,12094.919375,12095.886583,12096.897625,12097.917833,12098.914625,12099.911667,12100.916958,12101.915625,12103.23,12104.473833,12105.441583,12106.259458,12107.460667,12108.3595,12113.281292,12114.533667,12115.474167,12116.485417,12117.485,12118.501333,12119.500917,12120.497167,12121.500333,12122.500208,12123.502083,12124.496833,12125.497292,12126.501792,12127.50125,12128.501458,12129.505208,12130.497417,12131.5005,12132.502458,12133.499625,12134.500333,12135.501333,12136.502458,12137.500917,12138.50075,12139.501125,12140.501667,12141.500875,12142.482167,12145.5255,12147.76625,12149.012583,12149.954333,12150.8585,12151.846667,12152.998708,12153.967167,12154.972042,12155.973083,12156.973917,12157.970417,12158.973125,12159.97225,12160.96475,12161.9865,12162.984333,12163.987,12164.986125,12165.983792,12166.984875,12167.986417,12168.985208,12169.986125,12170.984792,12171.986792,12172.987,12173.986833,12174.987167,12175.985292,12176.987792,12177.987583,12178.993208,12179.966667,12181.012958,12181.984917,12182.97425,12183.991083,12184.98875,12185.991,12186.973875,12187.994958,12188.980875,12189.968125,12190.996333,12191.988542,12192.991333,12193.995792,12194.995083,12195.989125,12196.995667,12197.987792,12198.919708,12200.004083,12200.985333,12201.998,12202.990917,12203.989042,12204.988917,12205.990333,12206.994583,12207.991042,12208.99475,12209.881417,12211.020625,12211.987667,12212.995417,12213.990333,12214.991875,12215.995292,12216.989667,12217.99725,12218.994042,12219.997583,12220.992458,12221.990625,12222.997292,12223.997,12224.992292,12225.999542,12226.996417,12227.941917,12229.008125,12229.991417,12230.997792,12231.934167,12233.007833,12233.998,12234.9925,12235.997625,12236.996333,12237.992583,12239.000917,12239.992625,12241.001042,12241.993667,12242.999292,12243.998042,12244.997833,12245.997125,12246.999042,12247.996792,12248.99625,12249.978833,12250.998833,12251.977625,12252.979708,12253.989583,12254.998958,12255.999833,12256.840083,12257.803625,12259.078792,12259.883,12268.375417,12269.834167,12271.094917,12272.023167,12273.043042,12274.0375,12275.03875,12276.041542,12277.037875,12278.039208,12279.038625,12280.056292,12281.051333,12282.052917,12283.053833,12284.038667,12285.040917,12286.056333,12287.036833,12288.06,12289.0525,12290.037708,12291.0375,12292.035458,12293.063833,12294.053333,12295.032583,12296.067042,12297.051417,12298.065375,12299.054375,12300.05875,12301.057542,12302.055625,12303.060292,12304.056083,12305.056875,12306.056792,12307.027167,12308.066333,12309.056083,12309.991833,12310.901,12312.085583,12313.029875,12314.065875,12315.102042,12321.372083,12322.625875,12323.563667,12324.546,12325.577958,12326.5765,12327.571583,12328.580167,12329.577708,12330.580708,12331.601583,12332.585667,12333.591917,12334.586875,12335.59275,12336.590083,12337.591458,12338.593125,12339.589958,12340.592292,12341.59525,12342.591792,12343.582667,12344.594792,12345.592208,12346.592833,12347.592708,12348.5595,12349.603375,12350.586333,12351.593833,12352.569,12353.577292,12354.580917,12355.601,12356.603417,12357.591167,12358.573292,12359.581292,12360.592958,12361.598417,12362.592208,12363.599667,12364.593792,12365.597,12366.594083,12367.60125,12368.593792,12369.602375,12370.593792,12371.597875,12372.596292,12373.59725,12374.612625,12375.589375,12376.595708,12377.583625,12378.601125,12379.596083,12380.598083,12381.596708,12382.598375,12383.603792,12384.5965,12385.582583,12386.608917,12387.595833,12388.605458,12389.5995,12390.5685,12391.605125,12392.602125,12393.6045,12394.5975,12395.602708,12396.605792,12397.597208,12398.606083,12399.602792,12400.600458,12401.563583,12402.586833,12403.61,12404.603833,12405.5985,12406.60125,12407.5975,12408.601542,12409.598042,12410.600542,12411.603125,12412.60075,12413.604583,12414.599208,12415.603208,12416.609375,12417.600625,12418.582292,12419.608,12420.603,12421.6165,12422.6025,12423.617542,12424.597708,12425.606875,12426.600292,12427.588583,12428.609375,12429.598458,12430.606458,12431.60625,12432.606417,12433.604417,12434.604042,12435.602417,12436.609417,12437.604708,12438.603958,12439.604375,12440.603958,12441.61,12442.603583,12443.610083,12444.60625,12445.603583,12446.611208,12447.608833,12448.606583,12449.613417,12450.602042,12451.606625,12452.590333,12453.61425,12454.603458,12455.606792,12456.605833,12457.612208,12458.6095,12459.603667,12460.611875,12461.609625,12462.608208,12463.6115,12464.605417,12465.608292,12466.609958,12467.608208,12468.605583,12469.614417,12470.610417,12471.606708,12472.608708,12473.608083,12474.605625,12475.6085,12476.608917,12477.612,12478.6065,12479.612667,12480.615875,12481.612,12482.614792,12483.613292,12484.614625,12485.593333,12486.616375,12487.587667,12488.612083,12489.616125,12490.611,12491.61,12492.613917,12493.609042,12494.616292,12495.610458,12496.61525,12497.615042,12498.619542,12499.609667,12500.617333,12501.583792,12502.619875,12503.615083,12504.582,12505.625708,12506.608208,12507.617333,12508.609708,12509.615083,12510.613583,12511.618833,12512.611917,12513.614042,12514.610208,12515.615292,12516.618833,12517.613875,12518.612917,12519.619583,12520.612583,12521.613917,12522.615667,12523.619417,12524.618292,12525.615708,12526.61675,12527.614208,12528.593708,12529.621458,12530.613458,12531.614583,12532.618417,12533.613667,12534.616042,12535.620333,12536.620375,12537.616542,12538.620583,12539.616625,12540.619083,12541.612208,12542.615708,12543.622417,12544.620333,12545.620708,12546.616042,12547.617917,12548.622292,12549.614208,12550.595875,12551.638792,12552.584583,12553.635458,12554.612667,12555.619,12556.618125,12557.595417,12558.618083,12559.619333,12560.618167,12561.622542,12562.621917,12563.617792,12564.617417,12565.61925,12566.617333,12567.619792,12568.621792,12569.621292,12570.6225,12571.618917,12572.621125,12573.620875,12574.6235,12575.622625,12576.617917,12577.629917,12578.620125,12579.625167,12580.6265,12581.621208,12582.63,12583.621208,12584.627292,12585.629042,12586.628583,12587.623375,12588.629917,12589.621375,12590.625625,12591.630792,12592.623042,12593.6245,12594.626375,12595.629042,12596.630583,12597.626625,12598.624292,12599.625792,12600.622625,12601.626125,12602.64325,12603.625292,12604.625375,12605.627417,12606.624792,12607.630792,12608.625167,12609.626125,12610.624208,12611.630208,12612.632042,12613.630542,12614.623667,12615.629125,12616.631292,12617.607042,12618.648667,12619.625833,12620.610125,12621.633292,12622.634,12623.63025,12624.613708,12625.635625,12626.63225,12627.63125,12628.626958,12629.628417,12630.627542,12631.632458,12632.62925,12633.631208,12634.628417,12635.63,12636.628042,12637.636458,12638.629458,12639.63375,12640.629083,12641.631417,12642.632125,12643.6295,12644.631083,12645.630792,12646.634667,12647.628458,12648.636667,12649.632792,12650.634167,12651.632583,12652.638417,12653.632625,12654.640042,12655.63975,12656.633792,12657.640958,12658.631542,12659.6385,12660.640583,12661.636458,12662.61125,12663.649125,12664.629625,12665.638542,12666.636375,12667.63725,12668.64175,12669.636917,12670.542583,12671.6665,12672.633417,12673.63875,12674.637917,12675.637875,12676.640583,12677.638667,12678.635292,12679.63775,12680.644208,12681.635042,12682.642542,12683.634958,12684.639458,12685.635958,12686.637792,12687.63,12688.618458,12689.650333,12690.621875,12691.655208,12692.634292,12693.649458,12694.638458,12695.643292,12696.639125,12697.639708,12698.645,12699.640667,12700.644583,12701.637833,12702.623833,12703.6455,12704.637167,12705.640708,12706.638333,12707.647375,12708.644125,12709.640333,12710.643042,12711.643375,12712.640625,12713.643125,12714.644417,12715.646583,12716.609333,12717.649792,12718.640875,12719.6485,12720.647875,12721.640292,12722.648292,12723.646792,12724.648667,12725.643833,12726.639875,12727.648583,12728.643875,12729.647542,12730.644458,12731.643125,12732.650208,12733.643625,12734.644083,12735.647333,12736.64975,12737.648333,12738.647708,12739.642917,12740.649042,12741.643542,12742.645375,12743.646667,12744.649583,12745.651292,12746.649083,12747.644167,12748.644208,12749.646875,12750.64775,12751.625458,12752.651542,12753.650125,12754.650833,12755.645042,12756.647625,12757.651875,12758.647375,12759.627625,12760.652583,12761.649292,12762.62575,12763.656,12764.639958,12765.659167,12766.645083,12767.656125,12768.645917,12769.654833,12770.646792,12771.652792,12772.650708,12773.650042,12774.652,12775.653917,12776.648167,12777.650917,12778.65175,12779.655542,12780.650125,12781.648,12782.651875,12783.653833,12784.6485,12785.656792,12786.635,12787.654542,12788.655958,12789.652167,12790.651875,12791.65475,12792.654375,12793.624542,12794.659458,12795.650667,12796.656125,12797.649,12798.65925,12799.649542,12800.650458,12801.65975,12802.654875,12803.658125,12804.658292,12805.614958,12806.663375,12807.652917,12808.655,12809.656042,12810.651917,12811.66125,12812.657792,12813.652,12814.655333,12815.659917,12816.652708,12817.653667,12818.659167,12819.656417,12820.660958,12821.651792,12822.657583,12823.660875,12824.659917,12825.657917,12826.658917,12827.656083,12828.661917,12829.653875,12830.660375,12831.656917,12832.655125,12833.658333,12834.656667,12835.658625,12836.659292,12837.663667,12838.660583,12839.66225,12840.661417,12841.65725,12842.659625,12843.662417,12844.660208,12845.65675,12846.663625,12847.662125,12848.660708,12849.66125,12850.655833,12851.665875,12852.659542,12853.66625,12854.656917,12855.663292,12856.658708,12857.665667,12858.658083,12859.667,12860.65775,12861.665333,12862.658167,12863.664458,12864.665833,12865.665792,12866.659,12867.664292,12868.666583,12869.663417,12870.66225,12871.666708,12872.660417,12873.666458,12874.65825,12875.666042,12876.667958,12877.662042,12878.667917,12879.668,12880.663417,12881.664083,12882.664042,12883.669083,12884.662417,12885.66775,12886.662375,12887.666292,12888.66975,12889.667583,12890.666375,12891.668625,12892.668875,12893.649542,12894.673833,12895.661542,12896.672292,12897.6695,12898.666875,12899.665167,12900.666292,12901.672083,12902.663875,12903.670708,12904.670417,12905.671458,12906.665167,12907.670417,12908.665833,12909.664208,12910.667583,12911.666333,12912.667917,12913.666917,12914.666458,12915.667083,12916.667125,12917.669958,12918.666583,12919.670667,12920.664583,12921.668125,12922.671542,12923.672333,12924.668958,12925.668125,12926.673917,12927.668333,12928.658583,12929.675,12930.667042,12931.669208,12932.676042,12933.666542,12934.676542,12935.667625,12936.674833,12937.673083,12938.674125,12939.671125,12940.670333,12941.672708,12942.677875,12943.6745,12944.671375,12945.675333,12946.666833,12947.680083,12948.6545,12949.678292,12950.668833,12951.675542,12952.669417,12953.673417,12954.674208,12955.673833,12956.671167,12957.675833,12958.674208,12959.680042,12960.670625,12961.676417,12962.67075,12963.679667,12964.677,12965.67475,12966.671083,12967.678375,12968.672792,12969.676583,12970.674,12971.675917,12972.676583,12973.676167,12974.690708,12975.677333,12976.623208,12977.694125,12978.668292,12979.680292,12980.679917,12981.673,12982.675375,12983.678542,12984.680542,12985.678167,12986.678,12987.657542,12988.685708,12989.67975,12990.681917,12991.678125,12992.676083,12993.683167,12994.677375,12995.680833,12996.679208,12997.677292,12998.674958,12999.677917,13000.681167,13001.676917,13002.681292,13003.679458,13004.678417,13005.676833,13006.683,13007.679542,13008.680458,13009.677083,13010.657875,13011.683083,13012.684833,13013.674667,13014.667917,13015.683833,13016.679042,13017.678958,13018.683958,13019.67925,13020.688417,13021.632,13022.696,13023.679292,13024.684792,13025.678,13026.683917,13027.681458,13028.6785,13029.616583,13030.697667,13031.675375,13032.686042,13033.680833,13034.685,13035.679958,13036.684708,13037.679125,13038.684,13039.684333,13040.684875,13041.680708,13042.683792,13043.679375,13044.683708,13045.682417,13046.682083,13047.685417,13048.682125,13049.661792,13050.686125,13051.680708,13052.688208,13053.685167,13054.687292,13055.68475,13056.687792,13057.686083,13058.688333,13059.682042,13060.690167,13061.687708,13062.68925,13063.681875,13064.689833,13065.686083,13066.690042,13067.681417,13068.692417,13069.683375,13070.686375,13071.683917,13072.68125,13073.685375,13074.686042,13075.653083,13076.696458,13077.685875,13078.686083,13079.687333,13080.686458,13081.689333,13082.687292,13083.692458,13084.684167,13085.690042,13086.685625,13087.691,13088.691667,13089.69225,13090.687542,13091.688875,13092.689333,13093.692333,13094.692917,13095.690083,13096.685417,13097.695042,13098.682208,13099.69575,13100.692333,13101.690417,13102.690792,13103.691667,13104.689292,13105.692542,13106.687667,13107.693917,13108.693917,13109.693792,13110.688667,13111.694417,13112.6875,13113.696375,13114.689833,13115.694458,13116.690375,13117.696417,13118.688042,13119.690458,13120.692875,13121.690125,13122.689667,13123.692667,13124.689833,13125.693542,13126.693458,13127.689542,13128.691625,13129.692667,13130.690792,13131.694167,13132.699458,13133.687667,13134.693292,13135.69225,13136.692042,13137.697625,13138.697292,13139.692375,13140.698583,13141.691958,13142.693833,13143.692458,13144.648083,13145.704375,13146.688667,13147.6945,13148.662,13149.700708,13150.692458,13151.692792,13152.651875,13153.704958,13154.691292,13155.695875,13156.692458,13157.6995,13158.692458,13159.694333,13160.693708,13161.699333,13162.695583,13163.693875,13164.697667,13165.699875,13166.6945,13167.696125,13168.6945,13169.695625,13170.694333,13171.695708,13172.700167,13173.698042,13174.694458,13175.699708,13176.69875,13177.66525,13178.706333,13179.694875,13180.697375,13181.701708,13182.695792,13183.696792,13184.703,13185.700958,13186.675625,13187.705375,13188.698542,13189.699667,13190.700333,13191.696125,13192.704167,13193.69975,13194.698042,13195.698542,13196.705208,13197.663917,13198.713042,13199.694625,13200.681958,13201.682667,13202.704667,13203.528083,13204.745333,13205.687292,13206.704,13207.700292,13208.700875,13209.705625,13210.700917,13211.699333,13212.679292,13213.708208,13214.701375,13215.703125,13216.702625,13217.706458,13218.699542,13219.703208,13220.703417,13221.700833,13222.699417,13223.676042,13224.714583,13225.700708,13226.701667,13227.708792,13228.704458,13229.697792,13230.704792,13231.703958,13232.707458,13233.709375,13234.703542,13235.702708,13236.706542,13237.70225,13238.7035,13239.704708,13240.706458,13241.704042,13242.702417,13243.705875,13244.708,13245.702333,13246.706417,13247.707833,13248.710542,13249.705917,13250.702667,13251.708125,13252.707917,13253.688708,13254.710875,13255.704458,13256.70825,13257.683417,13258.705375,13259.706417,13260.705167,13261.707542,13262.707042,13263.707375,13264.705875,13265.711833,13266.706875,13267.710375,13268.706042,13269.708708,13270.709542,13271.707583,13272.708958,13273.712333,13274.708417,13275.695542,13276.714458,13277.712042,13278.714292,13279.708958,13280.713,13281.709958,13282.709458,13283.711708,13284.715292,13285.7085,13286.710542,13287.712625,13288.715458,13289.713833,13290.715083,13291.712333,13292.711792,13293.7135,13294.715208,13295.709458,13296.716667,13297.709542,13298.717583,13299.708,13300.711625,13301.711833,13302.710292,13303.725917,13304.706708,13305.71825,13306.71275,13307.713333,13308.714083,13309.710375,13310.712667,13311.71375,13312.7105,13313.718042,13314.711875,13315.7135,13316.718833,13317.709833,13318.713,13319.717708,13320.714167,13321.719542,13322.718417,13323.710875,13324.715875,13325.712542,13326.714958,13327.713125,13328.71325,13329.7125,13330.7215,13331.714917,13332.709917,13333.714458,13334.715167,13335.719333,13336.719333,13337.715208,13338.721208,13339.719667,13340.719042,13341.697458,13342.7225,13343.717917,13344.717875,13345.71925,13346.719167,13347.717875,13348.720208,13349.718792,13350.719458,13351.718792,13352.720375,13353.720583,13354.713292,13355.722667,13356.720458,13357.72525,13358.71775,13359.72075,13360.721875,13361.723333,13362.718375,13363.723125,13364.720667,13365.724958,13366.727125,13367.721958,13368.727792,13369.702333,13370.7405,13371.718375,13372.704042,13373.704708,13374.710333,13375.702292,13376.675917,13377.726417,13378.700458,13379.734667,13380.719583,13381.741042,13382.72525,13383.722083,13384.725833,13385.723417,13386.727667,13387.722833,13388.72625,13389.722125,13390.72575,13391.725542,13392.725083,13393.728083,13394.729042,13395.725333,13396.726333,13397.7315,13398.723917,13399.725208,13400.725125,13401.725375,13402.726833,13403.724917,13404.724375,13415.10325],"weight":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"weightType":"samples","threadCPUDelta":[6930,262,880,1002,900,999,937,1000,1002,996,958,990,957,893,1040,912,934,926,1009,896,984,817,840,963,1025,927,948,968,968,953,920,983,959,819,1090,877,1060,936,931,966,1015,874,1004,1040,939,977,972,941,1004,970,948,1031,957,974,975,949,1013,897,1035,903,1046,973,964,982,993,944,997,772,1213,898,1015,977,979,952,967,1016,959,973,987,986,973,967,993,933,960,997,960,969,975,974,975,949,979,971,992,996,957,979,971,986,877,1053,978,957,995,981,957,957,984,967,981,964,980,976,964,983,957,957,977,1002,968,971,959,994,973,938,1031,970,964,973,983,968,982,958,989,963,987,964,968,892,968,760,1199,1003,917,988,971,963,1004,949,999,972,953,972,993,963,975,1000,974,939,998,984,978,957,972,993,930,998,970,953,991,982,955,947,904,962,992,1003,948,995,950,978,963,937,1014,949,994,988,969,981,952,992,969,970,1007,988,940,1014,930,1015,955,953,1007,960,940,998,973,977,947,1009,958,972,996,959,1000,972,983,981,996,962,983,991,958,981,993,964,1002,982,976,972,974,997,967,951,958,978,990,967,993,995,970,995,935,990,957,985,968,1007,964,965,997,994,942,1000,963,950,975,992,952,991,956,979,977,978,999,969,984,988,978,957,1000,975,966,963,988,984,957,994,1000,951,1006,953,979,1004,985,965,969,981,991,971,973,914,1033,970,984,998,930,983,975,950,992,935,1011,971,993,961,996,976,986,946,1005,987,985,976,963,974,1009,951,966,1009,948,985,982,983,1009,948,995,972,1000,988,988,985,944,993,964,988,968,984,1009,975,996,973,963,966,981,997,962,978,992,980,963,1015,949,1000,955,990,992,964,956,986,905,969,963,953,1008,951,1012,963,981,935,1001,953,998,971,993,978,958,977,962,1016,948,1001,978,948,998,950,971,989,981,984,997,929,975,963,972,1005,953,968,973,968,958,977,981,983,988,931,982,983,946,996,757,1220,864,999,965,1006,963,974,963,998,963,1004,958,981,974,1006,975,966,1009,941,1006,986,988,969,951,1001,962,1020,933,981,981,973,977,982,1007,976,952,1013,949,983,1003,978,970,982,975,960,1001,960,967,974,1007,945,990,970,978,977,999,994,932,974,972,942,1011,964,967,971,993,1006,956,998,961,984,974,969,1002,967,991,993,949,999,951,1004,978,974,966,1005,962,986,967,997,987,964,981,1012,964,974,1007,962,968,984,959,1001,959,973,1010,964,979,987,956,1006,994,977,952,985,983,978,1006,955,1001,981,954,980,1001,997,921,984,997,962,965,974,1003,973,956,985,997,959,968,940,1038,967,984,972,994,952,994,971,981,1004,983,956,965,1021,945,993,1000,968,958,1008,986,947,1007,956,987,983,964,994,940,995,992,946,994,991,983,953,1009,983,962,968,963,992,976,998,976,969,988,957,956,969,1007,981,978,947,978,979,988,991,981,957,992,966,994,961,1004,967,970,997,969,965,998,982,980,975,976,985,967,1028,943,981,1014,947,975,1004,962,1008,981,960,991,963,956,985,978,983,1013,981,980,950,987,954,980,1014,947,1008,954,989,967,1012,958,976,990,978,993,975,948,974,945,971,989,1003,949,993,995,958,995,972,949,990,955,984,1011,959,971,974,982,976,985,982,981,989,966,962,995,979,1000,939,998,1006,966,965,983,981,996,976,986,974,1011,980,978,957,970,998,1000,962,990,983,983,980,984,1001,974,962,989,965,966,985,994,976,976,982,989,978,980,1011,947,973,1001,996,942,979,1013,947,1012,959,1001,983,970,1009,981,970,962,1005,951,1009,970,968,977,1017,944,983,973,1035,931,980,1003,994,977,955,984,995,974,980,989,967,982,999,996,969,972,968,1004,960,1008,963,969,992,1000,958,986,949,1010,962,974,1003,979,946,1008,954,987,1003,960,1008,949,1015,957,963,980,1005,959,998,957,980,945,1002,975,970,974,968,968,982,987,965,987,956,1004,963,959,924,1083,913,958,993,960,968,971,1004,959,966,985,979,952,1010,967,971,999,995,959,966,1009,974,972,953,976,979,999,993,971,985,945,976,979,1002,940,952,996,989,966,961,962,995,987,958,971,1011,981,951,1017,945,1001,966,978,980,996,988,970,970,1005,950,1016,969,954,1003,948,991,958,1014,970,984,959,996,932,1022,947,1005,956,991,984,975,984,961,1018,950,1000,1001,955,974,985,1010,955,970,981,987,965,1009,967,989,958,964,964,987,997,956,999,964,970,1009,975,979,952,985,973,992,969,989,977,990,977,965,994,985,951,988,1004,974,981,935,1009,952,980,984,992,972,987,975,997,944,1061,925,1001,971,1022,951,975,985,975,1014,954,993,963,1000,973,958,986,974,1004,958,999,991,947,954,1007,948,961,994,948,985,989,968,978,983,1002,964,976,1003,964,978,993,964,988,1009,970,948,989,969,985,1003,955,971,993,977,876,1082,979,968,979,993,989,968,987,990,989,953,972,996,962,971,1001,974,965,1007,975,951,988,972,997,947,980,987,996,964,1016,976,953,1015,943,1010,948,979,946,979,983,1006,958,976,988,953,982,929,1012,977,1003,950,1013,873,1065,942,971,1002,993,968,951,986,978,1002,967,973,994,981,974,992,962,991,954,964,990,969,1046,906,993,984,1002,976,992,963,1011,952,988,968,972,1006,990,981,962,1004,953,977,1000,996,976,973,975,995,953,962,971,1001,976,966,1011,956,1003,963,978,970,977,972,983,1005,988,963,960,929,985,997,944,1006,961,1004,951,987,1006,972,961,977,988,978,1006,958,1008,970,978,979,961,998,949,1007,952,1006,975,975,979,986,962,962,986,987,976,955,990,964,997,950,998,973,983,945,955,986,987,968,969,972,988,986,973,1001,959,1009,957,979,1008,984,971,970,1012,944,972,910,1033,967,1009,948,980,987,1000,982,962,960,970,1015,947,1007,983,961,996,944,978,975,994,998,930,1006,958,978,986,987,978,1005,964,1010,954,978,988,985,954,967,971,796,1123,901,966,1000,904,1002,956,958,981,978,970,969,977,1008,959,1007,975,942,999,983,949,976,995,977,954,980,979,969,972,994,989,987,955,1010,946,1001,976,965,978,980,959,978,967,1005,947,954,931,913,976,1032,898,994,991,943,997,957,981,972,988,986,976,1008,932,991,985,950,999,977,948,963,999,949,959,932,959,1006,978,979,952,996,949,991,974,973,979,970,978,950,878,1087,950,1000,976,950,980,973,1000,983,962,985,953,968,991,968,953,967,1008,962,972,978,969,993,972,997,964,862,1087,961,960,987,966,993,963,992,965,979,983,969,1004,960,986,962,983,960,974,969,996,972,977,973,949,998,953,979,966,983,1006,944,976,978,998,962,980,1001,942,980,983,987,991,965,979,985,975,972,984,975,999,952,997,992,971,955,967,1006,952,979,976,995,954,985,989,961,983,991,974,959,973,993,950,975,981,987,966,996,985,975,941,985,931,978,983,970,986,968,957,978,971,982,999,943,985,989,959,989,960,976,993,953,998,978,983,950,975,1001,979,968,954,916,1028,949,974,1002,941,989,972,941,1007,939,952,970,999,943,1002,951,1004,934,959,981,949,969,999,942,980,970,967,974,999,939,1001,981,973,963,974,987,946,969,1006,927,1011,961,949,968,979,964,984,960,983,999,938,1000,965,949,972,987,953,972,970,998,966,997,970,974,971,957,980,948,971,987,956,986,972,965,967,986,974,980,971,971,973,986,974,957,982,945,1004,954,955,997,970,970,974,961,990,956,969,952,976,1000,909,982,927,998,957,962,1002,970,932,1002,963,951,963,1007,958,1006,970,944,987,930,1007,956,957,986,945,1011,960,961,981,961,983,963,968,999,948,966,970,966,958,987,896,1088,947,949,923,1024,990,938,998,953,982,979,961,996,981,981,961,973,958,964,960,991,965,975,992,970,923,1003,967,980,937,972,997,938,1005,959,960,979,990,956,974,957,1001,968,940,990,960,998,964,970,949,998,951,983,959,974,954,954,971,1010,942,1003,948,978,961,973,1000,944,969,1003,968,954,989,949,963,964,1004,933,980,977,972,956,970,984,964,948,999,955,983,978,942,939,975,982,966,994,950,1000,951,976,951,996,950,997,972,941,996,946,1000,962,950,977,1000,974,952,982,976,967,990,964,945,997,953,958,996,981,944,974,973,977,972,1001,963,987,930,976,994,951,970,989,956,987,949,973,988,969,976,975,974,1001,957,970,959,979,984,956,950,941,996,951,971,967,1005,956,983,961,977,969,999,914,890,1043,960,993,960,989,949,969,996,945,1001,946,985,980,953,975,965,968,986,963,998,966,992,942,992,962,997,975,946,980,960,988,958,970,1000,983,957,964,964,981,965,971,970,987,951,995,988,989,981,955,965,980,937,978,999,952,997,934,982,971,968,1013,939,985,991,984,968,953,1004,928,966,981,941,969,964,939,983,935,946,992,959,978,946,978,938,952,967,915,1019,895,973,991,980,944,958,992,963,990,982,971,958,1000,990,867,1042,943,973,991,984,923,934,1019,923,969,983,964,959,961,981,964,974,965,969,998,963,959,990,961,948,996,958,981,977,978,958,995,988,958,992,935,981,1001,940,1000,953,967,993,945,953,1007,932,972,1005,981,973,980,947,979,956,968,1007,938,977,967,969,1005,944,982,993,953,976,999,943,957,1002,977,946,968,998,977,937,975,966,951,984,976,948,980,989,996,959,932,1007,958,978,962,963,991,980,944,982,952,879,1003,948,987,965,964,969,965,1003,938,967,1000,972,954,959,991,968,940,994,954,996,962,952,966,975,1004,971,966,987,941,983,967,996,943,975,998,974,947,972,995,986,875,1052,985,931,945,1013,986,960,956,976,960,965,1009,943,979,997,968,963,990,941,990,983,947,973,977,989,965,953,979,971,996,960,976,989,970,983,970,958,991,962,960,999,957,980,961,982,949,1008,949,969,990,984,949,975,979,944,995,968,957,976,985,962,1001,949,1001,929,1003,933,1001,971,936,979,994,931,1021,949,1007,950,992,937,1007,935,970,975,983,996,977,949,992,982,949,993,979,965,991,947,966,974,968,994,968,991,933,997,954,943,975,964,977,982,972,983,892,965,989,953,981,984,988,947,1000,951,993,936,1002,969,982,963,990,947,1001,944,975,945,998,937,985,985,994,952,947,970,994,971,971,950,973,963,1006,972,950,974,966,958,996,991,960,973,949,1000,975,969,969,984,941,991,982,954,982,990,945,1012,945,987,981,925,992,966,936,981,953,994,932,988,934,956,969,1004,953,974,982,980,992,979,936,962,997,901,976,1000,923,936,997,1012,889,1015,1004,927,988,989,948,948,985,976,982,959,906,1005,986,949,988,971,950,962,1007,947,1005,944,993,941,968,993,968,946,980,981,960,976,972,977,967,1003,956,980,994,978,944,974,995,948,993,945,962,973,968,977,959,972,928,1033,971,953,992,960,952,951,995,965,937,970,949,985,966,951,958,944,1017,952,966,973,961,981,981,842,1019,944,977,941,998,980,939,1003,944,1004,952,962,970,996,965,990,967,961,960,1001,950,994,971,953,979,943,969,984,965,999,971,973,962,976,1006,963,971,947,977,993,959,1002,953,1001,934,964,967,1014,927,922,917,1059,932,980,992,940,998,937,994,957,966,993,977,971,976,954,974,1014,975,960,979,953,959,953,973,982,963,983,986,962,961,966,979,979,961,974,991,962,988,964,951,967,1011,963,987,956,958,969,963,993,984,939,984,968,988,951,1001,960,972,955,944,985,965,1003,967,981,968,966,986,940,1014,982,965,952,975,966,962,974,958,970,997,946,978,963,975,975,1002,941,971,1013,964,981,937,966,979,994,944,1016,934,976,969,1012,941,1001,976,957,980,984,950,985,973,951,968,970,962,969,969,963,989,964,967,995,970,956,957,996,966,949,985,958,997,946,994,966,953,982,943,993,965,987,960,994,967,962,1006,955,982,955,965,991,951,971,996,976,938,996,946,980,985,1000,974,932,936,938,973,968,1011,944,983,969,937,993,954,958,865,1084,953,1022,962,960,984,935,1005,972,949,971,1001,963,909,997,962,961,962,1012,966,966,966,966,983,998,932,1003,945,1000,981,972,940,995,983,964,978,968,962,955,974,949,991,960,983,977,962,935,1004,969,940,997,908,1018,994,949,982,968,990,948,998,972,958,990,951,996,954,964,987,946,1009,932,985,978,982,984,957,953,1005,941,977,1000,938,1010,964,973,951,982,959,966,988,948,1011,968,958,985,932,1004,937,876,1076,963,995,948,978,969,992,975,959,963,1012,940,963,1015,934,972,989,947,973,964,985,990,959,968,967,946,975,995,975,960,984,997,927,961,949,987,961,991,963,966,928,1006,950,964,1000,957,1001,968,974,981,954,943,999,936,995,965,965,973,984,960,1003,950,985,970,998,962,981,980,943,980,959,970,987,962,988,951,1005,971,949,976,987,962,1007,974,952,974,967,998,953,1002,941,979,992,968,992,962,970,985,962,979,957,990,956,966,960,973,964,942,997,924,1007,933,992,986,960,952,989,961,986,993,979,945,965,987,971,959,969,963,984,970,982,997,962,941,982,968,1001,950,975,998,973,946,974,934,992,923,988,926,976,965,929,985,954,943,958,958,931,960,958,986,967,969,977,933,1026,933,976,981,965,970,979,995,949,1000,982,980,979,938,977,974,879,1073,990,942,971,945,945,962,951,978,966,958,941,1001,966,951,979,996,828,985,957,985,939,960,979,898,996,937,979,954,990,960,952,956,961,966,954,944,892,1061,935,952,902,1011,979,938,913,994,940,944,938,997,924,789,1161,934,966,934,949,886,968,922,1042,981,949,953,949,984,992,960,952,809,1143,778,1046,831,1174,693,1196,853,1028,907,988,905,1001,913,995,976,926,962,979,996,931,924,1026,934,952,1021,940,998,938,988,962,943,995,943,977,958,941,957,996,953,995,940,1005,964,957,988,914,993,992,902,976,1008,993,948,923,923,971,962,998,940,928,915,973,960,931,978,904,1047,906,968,862,1054,1002,914,953,969,846,1101,905,928,985,975,979,956,992,954,995,876,1031,944,977,995,954,949,990,973,992,942,997,970,946,917,966,938,984,961,979,977,957,977,969,948,975,984,966,977,959,873,974,828,1107,953,951,962,988,974,913,925,988,985,878,888,1050,990,998,909,1003,952,963,966,858,914,1012,889,896,986,998,882,1033,949,928,852,971,954,906,977,922,919,1003,953,980,940,971,983,907,981,946,978,942,982,917,942,927,801,981,804,1065,892,779,1045,906,877,929,920,844,953,866,920,878,956,877,992,882,882,921,793,1060,809,902,957,868,801,1057,958,902,1010,972,961,968,994,948,985,966,975,1009,942,1008,948,982,958,998,956,960,992,942,978,957,999,959,951,975,871,1059,997,942,952,980,996,955,999,941,968,972,962,1003,965,941,952,974,987,958,968,879,1012,1000,954,997,969,939,987,955,980,955,1004,981,942,999,960,953,967,1011,938,992,991,936,977,967,971,979,922,998,994,982,941,997,960,986,942,998,969,968,987,937,992,985,941,995,944,990,984,966,972,962,919,1054,931,960,1005,952,991,969,963,950,952,981,968,1007,929,1004,949,970,979,962,972,972,1006,951,971,986,981,937,983,976,940,1007,937,993,975,940,984,954,975,975,987,996,936,1004,962,964,975,895,1051,942,998,934,979,883,1072,948,968,988,939,969,998,942,976,1002,963,938,998,964,990,958,963,984,972,1011,890,982,963,985,993,946,974,976,985,948,1006,930,999,934,964,980,981,991,970,933,966,976,997,940,1004,983,966,923,1013,962,936,988,951,976,965,890,1008,1008,934,989,976,926,1007,960,964,972,964,998,960,951,977,1004,951,949,835,1109,995,962,1004,961,940,1003,940,1009,926,1026,910,980,934,1022,989,976,982,978,958,947,999,958,945,975,1004,940,1008,961,957,989,951,998,955,962,989,996,971,947,995,972,950,985,974,944,981,1016,977,935,976,942,999,947,932,1006,977,924,968,969,987,965,991,945,979,980,1010,957,963,995,940,1001,936,967,953,980,917,982,978,948,971,978,969,958,973,274,613,935,1118,831,998,891,971,958,956,999,940,986,946,980,974,953,968,934,994,935,985,991,955,972,973,940,775,1069,1012,907,1005,973,960,970,965,974,963,974,938,1012,936,1002,944,1000,938,960,991,974,964,983,757,1135,972,943,898,1096,936,965,945,972,1005,938,984,965,966,966,999,959,965,968,940,947,1000,962,970,938,986,991,938,993,980,970,954,1007,962,965,952,977,944,1001,941,959,1007,960,947,958,999,957,943,955,983,990,932,947,989,976,952,976,978,952,977,966,949,981,966,973,975,965,986,954,950,969,962,990,946,992,968,949,1009,950,951,977,1001,978,942,963,990,952,974,985,956,1011,945,979,992,967,954,998,963,956,973,947,970,986,966,952,975,994,980,960,964,992,974,971,940,968,974,989,949,968,967,966,980,974,974,973,971,946,1000,981,959,958,977,1008,971,906,979,969,991,936,919,1077,956,965,1003,951,994,964,970,989,930,991,951,981,964,932,969,951,982,973,1002,964,983,962,981,959,991,953,962,984,971,962,976,992,954,996,962,964,986,944,963,986,975,942,977,978,985,985,838,946,952,942,1000,1010,940,975,975,960,995,950,945,990,958,978,991,895,1022,964,970,972,968,963,1014,889,983,973,986,955,992,991,945,965,998,975,978,965,966,964,960,963,992,983,944,998,977,978,924,1000,954,988,967,993,968,967,951,979,951,997,945,1006,959,976,941,941,970,962,985,962,879,1045,987,1053,965,844,1012,942,952,1024,885,1019,780,1082,997,810,1120,886,974,1075,832,987,973,952,979,967,965,938,971,978,976,953,975,1008,945,974,975,983,957,974,995,958,949,950,1005,964,986,949,970,885,1076,972,965,955,952,1055,945,996,971,949,999,985,958,993,956,969,1018,975,963,953,967,1021,881,984,990,977,970,954,974,966,987,984,960,987,972,953,1008,969,961,1003,963,983,950,975,970,974,994,958,980,951,977,1012,939,996,975,977,978,960,999,969,954,961,1528,326,958,1118,827,1120,771,1012,972,1442,378,1024,950,903,1077,825,972,972,1055,871,1087,817,937,1052,929,978,974,981,932,990,975,994,972,966,984,973,940,962,986,958,1017,961,960,994,946,1007,960,949,976,972,971,980,964,964,975,1005,958,1005,974,964,977,983,982,992,950,783,1206,948,1010,949,1005,972,983,953,975,975,1008,942,981,969,1003,981,952,993,949,997,970,960,1010,972,945,1006,982,951,955,971,975,982,970,958,972,982,981,992,973,971,968,955,983,1048,930,946,975,994,942,1033,1035,797,1000,968,1020,819,1064,978,931,974,961,1000,983,973,990,949,979,986,978,1012,898,1013,981,993,976,945,986,972,979,991,962,993,971,976,995,954,984,978,998,946,940,976,1011,940,981,970,988,963,934,1017,980,940,966,975,980,932,1019,967,1007,970,967,999,978,962,976,981,989,997,935,985,973,979,1007,946,988,1000,956,972,980,983,977,982,979,940,1027,979,959,970,943,1033,1001,955,1007,975,943,976,1002,976,961,976,978,961,984,969,999,940,979,1018,944,970,972,981,979,980,968,985,981,981,999,973,982,949,958,991,794,789,1194,889,1012,957,2289,28,1215,793,1110,1048,1021,840,1046,894,959,933,837,1125,965,1006,954,962,973,1011,945,1014,934,1005,988,960,963,957,1025,956,976,962,944,975,1004,958,976,973,1010,912,994,974,965,1011,945,990,995,983,953,1022,957,993,968,957,987,894,963,1008,976,935,977,981,999,951,996,982,987,948,953,975,981,1005,947,970,972,987,961,962,974,994,947,972,965,999,969,943,981,991,963,972,1008,952,988,944,995,945,1003,933,993,960,971,967,986,969,938,978,1009,947,1005,974,949,973,995,989,932,1016,945,994,935,1007,971,964,981,943,1013,977,932,1006,954,964,978,985,960,971,969,976,977,809,20,1231,867,1035,932,833,1075,923,1000,953,1050,895,968,977,982,992,958,972,980,940,973,964,1008,947,966,1008,974,966,964,930,1022,988,939,985,977,1004,944,997,977,964,956,996,951,981,991,981,937,974,961,976,959,1000,968,954,981,981,976,972,935,978,962,410,1259,938,976,959,972,756,1152,869,1003,923,983,806,850,710,908,962,911,1030,779,994,992,920,1012,906,1002,869,1041,981,982,967,982,930,989,930,977,968,942,968,999,960,952,977,971,969,991,950,959,984,953,996,948,963,838,1118,934,1002,934,965,1000,935,990,1009,940,996,953,977,955,1019,937,993,969,983,952,989,959,971,989,936,983,971,976,976,979,958,995,969,980,954,973,951,991,942,989,954,978,1038,842,915,1008,1030,873,965,955,882,1092,958,719,1052,706,1131,1057,975,933,983,1003,964,965,943,980,972,921,957,989,972,953,990,964,949,978,941,985,973,989,977,1004,949,936,1019,957,946,992,973,954,983,977,959,982,992,941,996,935,970,979,992,932,968,1000,979,972,940,965,1011,965,910,991,1012,939,960,977,970,941,1000,948,971,970,1009,935,1000,953,971,966,977,988,985,974,944,983,942,998,944,980,979,956,979,953,973,1006,963,987,952,972,813,715,922,1256,697,1334,729,802,911,653,1336,801,1061,756,1086,1020,941,989,946,1023,957,923,910,940,959,920,1071,951,927,993,936,954,975,980,980,937,968,998,946,971,977,969,965,1008,945,985,983,971,976,911,995,942,990,970,956,975,996,923,978,964,981,973,990,985,978,936,998,960,1002,966,947,988,964,983,933,990,983,943,962,979,1002,938,973,967,999,976,953,1002,935,992,957,1000,935,960,976,965,983,1002,961,952,1008,1194,563,924,1021,989,847,1033,957,929,970,880,825,828,919,773,1014,906,790,888,786,839,851,826,858,942,1015,854,776,868,896,881,842,829,849,946,994,905,850,856,834,792,887,791,943,942,978,784,733,755,882,787,985,813,884,1006,934,875,780,943,838,978,839,801,825,1110,993,950,1006,968,946,999,974,958,980,973,974,956,971,989,996,968,1530,233,1078,928,1022,874,1011,936,957,951,988,955,939,973,1027,906,979,985,984,950,975,986,958,971,1006,941,1009,983,940,986,987,964,987,962,970,973,967,1004,945,966,1002,932,1008,938,983,982,987,970,954,1001,964,952,1007,938,976,982,987,1000,983,938,972,955,788,1098,1616,84,1061,907,973,808,969,935,819,789,1002,807,914,992,896,1042,896,970,957,991,988,910,975,956,976,956,965,991,969,944,977,997,960,978,952,978,717,1258,954,1017,942,938,999,905,970,957,970,971,985,985,958,958,990,951,1006,944,1020,906,1013,996,956,947,995,962,964,930,952,984,957,965,983,928,971,993,944,1001,943,996,973,956,1003,943,947,975,1048,990,975,967,985,966,983,957,985,946,1083,650,1046,893,962,959,964,1044,957,924,918,932,946,985,962,956,948,995,929,945,981,945,981,976,991,969,965,949,987,985,985,983,975,958,950,976,976,997,956,963,984,970,958,1014,934,975,994,992,957,954,1028,1000,1143,633,972,876,953,983,854,1047,976,992,972,949,972,994,953,997,974,961,989,954,925,984,948,993,972,977,924,972,993,981,971,948,1006,943,964,999,957,984,977,999,924,973,969,998,967,945,980,961,961,1002,981,941,957,996,958,970,1005,940,1010,934,995,980,952,977,937,968,921,1007,993,977,945,985,953,991,958,963,998,954,978,983,977,974,961,980,983,989,943,983,997,941,1001,900,1000,1316,212,1248,1046,800,959,932,975,872,1097,729,1056,965,760,1164,903,966,951,998,972,952,992,942,967,970,986,950,983,922,993,956,965,959,926,996,932,1003,955,946,997,948,977,965,997,968,995,945,984,975,936,988,988,963,973,949,996,963,985,963,976,951,1002,908,983,961,965,983,989,935,1000,972,982,949,990,851,1070,958,982,1075,932,844,1601,171,1181,925,920,871,864,1145,932,1016,972,951,982,985,986,986,953,953,1001,946,969,969,963,971,973,1002,917,986,948,989,992,959,994,970,989,963,935,974,967,983,842,1104,873,1018,885,1034,980,843,1059,971,917,1046,817,1086,673,1227,948,1018,939,975,1006,869,874,1047,859,985,957,901,893,993,957,966,964,1004,962,949,975,958,978,1004,954,876,930,1068,939,946,897,1031,885,815,1102,994,871,1013,787,1121,986,875,1005,935,931,990,1169,605,1579,277,1136,928,996,949,869,913,956,796,1069,930,968,971,976,950,976,998,940,970,1001,984,921,974,912,974,979,968,961,974,945,975,969,969,988,957,1010,832,1092,975,965,955,988,926,956,997,985,965,952,972,966,998,962,983,941,985,995,946,1001,978,953,979,945,948,966,1011,960,954,984,952,967,969,939,980,969,976,1789,109,1164,914,1767,176,1093,732,1073,937,262,1531,1112,933,943,1001,956,995,961,986,957,969,950,980,981,960,975,951,941,991,966,970,858,1063,948,1016,959,976,965,973,945,966,999,980,944,998,946,979,984,944,966,984,981,962,985,965,955,994,952,982,970,988,950,997,975,948,974,989,965,972,994,944,999,944,973,995,946,1003,971,975,947,998,951,972,971,983,980,969,932,1011,927,973,980,962,1009,980,952,966,989,980,981,946,987,969,949,967,975,995,854,1563,195,1166,886,957,816,1039,752,1040,944,944,983,949,1009,911,981,954,989,971,982,970,938,1012,935,998,1045,876,990,979,955,968,962,993,965,965,973,982,1000,948,1001,971,958,978,938,980,994,954,1018,958,987,937,991,956,993,967,965,1007,949,1005,959,952,974,974,987,978,957,973,994,988,950,975,967,942,978,994,966,964,992,988,946,989,966,933,980,977,933,991,936,998,975,957,983,950,983,949,992,951,978,983,958,980,975,978,976,964,964,1163,820,1003,1016,786,904,961,908,979,877,762,1190,827,994,989,962,968,995,945,952,996,977,940,976,993,946,983,998,958,982,941,962,1005,969,959,972,1015,932,982,975,990,975,963,986,931,999,938,1004,970,961,976,964,948,1000,949,967,986,994,959,983,966,960,1007,978,943,1001,944,980,982,997,956,978,994,964,999,925,979,974,980,1012,954,927,987,985,967,945,992,904,716,1194,951,1017,952,964,960,1007,957,961,991,962,1013,938,1003,933,1000,950,936,1009,963,928,1549,92,939,923,928,1017,864,941,897,782,1120,814,1217,761,916,1118,907,926,999,982,934,1001,952,999,959,980,942,1024,953,946,1029,924,980,973,960,951,980,980,976,968,995,953,966,984,987,952,1015,960,945,964,991,976,993,955,998,955,994,1002,969,931,946,959,998,967,981,933,1020,937,990,945,984,977,997,942,1000,967,963,1051,909,1266,803,1003,752,961,795,889,1161,863,952,1012,974,946,981,960,979,962,982,946,963,1008,971,960,950,979,977,966,975,992,970,977,942,975,1009,965,959,952,1009,958,993,940,1016,945,972,997,971,956,941,985,986,958,951,994,977,948,966,1005,983,983,964,960,989,971,947,971,978,955,1011,938,1006,974,944,988,981,977,974,931,986,985,933,969,973,998,949,1006,930,988,987,968,963,930,970,964,998,948,1009,973,944,994,946,1085,141,1211,2363,75,1127,946,993,959,980,916,1001,967,955,974,949,974,1052,647,1220,993,970,978,992,953,950,1011,965,949,1006,972,933,992,993,938,969,984,996,967,942,982,977,980,980,996,947,981,976,975,998,939,973,990,937,1010,964,968,958,977,1004,971,950,961,972,971,1005,944,1015,965,970,937,986,969,982,972,955,943,978,1003,950,972,1001,960,955,970,1004,959,965,976,982,974,974,972,991,976,949,1265,2438,71,1388,598,1331,1653,32,950,817,2140,42,1164,969,1008,870,982,978,961,977,992,957,938,973,978,978,994,969,979,939,1007,939,1002,971,944,977,1002,964,986,937,976,983,936,970,974,992,952,972,972,988,956,980,1000,983,964,954,982,984,991,978,950,990,940,1004,959,969,1001,953,960,974,1008,961,957,998,972,978,981,961,976,977,982,969,994,980,961,950,967,982,991,947,1002,951,962,1015,948,977,972,997,970,965,974,1007,946,967,928,1277,568,1062,956,924,1034,973,943,956,778,1082,981,1366,1114,61,1273,716,1209,892,983,972,970,984,984,936,971,987,944,972,969,989,969,944,972,962,993,978,948,964,974,996,942,972,987,965,991,960,971,972,978,975,962,969,960,982,945,969,972,988,992,893,997,976,950,873,1057,999,917,983,962,969,1015,963,945,1002,946,1010,968,950,968,989,959,972,995,953,979,984,942,985,963,963,1002,939,1000,974,953,969,1010,937,969,982,981,983,960,1002,963,974,977,988,980,847,1040,996,939,805,376,427,587,188,1017,980,1379,499,527,817,995,885,1118,881,951,987,957,977,982,986,950,971,983,960,951,972,1000,958,978,951,985,958,954,1000,944,988,961,976,970,992,961,1005,957,975,960,947,971,991,963,965,989,955,954,971,987,999,956,986,967,970,966,979,980,1000,940,1075,804,963,1004,987,942,943,943,1000,974,930,1001,965,915,985,946,837,1120,950,1016,962,981,1223,624,1056,961,982,839,619,840,899,1052,1368,294,1115,919,981,962,977,994,948,986,977,993,966,969,951,964,967,1008,949,953,991,959,992,980,919,988,1002,945,969,992,965,954,1012,958,939,986,948,989,975,975,962,949,1003,969,984,959,989,969,972,936,1001,947,990,976,961,972,994,942,1003,943,976,975,978,967,1007,933,994,975,969,941,969,995,940,1015,954,973,982,982,946,984,981,975,960,944,972,988,963,952,1006,940,1009,941,965,979,977,992,960,975,996,957,967,962,1000,976,943,973,974,996,956,985,971,944,974,991,593,506,752,864,398,956,1095,883,961,455,1576,864,971,984,964,958,981,974,995,961,968,956,1005,941,1013,935,992,960,957,981,1004,946,986,967,965,1000,949,993,982,950,964,968,919,1008,1003,948,974,991,983,955,996,986,977,972,957,971,991,931,962,982,955,1008,944,992,978,945,972,984,952,967,1001,968,947,965,984,987,989,946,988,956,998,982,956,947,1011,957,951,970,994,954,973,984,982,990,947,982,980,1003,931,994,967,949,987,950,1005,933,977,1010,937,982,986,628,755,451,983,734,873,1154,647,805,1032,991,873,886,1014,991,729,1243,806,705,1248,974,1005,927,991,952,985,982,941,981,932,970,1004,951,979,970,975,960,977,957,1003,942,1011,959,969,942,972,978,998,951,966,988,967,987,976,1009,931,993,957,1005,941,990,960,995,943,990,941,969,979,1004,940,966,992,965,957,979,973,1001,955,991,964,937,1002,944,985,998,958,950,937,992,978,957,968,993,957,959,979,977,990,959,972,983,960,998,944,964,1006,944,982,959,975,1002,972,941,999,946,962,976,972,986,971,974,975,839,1221,764,666,620,1242,712,781,1038,908,889,1043,899,699,1177,845,958,978,969,966,961,1019,961,976,942,990,932,974,971,955,981,956,997,953,990,976,976,931,1005,954,984,950,983,1004,964,977,935,988,953,968,1011,960,989,970,939,1008,953,979,971,961,971,982,982,948,983,975,995,952,956,988,942,968,996,980,959,979,915,966,998,903,952,965,977,958,971,1009,972,962,957,1011,948,955,953,968,960,862,1119,958,947,960,985,980,976,964,951,971,911,1044,943,977,977,992,1326,179,1390,1512,21,1592,426,1333,580,898,1059,864,837,761,1173,973,923,880,1071,983,952,983,984,987,956,979,967,969,952,982,966,960,1001,961,959,970,966,911,946,1000,951,970,996,955,953,1008,934,980,968,998,979,929,964,945,988,935,1003,956,1003,956,975,949,986,938,1005,975,965,982,1005,918,934,927,987,987,943,1007,938,985,966,983,955,971,937,988,953,978,983,947,996,961,1008,936,931,1037,945,995,972,952,978,993,967,952,975,983,968,959,990,954,956,983,962,973,943,988,961,958,998,940,972,756,906,1069,836,1086,894,780,967,647,4,1241,1290,334,1003,888,956,805,1171,943,951,973,973,997,963,945,1011,934,965,980,977,970,986,931,1001,963,953,963,969,960,1005,949,969,1008,967,972,944,961,938,1000,992,973,945,985,987,955,964,922,961,971,1001,943,967,1010,944,1022,937,967,982,969,989,980,977,965,931,964,1004,944,1006,935,986,969,999,962,952,1012,964,979,941,987,987,961,967,932,971,1003,941,982,970,967,962,1008,969,940,974,977,986,947,1008,933,984,980,966,977,986,388,979,866,1188,466,727,38,1238,846,994,832,985,1149,630,1031,893,1008,933,978,988,934,996,967,1000,944,964,989,985,955,1003,944,996,967,955,997,937,990,971,969,986,945,976,1005,975,954,974,998,963,959,959,999,947,991,952,998,948,966,969,968,972,961,1013,956,982,967,943,988,997,962,959,971,987,934,899,1032,974,954,991,955,1000,927,989,955,984,960,980,955,1008,954,968,997,237,464,352,547,432,468,356,460,700,728,897,964,2088,100,1195,732,1157,770,1176,905,775,1241,845,817,456,1604,951,968,981,954,973,988,968,937,963,973,984,977,958,995,948,966,1001,953,968,973,996,920,994,968,969,974,991,951,985,954,986,975,971,1006,966,937,1002,976,969,977,948,914,954,975,944,989,935,1001,978,966,968,957,1021,938,978,970,1004,967,950,977,981,999,984,959,945,1000,971,945,999,975,981,996,959,992,987,945,976,974,1006,978,947,1009,1003,969,906,980,1006,949,975,996,958,996,979,948,1013,949,994,952,986,982,965,954,988,1000,975,942,975,1009,947,982,978,977,1006,947,985,974,985,994,960,964,975,1006,975,949,972,978,987,983,1020,921,985,981,929,998,998,954,1003,929,5,1236,924,702,1286,1033,903,514,1273,1557,367,727,1159,889,1048,1002,948,998,939,989,977,960,956,981,990,949,974,982,981,999,955,1000,949,979,977,976,992,985,960,972,990,954,996,958,998,967,967,981,996,924,978,964,991,955,970,993,963,996,991,948,997,793,1154,947,1012,934,987,955,1004,927,1000,948,997,960,955,962,947,900,1077,932,1045,951,991,986,1013,968,889,1085,904,1081,971,981,1003,978,939,1019,1012,971,966,956,1010,940,1019,949,982,998,962,985,973,983,977,988,1008,960,976,984,974,1010,953,984,1007,959,976,1003,956,964,977,986,982,1011,959,974,967,992,968,984,980,1010,970,983,934,1004,958,963,977,972,977,989,950,975,974,960,967,994,957,1011,949,950,970,919,623,2,1240,912,987,1044,892,892,931,275,1142,774,1097,922,994,988,954,955,964,1013,942,986,968,983,962,976,970,949,992,970,972,972,992,997,216,1680,953,940,1006,935,988,948,997,952,945,965,976,993,813,1145,948,982,963,1004,975,985,939,1010,986,972,985,972,983,944,956,957,1003,930,968,966,1020,956,957,987,999,970,986,951,984,965,1002,967,939,964,990,956,983,999,961,964,1004,937,990,956,996,976,940,983,998,949,977,1009,816,1131,957,963,954,988,953,996,934,976,984,993,932,958,891,1747,44,1694,316,1138,323,336,1038,950,966,930,870,1067,966,966,986,948,980,1008,946,963,1012,953,974,988,946,998,962,990,969,931,998,941,1002,943,1002,953,1000,949,982,1015,924,972,975,956,958,978,1001,984,885,1059,955,973,1005,939,971,1006,951,961,953,988,989,953,995,940,1000,954,1006,955,975,970,985,989,972,943,977,996,943,1004,942,1012,969,946,976,1013,962,969,983,976,952,994,962,975,976,1007,951,974,950,974,1002,953,961,999,948,978,954,966,969,976,999,981,947,977,983,618,1171,984,599,1678,170,998,588,1193,674,887,1151,950,868,829,879,1153,969,991,958,990,950,1000,951,1000,975,951,969,970,976,973,968,971,991,969,978,953,988,958,970,970,984,968,978,968,1011,958,954,980,962,1000,971,974,955,950,978,954,989,955,970,986,887,1036,977,853,1101,965,968,977,979,998,949,962,942,1000,980,951,993,971,967,945,965,999,941,1009,958,979,960,979,949,988,970,962,1002,954,925,1005,950,962,1010,942,974,963,1012,928,997,949,982,990,941,985,977,984,960,976,991,971,960,815,954,2008,114,2351,10,1562,399,1057,980,1020,851,997,1122,499,1047,922,964,981,1001,927,915,1064,932,974,994,937,1015,933,1013,937,994,969,950,1005,888,990,963,968,952,1003,962,973,977,977,967,949,978,989,967,972,943,995,967,970,1018,954,940,967,992,985,963,998,951,966,975,1000,934,971,992,934,973,986,971,968,966,987,965,973,972,985,962,991,977,994,960,1011,944,973,954,999,953,967,1004,947,1007,942,973,1001,948,1016,937,929,987,952,979,983,1012,896,937,913,947,997,968,968,996,906,1001,984,956,995,951,949,1002,968,968,973,953,979,1005,976,2109,298,1391,287,1160,837,858,1077,1030,871,904,712,1064,954,986,920,1009,917,984,982,950,1007,964,936,989,987,951,972,945,964,987,978,966,933,992,790,1160,976,966,942,992,982,938,979,997,940,978,967,958,871,1080,920,982,999,971,940,987,987,954,964,938,949,943,1001,986,944,979,982,967,965,979,966,967,970,973,976,960,982,1016,946,952,983,960,958,984,951,1005,966,944,995,975,958,997,948,971,1003,954,968,963,959,978,1004,951,967,970,978,993,948,1009,954,1002,970,938,973,982,962,1004,973,957,979,945,975,1008,934,1013,941,971,1692,233,1248,492,1448,628,849,980,892,980,936,1019,915,968,909,882,1056,962,1006,938,1012,962,981,945,973,975,974,974,979,972,998,954,960,984,987,965,989,946,988,983,941,979,992,954,1010,951,959,968,984,961,969,980,977,972,976,952,971,956,974,1011,937,983,950,975,967,982,994,959,958,994,962,996,943,995,983,974,967,980,1000,947,984,971,984,900,1000,945,989,968,972,940,1008,967,961,975,942,977,1016,932,981,989,958,969,982,969,992,960,1002,938,974,989,959,996,973,966,957,980,960,976,1768,411,917,815,1056,903,887,1022,946,991,931,785,918,801,1245,955,969,1000,944,980,960,986,981,977,971,992,960,986,947,1001,972,928,982,990,957,956,964,994,975,952,994,960,859,1115,949,985,941,999,999,943,1003,964,960,992,934,985,964,952,959,1013,968,952,942,976,957,1004,936,974,980,995,955,947,979,1000,941,974,1009,929,970,981,955,980,975,949,1009,938,991,939,1004,937,978,980,935,984,987,926,983,956,968,998,976,930,998,959,951,959,973,994,958,949,976,978,1001,959,979,942,929,1006,1076,804,1027,946,867,997,962,771,1189,917,1012,938,985,984,982,930,978,973,974,978,947,976,1010,976,945,972,959,985,973,950,972,968,972,983,969,983,967,971,941,982,957,1006,961,986,878,1009,942,960,1002,939,994,942,994,947,1010,949,1012,934,971,983,980,1002,925,1010,960,963,969,1003,967,965,956,981,978,974,958,1007,952,933,867,1033,967,954,979,972,988,975,960,950,994,975,941,986,1006,963,954,985,975,951,962,985,975,989,946,966,954,1008,966,964,982,896,1043,913,906,1051,951,1008,975,907,984,694,987,1083,644,1083,846,1026,789,1088,1008,920,943,908,1074,980,963,956,1015,941,982,1001,942,966,981,968,1004,742,1190,889,995,952,963,987,933,1008,943,979,960,995,962,973,983,954,1002,955,955,990,950,980,956,1003,763,1201,937,981,1001,964,953,977,995,951,982,1019,930,987,956,1004,962,945,985,946,990,977,950,1008,951,943,945,982,967,946,962,969,997,959,974,968,961,968,972,964,970,1010,942,956,1012,925,1010,916,994,956,947,858,1092,942,1011,1007,745,1051,1127,773,798,1229,825,1082,855,1102,748,936,1000,930,994,962,958,978,1011,955,963,990,972,944,968,1019,950,990,976,947,986,954,992,939,988,956,1002,942,972,989,987,973,953,980,986,941,1020,937,981,1006,960,965,989,952,966,961,993,929,984,979,995,945,976,963,974,997,879,1002,906,1015,830,1141,968,990,952,954,973,950,981,950,975,992,941,972,998,973,950,956,985,950,980,966,936,1034,935,989,993,951,969,974,1001,960,962,970,962,972,969,996,960,983,965,975,981,982,988,976,975,946,988,1003,765,997,1242,912,1103,480,1067,944,921,691,1117,1045,1068,888,775,1130,956,961,974,998,973,940,935,990,976,952,1008,941,983,767,1167,958,1003,981,940,977,980,1004,958,974,950,1000,955,961,1015,944,985,981,998,911,1013,982,951,1006,943,961,979,1003,938,985,977,954,1001,945,981,969,994,974,964,959,981,995,932,975,971,991,963,952,976,971,980,1001,962,945,982,958,1008,975,920,1013,937,983,980,969,989,953,1004,956,962,991,935,971,972,961,999,940,1006,973,943,976,973,961,1010,948,979,979,994,975,933,1000,942,974,967,794,941,961,1136,685,790,1221,895,989,984,1480,333,945,1032,958,976,989,972,970,988,984,930,986,986,993,921,983,963,994,935,963,973,959,1009,977,932,1001,969,970,991,953,956,998,951,969,991,1000,959,953,989,979,986,980,897,1052,941,979,994,944,999,958,1003,948,969,1005,946,1003,948,980,957,994,960,1000,957,958,973,971,1010,940,34,1918,1018,918,1010,965,946,984,1003,966,958,1001,962,950,971,964,943,1003,968,927,1007,943,975,997,962,956,981,930,992,998,938,995,927,993,959,932,384,412,1309,675,1521,439,1396,341,1211,722,976,950,907,1017,945,1024,963,978,976,905,1031,972,992,900,1015,937,996,938,961,1009,969,946,999,959,969,974,959,994,974,948,988,925,992,968,945,885,1116,921,988,953,955,956,1038,920,981,974,1002,968,930,978,960,988,990,963,974,948,980,985,965,990,955,1001,949,1000,957,978,995,955,969,968,994,942,997,947,993,935,1033,931,953,968,975,909,982,936,1005,937,952,968,992,930,965,1003,958,941,973,986,953,963,983,977,944,1006,948,981,971,992,971,963,947,977,990,946,988,978,979,945,990,993,967,941,1003,979,941,997,905,1135,987,969,1119,664,1107,650,1041,1096,812,994,973,908,800,2265,26,1218,866,1002,823,1096,977,936,997,944,992,961,986,996,963,1003,946,1007,940,985,975,942,955,980,974,990,957,1001,980,938,1003,969,925,1002,966,1000,949,995,954,965,982,983,955,992,954,1005,965,969,947,974,970,1000,959,967,978,984,956,1001,949,983,1002,981,937,1009,948,1004,944,1003,948,998,959,960,1001,946,1021,952,960,978,967,962,981,949,969,1020,944,987,997,852,1055,888,990,964,977,960,1008,964,966,969,956,984,1006,968,950,971,982,980,973,947,1005,942,976,986,959,966,992,929,1002,967,972,970,975,997,1624,283,1085,767,1750,514,675,1011,850,1061,840,1004,825,1037,987,942,999,944,995,956,966,974,982,940,972,976,979,1004,950,992,966,957,1011,961,970,958,983,964,941,968,951,946,983,991,942,956,1003,946,962,991,941,995,969,931,1003,947,1012,944,989,949,975,989,962,954,1004,973,962,962,968,999,945,1004,964,980,968,962,963,971,977,973,1028,883,995,1014,928,969,983,965,995,940,984,1006,943,996,944,1013,951,950,937,976,1000,970,974,974,1001,949,1007,938,957,1061,2231,71,1183,835,1042,998,873,885,982,932,843,1134,921,997,971,943,980,974,979,980,982,977,941,970,962,1014,933,987,946,992,959,994,981,831,1101,963,938,943,1005,970,991,961,977,959,973,1000,973,940,1007,921,1018,891,969,980,970,982,958,976,984,985,961,960,1009,976,972,952,1007,966,954,946,1010,947,953,960,963,933,957,982,961,958,1002,927,981,968,967,977,998,955,999,947,994,991,964,962,947,973,988,968,999,926,983,965,971,1002,939,967,972,977,975,986,969,958,953,980,965,972,985,996,922,1000,965,951,961,977,1003,943,967,823,763,2252,34,1350,679,1032,985,872,945,1079,1004,1018,728,1144,921,987,971,991,951,997,937,1005,955,993,974,938,972,971,963,998,966,942,948,1010,948,1007,943,954,1000,941,970,961,991,948,991,994,946,1003,943,970,948,984,989,974,965,962,961,981,973,971,985,976,967,974,949,980,983,952,972,1012,967,926,996,942,984,990,954,970,974,1002,959,973,1001,948,957,970,992,949,1003,932,975,991,932,976,1008,936,997,944,977,1005,935,1003,965,1002,937,974,964,977,1009,927,962,971,1006,944,996,963,957,949,943,983,793,1130,976,995,964,914,1014,848,880,1474,333,1176,791,1015,1025,933,1376,365,1015,938,772,666,1268,943,974,988,948,983,1007,934,1003,985,946,962,978,1015,939,1001,939,981,957,977,979,962,959,1009,937,978,969,969,1008,936,1002,948,998,965,952,988,987,972,987,989,960,947,972,994,944,1010,950,994,972,943,1019,932,995,971,982,989,965,975,931,975,922,1078,959,967,980,971,935,1010,930,975,960,1022,923,974,1009,941,966,968,974,1001,940,976,974,983,982,981,1005,959,941,989,963,1005,939,889,1039,972,993,953,1012,931,967,971,977,1012,939,966,765,833,694,1261,1261,460,955,993,897,740,1121,937,1081,762,1081,916,955,881,1110,917,992,972,978,977,1012,965,948,977,992,960,1009,947,980,974,995,950,969,977,969,980,986,938,1009,955,975,952,975,981,987,985,972,955,984,1010,952,979,975,1001,950,969,972,979,983,996,951,969,981,1009,939,976,967,968,1007,919,989,933,982,972,716,569,1008,1107,870,1079,928,959,993,961,991,947,1015,984,899,1042,708,183,254,1163,933,1005,940,890,947,1003,1006,1590,259,1001,642,788,1410,957,963,975,951,950,956,962,972,962,958,853,1056,976,1002,917,1006,932,958,974,988,890,977,964,971,970,973,972,996,954,908,1021,937,986,983,1000,964,980,948,991,977,948,824,1114,951,936,1002,973,775,1061,295,924,1091,963,749,898,908,1021,879,1181,1207,508,833,1224,844,1090,941,990,970,954,939,999,971,950,956,991,946,952,981,938,1000,901,1000,985,909,750,1240,925,954,984,977,967,954,935,989,957,935,975,977,975,939,973,993,941,969,970,959,991,978,928,966,964,976,991,971,984,932,934,979,988,931,974,1323,484,1027,982,789,1099,819,789,925,1002,871,980,967,965,989,946,925,1033,814,1114,992,986,974,964,960,933,972,663,1268,956,963,978,971,965,975,924,1024,967,968,975,968,985,991,953,996,970,968,957,986,957,971,984,960,992,945,1000,967,962,945,1005,945,968,973,961,968,966,975,969,968,985,958,983,1021,942,973,953,989,981,948,997,1044,96,1310,834,1021,387,1225,1162,1331,63,1368,139,1207,610,1202,909,976,894,960,968,975,798,1145,847,1073,943,937,1008,916,933,739,1223,926,959,970,989,938,995,970,895,1007,945,1006,926,957,964,964,956,971,981,968,980,959,1007,942,995,952,974,970,964,957,980,978,947,968,1010,946,996,945,960,1033,908,976,1012,936,965,1011,903,994,951,976,981,979,939,981,964,910,950,1014,951,1039,265,1337,865,971,952,823,1076,961,1077,497,870,1187,864,961,946,1015,928,989,987,950,956,921,968,939,765,1169,953,921,953,1025,674,957,1193,956,977,980,943,995,959,959,995,961,971,1006,911,974,982,995,933,963,1013,961,929,994,936,1005,971,952,978,976,1001,938,966,979,1009,935,982,970,982,779,1157,956,977,960,975,974,998,939,964,863,862,1217,917,972,967,977,1003,952,1004,966,975,943,985,968,1003,930,970,982,971,885,842,1192,888,1194,707,809,1237,925,874,1000,776,669,1059,980,974,882,642,1289,796,571,1356,984,941,492,1298,149,1941,924,965,966,884,1046,951,966,975,972,943,941,976,961,982,986,971,942,979,993,962,917,966,952,971,950,1010,981,960,978,934,983,941,985,888,1008,1043,933,975,970,987,958,969,1010,945,999,951,960,977,983,961,984,1000,941,1011,876,1017,932,973,1006,948,981,976,950,971,987,972,988,940,999,950,975,997,973,961,970,986,941,1000,975,917,984,990,955,968,996,952,970,997,941,981,964,974,963,1013,932,958,1016,975,985,950,982,999,945,972,974,953,977,1000,951,992,970,974,962,935,1005,950,979,991,952,999,919,976,508,1700,580,605,1034,1044,1194,439,1124,896,864,896,1161,871,1843,41,1023,996,993,999,964,939,987,975,982,971,957,977,974,976,978,957,950,970,999,936,995,970,964,962,966,973,974,973,974,969,930,963,1004,945,991,956,996,943,973,1004,950,975,1013,959,960,975,905,989,965,984,947,999,944,982,984,969,1010,929,985,1016,906,797,1216,880,1026,927,982,959,992,959,997,984,954,991,957,1002,957,953,968,967,1011,926,1000,966,1003,953,979,999,963,970,916,1099,882,997,955,998,962,1003,968,948,1162,709,1166,847,1133,867,899,940,1001,870,1097,1432,307,1095,937,992,951,969,1003,932,1007,964,972,965,980,951,1002,938,982,911,1083,938,984,1000,954,1000,958,976,952,954,959,974,972,980,991,982,932,969,977,1008,923,982,956,980,981,989,964,957,982,982,979,1011,923,989,1003,960,950,1004,966,975,956,961,974,987,966,960,974,963,991,956,1018,936,992,957,985,985,955,956,982,983,962,956,979,977,975,998,937,971,985,951,971,973,952,994,954,999,960,950,985,961,1000,960,967,967,960,922,1000,815,1123,796,1149,952,991,945,965,956,984,991,918,1012,977,970,981,980,974,971,990,968,995,869,1033,934,992,979,954,890,1423,458,1355,535,1158,859,970,1017,546,739,1330,1183,628,1081,905,757,1197,974,994,937,985,953,1000,967,943,1002,957,973,949,977,970,942,980,1007,933,978,971,1016,937,967,990,956,997,938,980,959,975,970,1001,937,1005,970,927,973,973,957,1008,961,937,932,973,829,1111,959,981,889,1019,1009,979,940,973,1001,944,960,991,950,988,971,979,941,973,987,935,969,982,929,889,1017,963,1246,1225,294,1987,394,1216,11,1933,32,1268,841,952,929,231,1707,885,949,953,956,972,940,938,961,995,960,980,606,1277,943,950,924,977,1005,930,988,948,987,984,972,939,978,982,986,936,970,992,954,969,958,969,990,966,937,965,992,945,630,1301,912,949,883,1125,948,1008,929,988,969,1000,952,980,968,995,962,958,1009,914,962,968,995,960,967,939,974,999,948,960,997,981,940,981,964,989,975,949,983,974,982,956,971,960,963,1013,972,965,411,976,1033,789,974,1000,960,892,647,1127,1153,997,866,896,920,1104,553,1354,933,949,1000,979,962,969,955,981,964,989,929,975,969,957,975,937,991,949,1016,942,971,1014,943,983,974,1006,937,969,989,926,978,991,966,974,973,956,1003,947,958,1003,948,977,995,969,963,947,1005,953,983,963,1007,958,959,964,985,982,978,952,985,955,997,972,950,1006,934,1024,938,978,966,911,1046,987,933,977,985,892,1052,950,1010,915,979,974,971,999,969,982,935,968,1010,926,979,982,967,1007,968,949,1001,957,990,946,1013,925,989,972,965,967,983,682,919,979,1611,847,948,271,851,833,1385,546,1225,818,1067,840,1101,906,1013,972,932,994,862,1118,961,944,970,961,973,969,974,990,952,960,978,984,943,1000,942,973,997,950,1016,936,976,979,970,973,970,980,984,977,924,982,982,954,1001,955,994,951,992,954,998,975,963,944,973,977,929,975,963,1017,934,959,977,1001,970,945,960,1002,943,993,971,998,949,741,1202,982,968,998,924,991,980,939,1004,962,958,940,981,997,944,991,977,977,938,1136,790,1024,866,557,950,833,1009,882,1115,327,1583,957,999,974,1002,950,973,980,961,987,931,1008,944,971,977,972,937,1003,966,943,1003,972,944,1004,936,970,995,982,950,986,983,981,965,947,981,981,959,990,973,963,964,987,952,982,997,945,1005,941,980,978,994,975,967,968,987,979,984,958,929,977,998,946,972,982,997,959,977,976,974,948,963,992,957,971,1011,936,998,972,961,976,1001,969,953,981,963,996,988,982,917,978,951,978,944,986,943,982,973,976,824,1131,922,987,989,967,1303,620,1033,1730,0,1013,262,1323,1153,848,1061,905,981,843,960,521,1093,1321,912,964,1008,947,1002,962,978,939,994,990,924,990,983,938,958,975,975,1000,962,973,965,948,994,965,933,951,954,976,971,958,969,961,967,921,1009,971,996,967,968,970,966,987,1011,931,1011,955,961,983,898,800,1140,945,986,956,969,1007,926,971,1007,873,1036,888,899,1083,868,952,965,331,1482,1018,967,857,650,549,318,338,522,320,416,403,297,193,379,328,632,470,607,554,1044,939,983,966,985,961,995,972,979,965,863,46,316,107,409,350,326,99,374,971,922,908,940,452,669,1282,889,1058,970,945,1027,969,917,1024,933,977,960,970,995,955,949,964,967,991,952,970,1007,932,982,986,959,999,944,1015,966,978,966,937,1001,948,966,971,988,953,962,960,1008,941,1015,932,993,990,968,952,978,970,1001,959,1017,931,995,989,957,978,974,970,970,972,1001,976,960,963,1009,951,1006,920,980,978,999,951,974,983,982,978,1000,969,986,922,999,920,985,985,907,121,22,150,281,646,778,731,746,456,393,285,491,298,515,431,776,536,744,586,761,569,735,370,953,976,1003,960,938,995,985,960,987,968,990,988,985,981,980,975,993,981,987,938,1009,983,977,987,988,434,739,438,908,845,435,626,782,659,530,441,762,979,986,929,994,975,983,979,994,983,988,989,979,990,986,989,970,983,990,975,1000,978,990,985,941,986,991,963,656,723,156,194,359,344,255,593,670,616,646,625,679,669,1034,928,999,953,988,987,988,985,984,977,982,990,966,997,983,989,987,987,986,991,978,982,996,978,989,978,982,991,992,980,629,486,839,420,794,309,707,749,734,961,523,713,786,755,624,823,761,584,963,990,987,982,981,987,988,993,976,990,976,997,974,989,984,993,992,990,978,972,992,980,995,975,981,985,983,990,983,988,949,769,16,176,156,546,677,795,726,146,185,18,184,967,1005,980,991,960,990,984,990,983,983,991,994,977,980,974,995,985,980,996,980,977,985,974,977,970,999,989,980,990,988,691,859,755,886,612,809,529,648,801,460,240,147,421,245,576,473,311,843,1007,978,987,985,970,989,989,979,990,986,993,988,984,995,980,988,975,998,979,962,1013,958,1008,976,995,977,994,990,546,72,96,261,810,389,686,772,854,489,815,719,392,168,684,147,169,730,1027,979,990,979,998,983,979,988,987,985,996,976,1003,977,993,979,981,993,988,972,990,988,980,988,997,983,925,457,5,251,718,501,799,571,751,578,741,212,20,741,603,636,789,967,992,974,984,976,988,996,975,984,995,983,993,965,987,986,981,985,991,975,992,987,979,995,985,989,574,709,579,791,36,335,324,876,588,619,137,9,796,860,1025,971,976,1013,965,977,997,964,991,984,992,987,992,965,992,987,985,986,992,987,982,990,993,748,761,293,22,36,54,82,302,37,33,106,274,1133,938,999,1006,980,978,993,923,996,975,989,993,988,982,988,979,993,971,981,997,977,988,990,975,982,974,447,95,29,125,1182,928,1001,988,977,989,1005,976,987,990,985,990,992,990,987,986,991,988,992,982,991,983,987,982,993,988,537,407,571,715,431,26,21,157,39,64,6,1148,914,1011,983,987,988,988,990,980,986,974,993,974,981,988,994,986,992,981,981,995,989,976,972,1012,984,983,391,47,0,1202,920,994,962,988,982,979,985,1004,980,990,987,989,980,981,987,988,971,994,981,996,988,989,992,987,974,992,963,987,953,998,984,987,213,54,12,180,54,7,11,655,277,172,5,1176,903,998,956,1014,977,985,984,1000,976,990,971,993,986,988,989,988,995,976,987,975,989,987,985,987,984,990,947,1004,998,982,986,991,249,7,355,281,47,58,197,3,1219,927,966,977,999,986,987,990,986,992,982,978,992,985,988,995,982,980,986,983,993,989,984,984,988,984,984,990,352,92,13,474,109,82,135,0,111,526,972,985,990,988,984,970,1002,985,993,980,916,984,996,982,988,980,875,988,988,991,979,991,988,986,957,1028,956,975,985,1000,991,972,990,930,978,1012,977,985,990,979,978,991,907,907,1058,967,776,974,990,985,994,989,983,991,866,1128,953,999,987,977,992,983,992,983,990,980,976,993,983,988,989,798,928,1046,977,933,917,1063,963,986,993,984,984,986,987,991,978,990,961,988,981,988,982,983,972,651,966,999,988,997,986,685,3,154,248,86,0,454,917,1005,979,989,993,985,982,989,1008,983,988,992,972,984,868,962,1005,964,780,910,976,1007,963,959,1007,975,1001,963,989,987,979,978,982,988,926,951,1034,976,358,85,42,190,19,39,23,1204,869,957,1016,981,987,998,993,975,1005,964,991,976,996,985,992,984,980,989,996,845,972,1002,990,989,928,948,1032,979,993,954,995,985,1015,938,939,947,988,959,997,980,993,982,990,987,988,980,992,973,991,984,990,987,914,851,842,999,982,983,984,988,993,904,969,1010,976,995,963,946,1031,978,986,979,990,990,974,995,985,958,945,1006,991,1002,985,989,981,868,974,990,991,991,984,987,995,993,980,974,983,974,1003,964,997,967,995,984,980,1010,972,996,984,973,960,984,986,993,981,989,987,977,990,979,994,978,988,998,984,984,990,978,986,971,1003,981,995,994,994,981,980,991,987,986,992,984,991,988,834,973,999,983,987,989,978,989,992,987,985,980,992,988,977,990,979,911,962,968,967,970,992,974,959,989,983,994,979,992,986,985,981,948,953,1023,967,953,1031,974,987,980,992,989,989,984,992,984,993,991,984,983,989,970,980,982,989,986,980,994,927,966,1013,975,990,990,989,982,994,987,981,989,982,986,984,986,992,989,985,985,986,998,980,972,1049,918,1031,966,996,955,910,980,991,980,993,979,985,982,986,982,992,992,980,989,977,988,996,982,979,984,998,978,992,988,983,993,985,987,989,987,984,990,972,996,857,969,986,994,993,983,983,832,963,976,987,1009,967,989,989,983,993,850,978,980,994,984,986,977,994,984,942,1025,962,975,1002,964,977,977,997,985,990,984,988,980,990,985,990,988,992,981,993,984,991,982,994,989,982,988,995,988,976,990,984,987,990,993,971,997,983,985,997,976,995,993,944,963,1014,963,996,978,985,992,804,894,1111,950,988,990,989,987,987,981,992,993,969,954,981,993,986,993,978,975,842,953,1024,962,828,974,986,980,980,990,983,976,875,966,1008,980,990,978,1002,975,982,989,986,987,965,982,984,944,1025,979,985,991,980,999,983,987,857,984,1001,980,993,975,986,992,980,991,993,983,985,986,981,990,978,993,980,989,986,979,850,983,994,949,958,1015,991,986,984,980,991,873,961,1018,981,967,1017,951,1005,975,997,984,994,983,992,977,989,971,987,983,989,984,991,972,981,981,990,980,921,962,1010,986,987,988,977,980,945,1028,977,992,978,1000,978,980,997,980,989,976,938,1038,973,988,987,988,854,1004,985,984,986,985,991,983,985,984,982,995,989,988,856,983,986,993,979,989,987,983,986,986,986,986,989,981,987,985,983,985,990,985,979,993,982,985,994,972,998,984,988,975,997,981,984,988,997,978,973,980,989,987,986,986,988,985,985,992,989,983,988,980,997,989,976,988,983,981,993,984,989,985,989,977,988,990,983,980,986,910,966,1006,977,1000,986,975,989,990,989,978,993,986,989,980,986,987,980,994,987,991,985,941,986,990,991,984,836,982,981,995,994,981,987,985,925,976,1005,980,992,989,982,996,981,986,975,982,984,990,992,969,979,978,989,977,924,955,1016,975,996,986,991,989,983,984,994,991,974,960,1007,979,996,985,984,986,986,977,994,982,991,989,987,1008,856,927,1056,964,995,971,982,988,987,982,990,941,959,1011,979,991,989,979,994,977,984,983,975,958,991,993,978,985,980,990,985,990,948,988,940,967,1019,977,903,978,1004,988,980,982,981,833,927,1045,971,727,974,999,981,964,926,1065,959,1001,980,991,987,986,985,993,983,984,987,992,978,990,981,988,992,990,969,1006,982,994,979,987,979,992,980,990,980,995,981,990,987,988,990,990,977,997,979,989,977,969,990,806,948,1030,964,990,993,993,983,982,982,982,990,984,994,979,986,978,993,988,988,980,980,982,867,973,996,985,984,988,990,989,995,979,986,984,985,985,990,984,995,965,978,985,984,982,990,972,984,986,985,985,989,989,985,981,988,978,993,989,975,992,988,983,964,986,983,996,980,990,978,942,1044,960,977,954,1028,979,965,939,1026,960,991,974,993,981,994,988,993,990,990,988,987,991,986,976,992,970,999,975,999,981,993,960,949,1032,978,982,991,980,986,996,984,961,1012,975,1001,974,988,991,976,983,986,973,941,1035,963,976,988,954,813,1203,930,1008,981,989,989,984,916,968,1018,980,989,987,994,987,988,988,979,962,961,1026,963,986,997,906,977,994,987,990,977,986,994,991,980,987,989,989,978,995,993,988,981,992,988,992,982,981,994,943,957,1007,980,988,966,985,991,981,994,988,987,981,991,966,960,981,999,983,986,991,986,910,974,1003,984,993,983,991,988,987,987,988,984,987,991,988,985,986,979,984,980,985,985,989,984,994,824,984,994,983,1000,964,1002,985,978,989,985,996,977,982,996,983,986,998,978,989,991,987,991,844,860,988,975,994,980,988,984,999,893,982,987,992,990,987,987,992,987,930,953,1018,983,980,987,992,985,992,984,985,984,993,851,978,954,982,995,979,993,989,989,979,993,982,992,986,984,990,966,1016,969,971,992,970,861,808,980,943,1032,972,1004,975,983,942,977,985,990,988,957,1008,986,986,983,988,994,961,972,978,979,993,990,990,989,504,6340]},"stackTable":{"length":86577,"prefix":[null,0,1,2,3,4,5,6,7,4,9,10,11,12,13,14,12,16,17,12,19,12,21,22,11,24,25,26,27,28,12,30,11,12,33,26,12,36,37,12,39,12,41,42,43,44,45,46,47,12,9,50,51,52,53,54,55,56,57,52,59,60,61,62,63,64,65,66,67,68,69,53,71,72,73,74,75,76,77,78,50,80,81,82,83,9,85,86,87,88,89,90,91,92,86,94,95,96,97,98,99,100,101,85,103,104,105,106,107,108,109,110,111,112,113,85,115,116,117,118,119,120,121,122,123,124,125,126,121,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,122,151,152,153,154,155,156,157,158,159,160,151,162,163,164,165,166,167,168,169,170,171,172,173,174,175,163,177,178,179,180,181,182,183,184,185,186,151,188,189,190,191,192,193,194,195,196,197,198,151,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,122,223,224,225,226,227,228,229,230,231,232,233,234,235,236,128,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,128,267,268,269,270,271,272,273,274,275,128,277,278,279,280,281,282,283,284,285,286,287,288,289,117,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,327,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,345,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,367,386,387,388,389,390,391,392,393,394,123,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,415,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,151,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,200,527,528,529,530,531,532,533,534,535,536,310,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,543,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,200,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,122,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,538,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,656,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,267,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,267,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,655,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,658,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,656,825,826,827,828,829,830,831,832,833,834,835,787,837,838,839,840,841,842,660,844,845,846,847,848,849,850,851,852,853,854,855,404,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,278,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,238,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,658,950,951,952,953,954,955,956,957,958,959,960,961,962,826,964,965,966,967,968,969,970,971,972,973,272,975,976,977,978,951,980,981,982,983,984,985,675,987,988,989,990,991,992,993,994,995,996,997,998,999,676,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,825,1026,1027,1028,1029,1030,1031,744,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,115,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,281,1060,1061,1062,1063,1064,1065,1066,1067,1036,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,933,1089,1090,1091,1092,1093,1094,1095,1096,1097,278,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1116,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1138,1169,1170,1171,1172,1173,1174,1175,1176,1163,1178,1179,1180,1181,311,1183,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1196,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,744,1270,1271,1272,1273,1274,1275,1276,1073,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,618,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,278,1324,1325,1326,1327,1089,1329,1330,1331,1327,1333,1334,1335,1336,1337,1338,618,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,618,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,239,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1386,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1437,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1471,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1429,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1527,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1566,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1526,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1563,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1566,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1653,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1533,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1569,1711,1712,1713,1714,1715,1716,1717,1718,1719,1602,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1325,1738,1739,1740,1741,1742,1743,1744,1745,1411,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1460,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1494,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1508,1812,1813,1814,1815,1816,1817,1818,1539,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1583,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1609,1845,1846,1847,1848,1849,1850,1851,1633,1853,1854,1855,1856,1857,1660,1859,1860,1861,1566,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,1687,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1545,1916,1917,1918,1919,1667,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1727,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1395,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1759,1984,1985,1986,1987,1988,1989,1990,1991,1992,1791,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,1508,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,1529,2023,2024,2025,2026,2027,2028,2029,2030,2031,1711,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,1608,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,1700,2066,2067,2068,2069,2070,2071,2072,2073,1901,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,1608,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,1895,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,1702,2117,2118,2119,2120,2121,2122,2123,2124,2125,1936,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,1949,2145,2146,2147,2148,2149,2150,2151,600,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2166,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2194,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2179,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2249,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2287,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2290,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2276,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2304,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2304,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2348,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2362,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2388,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,243,2485,2486,2487,2488,2489,2490,2491,2492,130,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2531,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2558,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2522,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2610,2633,2634,2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2638,2685,2686,2687,2688,2689,2690,2691,2692,2622,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2646,2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2646,2736,2737,2738,2739,2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,2759,2760,2761,2762,2609,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2643,2782,2783,2784,2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2743,2799,2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2788,2812,2813,2814,2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,128,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2839,2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,224,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2920,2932,2933,2934,2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2945,2976,2977,2978,2979,2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,2911,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3011,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3038,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3013,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3039,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3074,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3010,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3035,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3068,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3167,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,239,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,1387,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3240,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3231,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3315,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3354,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3363,3391,3392,3393,3343,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3357,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3371,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3371,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3406,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3373,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3452,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,618,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3553,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3578,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3545,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3635,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3664,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3629,3713,3714,3715,3716,3717,3718,3719,3720,3659,3722,3723,3724,3725,3683,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3676,3744,3745,3746,3747,3748,3644,3750,3751,3752,3753,3754,3755,3683,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3691,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,1739,3802,3803,3804,3805,3806,122,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,223,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3843,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,744,3901,3902,3903,3904,1074,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3937,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3925,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4004,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4000,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4101,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4131,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,1074,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,128,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,3964,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,3980,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4038,4300,4301,4302,4303,4304,4305,4053,4307,4308,4106,4310,4311,4312,4313,4314,4315,4316,4317,4318,4138,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4331,4337,4338,4339,4340,4341,4342,4343,4344,4232,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,278,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,1325,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4379,4389,4390,4391,4392,4393,4394,1325,4396,4397,4398,4399,4400,280,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,128,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4414,4438,4439,4440,4441,4442,4422,4444,4445,4446,4447,4448,4449,4450,4451,4452,239,4454,933,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4456,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,932,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4482,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,239,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4514,4520,4521,4522,4513,4524,4525,4526,4527,4528,4529,4530,4531,1313,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,1380,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4558,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,1410,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4626,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4630,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4653,4686,4687,4688,4637,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,1747,4701,4702,4703,4704,4705,4706,4707,4648,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,115,4745,4746,4747,124,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4812,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4778,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4849,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4902,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4845,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4972,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,4758,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,1327,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,4549,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,4559,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,4582,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,4576,5100,5101,5102,5103,5104,5105,5106,5107,5108,4620,5110,5111,5112,5113,5114,5115,5116,4552,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,4584,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5037,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,4589,5165,5166,5167,5168,5169,5170,5171,5172,5036,5174,5175,5176,5177,5178,5179,5180,5181,5182,5083,5184,5185,5186,5187,5188,5189,5190,5191,5135,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,4560,5212,5213,5214,5215,4601,5217,5218,5219,5220,5221,5222,5223,5224,4550,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,5249,5250,4599,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5037,5324,5325,5326,5327,5328,5329,5330,5331,5332,5064,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,5354,4552,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5053,5376,5377,5378,5379,5380,5138,5382,5383,5384,5385,5386,5387,5388,4693,5390,5391,5392,5393,5394,5395,4653,5397,5398,5399,5400,5401,5402,5403,4693,5405,5406,5407,4653,5409,5410,5411,5412,5413,5414,5415,5416,4728,5418,5419,5420,5421,5422,5423,5424,3226,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,4713,5439,5440,5441,5442,4627,5444,5445,5446,5447,5448,5449,5450,4728,5452,5453,5454,5455,5456,5457,5458,5459,5460,5445,5462,5463,4728,5465,5466,5467,5468,5469,5470,5471,4673,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,5489,5490,5491,5492,4641,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5462,5505,5506,4688,5508,4672,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5410,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,4699,5535,5536,5537,4654,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552,5393,5554,5555,5556,4688,4691,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,1382,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,4641,5587,1387,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,4730,5646,5647,5648,5649,5650,5651,5652,5429,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,4712,5665,5666,5667,5668,5669,5670,5671,5672,5673,3232,5675,5676,5677,5678,5679,5680,5681,5682,5648,5684,5685,5686,5687,5484,5689,5690,5691,5692,5693,5694,4643,4627,5697,5698,5699,5700,5701,4654,5703,5704,4674,5706,5707,5708,5709,5710,5495,5712,5713,5714,5715,5716,5717,5718,5719,4691,5721,5722,5723,5724,5725,5726,5727,5728,5729,5703,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5724,5743,5744,5745,5746,5747,5541,5749,5750,5751,5752,5753,5754,5755,5756,5757,4709,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,3215,5772,5773,5774,5775,5776,5777,5452,5779,5780,5781,5782,5783,5784,5785,1387,5787,5788,5789,5790,5791,5792,5793,5794,5795,4729,5797,5798,5799,5800,5801,5802,5803,5804,5655,5806,5807,5808,5809,5810,5811,5812,5813,5439,5815,5816,5817,5818,5819,5462,5821,5822,5823,5824,5467,5826,5827,5828,5829,5830,5823,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,4653,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5483,5855,4637,5857,5406,5859,4654,5861,4712,5863,5864,5865,5866,5867,5787,5869,5465,5871,5872,5873,3226,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5419,5891,5892,5893,5894,5895,5896,5897,5449,4729,5900,5901,5902,5903,5904,5905,5906,5907,5908,5909,5910,5911,5912,4631,5914,4642,5916,5700,5918,4654,5920,5921,1386,5923,5924,5925,5926,5927,4637,5929,5930,5931,5932,5933,5934,5935,5936,130,5938,5939,5940,5941,5942,5943,5944,5945,1089,5947,5948,5949,5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,5996,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,5962,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6030,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6081,6112,6113,6114,6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,6149,6026,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6171,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,280,6235,6236,6237,6238,6239,6240,6241,224,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,6254,6255,1103,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6012,6277,6278,6279,6280,6281,6282,6283,6152,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6067,6298,6299,6300,6301,6302,6303,6304,6305,6101,6307,6308,6309,6310,6311,6312,6313,6314,6315,6157,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6364,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,5955,6384,6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,6404,6405,6406,6010,6408,6409,6410,6411,6412,6413,6414,6020,6416,6417,6418,6419,6030,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,6434,6076,6436,6437,6438,6439,6440,6441,6442,6145,6444,6445,6446,6330,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6454,6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,932,6475,6476,6477,6478,6479,6480,6481,6482,1325,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,6494,6495,280,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,718,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,5787,6523,6524,6525,6526,6527,6528,6529,6530,6531,1410,6533,6534,6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6540,6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6534,6610,6611,6612,6613,6614,6615,6616,6617,6618,6541,6620,6621,6622,6623,6624,6625,6626,6627,6628,6629,6630,6631,6534,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6539,6653,6654,6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,6689,6690,6691,6692,6693,6568,6695,6696,6697,6698,6699,6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6529,6712,6713,6714,6715,6716,6717,6718,6621,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6573,6742,6743,6744,6745,4638,6747,6748,6749,6750,6751,6733,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6698,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6655,6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6604,6801,6802,6803,6804,6805,6806,6807,6808,6809,6810,6811,6523,6813,6814,6815,6816,6558,6818,6819,6820,6573,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,5712,6833,6834,6835,6836,6837,6755,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6570,6869,6870,6871,6872,6873,6874,6875,6876,6534,6878,6879,6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6588,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,6959,6960,6961,6637,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6667,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,6989,6990,6991,6992,6772,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,6523,7005,7006,7007,7008,7009,7010,7011,7012,7013,6621,7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,6802,7032,7033,7034,7035,7036,6613,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,7049,7050,7051,7052,7053,6568,7055,7056,7057,7058,5774,7060,7061,7062,7063,6978,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,6770,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,7094,7095,7096,6527,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,7124,6858,6705,7127,7128,7129,7130,7131,6890,7133,7134,7135,7136,7137,7138,7139,7140,7141,6577,7143,7144,7145,6782,7147,7148,7149,7150,7151,7152,7153,7076,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,7169,7170,6873,7172,7173,7174,7175,7176,5789,7178,7179,7180,7181,7182,7183,5930,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7191,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,5863,7231,7232,7233,7234,7235,7236,7237,7238,7239,4716,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,4653,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,5876,7268,7269,7270,7271,4637,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7273,7302,7303,7304,7305,7306,4728,7308,7309,7310,4710,7312,7313,7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,5843,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,5484,7359,7360,7361,7362,7363,7364,7284,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,7291,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,5419,7394,7395,7396,7397,7398,4688,7400,1381,7402,7403,7404,7405,7406,7407,7408,7409,7410,7215,7412,7413,7414,7415,7416,7417,7418,7419,7413,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,5418,7432,7433,7434,7435,7436,7437,7438,7439,7440,7441,7318,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,5733,7466,7467,7468,7469,7470,7471,7472,7473,5857,7475,7277,7477,7478,7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7369,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,7514,4712,7516,7517,7258,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,7529,7270,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7369,7543,7544,7545,7546,7547,7548,7549,7550,7284,7552,7553,7554,7555,7556,7557,7558,4731,7560,7561,7562,7563,7564,7565,4641,7567,7568,7569,7570,7571,7572,7573,7574,7575,7466,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,7603,7604,4679,7606,7607,7608,7609,7610,7506,7612,7613,7614,7615,7616,7617,7618,7619,7371,7621,7622,7623,7624,7625,7626,7627,4728,7629,7630,7631,7632,7633,7634,7635,7636,7637,5704,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,5791,7666,7667,7668,7669,7670,7671,7672,7673,7674,7215,7676,7677,7678,7679,7680,7215,7682,7683,7684,7685,7686,7687,7688,7689,7690,7691,7692,4642,7694,7695,7696,7697,7698,7699,4732,7701,7702,7703,7704,7705,5398,7707,7708,7709,7710,7711,7712,7713,7714,5429,7716,7717,7718,7719,7720,7721,7722,7723,7724,7725,7726,7727,7728,7729,7730,7552,7732,7733,7734,7305,7736,7737,7738,7739,7740,7741,4729,7743,7744,7745,7746,7747,7748,7749,7750,7751,7752,4688,7754,4656,7756,7757,7758,7759,7760,7761,7762,7763,7199,7765,7766,7767,7768,7769,7770,7771,7772,7773,7774,7187,7776,7777,7778,7779,7780,7495,7782,7783,7784,7785,7786,7787,7788,7789,7790,7791,7792,7793,7794,7795,7796,7797,7798,7799,7800,7239,4654,7803,7804,7805,7806,7807,7808,7809,7270,7811,7812,7813,7814,7815,7816,7817,7818,7819,7820,7821,7822,7391,7824,7825,7826,7827,7552,7829,7830,7831,7832,7833,7834,7835,7836,7837,7560,7839,7840,7841,7842,7843,4644,7845,7639,7847,7848,7849,7850,7851,7852,7187,7854,7855,7856,7855,7858,7859,7860,7861,7862,7863,7864,7865,7866,5665,7868,7869,7870,7871,7872,7873,7874,4716,7876,7877,7694,7879,7880,7881,7882,7883,7884,7885,7886,7887,7888,7889,7890,7891,7892,7893,5832,7895,7896,7897,7898,7899,7900,7901,7902,7500,7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920,7921,7922,7923,7924,7925,7926,7927,7928,7929,7930,7931,7932,7933,7934,7935,7936,7937,7938,7939,7940,7941,7942,7943,7944,7945,7946,7947,7948,7949,7950,7951,7952,7953,7954,7955,7956,7957,7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7968,7969,7970,7971,7972,7973,7974,7975,7976,7977,7978,7979,7980,7981,7982,7983,7984,7985,7986,7987,7988,7989,7990,7991,7992,7993,7994,7995,7996,7997,7998,7999,8000,8001,8002,7506,8004,8005,8006,8007,8008,8009,5798,8011,8012,8013,5498,8015,8016,8017,8018,8019,8020,5733,8022,8023,8024,8025,8026,8027,8028,8029,8030,8031,8032,5445,8034,8035,8036,8037,8038,8039,8040,8041,7391,8043,8044,8045,8046,8047,8048,8049,8050,8051,8052,8053,7391,8055,8056,8057,8058,8059,8060,7243,8062,8063,8064,8065,8066,8067,5738,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,5431,8082,8083,8084,8085,5929,8087,8088,8089,7302,8091,8092,8093,8094,8095,8096,8097,8098,7310,8100,7475,8102,8103,5738,7858,8106,8107,8108,8109,8110,8111,7855,8113,8114,8115,8116,8117,8118,8119,8120,8121,5857,8123,8124,8125,8126,8127,8128,7245,8130,7884,8132,8133,8134,8135,8136,8137,8138,5822,7276,8141,8142,8143,8144,8145,8146,8147,8148,8149,8150,8151,7508,8153,8154,8155,8156,8157,8158,8011,8160,8161,8162,8163,8164,8165,8166,7335,8168,7756,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,8188,8189,7866,8120,8192,7508,8194,8195,8196,8197,8198,8199,8200,5714,8202,8203,8204,8205,8206,8207,4658,8209,8210,8211,8212,8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,5431,8228,8229,8230,7204,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,7422,8244,8245,5418,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,7696,7639,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,7855,7855,8278,8279,4725,8281,8282,8283,8284,8285,8286,8287,8288,8289,5916,5698,8292,8293,8294,8295,8296,8297,7552,8299,8300,8091,8302,8303,8304,7629,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,4637,8321,8322,8323,8324,5541,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,7774,7858,8338,7475,5817,8341,8342,8343,5749,8345,8346,8347,8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,5655,8365,8366,8367,8368,8369,8370,8371,8143,8373,8374,7209,8376,8377,8378,8379,8380,8381,8382,8383,8384,5863,8386,8011,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,4654,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,5511,8415,8416,8417,8418,8419,8420,7288,8422,8423,8424,8425,8426,7366,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,5648,8439,8440,8441,8442,8443,8444,8445,8446,8447,7754,7645,8450,8451,8452,8453,8454,8455,8456,8457,8458,8459,8460,8461,4627,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,8045,8474,8475,8476,7391,8478,8479,8480,8481,8482,8483,8484,1410,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,7335,8497,8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,8518,8519,8520,8521,5790,8523,8524,8525,7215,8527,8528,8529,8530,8531,8532,8533,8534,8535,7218,8537,5863,8539,8540,7629,8542,8543,8544,8545,8546,8547,7707,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8560,8561,8562,8563,4669,8565,8566,8567,8043,8569,8570,8571,8572,8573,8574,8575,8576,8577,7391,8579,8580,8581,5864,8583,5846,8585,8586,8587,8588,8589,8590,4454,8592,8593,7683,8595,8596,8597,8598,7208,8600,8601,8602,8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8321,8618,8619,8620,7561,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,5846,8633,8634,8635,4631,8637,8638,8639,7287,8641,8642,8643,8644,8645,8646,8647,8648,7510,8650,8651,5419,8653,8654,8655,8656,8657,8658,8659,8660,8661,7696,8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,8683,8684,5734,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,8698,8699,8700,8701,8115,8703,8704,7612,8706,8707,8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,7372,8720,8721,8722,8723,8724,8725,8726,8727,8728,8729,7313,8731,4657,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,5878,8749,8750,8751,8752,8753,8754,8755,8756,8757,7553,8759,8760,8761,8145,8763,8764,7310,7696,8767,8768,8769,8770,4654,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,4678,8783,8784,8785,8786,7506,8788,8789,8790,8791,8792,8793,8794,8795,8796,7372,8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,4724,8809,8810,8811,8812,8813,8814,8815,7577,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,5869,8832,8833,8834,8835,8836,8837,8838,8602,8840,8841,8842,8843,7766,8845,8846,8847,8848,8849,8850,8851,8656,8853,8854,8855,8856,8857,8858,8859,8860,8861,7243,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,5411,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,7270,8893,8894,8895,8896,8897,8898,8899,8900,8901,7824,8903,8904,8905,8906,8907,8908,7305,8910,8911,8912,8913,8914,8915,8916,8917,4728,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,5470,8931,8932,8933,8934,8935,8499,8937,8938,8939,8940,8941,8942,8943,8944,8945,5483,8947,8948,8949,8950,8951,8952,8953,8791,8955,8956,8957,7506,8959,8960,8961,8962,8963,8964,8965,8966,7697,8968,8969,8970,8971,5541,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,7532,8994,8995,8996,8997,8998,7392,9000,9001,9002,9003,9004,9005,8145,9007,9008,9009,9010,9011,9012,9013,9014,8100,8670,9017,9018,9019,9020,7586,5477,9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,8959,9064,9065,9066,9067,8428,9069,9070,9071,9072,9073,9074,9075,7310,5733,9078,9079,9080,9081,9082,1389,9084,9085,9086,9087,9088,7412,9090,9091,9092,9093,9094,7685,9096,9097,9098,9099,5857,9101,9102,4732,9104,9105,9106,9107,9108,9109,9110,9111,8103,5832,8959,9115,7277,9117,9118,9119,9120,9121,9122,9123,9124,4728,9126,9127,9128,9129,9130,9131,5467,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9101,5446,9148,8581,8581,8491,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,4686,9171,9172,9173,9174,1382,9176,9177,9178,9179,9180,9181,8609,9183,9184,8851,9186,9187,7310,9189,7310,9191,4688,5486,9194,9195,9196,7391,9198,9199,9200,9201,9202,9203,9204,9205,7294,9207,9208,9209,9210,9211,7315,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,9223,5500,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,7522,9244,9245,9246,9247,9248,9249,9250,9251,9252,9253,9254,7191,9256,9257,9258,9259,9260,9261,9262,9263,9264,8386,9266,9267,9268,9269,9270,9271,9272,7254,7258,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,7270,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,7293,9303,7305,9305,5891,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,4722,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,8551,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,5833,9356,9357,9358,9359,9360,9361,9362,9363,9364,8143,9366,8005,9368,9369,9370,9371,9372,9373,8011,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,5843,9397,9398,8175,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,7866,7185,9415,9416,9417,9418,9419,9420,9421,9422,9423,8007,9425,9426,9427,9428,9429,9430,9431,9432,9433,4717,9435,9436,9437,9402,9439,9440,9441,9442,9443,9444,9445,9446,9447,5431,9449,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,8381,9461,9462,9463,9464,9465,9466,9467,9468,7421,9470,9471,9472,9473,5818,9475,9476,9477,4729,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,5499,9491,9492,9493,9494,5824,8581,9497,9202,9499,9500,9501,9502,7316,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,7710,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9244,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,8278,9547,9548,9549,9550,7614,9552,9553,9554,9555,5798,9557,9558,9559,9560,9561,9562,9563,9564,7466,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,7060,9578,9579,9580,9581,7765,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9071,9595,9596,9597,9598,9599,9600,9601,8043,9603,5714,9605,8633,9607,9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,7403,9635,9636,9637,7218,8843,9640,9641,9642,9643,9644,9645,9646,9647,9557,9649,9650,9651,9652,9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,8015,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,5444,9683,9684,9685,8043,9687,9688,9689,9690,8581,9157,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,5508,5571,9712,9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,9733,9640,9735,9736,9737,9738,9739,9740,9741,9742,9743,7203,9745,9746,9747,9748,9749,9750,5779,9752,9753,9754,9755,9756,9757,9758,9759,8286,9761,9762,9763,9764,9765,8103,8035,9768,7495,9770,7284,9772,9773,9214,9775,9776,9777,9778,9779,9780,8469,8048,9783,9784,9785,9786,9787,8143,9789,9790,9791,9792,5872,9794,9795,8016,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,9808,9809,7882,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9747,9837,9838,9839,9840,9841,9842,9843,8845,9845,5891,9847,9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,5508,5698,9864,7552,9866,7276,9868,9869,9870,9871,9872,9873,9874,9875,8543,9877,9878,9879,9880,9881,9882,9883,9884,9885,9886,5410,9888,9889,9890,9891,8739,9893,9894,9895,9896,9897,9898,9899,7776,9901,9902,9903,9904,8103,8790,9907,9908,9909,9910,8388,9912,9913,8686,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,7668,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,7218,9957,8600,9959,9960,9189,7432,9963,9964,9965,9966,9967,9968,9969,9970,5450,7372,9973,9974,9975,8238,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,5716,9988,9989,9990,9991,4729,9993,9994,9995,9996,9997,9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,9337,10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021,10022,5444,10024,10025,9784,10027,10028,8482,10030,10031,10032,7320,10034,10035,4688,10037,4706,10039,10040,10041,10042,10043,10044,10045,8602,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,8845,10058,10059,10060,10061,10062,10063,8789,10065,10066,10067,10068,5712,10070,10071,10072,10073,10074,8209,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,10094,7717,10096,10097,10098,10099,10100,10101,10102,7276,10104,7412,10106,10107,10108,10109,7380,10111,4653,10113,5832,10115,10116,10117,7829,10119,10120,10121,8381,10123,10124,10125,10126,10127,4730,10129,10130,10131,10132,10133,4654,10135,10136,10137,10138,10139,10140,10141,10142,10143,121,10145,10146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10150,10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249,10250,128,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261,10262,5942,10264,10265,10266,10267,10268,10269,10270,10271,10272,10265,10274,10275,10276,715,10278,10279,10280,10281,10282,10283,10284,10285,6880,10287,10288,6621,10290,10291,10292,10293,10294,7089,10296,10297,10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,4627,10309,8959,10311,10312,10313,10314,10315,10316,9595,9995,10319,10320,10321,10322,7756,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,10338,7532,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354,10111,8643,10357,10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,4731,10369,10370,5934,10372,10373,10374,10375,5732,10377,10378,10379,10380,8279,10382,7278,8707,10385,10386,10387,10388,10389,8202,10391,10392,10393,10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,5543,10405,10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,8752,10418,10419,10420,10421,10422,10423,10424,7288,10426,10427,10428,10429,10430,10431,10432,10433,10434,10435,10436,10437,9308,10439,10440,10441,10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,7315,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,10470,10471,10472,744,10474,10475,10476,10477,10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,10494,10495,10496,10497,884,10499,10500,10501,10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,10519,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10546,10602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,10614,10615,10602,10617,10618,10619,10620,10621,10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10620,10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,10686,10687,10688,10689,10602,10691,10692,10693,10694,10695,10696,10697,10698,10699,10700,10701,10604,10703,10704,10705,10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,10746,10747,10748,10728,10750,10751,10752,10753,10754,10755,10539,10757,10758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,10818,10819,10502,10821,10822,10823,10824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10821,10841,10842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,10842,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,10902,10903,10904,10905,1099,10907,10908,10909,10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,10926,10927,10928,10929,10589,10931,10932,10933,10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10609,10945,10946,10947,10948,10949,10950,10951,10952,10642,10954,10955,10956,10957,10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10618,10970,10971,10972,10973,10974,10975,10976,10977,10978,10666,10980,10981,10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10707,10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,10740,11017,11018,11019,10535,11021,11022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,11090,10830,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,10844,11103,11104,11105,11106,11107,11108,11109,11110,10859,11112,11113,11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,11126,1315,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,1325,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,11154,11155,4552,11157,11158,11159,11160,11161,11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,11174,4620,11176,11177,11178,11179,11180,11181,11182,11183,9087,11185,11186,11187,11188,11189,11190,9191,9931,11193,7245,11195,11196,11197,7406,11199,11200,11201,11202,11203,11204,9127,11206,11207,11208,11209,11210,11211,5590,11213,11214,11215,11216,11217,11218,11219,11220,11221,5428,11223,11224,11225,11226,11227,7840,11229,5397,11231,11232,11233,11234,11235,11236,11237,11238,5699,11240,5712,11242,11243,11244,11245,11246,11247,11248,11249,11250,4701,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,11262,11263,11264,4654,11266,11267,11268,11269,11270,11271,8418,11273,11274,11275,7315,11277,11278,11279,11280,11281,11282,11283,11284,11285,11286,11287,239,11289,11290,9963,11292,11293,11294,11295,8549,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,7359,11310,11311,11312,11313,11314,7754,7717,11317,11318,11319,11320,11321,11322,11277,7467,11325,11326,11327,11328,11329,11330,11331,11332,5483,11334,11335,11336,11337,11338,11339,11340,11341,11342,11343,8585,11345,11346,11347,11348,5941,11350,11351,11352,11353,11354,11355,4798,11357,11358,11359,11360,11361,11362,11363,11364,11365,11366,11367,11368,11369,4831,11371,11372,11373,11374,11375,11376,11377,11378,11379,11380,11381,4946,11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11393,11394,11395,11396,4849,11398,11399,11400,11401,11402,11403,11404,11405,11406,11407,11408,11409,11410,11411,11412,11413,11414,11415,11416,11417,11418,11419,11420,11421,11422,11423,11424,11425,11426,11427,11428,11429,11430,11431,11432,11433,11434,11435,4849,11437,11438,11439,11440,11441,11442,11443,4951,11445,11446,11447,11448,11449,11450,11451,11452,11453,4993,11455,11456,11457,11458,11459,11460,11461,11462,4993,11464,11465,11466,11467,5014,11469,11470,5030,11472,5040,11474,11475,11476,5377,11478,11479,11480,11481,11482,5224,11484,11485,5227,11487,11488,11489,11490,11491,11492,11493,11494,11495,11496,11497,11498,11499,4589,11501,11502,4582,11504,11505,11506,11507,11508,11509,11510,5212,11512,11513,11514,11515,5157,11517,11518,11519,11520,11521,11522,5083,11524,11525,11526,11527,5243,11529,11530,11531,11532,11533,11534,11535,11536,11537,11538,11539,4601,11541,11542,11543,11544,11545,11546,5370,11548,11549,11550,11551,11552,11553,4576,11555,11556,11557,11558,11559,11560,11561,11562,11563,11564,11565,11566,4584,11568,11569,5155,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,5047,11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,11606,11607,5200,11609,11610,11611,11612,11613,11614,11615,11616,11617,11618,11619,11620,11621,11622,4557,11624,11625,11626,11627,11628,11629,11630,11631,11632,5201,11634,11635,11636,11637,11638,11639,11640,11641,11642,11643,5160,11645,11646,11647,11648,11649,11650,11651,11652,11653,5349,11655,11656,11657,11658,11659,11660,11661,4586,11663,11664,11665,11666,11667,11668,11669,5484,11671,11672,10037,7362,11675,11676,11677,8168,11679,11680,11681,5514,11683,11684,11685,11686,11687,11688,7333,11690,11691,11692,11693,11694,5514,11696,11697,11698,11699,11700,11701,4654,11703,11704,11705,11706,5480,11708,11709,11710,11711,11712,11713,11714,11715,11716,8550,11718,11719,11720,11721,11722,11723,11724,11725,5698,11727,6837,11729,5823,11731,11732,5857,11734,9148,11736,9213,11738,11739,11740,11741,11742,4669,11744,11745,11746,11747,11748,5833,11750,11751,11752,11753,11754,10347,4647,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,5429,11819,11820,11821,11822,11823,11824,11825,11289,11827,11828,11829,5769,11831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890,11891,8346,11893,11894,11895,11896,11897,5727,11899,11900,11901,11902,11903,11904,11905,11906,11907,5409,11909,11910,11911,11912,11913,11914,11915,11916,11917,11918,5724,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,11930,11931,11932,11933,11934,11935,11936,9813,11938,11939,11940,11941,11942,11943,11944,8619,11946,11947,8876,11949,11950,11951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,11920,5540,11968,11969,11927,11971,11972,11973,11974,11975,11976,11977,11978,11979,11266,11981,11982,11983,11984,11985,11986,11987,11988,11989,11990,4699,11992,5703,11994,11995,11996,11997,11998,11999,12000,12001,12002,4694,12004,12005,12006,12007,8589,12009,12010,12011,12012,12013,12014,4637,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,12038,12039,12040,8015,12042,12043,12044,12045,12046,12047,4693,8491,12050,4694,12052,12053,12054,12055,12056,10326,12058,7359,12060,12061,12062,12063,12064,12065,12066,12067,9335,12069,12070,12071,5445,12073,8321,12075,8783,12077,12078,12079,12080,12081,12082,9104,12084,12085,12086,12087,12088,12089,12090,11187,12092,12093,4723,8523,12096,12097,12098,12099,12100,12101,4716,12103,12104,12105,12106,12107,7406,12109,12110,12111,12112,12113,4713,12115,12116,12117,12118,12119,7060,12121,12122,12123,12124,1379,12126,4712,12128,12129,12130,12131,12132,12133,1381,12135,12136,12137,12138,12139,12004,12141,12142,12143,12144,12145,12146,12147,12148,5704,12150,12151,12152,12153,12154,12155,12156,12157,12158,12159,11920,12161,7754,5727,12164,9336,12166,12167,12168,12169,4699,12171,8125,5832,12174,12175,8666,12177,12178,12179,4704,12181,12182,12183,5712,12185,12186,12187,5411,12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,12206,5489,12208,12209,12210,12211,12212,12213,12214,12215,9105,12217,12218,12219,8326,12221,12222,12223,12224,12225,12226,5727,12228,12229,12230,7640,12232,12233,12234,12235,12236,12237,12238,12239,8367,12241,12242,12243,12244,12245,7242,12247,12248,12249,12250,12251,12252,12253,5916,4630,12256,12257,12258,12259,8102,12261,7258,12263,5537,7641,12266,12267,12268,12269,12270,12271,12272,12273,12274,8041,11734,12266,12278,12279,12280,12281,12282,12283,12284,12017,12286,12287,12288,12289,12290,12291,12292,12293,7709,11820,12296,7310,12298,5499,12300,12301,5934,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,12314,12315,12316,12317,12318,12319,12320,11258,12322,5563,7256,12325,12326,12327,12328,12329,12330,9356,12332,12333,12334,12335,7239,7641,12338,12339,12340,12341,12342,12343,12344,12345,12346,10037,7668,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,7868,12363,12364,12365,12366,12367,12368,5409,12370,12371,12372,12373,12374,12375,12376,12377,5484,12379,12380,12381,7309,8875,12384,12385,12386,12387,12388,12389,12390,12391,4693,12393,12325,12395,12396,12397,12398,12399,12400,12401,12402,8639,12298,7519,12406,12407,12408,12409,12410,12411,12412,12413,12414,4692,12416,12417,12418,8170,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,7270,12432,5871,12434,12435,12436,12437,11704,12439,12440,12441,12442,12443,12444,5484,12446,12447,12448,12449,12450,12451,12452,12453,12454,5398,12456,12457,12458,12459,9087,12461,12462,12463,12464,5893,12466,12185,12468,12469,12470,12471,12472,12473,7902,4730,12476,12477,12408,12479,12480,12481,12482,12483,12484,11971,12486,12487,12488,12489,12490,12491,7640,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,5807,12509,12510,12511,12512,12513,12514,12515,12516,5685,12518,12519,12520,12521,4656,12523,12524,12525,12526,12527,7433,12529,11266,12531,12532,12533,12534,12535,12536,12537,12538,12539,5395,12541,12542,11894,12544,5462,12546,12547,12548,12549,12550,12249,12552,12553,12554,12555,12556,12557,12558,12559,12560,8734,12562,12563,12564,12565,12566,5537,12267,12569,12570,12571,12572,12573,8038,9566,12576,4628,12578,12579,12580,12581,12582,7717,12584,12585,12586,12587,9191,4653,12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,9683,12606,12607,12608,9215,12610,12611,12612,11912,12614,12615,12616,12617,5391,12619,12620,12621,7756,12623,12624,12625,12626,10346,12628,12629,12630,12631,12632,12633,9995,12635,12636,12637,12638,4653,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,8415,12652,12653,12654,12655,12656,12657,7310,5411,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12020,12671,8733,12673,12674,12675,12676,12677,5821,5816,12680,12681,12682,12683,8734,12685,12686,12687,12688,12689,12690,12691,12692,12693,5727,12695,12696,12697,8498,12699,12700,12701,12702,12703,12704,12705,9295,12707,12708,12709,12710,9479,12712,12713,12714,4688,11684,12717,12718,12306,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12182,12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,7258,12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,12758,12759,12760,12761,12762,5444,12764,12765,4717,12767,5541,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,12782,12783,12784,12785,12786,12418,9079,12789,12790,12791,12792,12793,5655,12795,12796,12797,5455,12799,12800,12801,12802,12803,12187,12805,12806,12807,12808,12809,5487,12811,12812,12813,12814,12815,12816,12817,12610,12819,12820,12821,12822,12823,12824,12825,12826,5735,12828,12829,12830,5405,12832,12833,12834,12835,4654,12837,12838,12839,12840,12841,12842,12843,12844,12845,12846,7717,12848,12849,12850,12851,12852,12853,12854,11278,12856,12857,12858,12859,4688,5479,12862,12863,12864,12865,12866,12867,12868,12869,12870,9492,12872,12873,9084,12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12767,7567,5445,12177,12890,12891,12892,12893,12894,12895,5411,12897,12898,12899,12900,12901,12902,5542,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,7270,12915,12916,12917,12918,12919,12920,8323,12922,8818,12924,12925,12926,12581,12928,12929,12930,12931,12932,12933,12934,7707,12936,12937,12938,12939,12940,12941,12350,12943,12944,12945,12946,12947,12948,12372,12950,12951,12952,12953,12954,12955,9864,7243,12958,12959,12960,12961,12962,12963,12593,12965,12966,12967,12968,8417,12970,12971,5496,12973,12974,12975,11226,12977,12978,7243,12980,12981,12982,12983,5714,12985,12986,12987,12988,12989,12990,12991,12992,12606,5932,12995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,4454,13007,13008,13009,13010,13011,8133,13013,13014,13015,13016,13017,13018,13019,13020,11335,13022,12084,13024,7258,13026,13027,13028,13029,13030,13031,13032,13033,13034,12017,13036,13037,13038,10324,13040,13041,13042,13043,7270,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,13058,13059,9217,13061,13062,13063,13064,11703,13066,13067,13068,13069,13070,13071,8947,13073,13074,13075,13076,13077,4653,13079,13080,13081,13082,13083,13084,13085,13086,11217,13088,13089,13090,13091,13092,5541,13094,13095,13096,13097,13098,13099,13100,13101,13102,13103,9148,13105,9154,13107,13108,13109,13110,12314,13112,13113,5450,7630,13116,13117,10044,13119,13120,13121,11900,13123,13124,13125,13126,13127,12661,13129,13130,4681,13132,13133,13134,13135,12084,13137,13138,12661,13140,13141,13142,13143,13144,13145,13146,13147,7519,13149,13150,13151,13152,13153,13154,13155,13156,8639,9308,13159,13160,13161,5749,13163,13164,13165,13166,13167,13168,13169,13170,13171,12487,13173,13174,13175,13176,13177,13178,13179,13180,13181,12266,13183,13184,13185,13186,13187,13188,13189,13190,13191,13192,13193,10145,13195,13196,13197,13198,13199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,13286,13287,13288,13289,10262,13291,13292,13293,13294,13295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,13322,3841,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,13382,13383,13384,13359,13386,13387,13388,13389,13390,13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,13418,13339,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,13442,13443,13424,13445,13446,13447,13448,13449,13450,13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,13466,13424,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,13514,13515,13516,13510,13518,13519,13520,13521,13522,13523,13524,13420,13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,13554,13572,3839,13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,600,13586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,13611,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,13658,13659,13660,13661,13662,13663,13591,13665,13666,13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13668,13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13679,13714,13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13756,13762,13763,13764,13765,13766,13665,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,13774,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,13862,13863,13864,599,13866,13867,13868,13869,13870,13871,13872,13873,13874,13875,13876,13877,13878,13369,13880,13881,13882,13883,13884,13885,13886,13887,13888,13889,13404,13891,13892,13893,13894,13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,13423,13911,13912,13913,13914,13456,13916,13917,13918,13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,13946,13476,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,13970,13971,13972,13973,13974,13967,13976,13977,13978,13546,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,13994,13995,13996,13997,13998,13559,3815,14001,14002,14003,14004,14005,14006,14007,14008,14009,14010,3814,14012,14013,14014,14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,14066,14067,3813,14069,14070,14071,14072,14073,14074,14075,14076,14077,14078,14079,14080,14081,14082,14072,14084,14085,14086,14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14084,14111,14084,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,14069,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,14163,14175,14176,14177,889,14179,14180,14181,14182,14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,10487,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,14234,14235,1089,14237,14238,14239,14240,14241,14242,14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,14270,14271,14272,14273,3546,14275,14276,14277,14278,14279,14280,14281,14282,14283,14284,14285,4745,14287,14288,13011,14290,14291,14292,14293,4508,14013,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,14306,14307,14308,228,14310,14311,14312,14313,14314,14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,244,14326,14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,14342,14343,14344,14345,14346,14347,14125,14349,14350,14351,14352,14353,14354,14355,14356,14357,3546,14359,14360,14361,14362,14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14369,14386,14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,14394,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,1104,14422,14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,14438,14439,6257,14441,14442,14443,14444,14445,14446,14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14459,14486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14454,14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,14452,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,14558,14559,14560,14561,14562,14563,14486,14565,14566,14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,14507,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,14451,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,14460,14652,14653,14654,14655,14656,14657,14658,14659,14660,14490,14662,14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,14675,4379,14677,14678,14679,14680,14462,14682,14683,14684,14685,14686,14687,14688,14689,14690,14691,14692,14693,14694,14695,14495,14697,14698,14699,14700,14665,14702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,14642,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14581,14750,14751,14517,124,14754,14755,14756,14757,14758,14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,6258,14770,14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,14810,14811,14441,14813,14814,14815,14816,14817,14818,14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,14855,124,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,6270,14870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,14815,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,14906,10279,14908,755,14910,14911,14912,14913,14914,14915,14916,14917,14918,14919,14920,14921,10283,14923,744,14925,14926,14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14936,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,14917,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,15002,14976,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,15014,15015,755,15017,15018,15019,15020,15021,15022,15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,15038,15039,15040,6275,15042,15043,15044,15045,15046,15047,15048,15049,200,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,15098,15099,15089,15101,15102,15103,15104,15105,15106,15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,15117,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,15158,15159,15160,15161,15162,15163,15148,15165,15166,15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15087,15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15210,15230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,15266,15267,15268,15269,15270,15235,15272,15273,15274,15275,15276,15230,15278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,15302,15303,15304,15305,15306,15307,15230,15309,15310,15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,15319,15336,15337,15338,15339,15340,15341,15342,15343,15209,15345,15346,15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,15218,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,15289,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,15289,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15327,15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15321,15454,15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,15470,15471,15472,15473,15474,15340,15476,15477,15478,15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,15494,15495,15496,15363,15498,15281,15500,15501,15502,15503,15504,15505,15506,15507,15508,15323,15510,15511,15512,15513,15514,15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,15431,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,15542,15343,15544,15203,15546,15547,15548,15549,15550,15551,15552,15553,15554,15555,15556,15557,15256,15559,15560,15561,15562,15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15247,15578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,15590,15591,15323,15593,15594,15595,15596,15597,15598,15599,15600,15601,15602,15340,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,15614,15615,15616,15617,15618,15078,15620,15621,15622,15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,15639,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15659,15686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15627,15718,15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,15746,15747,15748,15749,15736,15751,15752,15753,15754,15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15727,15790,15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15752,15806,15807,15757,15809,15810,15752,15812,15813,15814,15815,15816,15817,15758,15819,15820,15821,15822,15823,15824,15812,15826,15827,15828,15829,15830,15831,15832,15833,15766,15835,15836,15837,15838,15839,15840,15841,15842,15843,15844,15845,15643,15847,15848,15849,15850,15851,15852,15853,15854,15855,15660,15857,15858,15859,15860,15861,15862,15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15689,15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15727,15902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,15914,15915,15916,15753,15918,15919,15920,15921,15922,15923,15924,15925,15926,15927,15928,15929,15930,15764,15932,15933,15934,15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,15815,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,15962,15963,15964,15965,15966,15967,15772,15969,15970,15971,15972,15732,15974,15975,15976,15977,15919,15979,15980,15981,15982,15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,15998,15999,15937,16001,16002,16003,16004,16005,16006,16007,16008,16009,16010,16011,16012,16013,16014,15741,16016,16017,16018,16019,16020,16021,16022,16023,16024,15756,16026,15938,16028,16029,15653,16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,16043,15706,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,16058,16059,16060,16061,15653,16063,16064,16065,16066,16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,16079,15753,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,15936,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,15827,16114,16115,16116,15788,15796,16119,15921,16121,16122,16123,16124,16125,15757,16127,16128,16129,16130,16131,16132,16133,15954,16135,16136,16129,16138,16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,15642,16150,16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,15676,16166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,15691,16187,16188,16189,16190,16191,16192,16193,16194,15959,16196,15970,16198,16199,16200,16201,16202,16203,16204,16205,16206,15737,16208,16209,16210,16211,16212,16213,16214,16215,16216,16217,16218,15768,16220,16221,16222,16223,16224,16225,16226,16227,16228,15936,16230,16231,16232,16233,16234,16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,15922,16246,16247,15936,16249,16250,16251,16018,16253,16254,16255,16256,16257,16258,16259,16260,16261,16262,15768,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,16002,16275,16276,16277,16278,15658,16280,16281,16282,16283,16284,16285,16286,16287,16288,16289,16290,16291,15699,16293,16294,16295,16296,16297,16298,16299,16300,16301,16302,16303,15791,16305,16306,16307,15928,16309,16310,16311,15937,16313,16314,16315,16316,16317,16318,16319,16115,16321,15788,15739,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,16334,16335,16336,16337,16338,15784,16340,16341,16342,16343,16344,16345,16346,16347,15732,16349,16350,16351,16352,16353,16354,16355,16356,16357,16358,16359,16360,16361,15930,15938,16364,16365,16366,16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,16382,15651,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,16394,16395,16396,16397,16168,16399,16400,16401,16402,16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,16191,16419,16420,16421,16422,15827,16424,16425,15753,16427,15905,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,16232,16443,16444,16445,16446,16447,16448,16424,16450,16451,15784,16453,16454,16455,16456,16457,16458,16254,16460,16461,16462,16463,16464,16465,16466,16467,16468,16469,16470,16471,15784,16473,16474,16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,15634,16486,16487,16488,16489,16490,16491,16492,16493,15862,16495,16496,16497,16498,16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,16514,15894,16516,16517,16518,16519,16520,16521,16522,16523,16210,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,16538,15937,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,16550,16121,16552,15936,16554,16555,16556,16557,16558,16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,15959,16570,16571,16572,16573,16574,16575,16576,15773,16578,16329,16580,16581,16582,16583,16584,16585,16586,16587,16578,15622,16590,16591,16592,16593,16594,16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,15862,16606,15878,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,15909,16622,16623,16624,16625,16626,16627,16628,16629,15993,16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16231,16135,16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,16718,15787,16720,16327,16722,16723,16724,16725,16726,16727,16728,16729,16730,16578,16305,16733,16734,16366,16736,16737,16738,16739,16385,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,15662,16762,16763,16764,16765,16766,16767,15886,16769,16770,16771,16772,16773,16774,16775,16776,16777,16778,15812,16780,16781,16782,16473,16784,16785,16786,16787,16788,16789,16790,16723,16792,16793,16794,16795,16796,16797,16798,16799,16800,16198,16802,15819,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,15826,16815,16816,16817,16818,16455,16820,16821,16822,16823,16018,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,16838,16839,16840,16841,15784,16843,16844,16845,16846,16847,16848,16849,16850,16851,15641,16853,16854,16855,16856,16857,15662,16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,15884,16872,16873,16874,16875,16876,16877,16878,16879,16880,16326,16882,16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,16898,16899,16900,16901,16902,16225,16904,16905,15751,16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,16922,16923,16924,16925,16926,16365,16928,16929,16930,16713,16932,16933,16934,16935,16936,16937,15784,16939,16940,16941,16942,16943,16944,15739,16946,16947,16948,16949,16950,16951,16271,16953,16954,16955,15937,16957,16958,16959,16287,16961,16962,16963,16964,16965,16966,16967,16968,16191,16970,16971,15791,16973,15993,16975,16976,16977,16978,15936,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16424,16994,16995,16996,16997,16998,16999,17000,17001,17002,15787,16723,17005,17006,17007,17008,17009,17010,17011,16578,15751,17014,17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,16002,17026,17027,17028,17029,17030,17031,17032,17033,16751,15694,17036,17037,17038,17039,17040,17041,17042,16995,17044,15788,16327,17047,17048,17049,17050,17051,15768,17053,17054,17055,17056,16128,17058,17059,17060,17061,17062,17063,15956,17065,15823,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,16019,17078,17079,17080,17081,17082,17083,15778,17085,17086,17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,15849,17124,17125,17126,16505,17128,17129,17130,17131,17132,17133,17134,17135,17136,15890,17138,17139,17140,17141,17142,17143,17144,17145,17146,17147,15737,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,17058,17160,16003,17162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,16552,17174,15939,17176,17177,17178,17179,17180,15816,17182,15769,17184,17185,17186,17187,17188,15737,17190,17191,17192,17193,17194,17195,17196,17197,17198,17199,17200,17201,15758,17203,15937,17205,17206,17207,17208,17209,17210,17211,17212,17213,17214,16286,17216,15692,17218,17219,17220,17221,17222,17223,15802,17026,17226,17227,17228,17229,17230,17231,17232,17233,17234,17235,17236,16135,17238,17239,17240,17241,17242,17243,17244,17245,17246,17247,17248,17249,17250,16340,17252,17253,17254,17255,17256,17257,17258,17259,17048,17261,17262,17263,17264,17265,17186,17267,17268,17269,17270,17271,17272,16542,17274,17275,17276,17277,17278,17279,17280,17281,17282,17283,17244,17285,17286,17287,17288,17289,17290,17291,17292,16097,17294,17295,17296,17297,17298,17299,17300,17301,16162,17303,17304,17305,17306,17307,17308,17309,17310,17311,16411,17313,17314,17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,17327,16051,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,17342,17343,17344,17345,17346,16829,17348,17349,17350,16474,17352,17353,17354,17355,17356,17357,17358,15793,17360,17361,17362,17363,17364,17365,17366,17367,15919,17369,17370,16557,17372,17373,17374,17375,17376,17377,17378,16825,17380,17381,17382,17383,17384,17385,17386,17387,17388,16845,17390,17391,17392,17393,17394,17395,17396,17397,16625,17399,17400,17401,17402,17403,16555,17405,17406,17407,17408,17409,17410,17411,17412,16036,17414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,17340,17427,17428,17429,16072,17431,17432,17433,16552,16554,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17065,17447,17448,17449,17450,17451,17452,17453,17454,17455,16266,17457,17150,17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,16542,17470,17471,17472,15921,17474,17475,17476,17477,17478,17479,17480,17481,17482,16251,17484,15074,17486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,15071,17542,17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17563,17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17611,17630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17657,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,17702,17703,17704,17705,17688,17707,17708,17709,17710,17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,17834,17835,17836,17837,17838,17839,17649,17841,17842,17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,17858,17859,17860,17848,17862,17863,17864,17865,17866,17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,17894,17895,17873,17897,17898,17899,17900,17901,17902,17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,17885,17979,17980,17981,17982,17983,17862,17985,17986,17987,17988,17989,17990,17991,17899,17993,17994,17995,17996,17997,17998,17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,17899,18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,18035,17853,18037,18038,18039,18040,18041,17883,18043,18044,18045,18046,18047,18048,18049,18050,18051,17899,18053,18054,18055,18056,18057,18058,18059,18060,17885,18062,18063,18064,18065,18066,18067,17551,18069,18070,18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,18086,18087,18088,18089,18090,17553,18092,18093,18094,18095,18096,18097,18098,18099,18100,17613,18102,18103,18104,18105,18106,18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,17644,18118,18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,18131,17683,18133,18134,18135,18136,18137,18138,18139,17709,18141,18142,18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,17849,18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,17876,18228,18229,18230,18231,18232,18233,18234,18235,18236,18053,18238,18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,17982,18264,18265,17989,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,17998,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,18290,18291,18024,18293,18294,18295,18296,18297,18298,18299,18300,18301,18302,18303,18304,18274,18306,18307,18308,17880,18310,18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18024,18326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,18338,18339,18340,18341,18342,17994,18344,18345,18346,18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,17544,18360,18361,18362,18363,18364,18365,18366,18367,17580,18369,18370,18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,18383,17620,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,18398,18399,18400,18401,17677,18403,18404,18405,18406,18407,18408,18409,18410,18411,18412,18413,18414,17695,18416,18417,18418,18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,17718,18432,18433,18434,18435,18436,18437,18438,18439,18267,18441,18442,18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18315,18458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,18024,18471,18472,18473,18474,17995,18476,18477,18478,18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,18494,18495,18496,18497,18452,18499,18500,18501,18502,18238,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,18530,18531,18018,18533,18534,18535,18536,18537,18538,18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,18566,18567,18270,18569,18570,18571,18572,18573,18574,18575,17868,18577,18578,18579,18580,18581,18241,18583,18584,18585,18586,18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18063,18599,18600,18601,18602,18603,18078,18605,17562,18607,18608,18609,18610,18611,18612,18613,18614,18615,18616,18617,18618,18619,17625,18621,18622,18623,18624,18625,17665,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,17700,18646,18647,18648,18649,18650,18651,18652,18653,18654,17719,18656,18657,18658,18659,18660,18661,18662,18663,18664,18665,18666,18667,18270,18669,18670,18671,18672,18673,17885,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,18328,18687,18688,18689,18690,18691,18692,18490,18694,18695,18696,18697,18698,18699,18700,18701,18702,18703,18452,18705,18706,18707,18708,18709,18710,18518,18712,18713,18714,18715,18716,18717,17869,18705,18720,18488,18722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,18734,18024,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,18746,18747,18748,18749,18750,17595,18752,18753,18754,18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18366,18793,18794,17599,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,18806,18807,18808,17631,18810,18811,18812,18813,18814,18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18404,18830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,18854,18855,18856,18857,17709,18859,18860,18861,18862,18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18436,18890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,18902,18446,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18722,18923,18924,18925,18926,18927,18928,18929,18930,18931,18736,18933,18934,18935,18936,18937,18938,18939,18940,18941,18942,18211,18944,18945,18946,18947,18948,17876,18950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,18962,18963,18516,18965,18966,18967,18968,18969,18970,18971,18972,18973,18974,18975,18533,18977,18978,18979,18980,18981,18982,18983,18984,18985,18986,18987,18988,18499,18990,18991,18992,18993,18494,18995,18996,18997,18998,18999,19000,18738,19002,19003,19004,19005,19006,19007,19008,19009,19010,19011,18785,19013,19014,19015,19016,19017,19018,19019,19020,19021,19022,19023,18361,19025,19026,19027,19028,19029,19030,18804,19032,19033,19034,19035,18823,19037,19038,19039,19040,19041,19042,18839,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,19058,19059,18861,19061,19062,19063,19064,19065,19066,19067,19068,19069,19070,18436,19072,19073,19074,19075,19076,19077,19078,18270,19080,19081,19082,19083,19084,19085,19086,17996,19088,19089,19090,19091,19092,19093,19094,19095,19096,19097,19098,18538,19100,19101,19102,19103,19104,19105,19106,17986,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,19118,18675,19120,19121,19122,19123,18023,19125,19126,19127,19128,19129,19130,19131,19132,19133,18317,19135,19136,19137,19138,19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19081,19153,19154,19155,19156,19157,17899,19159,19160,19161,18979,19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,18078,19178,19179,19180,19181,19182,19183,19184,19185,18094,19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,18798,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,17632,19222,19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,19051,19239,19240,19241,19242,19243,19244,19245,19246,19064,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,19259,18892,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,19274,19113,19276,19277,19278,17998,19280,19281,19282,19283,19284,19285,19286,19287,19288,19289,18473,19291,17843,19293,19294,19295,19296,19297,19298,19299,19300,19301,19302,19303,18578,19305,19306,19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,18513,19318,19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,18233,19334,19335,19336,19337,19338,19339,18446,19341,19342,19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,18722,19354,19355,19356,19357,19358,19359,19360,19361,19362,19363,18736,19365,19366,19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,19379,18078,19381,19382,19383,19025,19385,19386,19387,17580,19389,19390,19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,18812,19406,19407,19408,19409,19410,19411,19412,19413,19414,19415,18833,19417,19418,19419,19420,19421,19422,18874,19424,19425,19426,19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,18436,19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,19454,18705,19456,19457,19458,19459,19460,19461,19462,19463,18723,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,18741,19478,19479,19480,19481,19482,19483,19484,19485,19486,19487,18205,19489,19490,19491,19492,19493,19494,19495,19496,19497,18579,19499,19500,19501,19502,19503,19504,19329,19506,19507,19508,18235,19510,19511,19512,18452,19514,19515,19516,19517,19518,19519,19520,19521,19468,19523,19524,19525,19526,19480,19528,19529,19530,19531,19532,19533,19534,19535,19536,17607,19538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19386,19562,19563,19564,19393,19566,19567,19568,19569,19570,19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19412,19582,19583,19419,19585,19586,19587,19588,19589,19590,19591,18875,19593,19594,19595,19596,19597,19442,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,19610,19081,19612,19613,19614,19615,19616,19617,19618,19619,18600,19621,18241,19623,19624,19625,19335,19627,19628,19629,19630,19631,19114,19633,19634,19635,18483,19637,19638,19639,19640,19641,19642,19643,19644,18029,19646,19647,19648,19649,19650,19651,19652,18205,19654,19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,18233,19668,19669,19670,19671,17912,19673,19674,19675,19676,19677,19678,19679,19680,19681,19682,19683,19684,19685,17885,19687,19688,19689,19690,19691,18069,19693,19694,19695,19696,19697,19698,19699,19700,19701,18609,19703,19704,19705,19706,19707,19708,19709,18622,19711,19712,19713,18634,19715,19716,17700,19718,19719,19720,19721,19722,19723,19724,17719,19726,19727,19115,19729,19730,19688,19732,19733,19734,19735,19736,19737,18979,19739,19740,19741,19742,19743,19744,19138,19746,19747,19748,19749,19750,19751,19752,19082,19754,19755,19756,19757,17996,19759,19760,19761,19762,18026,19764,19765,19766,19767,19768,18205,19770,19771,19772,19773,19774,19775,19776,19777,19778,19779,19780,19781,17862,19783,19784,19785,19786,19787,19788,19789,19790,19791,18712,19793,19794,19795,19796,19797,19798,19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,18579,19810,19811,18074,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,19826,19827,19198,19215,19830,19831,19832,19833,19834,19835,19836,19837,19838,19839,18810,19841,19842,19843,19844,19845,19846,19847,19848,19849,19850,19851,19852,19050,19854,19855,19856,19857,18865,19859,19860,19861,19862,19074,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,19874,19614,19876,19877,19878,19879,19880,19881,19089,19883,19884,19885,19886,19165,19888,19889,19890,19891,19892,19893,19894,19895,19082,19897,19898,19899,19145,19901,19902,19903,19904,18473,18520,19907,19908,19909,19910,19911,19912,19913,19914,19915,18446,19917,19918,19919,19920,19921,19793,19923,19924,19925,18950,19927,19928,19929,18078,19931,19932,19933,19934,19935,19936,19937,17553,19939,19940,19941,19942,19943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,17616,19955,19956,19957,19958,17644,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,17691,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,18144,19982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,18216,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,18233,20006,20007,20008,20009,20010,18241,20012,20013,20014,20015,20016,20017,20018,20019,20020,20021,20022,19335,20024,20025,20026,18913,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,18925,20042,20043,20044,20045,20046,18744,20048,20049,20050,20051,20052,20053,20054,20055,20056,19778,20058,20059,20060,20061,20062,20063,20064,20065,19500,20067,20068,20069,20070,20071,20072,20073,20074,20075,18712,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,19889,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,19818,20099,20100,20101,20102,20103,20104,20105,18092,20107,20108,20109,20110,18110,20112,20113,20114,18123,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,17679,20127,20128,20129,20130,20131,20132,20133,20134,18150,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,19998,20158,20159,20160,20161,18233,20163,20164,20013,20166,20167,20168,20169,20170,20171,20172,20173,20174,20175,20176,20177,20178,20179,18600,20181,19730,17998,20184,20185,20186,20187,18027,20189,20190,20191,20192,20193,20194,20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,17986,20210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,17883,20223,20224,20225,20226,20227,20228,19677,20230,20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,20243,19690,19816,20246,20247,20248,20249,20250,20251,20252,20253,20254,18609,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,20270,20271,20272,20273,20274,17625,20276,20277,20278,20279,20280,18631,20282,20283,20284,20285,20286,17701,20288,20289,20290,20291,20292,17709,20294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,20318,19660,20320,20321,20322,20323,20324,20024,20326,20327,20328,20329,18241,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,18065,20350,20351,19113,20353,20354,20355,19354,20357,20358,20359,20360,20361,20362,20363,20364,20365,20366,20367,20368,18742,20370,20371,20372,20373,20374,20375,20376,20377,20378,20379,20380,20381,18712,20383,20384,20385,20386,20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,20462,19113,20464,20465,20466,20467,19637,20469,20470,19646,20472,20473,20474,20475,20476,18071,20478,20479,20480,20481,20482,20483,20484,20485,20486,20487,17543,20489,20490,20491,20492,20493,20494,20495,20496,19203,20498,20499,20500,20501,20502,20503,20504,20505,20506,18816,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,20522,20523,20524,20525,20526,20527,18410,20529,20530,20531,20532,19061,20534,20535,20536,20537,20538,20539,20540,20541,20542,17717,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,20570,18452,20572,20573,20574,20575,20576,20577,20578,20579,19907,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,20591,19739,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,19153,20606,20607,20608,20609,20610,19142,20612,20613,20614,20615,20616,20617,20618,20619,18024,20621,20622,18353,20624,20625,18501,20627,18520,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,19739,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,20654,20247,20656,20657,20658,19830,20660,20661,19845,20663,20664,20665,20666,20667,20668,20669,20670,20671,19419,20673,20674,20675,20676,20677,20678,20679,20680,19061,20682,20683,20684,20685,20686,20687,20688,20689,20550,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,20702,20703,18269,20705,18000,20707,20708,20709,20710,20711,20712,20713,18736,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,18214,20726,20727,20728,20729,20730,20731,20732,20733,19668,20735,20736,19794,20738,20739,20740,18950,20742,20743,20744,18452,20746,20747,20748,20749,20750,20751,20752,19525,20754,20755,20756,20757,20051,20759,20760,19544,20762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,19386,20787,20788,20789,20790,20791,20792,20793,17580,20795,20796,20797,20798,20799,17625,20801,20802,20803,20804,20805,20806,20807,17663,20809,20810,20811,20812,17700,20814,20815,20816,20817,20818,18435,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,20834,18270,20836,20837,20838,18676,20840,20841,20842,20843,19126,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,19146,20859,20860,20861,20862,19081,20864,20865,20866,20867,20868,20869,17996,20871,20872,20873,20874,20875,20876,20877,20878,20879,18543,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,20891,19897,20893,20894,20895,20896,20897,20898,20899,20900,19690,20902,20903,20904,19165,20906,20907,20908,20909,20910,20911,20912,20913,20914,18324,20916,20917,20918,18078,20920,20921,20922,20923,20924,20925,20926,18609,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,17626,20942,17659,20944,20945,20946,20947,20948,20949,20950,20951,17691,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,18142,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,18217,20979,20980,20981,20982,20983,19927,20985,20986,20987,20988,20989,20990,18713,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,21002,21003,20593,21005,21006,21007,21008,21009,21010,21011,21012,21013,19153,21015,21016,21017,21018,21019,19148,18473,21022,19294,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,21035,18909,21037,21038,21039,19795,21041,21042,21043,21044,21045,21046,21047,21048,21049,21050,18229,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,21062,21063,21064,21065,21066,18073,21068,21069,21070,21071,21072,21073,21074,21075,21076,21077,19941,21079,21080,21081,21082,21083,21084,21085,21086,21087,18110,21089,21090,21091,18121,21093,21094,21095,21096,21097,21098,18134,21100,21101,21102,20150,18215,21105,21106,21107,21108,21109,18579,21111,21112,21113,21114,21115,21116,21117,21118,17885,21120,21121,21122,21123,18473,18310,21126,21127,21128,21129,21130,21131,21132,18501,18521,21135,21136,21137,21138,21139,18542,21141,21142,21143,21144,21145,21146,21147,21148,21149,21150,21151,19876,21153,21154,21155,21156,20843,18536,21159,21160,21161,21162,21163,21164,20840,19178,21167,21168,21169,20274,21171,17625,21173,21174,21175,21176,21177,20282,21179,21180,21181,21182,21183,21184,17698,21186,21187,21188,21189,21190,21191,20970,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,20694,21207,21208,21209,21210,21211,21212,21213,21214,18500,18716,21217,21218,21219,21220,21221,21222,21223,21224,18579,21226,18707,21228,21229,21230,18723,21232,21233,21234,21235,18745,21237,21238,21239,21240,21241,21242,21243,18218,21245,21246,21247,21248,21249,20990,21251,21252,18586,21254,21255,18233,21257,20100,21259,21260,18610,21262,21263,21264,21265,21266,21267,21268,21269,21270,21271,18625,21273,21274,20945,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,21314,21315,21316,21317,21318,21319,20959,21321,21322,20966,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,20726,21346,21347,21348,21349,21350,21351,21352,19668,21354,21355,21356,18244,21358,21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,21374,21375,21376,17883,21378,21379,21380,21381,21382,21383,21384,21385,21386,21387,17986,21389,21390,21391,21392,18722,21394,21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,19366,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,18217,21422,21423,21424,21425,21426,21427,21428,18579,21430,21431,18715,21433,21434,21435,21436,21437,21438,21439,21440,17864,21442,21443,18078,19190,21446,21447,21448,21449,21450,19209,21452,21453,21454,21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,19413,21468,21469,21470,19588,21472,21473,21474,21475,21476,19425,21478,21479,21480,21481,21482,21483,21484,18890,21486,21487,21488,21489,21490,21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,20030,21503,21504,21505,21506,21507,21508,21509,21510,21396,21512,21513,21514,21515,21516,21517,21518,21519,21520,21521,18736,21523,21524,21525,21526,21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,17986,21538,21539,21540,21541,21542,18063,21544,21545,21546,21547,21548,21549,21550,21551,21552,17915,21554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,20918,19613,21568,21569,21570,21571,21572,19092,21574,21575,21576,21577,21578,21579,21580,21581,21582,18979,21584,21585,21586,21587,20101,21589,21590,21591,18093,21593,21594,21595,21453,21597,21598,20513,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,21614,21615,21616,20529,21618,21619,21620,21621,21622,20685,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21207,21635,21636,21637,21638,21639,21640,21641,21642,19081,21644,21645,21646,21647,21648,21649,21650,21651,19760,21653,21654,21655,21656,21657,21658,21659,21660,21661,21662,18027,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,21674,20726,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,21686,21687,19501,21689,21690,21691,21692,21693,21694,21695,20740,21697,21586,21699,21700,21701,21702,21703,21704,21705,18209,21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,19305,21720,21433,21722,21723,21724,21725,21726,21727,21728,19368,21730,21731,21732,21733,21734,21735,21736,21737,21738,18761,21740,21741,21742,21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,21758,21759,19028,21761,21762,21274,17652,21765,21766,21767,21768,21769,21770,21771,21772,21773,21774,21775,19063,21777,21778,21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21488,21790,21791,21792,21793,21794,21795,21796,21797,21798,21799,20574,21801,21802,21803,21804,21805,19747,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,21818,20231,21820,21821,21544,21823,21824,21825,21826,19277,21828,21829,20470,21831,21832,21833,21834,21835,21836,21529,21838,21839,21840,21841,21842,21843,21346,21845,21846,21847,21848,21849,21850,21851,21852,21853,19510,21855,18252,21857,21858,21859,21860,21861,21862,21863,21864,21865,21866,21867,17883,21869,21870,21871,21872,21873,20103,21081,21876,21877,21878,18102,21880,21881,21882,21883,21884,18120,21886,21887,21888,21889,21890,21891,21892,21893,19586,21895,21896,21897,21898,21899,21900,21901,20535,21903,21904,21905,21906,21907,21908,21909,21910,20544,21912,21913,21914,21915,21916,21917,21918,21919,18270,21921,21922,21923,21924,21925,21926,21927,21928,17998,21930,21931,21932,21933,21934,21935,21936,21937,21938,21939,21940,21941,21942,21943,19768,21945,21946,21947,21948,19655,21950,21951,21952,21953,21954,21955,18234,21957,21958,21959,21960,19318,21962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,18233,21975,21976,21977,21978,21979,21676,21981,21982,21983,21984,21985,17876,21987,21988,20014,21990,21991,21992,21993,21994,21995,21996,21997,21998,21999,21378,22001,22002,22003,22004,18076,22006,22007,22008,22009,21262,22011,22012,22013,22014,22015,22016,22017,22018,22019,19956,22021,22022,22023,22024,22025,22026,22027,22028,17652,22030,22031,22032,22033,22034,22035,22036,22037,22038,22039,20954,22041,22042,22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,20966,22118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,20727,22138,22139,22140,22141,22142,22143,22144,22145,20735,22147,22148,22149,18244,22151,22152,22153,22154,22155,22156,22157,22158,21544,22160,22161,22162,22163,22164,22165,22166,22167,20354,22169,21831,22171,22172,22173,22174,22175,22176,22177,22178,22179,18745,22181,22182,22183,22184,22185,22186,22187,18947,22189,17864,22191,22192,22193,20082,22195,22196,22197,22198,22199,22200,19500,22202,22203,22204,22205,22206,22207,22208,18078,22210,22211,17553,22213,22214,22215,17607,22217,22218,22219,22220,22221,22222,22223,22224,22225,22226,17636,22228,22229,22230,22231,22232,22233,22234,19586,22236,22237,22238,22239,22240,22241,20142,22243,22244,22245,22246,22247,22248,22249,22250,22251,22252,22253,20692,22255,22256,22257,22258,22259,22260,22261,22262,18502,20631,22265,19165,22267,22268,22269,22270,22271,22272,22273,22274,22275,19278,19305,22278,22279,22280,22281,22282,22283,22284,17998,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,21159,22301,22302,22303,22304,22305,22306,22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,18271,22322,22323,22324,22325,22326,20902,20849,22329,22330,22331,22332,22333,22334,22335,19146,22337,22338,22339,18361,22341,22342,22343,22344,22345,22346,22347,18374,22349,22350,22351,22352,18397,22354,22355,18404,22357,22358,18421,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,22382,22383,18436,22385,22386,22387,22388,22389,22390,22391,22392,22393,22394,22395,22396,22397,22398,21017,22400,22401,22402,22403,22404,22405,20614,22407,22408,22409,22410,18327,22412,22413,22414,22415,22416,22417,18485,22419,22420,22421,18501,22423,21136,22425,22426,22427,22428,21149,22430,21926,22432,22433,19733,22435,22436,22437,18979,22439,22440,22441,22442,18675,22444,22445,22446,17549,22448,22449,22450,22451,22452,17567,22454,22455,22456,22457,22458,22459,22460,22461,20279,22463,22464,20283,22466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,22478,22479,17698,22481,22482,22483,22484,22485,21326,22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,21676,22499,22500,18234,22502,22503,22504,22505,19089,22507,22508,22509,22510,22511,22512,22513,22514,22515,18296,22517,22518,22519,22520,22521,22522,22523,22524,22525,22526,18270,22528,22529,22530,22531,22532,22533,19733,22535,22536,22537,22538,19125,22540,22541,22542,22543,22544,22545,22546,18463,22548,22549,22550,22551,22552,22553,22554,22555,22556,21650,22558,17993,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,20596,22571,22572,22573,22574,22575,22576,22577,22578,22579,19179,22213,22582,22583,17606,22585,22586,22587,22588,22589,22590,22591,22592,22593,22232,22595,22596,22597,22598,22599,21898,22601,22602,22603,20143,22605,22606,22607,22608,22609,22610,22611,22612,22613,22614,20547,22616,22617,22618,22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,21229,22632,22633,22634,19908,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,20593,22647,22648,22649,22650,19756,22652,18318,22654,22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,18024,22666,22667,22668,22669,22670,22671,18463,22673,22674,22675,22676,22677,22678,22679,22680,19613,22682,22683,17997,22685,22686,22687,18738,22689,22690,22691,22692,21809,22694,22695,22696,22697,22698,22699,22700,22701,19025,22703,22704,22705,22706,22707,22708,22709,22710,22711,21173,22713,22714,22715,21770,22717,22718,20958,22720,22721,22722,22723,22724,22609,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,18893,22738,22739,22740,22741,20465,22743,22744,20362,22746,22747,22748,21526,22750,22751,22752,22753,22754,22755,22756,22757,22758,22759,19658,22761,22762,22763,22764,20223,22766,22767,22768,22769,22770,22771,22772,22773,22774,22775,20230,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,18675,22788,22789,22790,20705,22792,22793,22794,22795,21933,22797,22798,22799,22800,22801,22802,22803,22804,22805,22806,22807,20190,22809,22810,22811,22812,22813,22814,22815,22816,22817,19816,22819,22820,22821,22344,22823,22824,22825,22826,18804,22828,22829,22830,22831,18821,22833,22834,22835,22836,22837,22838,22839,18845,22841,22842,22843,22844,22845,19593,22847,22848,22849,22850,22851,21489,22853,22854,22855,22856,22857,22858,22859,22860,22861,22862,22863,22864,22865,22866,18914,22868,22869,22870,22871,22872,18723,22874,22875,22876,22877,22878,22879,18741,22881,22882,22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,18203,22895,22896,22897,22898,22899,22900,22901,22193,22903,22904,22905,22906,22907,22908,22909,22910,22911,19797,22913,22914,22915,22916,22917,17869,22919,22920,22921,22922,22923,19902,22925,22926,22927,22928,22929,22930,22931,18329,22933,19142,22935,22936,19386,22938,22939,22940,22458,22942,22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22587,22955,22956,22957,22958,22959,22960,20520,22962,22963,22964,22965,22966,22967,22968,18411,22970,22971,22972,18879,22974,22975,22976,22977,22978,22979,22980,22981,18890,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,22994,19276,22996,22997,22998,21833,23000,23001,23002,23003,23004,21411,23006,23007,23008,21678,23010,23011,23012,23013,23014,23015,20164,23017,23018,23019,18583,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23033,23034,23035,18043,23037,23038,23039,23040,23041,23042,20213,23044,23045,23046,23047,23048,23049,18723,23051,23052,23053,23054,21408,23056,23057,23058,23059,23060,23061,17585,23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,20788,23110,23111,23112,18798,23114,23115,23116,23117,23118,23119,23120,18819,19586,23123,23124,23125,23126,23127,19593,23129,23130,23131,23132,23133,23134,23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,21490,23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,23159,18905,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,18727,23172,23173,23174,23175,23176,23177,23178,23179,23180,20048,23182,23183,23184,23185,22900,23187,23188,23189,23190,17864,23192,23193,23194,23195,23196,23197,23198,21041,23200,23201,23202,23203,23204,23205,23206,19307,23208,23209,23210,23211,21015,23213,23214,23215,23216,23217,18317,23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,23234,23235,23236,18244,23238,23239,23240,23241,23242,17980,23244,23245,23246,23247,23248,23249,20248,23251,23252,23253,20274,23255,21176,18633,23258,23259,23260,17697,23262,23263,20312,23265,23266,23267,19114,23269,23270,20902,22540,23273,23274,23275,23276,23277,19142,23279,23280,19080,23282,23283,23284,20872,23286,23287,23288,23289,23290,23291,23292,23293,21142,23295,23296,23297,23298,23299,23300,23301,23302,19084,23304,23305,23306,20840,23308,22331,23310,23311,23312,23313,23314,23315,23316,23317,20918,19386,23320,23321,23322,23323,22943,23325,23326,23327,23328,23329,23330,23331,20279,23333,23334,23335,23336,18636,23338,23339,23340,23341,23342,23343,23344,23345,20958,23347,23348,23349,23350,23351,23352,20966,23354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,23366,19660,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,19668,23379,23380,23381,21358,23383,23384,23385,23386,23387,23388,23389,23390,23391,18229,18915,23394,23395,23396,23397,23398,18725,23400,23401,23402,23403,23404,23405,23406,23407,19486,23409,23410,23198,23412,23413,23414,18501,22338,23417,23418,18473,22638,23421,23422,23423,23424,23425,23426,22344,23428,23429,23430,23431,19393,23433,23434,23435,23436,23437,23438,17614,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,23450,23451,20530,23453,23454,22370,23456,23457,23458,23459,23460,23461,23462,23463,18452,23465,23466,23467,23468,23469,18477,23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,19908,23482,23483,23484,23485,23486,23487,23488,21230,23490,23491,23492,23493,23494,23495,20993,23497,23498,23499,23500,23501,23502,18983,23504,23505,23506,23507,21647,23509,23510,23511,23512,17884,23514,23515,18024,23517,23518,23519,23520,23521,21809,23523,23524,23525,23526,23527,23528,23529,23530,23531,17544,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,20274,21173,23572,23573,17661,23575,23576,23577,23578,23579,23580,23581,23582,23583,23584,20958,23586,23587,23588,23589,23590,20969,23592,23593,23594,20726,23596,23597,23598,23599,23600,23601,23602,23603,21957,20019,23606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,23618,21976,23620,23621,19276,23623,23624,23625,17869,23627,18241,23629,23630,23631,23632,23633,23634,23635,23636,23637,20224,23639,23640,18905,18926,23643,23644,23645,23646,23647,23648,23649,23650,19367,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,17558,23674,23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,20788,23711,23712,19203,23714,23715,22833,23717,23718,23719,23720,23721,23722,23723,18849,23725,23726,23727,23728,23729,23730,23731,23732,23733,18875,23735,23736,23737,23738,23739,23740,23741,23742,23743,18897,23745,23746,23747,23748,23749,23750,18913,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,23762,18923,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,23774,23652,23776,23777,23778,23779,23780,23781,23782,21676,23784,23785,23786,23787,23788,23789,21252,21963,23792,23793,23794,23795,23796,23797,23798,23799,23800,18502,21810,23803,23804,23805,23806,23807,23808,18326,23810,23811,23812,23813,19142,23815,23816,23817,23818,23819,23820,23821,23822,23823,19026,23825,23826,18375,23828,23829,23830,23831,23832,23833,23834,23835,18390,23837,23838,23839,23840,23841,23842,23843,23844,23845,23846,23847,23848,23849,23850,23851,20811,23853,23854,23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,23870,23871,23872,23873,23874,17701,23876,23877,20312,23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,21712,23891,23892,23893,23894,19670,22638,23897,23898,23899,23900,23901,17869,23903,23904,23905,20627,18465,23908,23909,18024,23911,23912,23913,23914,23915,23916,23917,23918,17843,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,23930,23931,23932,19920,23934,23935,23936,18716,23938,23939,23940,23941,23942,21011,23944,23945,23946,23947,23948,18078,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,22213,23961,19204,23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,21610,23979,23980,23981,23982,23983,23984,23985,23986,19419,23988,23989,23990,23991,20538,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,21913,24006,24007,24008,24009,24010,24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,24110,24111,19082,24113,24114,24115,24116,24117,19091,24119,24120,24121,24122,18295,24124,24125,24126,24127,24128,24129,22996,24131,24132,17887,24134,24135,24136,24137,19674,24139,24140,24141,24142,18063,24144,24145,24146,19788,24148,24149,24150,22876,24152,24153,24154,24155,24156,24157,24158,24159,24160,19479,24162,24163,24164,24165,24166,24167,24168,24169,24170,24171,20768,24173,24174,24175,24176,24177,24178,24179,24180,24181,22703,24183,24184,24185,24186,24187,24188,23434,24190,24191,24192,24193,24194,24195,24196,24197,18812,24199,24200,24201,20529,24203,24204,24205,23456,24207,24208,24209,24210,24211,24212,24213,24214,24215,20966,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,20726,24231,24232,24233,24234,22503,20013,24237,24238,24239,24240,24241,24242,22160,24244,19114,24246,24247,24248,19639,24250,24251,24252,24253,24254,21664,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,24266,20736,24268,24269,19623,24271,24272,24273,17979,24275,24276,24277,24278,24279,18077,24281,24282,24283,24284,24285,21263,24287,24288,24289,24290,24291,24292,24293,24294,24295,22025,24297,24298,24299,18123,24301,24302,24303,24304,24305,24306,24307,24308,24309,22236,24311,24312,24313,24314,24315,20535,24317,24318,24319,24320,24321,24322,24323,24324,24325,24326,24327,19078,24329,24330,24331,24332,24333,24334,18917,24336,24337,24338,24339,24340,24341,24342,18493,24344,24345,24346,24347,24348,24349,24350,24351,24352,24353,24354,19139,22322,24357,24358,24359,24360,24361,24252,24363,24364,24365,24366,24367,23653,24369,24370,24371,24372,24373,24374,24375,24376,24377,24378,24379,19910,24381,24382,24383,24384,24385,24386,19897,24388,24389,24390,18284,24392,24393,24394,24395,24396,24397,20189,24399,24400,24401,24402,24403,24404,24405,20247,24407,24408,24409,18362,24411,24412,24413,24414,21263,24416,24417,20502,24419,24420,24421,24422,24423,24424,20519,24426,24427,24428,22357,24430,24431,24432,24433,24434,24435,24436,24437,24438,19251,24440,24441,24442,24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,18436,24454,24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,22683,24471,18004,24473,24474,24475,24476,21528,24478,24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,21707,24490,24491,24492,24493,24494,24495,24496,24497,24498,21977,24500,24501,21722,24503,24504,24505,24506,24507,24508,21141,24510,24511,24512,24513,24514,24515,24516,24517,24518,20210,24520,24521,18234,24523,24524,24525,19924,24527,24528,24529,24530,24531,19307,24533,24534,24535,24536,24537,22819,24539,24540,24541,24542,24543,21462,24545,24546,24547,24548,24549,24550,24551,24552,24553,20524,24555,19054,24557,24558,24559,24560,19593,24562,24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,21491,24574,24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,19514,24587,24588,24589,24590,21130,24592,24593,24594,24595,24596,24597,24598,24599,24600,18687,24602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,21921,24614,24615,24616,24617,24618,24619,24620,24621,24622,19643,24624,24625,24626,24627,24628,24629,21525,24631,24632,24633,24634,24635,24636,24637,24638,24639,23012,24641,24642,24643,21226,24645,24646,24647,21137,24649,24650,24651,24652,24653,24654,24655,21665,24657,24658,24659,24660,24661,19821,24663,24664,24665,18093,24667,24668,24669,24670,24671,24672,24673,24674,20502,24676,24677,24678,24679,24680,24681,24682,24683,24684,18821,24686,24687,24688,24689,19054,24691,24692,24693,24694,24695,24696,18875,24698,24699,24700,24701,24702,24703,24704,24705,24706,22986,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,24719,18270,24721,21934,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24659,24734,24735,24736,24737,24738,24739,22762,24741,24742,24743,24744,24745,24746,24747,24748,17883,24750,24751,24752,24753,24754,17907,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,24770,20902,20211,24773,24774,24775,20042,24777,24778,24779,24780,24781,24782,23006,24784,24785,24786,24787,24788,24789,24790,23063,24792,24793,24794,22344,24796,24797,24798,24799,24800,17594,24802,24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,19411,24814,24815,24816,22236,24818,24819,18427,24821,24822,24823,24824,18439,18501,23803,24828,24829,24830,24831,18688,24833,24834,24835,24836,24837,24838,24839,24840,19142,24842,24843,24844,21645,24846,24847,24848,22294,24850,24851,24852,23912,24854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,24866,24867,24868,19149,24870,21570,24872,24873,24874,18003,24876,24877,24878,24879,24880,24881,24882,24883,19366,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,24793,24900,24901,24902,24903,23825,24905,23115,24907,24908,24909,24910,24911,24912,24913,24914,19411,24916,24917,24918,24919,24920,24921,24922,24818,24924,17689,24926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,24938,24939,24940,24941,19442,24943,24944,24945,24946,24947,19516,24949,24950,24951,24952,18695,24954,24955,24956,24957,24958,24959,24960,24961,24962,24857,24964,24965,24966,20630,24968,24969,24970,24971,18705,24973,24974,24975,24976,19089,24978,24979,24980,24981,24982,24983,24984,24985,24986,24987,24988,24989,20881,24991,24992,24993,24994,24995,24996,23049,22503,24999,23634,25001,23379,25003,25004,25005,25006,25007,18078,25009,25010,25011,25012,25013,25014,19944,25016,25017,25018,25019,25020,25021,25022,25023,25024,22589,25026,25027,25028,25029,25030,25031,22230,25033,25034,25035,19419,25037,25038,25039,25040,25041,25042,25043,25044,21778,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,18439,24247,25059,20007,25061,25062,19329,23627,17843,25066,25067,25068,25069,25070,25071,25072,18446,25074,25075,25076,25077,25078,25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,18713,25092,25093,25094,25095,25096,25097,25098,25099,20744,25101,18441,25103,21810,25105,25106,25107,25108,24604,25110,25111,25112,25113,25114,25115,22420,25117,25118,25119,25120,19026,25122,25123,25124,21173,25126,25127,25128,25129,18633,25131,25132,25133,20972,25135,25136,25137,25138,25139,25140,25141,25142,25143,25144,25145,21346,25147,25148,25149,25150,25151,22504,20167,25154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,21257,25167,25168,25169,25170,25171,25172,25173,25174,18914,25176,25177,25178,25179,25180,25181,25182,19469,25184,25185,25186,25187,18738,25189,25190,18712,25192,21016,25194,22509,25196,25197,25198,25199,25200,25201,25202,25203,18979,25205,25206,25207,25208,25209,25210,20101,25212,25213,23826,25215,25216,20500,25218,25219,25220,25221,23717,25223,25224,25225,18841,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,23131,25238,25239,25240,25241,25242,25243,25244,25245,25246,18890,25248,25249,25250,25251,25252,18705,25254,25255,25256,25257,25258,25259,25260,25261,25262,18580,25264,25265,25266,20080,25268,25269,25270,25271,25272,25273,25274,23161,25276,25277,25278,25279,25280,25281,19467,25283,25284,25285,25286,25287,25288,25289,25290,18745,25292,25293,25294,25295,25296,25297,25298,25299,19776,25301,25302,25303,25304,25305,25306,18913,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,21434,25319,25320,25321,18579,19821,25324,25325,23114,25327,25328,25329,25330,25331,25332,25333,25334,25335,25336,25337,25338,25339,23440,25341,25342,25343,25344,25345,20532,25347,22361,25349,25350,25351,25352,25353,25354,25355,25356,25357,25358,22387,25360,25361,25362,25363,25364,22558,25366,20840,19127,25369,25370,25371,25372,25373,25374,25375,19749,25377,25378,25379,25380,25381,23305,24392,25384,25385,25386,25387,25388,25389,21664,25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,25403,22763,25405,25406,25407,25408,25409,25410,25411,20164,25413,25414,25415,25416,25417,18239,22502,25420,25421,25422,22820,25424,25425,21079,25427,25428,25429,25430,22589,25432,25433,25434,25435,25436,19224,25438,25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,18410,25502,25503,25504,25505,25506,25507,25508,23132,25510,25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,25526,25527,21491,25529,25530,25531,25532,25533,25534,25535,23754,25537,25538,25539,25540,24156,25542,25543,25544,25545,25546,25547,19368,25549,25550,25551,25552,25553,25554,21984,25556,25557,25558,25559,25560,25561,19307,25563,25564,25565,25566,25567,18712,25569,25570,25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,21958,25586,25587,25588,25589,25254,25591,25592,21131,25594,25595,25596,23911,25598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,25610,25611,25612,25613,21136,25615,25616,25617,25618,25619,25620,22706,25622,25623,25624,25625,18372,25627,25628,25629,25630,23838,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,24438,23877,25648,25649,25650,24006,25652,25653,25654,25655,25656,25657,25658,25659,25660,25661,25662,19114,25664,25665,22160,25667,25668,25669,17910,25671,25672,25673,25674,25675,25676,19115,22174,25679,25680,25681,25682,25683,25684,25685,21525,25687,25688,25689,25690,25691,25692,25693,25694,25695,25696,25697,25698,25699,21679,25264,25702,22914,25704,25705,25706,25707,25708,17869,25710,25711,25712,25713,25714,25715,18078,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,22703,25729,25730,25731,25732,25733,25734,25735,25736,25737,18372,25739,25740,25741,25742,25743,25744,25745,25640,25747,25748,25749,25750,25751,25752,25753,25754,24436,25756,25757,25758,17700,25760,25761,25762,25763,25764,20547,25766,25767,25768,25769,25770,25771,19897,25773,22789,25775,25776,25777,20641,25779,25780,20918,19082,25783,25784,19089,25786,25787,25788,25789,22305,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,24775,25802,25803,21355,22151,25806,25807,25808,25809,25810,25811,25812,25813,25814,25815,21872,25817,25818,19821,25820,25821,25822,24290,25824,25825,25826,25827,25828,25829,25830,25831,19964,25833,25834,25835,25836,25837,25838,25839,25840,18849,25842,25843,25844,25845,25846,25847,25848,25849,22605,25851,25852,25853,25854,25855,25856,21031,25858,25859,25860,25861,25862,25863,19517,25865,25866,18520,25868,25869,25870,25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,20594,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,22530,25893,20904,25895,25896,25897,17915,25899,25900,25901,25902,25903,25904,17983,25906,23753,25908,25909,25910,25911,25912,25913,18723,25915,25916,25917,25918,25919,25920,22686,25922,25923,25924,25925,25926,25927,25391,25929,25930,25931,23697,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,24185,25946,25947,25948,25949,25950,25951,19411,25953,25954,25955,25956,25957,25958,24818,25960,18860,25962,25963,25964,25965,25966,25967,25968,25969,25970,25971,25972,19439,25974,25975,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,23465,25987,25988,25989,25990,25991,25992,18463,25994,25995,25601,25997,25998,25999,26000,26001,26002,23803,26004,26005,26006,26007,26008,19155,26010,19760,26012,26013,26014,22517,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,23047,26027,24523,26029,21993,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,19668,26043,26044,26045,21073,26047,26048,26049,17558,26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,18110,26062,26063,26064,26065,26066,26067,18121,26069,26070,26071,26072,26073,26074,26075,26076,26077,26078,22236,26080,26081,26082,20683,26084,26085,26086,26087,20549,26089,21645,26091,26092,26093,26094,26095,26096,26097,18281,26099,26100,26101,26102,26103,26104,26105,18024,26107,26108,26109,19776,26111,26112,26113,26114,26115,26116,26117,26118,26119,18579,26121,26122,26123,26124,21726,26126,26127,26128,21414,26130,26131,26132,26133,26134,26135,26136,23011,26138,26139,26140,26141,26142,26143,21689,26145,26146,26147,26148,26149,25570,26151,26152,26153,26154,26155,20010,26157,25009,26159,26160,26161,26162,19948,21880,26165,26166,26167,26168,26169,26170,26171,26172,26173,21891,26175,26176,22236,26178,26179,26180,26181,26182,20140,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,22617,26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,18501,20875,26207,26208,19888,26210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,18270,26223,26224,17979,26226,26227,17913,26229,26230,26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,22436,26242,26243,26244,20210,26246,26247,26248,26249,26250,26251,26252,26253,23400,26255,26256,26257,26258,20048,26260,26261,26262,26263,26264,17600,26266,26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,22345,26290,23435,26292,26293,26294,26295,18399,26297,26298,26299,26300,26301,25761,26303,26304,26305,26306,26307,26308,26309,18663,26311,26312,26313,19113,26315,26316,26317,26318,26319,26320,25004,24237,26323,26324,26325,26326,26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,26342,21976,26344,21921,26346,26347,26348,26349,26350,26351,20902,26353,23311,26355,26356,26357,26358,26359,21812,26361,26362,26363,22322,26365,26366,26367,26368,26369,26370,18001,26372,26373,26374,26375,26376,26377,26378,26379,26380,26381,26382,24660,26384,26385,26386,26387,26388,26389,20485,26391,24674,20500,26394,26395,26396,26397,26398,26399,26400,24686,26402,26403,26404,26405,26406,26407,26408,26409,23126,26411,26412,24208,26414,26415,26416,26417,26418,24008,26420,26421,26422,26423,26424,26425,19876,26427,26428,26429,26430,26431,17979,26433,26434,26435,26436,26437,18535,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,22436,26451,19113,26453,26454,26455,26456,26457,26458,26459,25683,26461,25687,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,26474,26475,26476,26477,26478,26479,21983,26481,26482,26483,26484,26485,23170,20872,26488,26489,26490,26491,21669,26493,26494,26495,26496,26497,18086,26499,26500,20499,26502,26503,26504,26505,26506,26507,26508,26509,26510,26511,22834,26513,26514,19586,26516,26517,26518,26519,26520,26521,26522,26523,19428,26525,26526,26527,26528,26529,26530,26531,25976,26533,26534,26535,26536,26537,26538,18452,26540,26541,26542,26543,26544,24523,26546,26547,25807,26549,26550,26551,26552,26553,26554,18066,20355,21396,26558,26559,26560,26561,26562,26563,23653,26565,26566,26567,26568,26569,26570,26571,26572,21676,26574,26575,26576,26577,26578,26579,26580,26581,26582,26583,18579,26585,26586,26587,26588,20079,26590,26591,26592,26593,26594,26595,26596,26597,26598,21987,26600,21259,26602,26603,26604,26605,21081,26607,26608,26609,26610,26611,26612,26613,26614,22587,26616,26617,26618,22229,26620,26621,26622,26623,26624,26625,21473,26627,26628,26629,20685,26631,26632,22618,26634,26635,26636,26637,26638,26639,26640,18501,20871,26643,26644,26645,22267,26647,26648,26649,26650,19635,26227,26653,26654,26655,26656,26657,26658,20231,26660,26661,17981,26663,19346,26665,26666,26667,19465,26669,26670,26671,26672,26673,26674,18740,26676,26677,26678,18053,26680,26681,26682,26683,26684,26685,26686,26687,26688,19028,26690,26691,26692,26693,26694,25628,26696,26697,26698,26699,26700,26701,26702,26703,26704,26705,26706,26707,17626,26709,26710,26711,20282,26713,26714,26715,26716,26717,26718,26719,18135,26721,26722,26723,26724,26725,26726,26727,26728,26729,26730,21907,26732,26733,26734,26735,26736,26737,26738,20692,26740,26741,26742,26743,26744,20574,26746,26747,26748,26749,24979,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,26762,25883,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,26774,26775,22683,26777,26778,19736,20847,26781,26782,26783,26784,26785,26786,26787,26788,26789,18318,26791,26792,26793,19111,18925,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,24373,26808,26809,26810,26811,26812,26813,23689,26815,26816,26817,26818,26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,26843,22345,26845,26846,26847,26848,26849,26850,24803,26852,26853,26854,26855,26856,26857,26858,26859,26860,19407,26862,26863,26864,26865,26866,26867,18411,26869,17700,26871,26872,26873,26874,26875,26876,18433,26878,26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,19153,26890,26891,26892,17981,26894,18019,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,19732,26911,26912,26913,26914,26915,26916,23269,26918,26919,26920,20358,26922,26923,26924,26925,26926,26927,26928,26929,26930,25549,26932,26933,26934,26935,26936,26937,26938,26939,19998,26941,26942,18905,26944,26945,26946,26947,20993,26949,26950,26951,26952,20642,26954,26955,26956,26957,26958,26959,26960,19178,26962,26963,26964,26965,18361,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,23438,18396,26979,26980,26981,18410,26983,26984,26985,26986,26987,17701,26989,26990,26991,26992,24008,26994,26995,26996,26997,26998,26999,19081,27001,27002,27003,27004,27005,27006,27007,19688,27009,27010,27011,22329,27013,27014,27015,27016,27017,27018,27019,27020,26792,21647,27023,27024,19760,27026,27027,27028,27029,27030,27031,18543,27033,27034,27035,27036,27037,27038,27039,27040,27041,27042,27043,23625,21870,27046,27047,27048,27049,27050,27051,27052,27053,20338,27055,27056,27057,27058,27059,27060,22768,27062,21259,27064,27065,24289,27067,22024,27069,27070,27071,27072,27073,18123,27075,27076,27077,23125,22249,27080,27081,27082,27083,27084,27085,27086,20694,27088,27089,27090,27091,27092,27093,27094,21647,27096,27097,27098,27099,20707,18736,27102,26116,27104,27105,27106,27107,19307,27109,27110,27111,27112,27113,19795,27115,27116,27117,27118,27119,22193,19876,27122,22160,27124,27125,27126,27127,18507,27129,27130,27131,27132,27133,27134,27135,27136,27137,20596,27139,27140,27141,27142,18078,27144,27145,27146,27147,19188,27149,21457,27151,27152,27153,27154,27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,21601,27166,27167,27168,27169,27170,27171,27172,27173,27174,27175,24440,27177,27178,27179,27180,27181,19865,27183,27184,27185,19876,27187,27188,27189,27190,27191,24723,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,24259,27204,27205,27206,27207,21851,27209,27210,27211,27212,25061,27214,27215,18505,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,21354,27243,27244,27245,18707,27247,27248,27249,19142,27251,18688,27253,27254,27255,27256,27257,19139,20787,27260,27261,27262,17623,27264,27265,27266,19964,27268,27269,27270,27271,27272,27273,27274,17679,27276,27277,22244,27279,27280,27281,27282,27283,27284,21635,27286,27287,27288,27289,27290,27291,27292,26347,27294,27295,27296,27297,27298,27299,18481,27301,27302,27303,27304,19373,27306,23925,27308,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,18913,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,23500,27334,27335,27336,27337,27338,27339,27340,27341,17976,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,20842,23269,27370,26922,27372,27373,27374,27375,27376,27377,27378,18031,27380,27381,27382,27383,27384,27385,27386,19182,27388,27389,27390,27391,27392,27393,27394,19562,27396,18804,27398,27399,27400,27401,27402,27403,22833,27405,27406,27407,19593,27409,27410,27411,27412,27413,27414,27415,21487,27417,27418,27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,19919,27431,27432,18491,27434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,18736,27446,27447,27448,27449,27450,27451,27452,27453,27454,23904,27456,27457,27458,27459,27460,23170,18713,27463,27464,27465,27466,27467,27468,23192,27470,27471,27472,26093,27474,27011,18538,27477,27478,27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,27494,27495,27496,27497,27498,20902,20923,27501,21262,27503,27504,27505,27506,18112,27508,27509,27510,27511,26070,27513,27514,27515,27516,24312,27518,20535,27520,27521,27522,27523,27524,24455,27526,27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,18673,20362,27541,27542,27543,19006,27545,27546,19146,27548,27549,19157,19091,27552,24991,27554,27555,27556,27557,27558,27559,27560,27561,27562,27563,17988,27565,17880,27567,24761,27569,27570,27571,27572,27573,27574,27575,27576,27577,27011,27579,18080,27581,27582,27583,20274,22024,27586,27587,27588,27589,27590,27591,21770,27593,27594,27595,27596,27597,27598,27599,26722,27601,27602,27603,27604,27605,27606,27607,27608,20146,27610,27611,27612,27613,27614,27615,27616,19489,27618,27619,27620,27621,27622,23198,21433,27625,27626,27627,27628,27629,22203,27631,27632,27633,27634,27635,27636,27637,27638,20850,27640,27641,27642,22998,24777,27645,27646,18934,27648,26273,27650,27651,27652,27653,27654,27655,27656,27657,24185,27659,23434,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,25638,27672,27673,27674,27675,17661,27677,27678,27679,27680,27681,27682,27683,27684,27685,27686,27687,27688,17698,27690,27691,27692,27693,27694,27695,27696,22121,27698,27699,27700,27701,27702,23927,27704,27705,27706,27707,23753,27709,27710,27711,27712,27713,27714,25918,18740,27717,27718,27719,27720,27721,27722,27723,23925,27725,27726,27727,27728,27729,27730,24973,27732,26951,27734,27735,27736,27737,27738,19305,27740,27741,27742,27743,26454,27745,27746,27747,27748,27749,20024,27751,20331,27753,27754,27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,18066,25011,25019,27769,27770,27771,27772,27773,27774,27775,17632,27777,27778,27779,27780,27781,27782,27783,20529,27785,27786,27787,27788,19063,27790,27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27526,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,27818,27819,27820,27821,24390,27823,26373,27825,27826,27827,27828,27829,27830,27831,18025,27833,27834,27835,27836,27837,27838,27839,27840,21676,27842,27843,27844,27845,27846,27847,27848,27849,27850,27851,20077,27853,27854,27855,27856,18452,27858,27859,27860,27861,27862,27863,27864,27865,19733,27867,27868,27869,27870,27498,27872,27873,27874,27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,24408,27934,27935,27067,27509,27938,27939,27940,18123,27942,27943,27944,27945,27946,27947,27948,18848,27950,27951,27952,27953,27954,27955,27956,18875,27958,27959,27960,27961,27962,24576,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,27974,25908,27976,27977,27978,27979,27980,27981,27982,19468,27984,27985,27986,27987,27988,19481,27990,27991,27992,27993,27994,27995,27996,23924,27998,27999,28000,28001,28002,21136,28004,28005,28006,28007,28008,28009,28010,28011,21141,28013,28014,28015,28016,28017,28018,27745,28020,28021,28022,25170,28024,28025,28026,28027,24238,28029,28030,28031,28032,28033,28034,28035,28036,28037,28038,28039,20736,28041,20478,28043,28044,28045,28046,28047,19948,28049,28050,28051,28052,28053,17602,28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,28082,28083,28084,28085,28086,28087,27166,28089,28090,28091,18876,28093,28094,28095,28096,28097,18895,28099,28100,28101,28102,28103,28104,28105,28106,28107,28108,28109,25179,28111,28112,28113,28114,19525,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,18737,28127,28128,28129,28130,28131,24969,28133,28134,28135,28136,27006,22177,18742,28140,28141,28142,28143,28144,28145,28146,28147,28148,18712,28150,28151,28152,28153,28154,28155,28156,28157,19156,25384,28160,28161,28162,24259,28164,28165,28166,28167,28168,17874,28170,28171,28172,28173,28174,28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,20100,28188,28189,28190,22013,28192,18109,28194,28195,28196,28197,28198,28199,21887,28201,28202,28203,28204,28205,28206,28207,24924,20683,28210,28211,28212,28213,26200,28215,28216,28217,28218,28219,26890,28221,19760,28223,28224,28225,28226,24478,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,28238,23785,28240,28241,18579,28243,28244,28245,28246,28247,28248,28249,28250,28251,28252,23286,28254,28255,28256,28257,28258,28259,28260,28261,28262,22301,28264,28265,28266,28267,28268,28269,23598,28271,28272,28273,28274,23466,28276,28277,28278,28279,28280,28281,22513,28283,28284,28285,28286,28287,28288,28289,28290,24257,28292,28293,28294,28295,28296,28297,28298,28299,17600,28301,28302,28303,28304,28305,28306,28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,27260,28342,28343,24293,28345,28346,28347,28348,28349,28350,28351,28352,21453,28354,28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,28367,20519,28369,28370,28371,28372,28373,28374,18836,28376,18427,28378,28379,28380,28381,28382,28383,22389,28385,28386,28387,28388,28389,28390,18272,28392,28393,24978,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,28406,28407,28408,18295,28410,28411,28412,28413,28414,28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,22896,28431,28432,28433,28434,28435,28436,28437,19917,28439,21512,28441,28442,28443,28444,28445,25600,28447,28448,28449,28450,28451,28452,28453,18961,23269,28456,28457,21503,28459,28460,28461,28462,28463,28464,28465,17882,28467,28468,28469,28470,28471,28472,28473,28474,18241,28476,28477,28478,28479,22502,28481,19936,28483,28484,28485,28486,28487,18371,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,28502,17623,28504,28505,28506,25833,28508,28509,28510,28511,28512,28513,24315,27793,28516,28517,28518,28519,28520,28521,28522,22988,28524,28525,28526,28527,28528,18241,28530,28531,28532,28533,19117,24645,28536,28537,24649,28539,28540,28541,28542,28543,28544,28545,18296,28547,28548,28549,28550,28551,28552,28553,28554,26115,28556,28557,28558,20707,28560,28561,28562,28563,28564,28565,28566,19373,28568,28569,19142,28571,28572,28573,28574,28575,28189,28577,28578,18094,28580,28581,18805,28583,28584,28585,28586,18396,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,28598,20283,28600,26722,28602,28603,28604,28605,28606,28607,27520,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,24708,28622,28623,28624,28625,28626,28627,28628,25254,28630,28631,28632,28633,28634,28635,20916,28637,20845,28639,28640,28641,28642,28643,28644,28645,19733,28647,28648,28649,22870,28651,28652,28653,28654,28655,20613,28657,28658,28659,21435,28661,28662,28663,28664,28665,28666,23627,21016,28669,18264,25673,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,24282,28691,28692,28693,28694,28695,28696,28697,28698,28699,18362,28701,28702,28703,28704,28705,28706,19215,28708,28709,28710,22232,28712,28713,28714,28715,28716,28717,28718,28719,28720,21896,28722,28723,28724,19980,27795,28727,28728,28729,28730,28731,19072,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,25256,28744,28745,28746,28747,28748,28749,28750,28751,25563,28753,28754,28755,28756,28757,28758,28759,28760,19091,28762,28763,28764,28765,26467,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28779,27869,18244,28782,28783,28784,28785,28786,28787,21155,28789,28790,28791,28792,21355,28794,25571,28796,28797,28798,28799,28800,28801,28802,28803,26212,28805,28806,28807,28808,28809,28810,28303,28812,28813,28703,28815,28816,28817,26053,20502,28820,28821,28822,28823,28824,28825,28826,28827,28828,23718,28830,28831,28832,22239,28834,24006,28836,28837,28838,24491,28840,28841,28842,27471,28844,22640,24602,28847,28848,28849,28850,28851,28852,28853,19121,28855,28856,28857,19342,28859,18463,28861,28862,28863,28864,28865,28847,28867,28868,28869,28870,28871,28872,28873,28874,28875,28876,22549,28878,28879,28880,28881,28882,28883,28884,24615,28886,28887,28888,21930,28890,28891,28892,28893,28894,28895,28896,28897,28292,28899,28900,28901,28902,28903,23253,24412,28906,28907,28908,28909,28910,25740,28912,28913,28914,28915,28916,28917,28918,20277,28920,28921,28922,28923,28924,28925,19966,28927,28928,28929,28930,28931,28932,28933,28934,23123,28936,28937,28938,28939,28940,28941,28942,28943,19061,28945,28946,28947,28948,28949,28950,28951,28952,19268,28954,28955,28956,26903,28958,28959,28960,28961,28962,28963,28964,28965,28966,28967,20093,28969,28970,23925,28972,28973,28974,28975,20869,17997,28978,28979,28980,18739,28982,28983,28984,28985,28986,28987,28988,28989,28990,28991,17843,28993,28994,28995,28996,20705,28998,28999,29000,29001,29002,29003,18489,29005,29006,29007,29008,29009,29010,22667,29012,29013,29014,29015,29016,29017,29018,29019,29020,22163,29022,29023,26962,29025,29026,29027,19198,23849,29030,29031,29032,19964,29034,29035,29036,29037,29038,29039,29040,18411,29042,23735,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,29054,19441,29056,29057,29058,29059,29060,29061,17850,29063,29064,29065,19876,29067,29068,29069,21394,29071,29072,29073,29074,29075,29076,29077,29078,29079,29080,27990,29082,29083,29084,29085,18677,29087,25103,19336,29090,29091,29092,18713,29094,29095,29096,29097,29098,29099,29100,19312,29102,29103,29104,29105,23047,25704,29108,19500,29110,29111,29112,29113,29114,29115,29116,27146,18363,29119,29120,18110,29122,29123,29124,29125,29126,29127,29128,29129,23980,29131,19593,29133,29134,29135,29136,29137,23148,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,25257,18310,29151,19164,29153,29154,29155,24500,25254,29158,29159,26896,29161,29162,29163,29164,29165,19335,29167,29168,29169,29170,29171,23304,29110,29174,29175,29176,29177,29178,29179,29180,21137,29182,29183,29184,19888,29186,29187,29188,20247,29190,29191,29192,23429,23834,29195,25127,29197,26075,29199,29200,29201,29202,20283,29204,29205,29206,29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,18136,29220,29221,29222,22605,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,23921,29235,29236,29237,29238,29239,29240,29241,18452,29243,29244,29245,29246,20873,29248,29249,29250,29251,29252,29253,26770,29255,22743,29257,29258,24473,29260,29261,29262,21526,29264,29265,29266,29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,25303,29278,29279,18502,18001,29282,29283,29284,29285,21738,29287,26278,29289,28701,29291,29292,29293,29294,29295,27504,21463,29298,19038,29300,29301,29302,29303,19591,29305,29306,29307,19719,29309,29310,19987,29312,29313,29314,29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,19298,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29343,19081,29345,29346,29347,29348,29349,29350,29351,19281,29353,29354,29355,21409,29357,29358,29359,29360,29361,29362,29363,29364,29365,18694,29367,29368,29369,29370,29371,29372,25783,29374,29375,29376,29377,29378,29379,23400,29381,29382,29383,29384,29385,29386,29387,21022,19995,29390,26797,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,24855,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,29414,29415,29416,18960,26604,29419,19027,29421,29422,29423,29424,29425,29426,17567,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,29498,22024,29500,29501,29502,29503,25438,29505,29506,29507,29508,29509,29510,29511,29512,24430,29514,29515,29516,29517,29518,20958,29520,29521,29522,29523,25852,29525,29526,29527,29528,29529,29530,29531,29532,29533,29534,20691,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29548,29549,27980,29551,29552,29553,20624,29555,29556,29557,29558,29559,29560,21010,29562,29563,29564,29565,29566,29567,29568,29569,29570,29571,19122,19788,29574,19469,29576,29577,29578,29579,29580,29581,29582,29583,29584,29585,29586,19480,29588,29589,29590,29591,29592,29593,29594,29595,23476,29597,29598,29599,29600,29601,19276,29603,29604,29605,19144,29607,29608,29609,20847,29611,29612,29613,29614,29615,29616,29617,29618,24500,18078,29621,29622,29623,25628,29625,29626,29627,29500,29629,29630,19845,29632,29633,29634,29635,29636,17691,29638,29639,29226,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,23747,28631,29653,29654,29655,29656,25062,29658,29659,29660,29661,17998,29663,21239,29665,29666,29667,29668,29669,22788,29671,29672,19880,25413,29675,29676,22509,29678,29679,29680,29681,29682,29683,29684,29685,28128,29687,29688,29689,29690,29691,29692,29693,29694,22446,29696,29697,29698,29699,29700,29701,19776,29703,29704,29705,29706,29707,29708,29709,29710,29711,21569,29713,29714,18705,29716,29717,29718,29719,29720,23402,29722,29723,29724,29725,29726,29727,29728,29729,25775,20247,29732,24413,29734,29735,29736,29737,21452,29739,22833,29741,29742,26713,29744,29745,29746,29747,24311,29749,29750,29751,29752,29753,23739,29755,29756,29757,29758,22389,26577,29761,29762,29763,29764,29765,29766,18271,29768,29769,29770,29771,29772,29773,29774,29775,29776,21375,29778,20164,29780,29781,29782,18449,29784,29785,29786,29787,29788,19690,19683,29791,29792,26894,29794,29795,23524,29797,29798,29799,29800,29801,29802,19126,29804,29805,29806,18319,29808,29809,29810,19182,29812,29813,22016,29815,29816,17602,29818,29819,29820,29821,29822,19050,29824,29825,29826,29827,29828,29829,29830,22850,29832,29833,29834,29835,29836,29837,29838,29839,29840,23147,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,25257,29855,29856,29857,29858,29859,29860,19166,29862,29863,29864,29865,29866,29867,29868,24276,20030,29871,29872,29873,18995,29875,29876,29877,29878,29879,29880,29881,29882,19320,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,18950,29896,29897,29898,18452,29900,29901,21976,21963,29904,29905,29906,26603,29908,20500,29910,29911,29912,29913,29914,29915,29916,18819,29918,29919,29920,29921,29922,29923,29924,29925,19591,29927,29928,20824,29930,29931,29932,29933,29934,29935,29936,29937,28789,29939,18067,19679,29942,29943,29944,29945,29946,29947,29948,29949,29950,17883,29952,29953,29954,18917,29956,24955,29958,29959,29960,29961,29962,29963,29404,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,22673,29978,29979,29980,19277,29982,29381,29984,29985,29986,27718,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,30002,30003,18972,30005,30006,30007,30008,30009,22823,17577,29503,30013,21095,30015,30016,30017,30018,30019,21898,30021,30022,30023,24317,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,30035,27527,30037,30038,30039,30040,24357,30042,30043,30044,30045,30046,30047,19354,30049,30050,30051,27014,30053,30054,30055,30056,30057,30058,30059,30060,23305,28891,30063,30064,24400,30066,30067,30068,30069,30070,30071,18207,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,30143,18579,30145,30146,30147,19795,30149,30150,30151,30152,30153,23950,30155,30156,30157,30158,30159,19190,30161,30162,30163,30164,30165,30166,30167,30168,30169,30170,20503,30172,30173,30174,30175,30176,30177,30178,19038,30180,25233,18416,30183,30184,18439,30186,22423,20230,30189,30190,30191,30192,30193,30194,30195,30196,30197,30198,21380,30200,30201,18913,30203,27437,30205,30206,30207,30208,30209,24856,30211,30212,30213,30214,30215,30216,30217,30218,30219,18722,30221,30222,30223,30224,30225,30226,30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,30242,30243,19757,30245,30246,30247,30248,21933,30250,30251,24888,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,23066,22706,30268,19393,30270,30271,30272,30273,30274,30275,30276,30277,30278,30279,30280,25642,30282,30283,30284,20282,30286,30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,29520,30298,30299,24217,30301,30302,30303,30304,30305,30306,30307,30308,30309,18439,30311,25258,30313,30314,30315,30316,19137,30318,24596,30320,30321,18501,30323,21931,30325,30326,30327,30328,30329,18293,30331,30332,30333,30334,30335,30336,30337,21848,30339,30340,30341,30342,30343,30344,30345,30346,20072,30348,30349,30350,21722,30352,30353,30354,30355,30356,30357,30358,30359,18579,30361,30362,30363,30364,30365,30366,28044,30368,30161,30370,30371,20502,30373,30374,30375,30376,30377,30378,30379,24686,30381,30382,30383,30384,30385,28381,30387,30388,30389,30390,30311,30323,27640,30394,30395,20842,24246,30398,30399,30400,18723,30402,30403,30404,30405,30406,30407,30408,30409,20370,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,29236,30422,30423,30424,30425,30426,20576,30428,27027,30430,30431,30432,24256,30434,30435,30436,30437,30438,30439,30440,30441,30442,26823,30444,30445,30446,30447,30448,30449,18361,30451,19389,30453,30454,30455,30456,30457,25639,30459,28369,30461,30462,30463,30464,30465,30466,18849,30468,30469,30470,30471,30472,30473,30474,30475,30476,21479,30478,30479,30480,30481,30482,30483,21488,30485,30486,30487,30488,30489,30490,30491,30492,30493,18463,30495,30496,30497,30211,30499,30500,30501,30502,30503,30504,30505,30506,18712,18705,30509,30510,30511,30512,30513,30514,28401,30516,30517,27035,30519,23047,19929,30522,19321,30524,30525,30526,30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,21987,30587,19179,30589,30590,30591,30592,19942,30594,30595,30596,30597,30598,30599,30600,30601,21463,30603,30604,30605,30606,30607,30608,30609,30610,30611,22962,30613,30614,30615,30616,30617,29825,30619,30620,23130,30622,30623,30624,19600,30626,30627,30628,30629,30630,30631,21228,30633,30634,30635,30636,30637,30638,30639,22694,30641,30642,30643,22933,30645,30646,19732,30648,30649,30650,30651,30652,18905,30654,30655,30656,30657,30658,30659,30660,30661,30662,30663,30664,22695,30666,30667,30668,30669,30670,30671,30672,30673,27642,30675,30676,30677,30678,30679,30680,30681,23308,27328,30684,30685,30686,30687,30688,25995,30690,30691,30692,30693,30694,30695,30696,30697,20848,30699,30700,30701,30702,30703,30704,30705,30499,30707,30708,30709,30710,30711,30712,30713,24381,30715,30716,30717,30718,22703,30720,30721,30722,30723,30724,30725,26700,30727,30728,30729,30730,30731,30732,30733,22468,30735,30736,30737,30738,30739,30740,30741,30742,19985,30744,21676,30746,30747,30748,30749,25571,30751,30752,30753,30754,30755,18502,30645,30758,30759,26251,30761,30762,30763,30764,30765,30766,30767,25595,30769,30770,30771,30772,30773,25998,30775,30776,30777,30778,30779,30780,30781,30782,30783,26363,30785,30786,30723,30788,30789,30790,22943,30792,30793,17623,30795,30796,29034,30798,30799,30800,30801,30802,30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,27081,30814,20551,30816,30817,19879,20359,30820,30821,30822,30823,30824,30825,30826,21409,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,29238,30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,24980,30850,30851,30852,30853,30854,30855,30856,30857,30858,25797,30860,30861,30862,30863,30864,30865,30866,18467,30868,30869,30870,30871,30872,25257,30874,30875,30876,30877,30878,17885,30880,30881,30882,30883,30884,30885,30886,30887,27013,30889,30890,30891,30892,30893,30894,30895,23111,29501,27942,30899,30900,18410,30902,30903,30904,30905,30906,30907,19062,30909,30910,30911,30912,30913,30914,30915,18890,30917,30918,30919,30920,29982,30922,30923,24152,30925,30926,30927,30928,30929,20370,30931,30932,30933,30934,30935,30936,30937,30938,30939,30940,23925,30942,30943,30944,18705,30946,30947,30948,30949,30950,30951,30952,30953,19089,30955,30956,30957,30958,22312,30960,30961,30962,20986,30964,30965,30966,20077,30968,30969,30970,30971,28243,30973,30974,30975,30976,30977,30978,21259,30980,30981,30982,19188,30984,28354,30986,30987,30988,30989,30990,30991,30992,30993,30994,30461,30996,30997,30998,30999,31000,31001,31002,18841,31004,31005,31006,31007,31008,17688,31010,31011,31012,30311,24848,27011,31016,31017,31018,20230,31020,31021,31022,31023,31024,31025,31026,31027,28469,31029,31030,31031,31032,31033,31034,18912,31036,31037,31038,31039,31040,31041,31042,31043,31044,30884,31046,29015,31048,31049,31050,31051,31052,31053,31054,23623,31056,31057,31058,30407,31060,31061,31062,31063,25550,31065,17595,31067,31068,31069,31070,31071,18363,31073,31074,31075,31076,19573,31078,31079,31080,31081,31082,31083,31084,31085,23839,31087,31088,31089,31090,31091,31092,31093,31094,31095,30735,31097,31098,31099,31100,31101,31102,31103,31104,20143,31106,31107,31108,29063,22904,31111,31112,31113,18716,31115,31116,31117,31118,31119,31120,19308,31122,31123,31124,28221,31126,31127,31128,19736,31130,20234,31132,31133,31134,31135,31136,17982,18915,31139,31140,31141,31142,31143,31144,22337,31146,31147,31148,21022,23531,25215,31152,31153,31154,31155,31156,20274,31158,22024,31160,31161,31162,31163,31164,31165,18121,31167,31168,31169,31170,20673,31172,31173,31174,21779,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,31190,31191,18890,31193,31194,31195,31196,31197,31198,31199,31200,31201,29982,31203,31204,18726,31206,31207,31208,31209,31210,26896,31212,31213,31214,22446,31216,31217,26918,18723,31220,31221,31222,31223,19367,31225,31226,31227,31228,31229,29704,31231,31232,31233,31234,19921,31236,31237,31238,31239,31240,31241,31242,31243,18968,31245,31246,31247,31248,31249,20594,31251,31252,31253,31254,31255,31256,31257,31258,30980,19411,31261,31262,31263,27786,31265,31266,25761,31268,31269,31270,20968,31272,31273,31274,31275,31276,31277,31278,23925,31280,31281,31282,30510,31284,31285,31286,27193,31288,31289,31290,25294,23474,31293,31294,31295,28999,31297,31298,31299,31300,31301,31302,31303,31304,29722,31306,31307,31308,31309,30214,31311,31312,31313,31314,31315,31316,18463,31318,31319,31320,31321,31322,23269,18726,31325,31326,31327,31328,31329,31330,18736,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,18311,22705,31348,31349,17569,31351,31352,31353,31354,31355,29503,19961,31358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,21897,31371,31372,31373,31374,31375,31376,21905,31378,31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,25977,31390,31391,31392,31393,31394,31395,31396,31397,31398,31399,25255,31401,31402,31403,31404,31405,31406,22648,31408,31409,31410,31411,31412,31413,31414,19122,23401,31417,31418,31419,31420,31421,31422,31423,31424,21416,31426,31427,31428,29063,31430,31431,31432,18270,31434,18283,31436,31437,31438,28547,31440,31441,31442,31443,31444,31445,31446,31447,31448,27144,31450,31451,31452,31453,31454,27261,31456,26856,31458,31459,31460,31461,31462,20503,31464,31465,31466,31467,31468,23844,31470,17652,31472,31473,31474,31475,31476,31477,31478,31479,31480,31481,29523,31483,22606,31485,31486,31487,31488,22618,31490,31491,31492,31493,23163,31495,28471,31497,31498,30149,31500,31501,31502,31503,31504,31505,28805,31507,31508,31509,31510,31511,31512,31513,31514,28432,31516,31517,31518,31519,31520,31521,31522,31523,20627,28561,31526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,31538,21525,31540,31541,31542,31543,31544,31545,31546,31547,24970,31549,31550,19276,31552,31553,31554,29556,31556,31557,31558,30645,31560,31561,31562,31563,31564,31565,31566,31567,21824,31569,31570,31571,31572,31573,31574,31575,31576,28189,31578,31579,19189,31581,31582,31583,29442,31585,31586,31587,31588,31589,25639,31591,31592,20283,31594,31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,31607,17684,31609,22605,31611,31612,31613,31614,31615,31616,31617,24455,31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,27243,31630,31631,25094,31633,31634,31635,31636,31637,31638,31639,26766,31641,31642,31643,31644,21107,31646,31647,31648,23168,31650,31651,27552,31653,31654,31655,31656,31657,31658,31659,31660,31440,31662,31663,31664,31665,31666,31667,18205,28277,31670,31671,31672,18002,31674,31675,31676,31677,31678,31679,31680,31681,31682,21735,17637,31685,31686,31687,31688,31689,31690,31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,18366,24291,31704,31705,26403,28723,17700,31709,31710,31711,31712,31713,31714,18657,31716,31717,31718,31719,31720,22762,31722,31723,31724,31725,31726,31727,31728,17866,31730,31731,31732,21135,31734,31735,31736,31737,31738,31739,31740,31741,31742,31743,30332,28432,31746,31747,31748,31749,31750,31751,20747,31753,31754,31755,31756,31757,31758,21935,31760,31761,31762,31763,21731,31765,31766,31767,31768,31769,31770,31771,24344,29604,31774,31775,18696,31777,31778,31779,31780,27222,31782,31783,31784,31785,31786,31787,31788,31789,31790,31791,31792,31793,31794,24256,31796,31797,31798,31799,31800,26281,31802,26846,31804,31805,20272,31807,31808,20661,31810,24428,31812,22365,31814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,31826,25360,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,26366,31846,31847,31848,31849,29780,28796,31852,31853,31854,31855,31856,31857,31858,29110,31860,31861,31862,31863,19897,31865,31866,31867,31868,31869,31870,18233,31872,31873,31874,31875,31876,31877,31878,18586,31880,31881,31882,21923,31884,31885,25414,26590,31888,31889,31890,31891,31892,31893,31894,22193,19178,31897,31898,24412,31900,24297,31902,31903,26072,31905,31906,31907,31908,31909,22970,22974,31912,31913,31914,31915,31916,31917,31918,31919,31920,25529,31922,31923,31924,31925,31926,31927,31928,26655,31930,31931,31932,31933,26031,31935,31936,31937,31938,31939,31940,31941,27190,31943,20735,28796,31946,31947,31948,31949,31950,31951,31952,31953,18750,31955,31956,31957,31958,31959,20024,31961,31962,31963,31964,20577,31966,31967,20225,31969,31970,31971,31972,27756,31974,31975,31976,31977,31978,31979,31980,31981,31982,31983,31984,31985,31986,31987,20100,31989,31990,31991,31992,17590,31994,31995,31996,31997,31998,31999,32000,31595,32002,32003,32004,32005,32006,32007,32008,32009,32010,31108,32012,32013,32014,32015,32016,32017,32018,26119,23192,23498,32022,32023,32024,32025,32026,32027,32028,32029,21008,32031,32032,32033,32034,32035,25893,32037,32038,32039,18601,20335,32042,32043,32044,32045,32046,32047,32048,18045,32050,32051,32052,32053,18330,32055,32056,32057,20103,32059,32060,27503,32062,32063,32064,25432,32066,32067,32068,32069,32070,28089,32072,32073,32074,32075,32076,32077,32078,19593,32080,32081,32082,32083,32084,32085,32086,32087,21495,32089,32090,32091,32092,19149,32094,32095,32096,27254,32098,32099,32100,32101,32102,21230,32104,32105,32106,32107,32108,23192,32110,32111,23497,32113,32114,32115,32116,32117,32118,32119,32120,32121,30363,32123,32124,32125,32126,21572,21257,32129,32130,32131,32132,32133,32134,32135,28786,32137,32138,32139,32140,32141,20350,32143,32144,25009,32146,32147,32148,32149,32150,32151,17557,32153,32154,32155,32156,32157,32158,25026,32160,32161,32162,32163,32164,32165,32166,27166,32168,32169,22848,32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,21493,32182,32183,32184,32185,32186,32187,32188,32189,32190,19145,32192,32193,32194,32195,32196,22415,32198,32199,32200,32201,19746,32203,20705,32205,32206,32207,24155,32209,32210,32211,18933,19298,32214,32215,32216,32217,32218,32219,32220,24848,32222,20470,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,21730,32236,32237,32238,32239,19559,32241,32242,22938,32244,18374,32246,32247,32248,32249,32250,32251,29197,32253,32254,31477,32256,32257,30470,32259,32260,32261,32262,32263,27279,32265,32266,32267,32268,32269,22255,32271,32272,32273,32274,32275,32276,19614,32278,32279,32280,32281,32282,32283,32284,32285,25917,32287,32288,32289,32290,28641,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,18270,32303,32304,32305,26561,32307,32308,32309,19369,32311,32312,32313,32314,32315,32316,32317,32318,32319,19776,32321,32322,32323,32324,32325,32326,32327,32328,18709,32330,32331,26489,32333,32334,32335,32336,32337,32338,32339,32340,20645,32342,32343,32344,32345,32346,32347,32348,32349,30155,32351,32352,32353,25954,32355,32356,32357,32358,32359,32360,20674,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,26990,32374,32375,19726,32377,32378,32379,32380,27747,32382,23381,20014,32385,32386,32387,32388,32389,32390,25421,32392,32393,32394,32395,32396,27861,32398,26433,32400,32401,23633,32403,32404,32405,32406,32407,32408,20744,32410,32411,28221,32413,32414,24752,32416,32417,28031,32419,32420,32421,32422,32423,32424,32425,32426,32427,32428,32429,32430,29782,23251,18093,32434,32435,20502,32437,32438,32439,26513,32441,32442,21476,32444,20814,32446,32447,32448,32449,20535,32451,32452,32453,32454,32455,32456,32457,20691,32459,32460,32461,32462,19282,32464,32465,20189,32467,32468,27846,32470,32471,32472,32473,18579,32475,19796,32477,32478,32479,32480,32481,32482,32483,32484,32485,32486,32487,21647,32489,32490,32491,32492,25171,21361,32495,32496,19627,32498,32499,32500,19180,32502,32503,32504,32505,32506,32507,32155,32509,26616,32511,32512,32513,21608,32515,32516,32517,32518,32519,32520,32521,29834,32523,32524,32525,32526,32527,24577,32529,32530,32531,26791,32533,32534,31050,32536,32537,32538,22445,19118,18726,32542,32543,32544,32545,32546,32547,32548,32549,32550,32551,23182,32553,32554,17899,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,32654,32655,32656,24621,32658,18923,32660,32661,32662,32663,32664,32665,32666,32553,32668,32669,32670,32671,32672,20437,18078,32675,32676,32677,32678,32679,21084,32681,32682,32683,18372,32685,32686,32687,32688,32689,32690,32691,32692,29629,32694,32695,30015,32697,32698,32699,32700,32701,32702,32703,25971,32705,32706,32707,32708,32709,32710,32711,32712,32713,32714,32715,22388,32717,32718,32719,32720,32721,32722,32723,32724,32725,32726,22683,32728,32729,26949,32731,32732,32733,20598,32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,31057,24523,18584,32748,23621,18264,26898,32752,32753,32754,32755,32756,24276,32758,20247,32760,32761,32762,32763,21877,32765,32766,32767,32768,32769,32770,30996,32772,32773,32774,32775,32776,32777,32778,32779,32780,23458,32782,32783,32784,32785,32786,32787,32788,25363,32790,32791,32792,32793,25784,32795,29952,25808,32798,32799,32800,32801,32802,19928,32804,32805,32806,32807,32808,24390,32133,32811,18587,32813,32814,32815,32816,32817,32818,32819,32820,32821,32822,27474,32824,20329,26753,32827,32828,32829,26932,32831,32832,32833,32834,32835,32836,18768,32838,32839,32840,32841,32842,32843,32844,32845,32846,32847,32848,32849,32850,32851,32852,32853,32854,32855,32856,32857,32858,32244,32860,32861,17580,32863,32864,32865,32866,28921,32868,32869,32870,23579,32872,32873,32874,32875,32876,32877,32878,28602,32880,29227,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,23925,32893,32894,32895,32896,32897,19516,32899,32900,32901,32902,32903,24982,32905,32906,32907,32908,32909,32910,26210,32912,32913,32914,32915,32916,32917,32918,22996,32920,29781,19327,32923,32924,32925,32926,32927,25194,32929,32930,20226,32932,32933,32934,26550,32936,28469,32938,32939,32940,32941,32942,19823,32944,32945,32946,32947,21081,32949,32950,32951,27154,32953,32954,30613,32956,32957,32958,32959,19046,32961,32962,32963,32964,32965,32966,32967,32968,32969,32970,30183,32972,32973,32974,32975,32976,32977,32978,32979,32980,32981,32982,22387,32984,32985,32986,32987,32988,32989,32990,25784,32992,32993,22768,24237,32996,32997,32998,32999,33000,33001,33002,33003,33004,25414,20572,33007,33008,33009,33010,19690,33012,20335,33014,33015,33016,33017,33018,33019,33020,33021,33022,33023,33024,33025,33026,25997,33028,33029,33030,33031,33032,33033,18543,33035,33036,33037,33038,33039,33040,33041,33042,33043,18913,33045,33046,18519,31642,33049,33050,33051,33052,33053,21260,33055,33056,31582,33058,33059,33060,24914,18397,33063,33064,33065,33066,33067,33068,33069,31596,33071,33072,33073,33074,20814,33076,33077,33078,33079,19989,33081,29335,33083,33084,33085,21389,33087,21232,33089,33090,33091,33092,33093,33094,18739,33096,33097,33098,33099,33100,33101,23221,33103,33104,33105,33106,33107,33108,33109,33110,33111,33112,33113,33114,33115,33116,33117,33118,33119,33120,33121,33122,33123,33124,33125,33126,33127,33128,33129,33130,33131,33132,33133,33134,33135,33136,33137,33138,33139,33140,33141,33142,33143,33144,33145,33146,33147,33148,33149,33150,33151,33152,33153,33154,33155,33156,33157,33158,33159,33160,33161,33162,33163,33164,33165,33166,33167,33168,33169,33170,33171,21571,18351,33174,33175,33176,33177,33178,33179,33180,33181,33182,33183,33184,33185,33186,30758,33188,18678,33190,33191,20577,33193,33194,33195,21977,18511,33198,33199,33200,33201,33202,33203,33204,33205,25712,33207,33208,29191,33210,33211,25122,29431,33214,33215,33216,33217,33218,33219,33220,33221,31161,33223,33224,33225,29506,33227,33228,33229,24438,22849,33232,33233,33234,33235,33236,33237,33238,33239,33240,19444,33242,33243,18446,26653,33246,24239,33248,33249,33250,33251,33252,33253,33254,33255,33256,33257,23485,33259,33260,33261,32992,33263,33264,26922,33266,33267,33268,33269,33270,33271,33272,33273,33274,26465,33276,33277,33278,33279,33280,33281,33282,33283,33284,33285,33286,33287,33288,33289,20058,33291,33292,33293,33294,33295,21647,33297,33298,33299,33300,22172,33302,33303,33304,33305,19478,33307,33308,33309,33310,33311,33312,33313,17993,33315,33316,33317,22707,33319,33320,20274,18106,33323,33324,33325,23725,33327,33328,33329,33330,33331,33332,33333,33334,33335,31817,33337,33338,33339,33340,33341,33342,20551,33344,33345,33346,33347,33348,33349,33350,33351,33352,33353,33354,33355,33356,33357,33358,24132,33360,31500,33362,33363,33364,18579,33366,33367,33368,33369,21155,33371,33372,19668,33374,33375,33376,23021,33378,33379,33380,33381,33382,33383,33384,33385,33386,33387,33388,33389,33390,21252,22652,33393,21355,21993,33396,33397,33398,33399,33400,33401,33402,29780,25721,33405,33406,33407,33408,19034,33410,19411,33412,33413,33414,33415,33416,22077,20143,33419,33420,33421,33422,33423,33424,33425,33426,32215,33428,33429,33430,33431,21645,33433,33434,33435,33436,28257,33438,33439,33440,33441,33442,33443,33444,33445,33446,26765,33448,33449,33450,33451,33452,20466,33454,33455,20742,31946,33458,33459,33460,33461,33462,32992,21356,21994,33466,33467,33468,33469,33470,21960,29813,33473,22828,33475,33476,19411,33478,33479,33480,33481,33482,23587,22118,33485,31231,33487,33488,19884,33490,33491,33492,33493,33494,33495,33496,33497,26017,33499,33500,21678,33502,33503,33504,33505,33506,33507,33508,33509,33510,33511,22906,33513,33514,33515,27134,33517,33518,33519,33520,18544,33522,33523,33524,33525,33526,33527,33528,33529,33530,33531,19656,33533,33534,33535,33536,33537,33538,33539,33540,33541,19760,33543,33544,21527,33546,33547,33548,33549,33550,33551,33552,33553,33554,17599,33556,21761,32685,33559,33560,33561,33562,33563,33564,33565,33566,17623,33568,33569,33570,33571,33572,33573,19964,33575,33576,33577,19422,33579,19425,33581,33582,33583,33584,33585,33586,33587,33588,33589,33590,33591,26881,33593,33594,33595,33596,33597,33598,33599,33600,22324,33602,30406,33604,33605,33606,33607,33608,33609,20996,33611,33612,33613,33614,33615,33616,31642,33618,33619,33620,19614,33622,33623,33624,33625,33626,33627,33628,33629,33630,19928,33632,18586,33634,33635,33636,33637,33638,33639,33640,33641,33642,33643,33644,33645,33646,33647,33648,33649,27554,33651,33652,33653,33654,21676,33656,33657,33658,33659,33660,33661,33662,30323,27228,33665,33666,33667,33668,33669,28848,33671,33672,33673,33674,33675,33676,33677,33678,25212,33680,33681,19027,33683,33684,33685,33686,15067,33688,33689,33690,33691,33692,33693,33694,33695,33696,33697,33698,33699,33700,33701,33702,33703,33704,33705,33706,33707,33708,33709,33710,33711,33712,33713,33714,33715,33716,33717,33718,33719,33720,33721,33722,33723,33724,33725,33726,33727,33728,33729,33730,33731,33732,33733,33734,33735,33736,33737,33738,33739,33740,33741,33742,33743,33744,33745,33746,33747,33748,33749,33750,33751,33752,33753,33754,33755,33756,33757,33758,33759,33760,33761,33762,33763,33764,33765,33766,33767,33768,33769,33770,33771,33772,33773,33774,33775,33776,33777,33778,33779,33780,33781,33782,33783,33784,33785,33786,33787,33788,33789,33790,33791,33792,33793,33794,33795,33796,33797,33798,33799,33754,33801,33802,33803,33804,33805,33806,33807,33808,33809,33810,33811,33812,33813,33814,33815,33816,33817,33818,33819,33820,33821,33822,33823,33824,33825,33826,33827,33828,33829,33830,33831,33832,33833,33834,33835,33836,33837,33838,33839,33840,33841,33842,33843,33844,33845,33846,33847,33848,33849,33850,33851,33852,33853,33854,33855,33856,33857,33858,33859,33860,33861,33862,33725,33864,33865,33866,33867,33868,33869,33870,33871,33872,33873,33874,33875,33876,33877,33878,33879,33880,33881,33882,33883,33884,33885,33886,33887,33888,33889,33890,33891,33892,33893,33894,33895,33896,33897,33898,33899,33900,33901,33902,33903,33904,33905,33906,33907,33908,33909,33910,33911,33912,33913,33914,33915,33916,33917,33918,33919,33920,33921,33922,33923,33924,33925,33926,33927,33928,33929,33930,33931,33932,33933,33934,33935,33709,33937,33938,33939,33940,33941,33942,33943,33944,33945,33946,33947,33948,33949,33950,33951,33952,33953,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33967,33968,33969,33970,33971,33972,33973,33974,33975,33976,33977,33978,33979,33980,33981,33982,33983,33984,33985,33986,33987,33988,33989,33990,33991,33992,33993,33994,33995,33996,33997,33998,33999,34000,34001,34002,34003,34004,34005,34006,34007,34008,34009,34010,34011,34012,34013,34014,34015,34016,34017,34018,34019,34020,34021,34022,34023,33946,34025,34026,34027,34028,34029,34030,34031,34032,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34044,34045,34046,34047,34048,34049,34050,34051,34052,34053,34054,34055,34056,34057,34058,34059,34060,34061,34062,34063,34064,34065,34066,34067,34068,34069,34070,34071,34072,34073,34074,34075,34076,34077,34078,34079,34080,34081,34082,34083,34084,34085,34086,34087,34088,34089,34090,34091,34092,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34103,34104,34105,34106,34107,34108,34109,34110,34111,34112,34113,34114,34115,34116,34117,34118,34119,34120,34121,34122,34123,34124,34125,34126,34127,34128,34129,34130,34053,34132,34133,34134,34135,34136,34137,34138,34139,34140,34141,34142,34143,34144,34145,34146,34147,34148,34149,34150,34151,34152,34153,34154,34155,34156,34157,34158,34159,34160,34161,34162,34163,34164,34165,34166,34167,34168,34169,34170,34171,34172,34173,34174,34175,34176,34177,34178,34179,34180,34181,34182,34183,34184,34185,34186,34187,33698,34189,34190,34191,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34203,34204,34205,34206,34207,34208,34209,34210,34211,34212,34213,34214,34213,34216,34217,34218,34219,34220,34221,34222,34223,34224,34225,34226,34227,34228,34229,34230,34231,34232,34233,34234,34235,34236,34237,34238,34239,34240,34241,34242,34243,34244,34245,34246,34247,34248,34249,34250,34251,34252,34253,34254,34255,34256,34257,34258,34259,34260,34261,34262,34263,34264,34265,34266,34267,34268,34269,34270,34271,34272,34273,34274,34275,34276,34277,34278,34279,34280,34281,34282,34198,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,34297,34298,34299,34300,34301,34302,34303,34304,34305,34306,34307,34308,34309,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34321,34322,34323,34324,34325,34326,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34343,34344,34345,34346,34347,34193,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34360,34361,34362,34363,34364,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34381,34382,34383,34384,34385,34386,34387,34388,34389,34390,34391,34392,34393,34394,34395,34396,34397,34398,34399,34400,34401,34402,34403,34404,34405,34406,34407,34408,34409,34410,34411,34412,34413,34414,34415,34416,34417,34418,34419,34420,34421,34422,34423,34424,34425,34426,34427,34428,34429,34430,34431,34432,34189,34434,34435,34436,34437,34438,34439,34440,34441,34442,34443,34444,34445,34446,34447,34448,34449,34450,34451,34452,34453,34454,34455,34456,34457,34458,34459,34460,34461,34462,34463,34464,34465,34466,34467,34468,34469,34470,34471,34472,34473,34474,34475,34476,34477,34478,34479,34480,34481,34482,34483,34484,34485,34486,34487,34488,34489,34490,34491,34492,34493,34494,34495,34496,34497,34498,34499,34500,34501,34502,34503,34504,34505,34506,34507,34508,34509,34510,34511,34512,34513,34514,34515,34516,34517,34518,34519,34520,34521,34522,34523,34524,34525,34526,34527,34528,34529,34530,34531,34532,34533,34534,34535,34536,34442,34538,34539,34540,34541,34542,34543,34544,34545,34546,34547,34548,34549,34550,34551,34552,34553,34554,34555,34556,34557,34558,34559,34560,34561,34562,34563,34564,34565,34566,34567,34568,34569,34570,34571,34572,34573,34574,34575,34576,34577,34578,34579,34580,34581,34582,34583,34584,34585,34586,34587,34588,34589,34590,34591,34592,34593,34594,34595,34596,34597,34598,34599,34600,34601,34602,34603,34604,34605,34606,34607,34608,34609,34610,34437,34612,34613,34614,34615,34616,34617,34618,34619,34620,34621,34622,34623,34624,34625,34626,34627,34628,34629,34630,34631,34632,34633,34634,34635,34636,34637,34638,34639,34640,34641,34642,34643,34644,34645,34646,34647,34648,34649,34650,34651,34652,34653,34654,34655,34656,34657,34658,34659,34660,34661,34662,34663,34664,34665,34666,34667,34668,34669,34670,34671,34672,34673,34674,34675,34676,34677,34678,34679,34680,34681,34682,34683,34684,34685,34686,34687,34688,34689,34690,34691,34692,34693,34694,34695,34696,34697,34698,34699,34700,34701,34702,34703,34704,34705,34706,34707,34708,34709,34616,34711,34712,34713,34714,34715,34716,34717,34718,34719,34720,34721,34722,34723,34724,34725,34726,34727,34728,34729,34730,34731,34732,34733,34734,34735,34736,34737,34738,34739,34740,34741,34742,34743,34744,34745,34746,34747,34748,34749,34750,34751,34752,34753,34754,34755,34756,34757,34758,34759,34760,34761,34762,34763,34764,34765,34766,34767,34768,34769,34770,34771,34772,34773,34774,34775,34776,34777,34778,34779,34780,34781,34782,34783,34784,34785,34786,34787,34788,34789,34790,34791,34792,34793,34794,34795,34796,34797,34798,34799,34800,34801,34802,34803,15060,34805,34806,34807,34808,34809,34810,34811,34812,34813,34814,34815,34816,34817,34818,34819,34820,34821,34822,34823,34824,34825,34826,34827,34828,34829,34830,34831,34832,34833,34834,34835,34836,34837,34838,34839,34840,34841,34842,34843,34844,34845,34846,34847,34848,34849,34850,34851,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34866,34867,34868,34869,34870,34871,34872,34873,34874,34875,34876,34877,34878,34879,34880,34881,34882,34883,34884,34885,34886,34887,34888,34889,34890,34891,34892,34893,34894,34895,34896,34897,34898,34899,34900,34901,34902,34903,34904,34905,34906,34907,34908,34909,34910,34911,34912,34913,34914,34915,34916,34917,34918,34919,34920,34921,34922,34923,34827,34925,34926,34927,34928,34929,34930,34931,34932,34933,34934,34935,34936,34937,34938,34939,34940,34941,34942,34943,34944,34945,34946,34947,34948,34949,34950,34951,34952,34953,34954,34955,34956,34957,34958,34959,34960,34961,34962,34963,34964,34965,34966,34967,34968,34969,34970,34971,34972,34973,34974,34975,34976,34977,34978,34979,34980,34981,34982,34983,34984,34985,34986,34987,34988,34989,34990,34991,34992,34993,34994,34995,34996,34997,34998,34999,35000,35001,35002,35003,35004,35005,35006,35007,35008,34816,35010,35011,35012,35013,35014,35015,35016,35017,35018,35019,35020,35021,35022,35023,35024,35025,35026,35027,35028,35029,35030,35031,35032,35033,35034,35035,35036,35037,35038,35039,35040,35041,35042,35043,35044,35045,35046,35047,35048,35049,35050,35051,35052,35053,35054,35055,35056,35057,35058,35059,35060,35061,35062,35063,35064,35065,35066,35067,35068,35069,35070,35071,35072,35073,35074,35075,35076,35077,35078,35079,35080,35081,35082,15055,35084,35085,35086,35087,35088,35089,35090,35091,35092,35093,35094,35095,35096,35097,35098,35099,35100,35101,35102,35103,35104,35105,35106,35107,35108,35109,35110,35111,35112,35113,35114,35115,35116,35117,35118,35119,35120,35121,35122,35123,35124,35125,35126,35127,35128,35129,35130,35131,35132,35133,35134,35135,35136,35137,35138,35139,35140,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35166,35167,35168,35169,35170,35171,35172,35173,35174,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35106,35195,35196,35197,35198,35199,35200,35201,35202,35203,35204,35205,35206,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35265,35266,35267,35268,35269,35270,35271,35272,35273,35274,35275,35276,35277,35278,35279,35280,35281,35282,35283,35284,35285,35095,35287,35288,35289,35290,35291,35292,35293,35294,35295,35296,35297,35298,35299,35300,35301,35302,35303,35304,35305,35306,35307,35308,35309,35310,35311,35312,35313,35314,35315,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35328,35329,35330,35331,35332,35333,35334,35335,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35390,35391,35392,35393,35394,35395,35396,35397,35398,35399,35400,35401,35291,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35449,35450,35451,35452,35453,35454,35455,35456,35457,35458,35459,35460,35461,35462,35463,35464,35465,35466,35467,35468,35469,35470,35471,35472,35473,35474,35475,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35287,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,122,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35591,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35622,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35686,35687,35688,35689,35690,35691,35692,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35592,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35744,35745,35746,35747,35748,35749,35750,35751,35752,35753,35754,35755,35756,35757,35758,35759,35760,35761,35762,35763,35764,35765,35766,35767,35768,35769,35770,35771,35772,35773,35774,35775,35776,35777,35778,35779,35780,35781,35782,35783,117,35785,35786,35787,35788,35789,35790,35791,35792,35793,35794,35795,35796,35797,35798,35799,35800,35801,35802,35803,35804,35805,35806,35807,35808,35809,35810,35811,35812,35813,35814,35815,35816,35817,35818,35819,35820,35821,35822,35823,35824,35825,35826,35827,35828,35829,35830,35831,35832,35833,35834,35835,35836,35837,35838,35839,35840,35841,35842,35843,35844,35845,35846,35847,35848,35849,35850,35851,35852,35853,35854,35855,35856,35857,35858,35859,35860,35861,35862,35863,35864,35865,35866,35867,35868,35869,35870,35871,35872,35873,35874,35875,35876,35877,35878,35879,35880,35881,35882,35883,35884,35885,35886,35887,35888,35889,35890,35891,35892,35893,35894,35895,35896,35897,35898,35899,35900,115,35902,35903,35904,35905,35906,35907,35908,35909,35910,35911,35912,35913,35914,35915,35916,35917,35918,35919,35920,35921,35922,35923,35924,35925,35926,35927,35928,35929,35930,35931,35932,35933,35934,35935,35936,35937,35938,35939,35940,35941,35942,35943,35944,35945,35946,35947,35948,35949,35950,35951,35952,35953,35954,35955,35956,35957,35958,35959,35960,35961,35962,35963,35964,35965,35966,35967,35968,35969,35970,35971,35972,35973,35974,35975,35976,35977,35978,35979,35980,35981,35982,35983,35984,35985,35986,35987,35988,35989,35990,35991,35992,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,6244,36027,36028,36029,36030,36031,36032,36033,36034,224,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36039,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36072,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36125,36126,36127,36128,36104,36130,36131,36132,36133,36134,36135,36136,36137,36138,36139,36140,36141,36142,36143,36144,36145,36146,36147,36148,36149,36150,36151,36152,36153,36154,36155,36156,36157,36158,36138,36160,36161,36162,36163,36164,36165,36166,36167,36168,36169,36170,36171,36172,36173,36174,36175,36176,36177,36178,36179,36180,36181,36182,36183,36184,36185,36186,36187,36188,36189,36190,36191,36192,36193,36194,36093,36196,36197,36198,36199,36200,36201,36202,36203,36204,36205,36206,36207,36208,36209,36210,36211,36212,36213,36214,36204,36216,36217,36218,36219,36220,36221,36222,36223,36224,36225,36226,36227,36228,36229,36230,36231,36232,36233,36234,36235,36236,36237,36238,36239,36240,36241,36242,36243,36244,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36255,36227,36257,36258,36259,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36273,36274,36275,36276,36261,36278,36279,36280,36281,36282,36283,36284,36285,36286,36287,36288,36289,36290,36291,36292,36293,36294,36295,36296,36297,36298,36299,36300,36301,36302,36303,36304,36305,36306,36307,36227,36309,36310,36311,36312,36313,36314,36315,36316,36317,36318,36319,36320,36321,36322,36323,36324,36325,36326,36327,36328,36329,36330,36331,36332,36333,36334,36335,36319,36337,36338,36339,36340,36341,36342,36343,36344,36341,36346,36347,36348,36349,36350,36351,36352,36353,36354,36355,36356,36357,36358,36359,36360,36361,36226,36363,36364,36365,36366,36367,36368,36290,36370,36244,36372,36373,36374,36375,36376,36377,36378,36379,36380,36381,36382,36383,36384,36385,36386,36387,36388,36389,36390,36391,36392,36393,36394,36321,36396,36397,36398,36399,36400,36401,36402,36403,36313,36405,36406,36407,36408,36409,36410,36411,36412,36413,36414,36415,36416,36417,36418,36419,36350,36421,36422,36423,36424,36425,36426,36427,36428,36429,36430,36431,36432,36433,36434,36435,36204,36437,36438,36439,36440,36441,36442,36443,36444,36445,36446,36232,36448,36449,36450,36451,36452,36453,36454,36455,36456,36457,36458,36291,36460,36461,36462,36463,36464,36284,36466,36467,36468,36469,36470,36471,36472,36473,36474,36475,36291,36477,36478,36479,36480,36481,36482,36483,36484,36485,36402,36487,36488,36489,36490,36491,36492,36493,36494,36495,36496,36497,36498,36499,36500,36501,36502,36503,36411,36505,36506,36507,36508,36509,36510,36511,36512,36341,36514,36515,36516,36517,36518,36366,36520,36521,36522,36284,36524,36525,36526,36527,36528,36529,36530,36531,36532,36533,36534,36535,36536,36537,36380,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36312,36550,36551,36552,36553,36554,36555,36556,36557,36558,36559,36560,36561,36562,36563,36564,36565,36566,36567,36497,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,36309,36582,36583,36584,36585,36064,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36606,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36630,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36594,36671,36672,36673,36674,36675,36676,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36680,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36710,36711,36712,36713,36705,36715,36716,36717,36718,36719,36720,36721,36722,36723,36724,36725,36726,36727,36728,36729,36730,36731,36732,36733,36734,36735,36736,36737,36738,36739,36740,36704,36742,36743,36744,36745,36746,36747,36748,36719,36750,36683,36752,36753,36754,36755,36756,36757,36758,36759,36760,36707,36762,36763,36764,36765,36766,36767,36768,36769,36770,36771,36772,36773,36774,36775,36776,36777,36778,36779,36780,36781,36782,36783,36784,36785,36786,36787,36788,36789,36790,36791,36792,36793,36794,36730,36796,36797,36798,36799,36800,36801,36802,36803,36742,36805,36806,36807,36808,36809,36810,36725,36812,36813,36814,36815,36816,36817,36818,36819,36820,36821,36822,36823,36824,36597,36826,36827,36828,36829,36830,36831,36832,36833,36631,36835,36836,36837,36838,36839,36840,36841,36647,36843,36844,36845,36846,36847,36848,36849,36850,36851,36852,36853,36854,36855,36680,36857,36858,36859,36860,36861,36862,36863,36864,36865,36866,36709,36868,36869,36870,36871,36872,36718,36874,36875,36876,36877,36878,36879,36702,36881,36882,36883,36884,36885,36886,36887,36888,36889,36890,36891,36892,36893,36894,36895,36896,36897,36898,36899,36813,36901,36902,36903,36904,36905,36906,36907,36908,36909,36910,36911,36912,36913,36914,36798,36916,36917,36918,36919,36920,36921,36922,36923,36924,36745,36926,36927,36928,36929,36930,36931,36932,36933,36934,36935,36936,36937,36938,36939,36940,36941,36942,36943,36944,36945,36946,36947,36906,36949,36950,36951,36952,36953,36954,36955,36956,36957,36958,36959,36960,36961,36962,36963,36964,36965,36966,36967,36968,36969,36970,36971,36972,36973,36974,36975,36976,36977,36978,36979,36980,36981,36982,36983,36984,36985,36986,36987,36988,36989,36990,36991,36992,36993,36994,36995,36996,36997,36998,36999,37000,37001,36883,37003,37004,37005,37006,37007,37008,37009,37010,37011,37012,37013,37014,37015,37016,36776,37018,37019,37020,37021,37022,36730,37024,37025,37026,37027,37028,37029,37030,37031,37032,37033,37034,37035,37036,36622,37038,37039,37040,37041,37042,37043,37044,37045,37046,37047,37048,37049,37050,37051,37052,37053,37054,37055,37056,37057,37058,37059,37060,37061,37062,37063,36624,37065,37066,37067,37068,37069,37070,37071,37072,37073,37074,37075,37076,37077,37078,37079,37080,37081,36635,37083,37084,37085,37086,37087,37088,37089,37090,37091,37092,37093,37094,37095,37096,37097,37098,37099,37100,36844,37102,37103,37104,37105,37106,37107,37108,37109,37110,37111,36881,37113,37114,37115,37116,37117,37118,37119,37120,37121,37122,37123,37124,37018,37126,37127,37128,37129,37130,36876,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,36806,37144,37145,37146,37147,37148,37149,36954,37151,37152,37153,37154,37155,37156,37157,37158,37159,37160,37006,37162,37163,37164,37165,37166,37167,37168,37169,37024,37171,37172,37173,37174,37175,37176,36805,37178,37179,37180,37181,37182,37183,37184,37185,36833,37187,37188,36839,37190,37191,37192,37193,37194,37195,37196,37197,36849,37199,37200,37201,37202,37203,37204,36651,37206,37207,37208,37209,37210,37211,37212,37213,37214,37215,37216,37217,37218,36805,37220,37221,37222,37159,37224,36703,37226,37227,37228,37229,37230,37231,37232,37233,37234,37235,37236,37237,37238,37239,37240,37241,37242,36742,37244,37245,37246,37247,37248,37249,37250,37251,37252,37253,36949,37255,36697,37257,37258,37259,37260,37261,37262,37263,37264,36869,37266,37267,37268,37269,37270,37271,36796,37273,37274,37275,37276,37277,37278,37279,37280,37281,37282,37283,37284,37285,37286,37287,37288,37289,37290,37291,37251,37293,37294,36705,37296,37297,36601,37299,37300,37301,37302,37303,37304,37305,37306,37307,36840,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37319,37320,37321,37210,37323,37324,37325,37326,37327,37328,37329,37330,36858,37332,37333,37334,37335,37336,37337,37338,36709,37340,36730,37342,37343,37344,36807,37346,37347,37348,37349,37350,37351,37352,37353,37354,37355,37356,37357,37156,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,36719,37370,37371,37372,37373,37374,37375,37376,37377,37378,36710,37380,37134,37382,37383,37384,37385,37386,37387,37388,37389,36888,37391,37392,37393,37394,37395,37396,37156,37398,37399,37400,37401,37402,37403,37275,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,36629,37416,37417,37418,37419,37420,37421,37422,37086,37424,37425,37426,37427,37428,37429,36691,37431,36709,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37296,37444,37445,37446,37447,37448,37449,37351,37451,37452,37453,36902,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,36694,37466,37467,37468,37469,37433,37471,37472,37473,37474,37475,37476,37477,37478,37344,37480,37294,37360,37483,37484,37485,37486,37487,37488,37489,37490,37491,37492,37493,36609,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37094,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37104,37519,37520,37521,36881,37523,37524,37525,37526,37527,37528,37529,37530,36707,37532,37533,37534,37344,37536,37349,37538,37539,37540,37541,37542,37543,37462,36857,37546,37547,37271,36876,37550,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37393,37562,37563,37564,37565,37566,37156,37568,37569,37570,37571,37572,37573,36731,37575,37576,37577,37578,37579,37580,37581,37582,37422,37519,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,36669,36806,37614,37615,37616,36686,37618,37619,37620,37621,37622,37407,37624,37625,37626,36929,37628,37629,37630,37631,37632,37633,36703,37635,37636,36682,37638,37639,37640,37641,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,36705,37653,37654,37655,37656,37657,36916,37659,37660,37039,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37094,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37694,37695,37696,37697,37698,37699,37700,37701,37702,37602,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,36649,37726,37727,37728,37729,37730,37336,37732,37733,37734,37027,37736,37737,37738,37739,37740,37741,37742,37743,36805,37745,37746,37747,37635,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,36684,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37775,37776,37380,37756,37779,37780,37781,37616,37783,36610,37785,37786,37787,37788,37789,37087,37791,36659,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37332,37813,37476,37815,37816,37817,36796,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,36806,37159,37576,37836,37837,37838,37839,37840,37841,37842,37433,37844,37845,37846,37847,36730,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37147,37867,37868,37869,37870,37871,37872,37873,37874,37361,37876,37877,37878,36589,37880,37881,37882,37883,37884,37885,37886,37887,37418,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37715,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,36624,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,36938,37934,37935,37936,37937,37938,37939,37940,37941,37942,37943,36817,37945,37946,37947,37948,37949,37950,37951,37952,37953,37954,37163,37956,37957,37958,37959,37960,37961,37962,37963,37964,37464,37736,37967,37968,37969,37970,37971,36745,37973,37974,37975,37976,37224,36881,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,36877,36624,37992,37993,37994,37995,37996,37997,37998,37999,38000,38001,36633,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,36657,38016,38017,38018,38019,38020,38021,38022,38023,38024,38025,38026,38027,38028,38029,36903,38031,38032,38033,38034,37981,38036,38037,38038,38039,38040,36708,38042,38043,36742,38045,38046,38047,37156,38049,38050,38051,38052,38053,38054,38055,37121,38057,38058,38059,38060,36766,38062,38063,38064,38065,38066,37171,38068,38069,38070,38071,38072,38073,38074,38075,38076,38077,38078,38079,37994,38081,38082,38083,38084,38085,38086,38087,38088,38089,38090,38091,38092,38093,37588,38095,37801,38097,38098,38099,38100,38101,38102,38103,38104,38105,38106,38107,38108,38109,36645,38111,38112,38113,38114,38115,38116,38117,38118,38050,38120,38121,38122,38123,38124,38125,38126,38127,38128,37005,38130,38131,38132,38133,38134,38135,38136,38137,38138,38139,38140,38141,38142,38143,38144,38062,38146,38147,38148,38149,38150,38151,38152,37846,37844,38155,38156,37819,38158,38159,38160,38161,38162,38163,38164,37936,38166,38167,38168,38169,36876,38171,38172,38173,37785,38175,38176,38177,36633,38179,38180,38181,38182,38183,38184,38185,38186,38187,38188,38189,36849,38191,38192,38193,38194,36602,38196,38197,38198,38199,36926,38201,38202,38203,38204,38205,38206,38207,38208,38209,38210,38211,37159,37769,38214,38215,38216,38217,38218,38219,37533,38221,38222,37344,37165,38225,38226,38227,38228,38229,38230,38231,38232,38233,37296,38235,38236,38237,37857,36903,38240,38241,38242,38243,38244,38245,38246,38247,38248,37786,38250,38251,38252,38253,38254,38255,38256,38257,36840,38259,38260,38261,37214,38263,38264,38265,38266,37920,38268,38269,38270,38271,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38140,38283,36765,38285,38286,38287,38288,38289,38290,38291,37344,37614,38294,38295,36705,38297,38298,38215,38300,38301,38302,38303,36705,37576,38306,38307,38308,38309,38167,38311,38312,38313,38254,38315,38316,38317,38318,38319,38320,38321,36632,36669,37642,38325,38326,38327,38328,38287,38069,38331,38332,38333,38334,38335,37485,38337,38338,38339,38340,38341,38342,38343,37336,38345,38346,38347,38348,38349,38350,38351,38352,38069,38354,38355,38356,38357,38358,38359,38360,38361,37349,37156,38364,38365,38366,38367,38368,38369,36060,38371,38372,38373,38374,38375,38376,38377,38378,38379,38380,38381,38382,38383,38384,38385,38386,38387,38388,38389,38390,38391,38392,38393,38394,38395,38396,38397,38398,38399,38400,38401,38402,38403,38404,38405,38406,38407,38408,38409,38410,38411,38412,38413,38414,38415,38416,38417,38418,38419,38420,38421,38422,38423,38424,38425,38426,38427,38428,38429,38430,38431,38432,38433,38434,38435,38436,38437,38438,38439,38440,38441,38442,38443,38444,38445,38446,38447,38448,38449,38450,38451,38452,38453,38454,38455,38456,38457,38458,38459,38460,38461,38462,38463,38464,38465,38466,38467,38380,38469,38470,38471,38472,38473,38474,38475,38476,38477,38478,38479,38480,38481,38482,38483,38484,38485,38486,38487,38488,38489,38490,38491,38492,38493,38494,38495,38496,38497,38498,38499,38500,36057,38502,38503,38504,38505,38506,38507,38508,38509,38510,38511,38512,38513,38514,38515,38516,38513,38518,38519,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38533,38534,38535,38536,38537,38538,38539,38540,38541,38527,38543,38544,38545,38546,38547,38548,38549,38550,38551,38552,38553,38554,38555,38556,38557,38558,38544,38560,38561,38562,38563,38564,38565,38566,38567,38568,38569,38570,38571,38572,38573,38574,38575,38576,38577,38578,38579,38580,38581,38582,38583,38584,38585,38586,38587,38588,38589,38590,38591,38592,38593,38594,38595,38596,38597,38598,38599,38600,38601,38602,38603,38604,38605,38606,38607,38608,38609,38610,38590,38612,38613,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38624,38625,38626,38627,38628,38629,38630,38631,38632,38633,38634,38635,38636,38637,38638,38639,38640,38641,38642,38643,38644,38645,38646,38647,38648,38649,38634,38651,38652,38653,38654,38655,38656,38657,38658,38659,38660,38661,38662,38663,38664,38665,38666,38667,38668,38669,38670,38656,38672,38673,38674,38675,38676,38677,38678,38679,38680,38681,38682,38683,38684,38685,38686,38687,38688,38689,38690,38691,38692,38693,38694,38695,38696,38697,38698,38699,38700,38701,38702,38685,38704,38705,38706,38707,38708,38709,38710,38711,38712,38713,38714,38715,38716,38717,38718,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38631,38733,38734,38735,38736,38737,38738,38739,38740,38741,38742,38743,38744,38745,38746,38747,38748,38749,38750,38751,38752,38753,38754,38755,38756,38757,38758,38759,38760,38761,38762,38763,38764,38765,38741,38767,38768,38769,38770,38771,38772,38773,38774,38775,38776,38777,38778,38779,38780,38781,38782,38783,38784,38785,38786,38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,38777,38798,38799,38800,38801,38802,38803,38804,38805,38806,38807,38808,38809,38810,38811,38812,38813,38814,38815,38816,38817,38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830,38784,38832,38833,38834,38835,38836,38837,38838,38839,38840,38841,38765,38792,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38800,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38812,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38743,38887,38888,38889,38890,38891,38892,38893,38894,38895,38896,38768,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,38908,38909,38800,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930,38931,38932,38933,38815,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38511,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38504,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38578,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38599,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,38655,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,39023,39024,39025,39026,39027,39028,38682,39030,39031,39032,39033,39034,39035,39036,39037,39038,39039,39040,39041,39042,38685,39044,39045,39046,39047,39048,39049,39050,39051,39052,39053,39054,39055,39056,39057,39058,39059,39060,39061,39062,39063,39064,39065,39066,39067,38735,39069,39070,39071,39072,39073,39074,39075,39076,39077,39078,39079,39080,39081,39082,38753,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,38800,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,38808,39115,39116,39117,39118,39119,39120,39121,39122,39123,39124,39125,39126,39127,39128,39129,39130,39131,39132,39133,39134,39135,39136,38740,39138,39139,39140,39141,39142,39143,39144,39145,39146,39147,39148,39098,39150,39151,39152,39153,39154,39155,39156,39157,39158,39120,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39139,39171,39172,39173,39174,39175,39176,39177,39178,39179,39180,39181,39182,39183,39184,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39089,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39102,39209,39210,39211,39212,39213,39214,39215,39216,39217,39218,39219,39220,39120,39222,39223,39224,39225,38586,39227,39228,38962,39230,39231,39232,39233,39234,38544,39236,39237,39238,39239,39240,39241,39242,39243,39244,38595,39246,39247,39248,39249,39250,39251,39252,39253,38626,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,38658,39266,39267,39268,39269,39270,39271,39272,39273,39274,39275,38688,39277,39278,39279,39280,39281,39282,39283,39284,39285,39286,39287,39288,39289,39290,39291,39292,39293,39294,39295,39296,39297,39298,39299,39300,39301,38718,39303,39304,39305,39306,39307,39308,39309,39310,39311,39312,39313,39314,39315,39316,39317,39318,39319,39320,39321,39322,39092,38836,39325,39326,39327,39328,39329,39330,39331,39332,38863,39334,39335,39336,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,38780,39352,39353,39354,39355,39356,39357,39358,39359,39092,39361,38755,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,38809,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,38785,39405,38812,39407,39408,39409,39410,39326,39412,39413,38952,39415,39416,39417,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,38513,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,38975,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,38613,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,38662,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39032,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39045,39512,39513,39514,39515,39516,39517,39518,39519,39520,39521,39522,39182,39524,39525,39526,39527,39528,39529,39530,39531,39532,39533,38753,39535,39536,39537,39538,39539,39540,38927,39542,39543,39544,39545,39546,39547,39548,39549,39550,38812,39552,39553,39554,39555,39556,39557,39558,39559,39560,39561,39562,39563,39564,39565,39566,39567,39176,39569,39570,39571,39572,39573,39574,39575,39576,39577,38772,39579,39580,39581,39582,39583,39584,39585,39586,38929,39588,39589,39590,39591,39592,39593,39594,39595,39596,39597,39598,39599,39600,39601,39602,39391,39604,39605,39606,39607,39608,39609,39610,39611,39612,39613,39614,39615,38771,39617,39618,39544,39620,39621,39622,39623,39624,39625,39626,39627,39628,39629,39630,39631,39632,39633,39634,39635,39555,39637,39638,39639,39640,39641,39642,39643,39644,39645,39646,39647,39648,39419,39650,39651,39652,39653,39654,38964,39656,39657,39658,39659,39660,39661,39662,39663,39664,39665,39666,39237,39668,39669,39670,39671,39672,39673,39674,39675,39676,39677,39678,38602,39680,39681,39682,39683,39684,39685,39686,39687,38626,39689,39690,39691,39692,39693,39694,39695,39696,39697,39698,39699,39700,39701,39702,39703,39489,39705,39706,39707,39708,39709,39284,39711,39712,39713,39714,39715,39716,39717,39718,38721,39720,39721,39722,39723,39209,39725,39726,39727,39728,39729,39730,39731,39732,38773,39734,39735,39736,39737,39738,39571,39740,39741,39742,39743,39744,39745,39585,39747,39748,39749,39750,39751,39752,39753,38928,39755,39756,39757,39758,39759,39760,39761,39762,39763,39120,39765,39766,39767,39768,39769,39770,38926,38887,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,38790,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39119,39798,39799,39800,39801,39802,39803,39804,39805,39806,39807,39808,39809,39405,39415,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,38515,39825,39826,39827,38569,39829,39830,39831,39832,39833,38992,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39019,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,38677,39870,39871,39872,39873,39874,39060,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,38711,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,39900,39901,39902,38747,39904,39905,39906,39907,39908,39909,39910,39911,39912,39097,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39765,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,38735,39953,39954,39955,39956,39092,39958,39932,39960,39961,39962,39963,39964,39965,39939,39967,39968,39969,39970,39971,39926,39973,39974,39975,39976,39977,39978,39979,39980,39981,38743,39983,39984,39985,39986,39987,39988,39989,39990,39991,39927,39993,39994,39995,39996,39997,39998,39999,40000,40001,40002,40003,39120,40005,40006,40007,40008,40009,40010,40011,40012,40013,38838,40015,40016,40017,40018,40019,40020,39426,40022,40023,38515,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,39830,40036,40037,40038,40039,40040,40041,40042,40043,39836,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,39015,40056,40057,40058,40059,40060,40061,40062,40063,40064,40065,40066,40067,40068,40069,40070,40071,40072,40073,38663,40075,40076,40077,40078,40079,40080,40081,40082,40083,40084,40085,40086,40087,40088,40089,40090,40091,38689,40093,40094,40095,40096,40097,40098,40099,40100,40101,40102,40103,40104,40105,40106,39879,40108,40109,40110,40111,40112,38678,40114,40115,40116,40117,40118,40119,38748,40121,39100,40123,40124,40125,40126,40127,40128,40129,40130,40131,40132,40133,40134,40135,40136,40137,39127,40139,40140,40141,40142,40143,40144,40145,39182,40147,40148,40149,40150,40151,40152,40153,38748,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164,39622,40166,40167,40168,40169,40170,39608,40172,39174,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,39196,40253,40254,40255,40256,40257,39098,40259,40260,40261,39767,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,38619,40281,40282,40283,40284,40285,40286,40287,38963,40289,40290,40291,40292,40293,40294,39432,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,39448,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,39467,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,39271,40335,40336,40337,40338,40339,39032,40341,40342,40343,40344,40345,40346,40347,40348,40349,39061,40351,40352,40353,40354,40355,40356,40357,40358,40359,40360,40361,40362,40117,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,39906,40375,40376,40377,40378,40379,39993,40381,40382,40383,40384,40385,40386,40387,40388,40389,39120,40391,40392,40393,38836,40395,40396,40397,40398,40399,38836,40401,40402,40403,39927,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,39765,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40401,40430,40431,40432,40433,39908,40435,40436,40437,40438,39583,40440,40441,40442,40443,40444,40445,40446,40447,40448,39100,40450,40451,40452,40453,40454,38912,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40479,40480,40481,40482,40483,40484,39115,40486,40487,40488,40489,40490,40491,40492,40493,40494,40495,40496,40497,40498,40499,40500,40501,40502,40503,39160,40505,40506,40507,40508,40509,40510,40511,40512,40513,40514,40515,39359,40517,39974,40519,40520,40521,40522,38950,40524,40525,40526,40527,40528,40529,40530,40531,40532,40533,40534,38515,40536,40537,40538,40539,40540,40541,40542,40543,38526,40545,40546,40547,40548,40549,39669,40551,40552,40553,40554,40555,40556,38585,40558,40559,40560,40561,40562,40563,40564,40565,40566,40567,40568,39476,40570,40571,40572,40573,40574,39012,40576,40577,40578,40579,40580,40581,40582,40583,40584,40585,40586,40079,40588,40589,40590,40591,40592,40593,40594,40595,40596,40597,40598,40599,40600,40601,40602,38689,40604,40605,40606,40607,40608,40609,40610,40611,38717,40613,40614,40615,40616,40617,40618,40619,40620,40621,40622,40623,40624,40625,40626,40627,40628,40629,40630,40631,40632,40633,39906,40635,40636,40637,40638,40639,40640,40641,40642,39993,40644,40645,40646,40647,40648,40649,39765,40651,40652,40653,40654,40655,39790,40657,40658,40659,40660,40661,40662,40663,39910,40665,40666,40667,40668,40669,40670,39927,40672,40673,40674,40675,40676,40677,40678,40679,40680,40681,40682,40683,39940,40685,40686,40687,40688,40689,40690,40691,39974,40693,40694,40695,40696,39989,40698,40699,40700,40701,40522,40703,40704,40705,40706,40707,40708,40709,40710,40711,40391,40713,40714,40715,40716,40717,40718,40719,40720,40721,38792,40723,40724,40725,40726,40727,40728,40729,40730,40731,40732,40733,40734,40735,39651,40737,40738,40300,40740,40741,40742,39457,40744,40745,40746,40747,40748,40749,40750,40751,40752,40570,40754,40755,40756,39490,40758,40759,39504,40761,40762,40763,40764,40765,40766,40767,38685,40769,40770,40771,40772,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40784,40785,40786,40787,40788,40789,40790,40791,39182,40793,40794,40795,40796,40797,40798,40124,40800,40801,40802,40803,40804,40805,40806,39938,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,39542,40821,40438,40823,40824,40673,40826,40827,40828,40829,40830,40715,40832,40833,40834,40835,40836,40837,40838,40839,40840,40841,40726,40843,40844,40845,40846,40847,40848,39790,40850,40851,40852,40853,40854,40855,40856,39543,40858,40859,40860,40861,40862,40863,40864,40865,40866,40867,40868,40869,39765,40871,40872,40873,38928,40875,40876,40877,40878,40879,40880,40881,40882,40883,40884,40885,40886,40887,40888,40889,40890,40891,40892,40893,40894,40895,40896,40897,40898,40899,40900,40901,40902,40903,40904,40905,40906,40907,40908,40909,40910,40911,40912,40913,40914,40915,40916,40917,40918,40919,40920,40921,40922,40923,40924,40925,40926,40927,40928,40929,40930,40931,40932,40933,40934,40935,40936,40937,40938,40939,40940,40941,40942,40943,40944,40945,40946,40947,40948,40949,40950,40951,40952,40953,40954,40955,40956,40957,40958,40959,40960,40961,40962,40963,40964,40965,40966,40967,40968,40969,40970,40971,40972,40973,40974,40975,38962,40977,40978,40979,40980,40981,40982,40983,40984,40547,40986,40987,40988,38592,40990,40991,40992,40993,40994,40995,40996,40997,39471,40999,41000,41001,41002,41003,41004,41005,41006,41007,41008,41009,41010,41011,40593,41013,41014,41015,41016,41017,41018,39499,41020,41021,41022,41023,41024,41025,41026,41027,41028,41029,41030,41031,41032,41033,41034,41035,41036,41037,41038,41039,41040,38717,41042,41043,41044,41045,40018,41047,40458,41049,41050,41051,41052,41053,41054,41055,41056,41057,41058,41059,41060,41061,41062,41063,41064,41065,39358,41067,41068,41069,41070,39196,41072,41073,41074,41075,41076,41077,39328,41079,41080,41081,41082,38911,41084,41085,41086,41087,41088,41089,41090,41091,41092,38833,41094,41095,41096,41097,39958,38834,41100,41101,41102,41103,41104,41105,41106,41107,41108,41109,40458,41111,41112,41113,41114,41115,41116,41117,41118,41119,41120,41121,41122,41123,41124,41125,41126,41127,41128,38780,41130,41131,41132,41133,41134,41135,41136,41137,41138,41139,39815,41141,41142,41143,41144,41145,40543,38573,41148,41149,41150,41151,41152,41153,41154,41155,41156,41157,39859,41159,41160,41161,41162,41163,41164,41165,41166,41167,41168,41169,40081,41171,41172,41173,41174,41175,41176,41177,41178,41179,41180,41181,41182,40102,41184,40615,41186,41187,41188,41189,41190,41191,41192,41193,41194,41195,41196,41197,41198,41199,41200,41201,39988,41203,41204,41205,41206,41207,39924,41209,41210,41211,41212,41213,41214,41215,41216,41217,40006,41219,41220,41221,41222,41223,41224,41225,41226,38785,41228,41229,41230,41231,41232,41233,41234,41235,41236,41237,39370,41239,41240,41241,41242,41243,38792,41245,41246,41247,41248,41249,41250,41251,39117,41253,41254,41255,41256,41257,41258,41259,41260,41261,41262,41263,41264,41265,39611,41267,41268,41269,41270,41271,41272,41273,41274,41275,39183,41277,41278,41279,41280,41281,41282,41283,39196,41285,41286,41287,41288,41289,41290,41291,41292,39928,41294,41295,41296,41297,41298,41299,41300,41301,41302,40715,41304,41305,41306,41307,41308,41309,41310,41311,41312,41313,41314,41315,41316,41317,40401,41319,41320,41321,41322,41323,39417,41325,41326,41327,39233,41329,39669,41331,41332,41333,41334,41335,39251,41337,41338,41339,41340,41007,41342,41343,41344,41345,41346,41347,41348,41349,41350,41177,41352,41353,41354,41355,41356,41357,39505,41359,41360,41361,39883,41363,41364,41365,41366,39889,41368,41369,41370,41371,41372,41373,41374,41375,41376,39328,41378,40493,41380,41381,41382,41094,41384,41385,41386,41387,41388,41389,41390,41391,41392,41393,39958,40432,41396,40458,41398,41399,41400,41401,41402,41403,41404,41405,41406,41407,41408,41409,39357,41411,41412,41413,39908,41415,41416,41417,41418,41419,41420,41421,41422,41423,41424,41139,38929,41427,41428,41429,41430,41431,41432,41433,38936,41435,41436,41437,41438,41439,41440,38565,41442,41443,41444,41445,41446,41447,41448,41449,41450,41451,41452,41453,41454,41455,41456,41457,41458,41459,41460,41461,41462,41463,41464,41465,41466,41467,41468,41469,41470,41471,41472,38967,41474,41475,41476,41477,40549,41479,41480,41481,41482,41483,41484,41485,41486,41487,41488,41489,41490,41491,39456,41493,41494,41495,41496,41497,41498,41499,41500,41501,41502,41503,41504,39476,41506,41507,41508,41509,41510,41511,39490,41513,41514,41515,41516,41517,39504,41519,41520,41521,41522,41523,41524,41525,39514,41527,41528,41529,41530,41531,41532,41533,41534,41535,41536,41537,41538,41539,41540,41541,41542,39183,41544,41545,41546,41547,41548,41549,41550,39100,41552,41553,41554,41555,41556,41557,41558,41559,40263,41561,41562,41563,41564,41565,41566,41567,41568,41569,41570,41571,41572,41573,41574,38800,41576,41577,41578,41579,41580,41581,41582,40635,41584,41585,41586,41587,41588,41067,41590,41591,38922,41593,41594,41595,41596,41597,41598,41599,41600,41601,41602,41603,41604,41417,41606,41607,41608,41609,39353,41611,41612,41613,41614,41615,41616,41617,41618,41619,41620,41621,41622,41623,41624,41625,41626,41627,41628,41629,41630,41631,41632,41633,41634,41635,41636,41637,41638,41639,41640,41641,41642,41643,41644,41645,41646,41647,41648,41649,41650,41651,41652,41653,41654,41655,41656,41657,41658,41659,41660,41661,41662,41663,41664,41665,41666,41667,41668,41669,41670,41671,41672,41673,41674,41675,41676,41677,41678,41679,41680,41681,41682,41683,41684,38928,41686,41687,41688,41689,41690,41691,41692,41693,41694,41695,41696,41697,41698,39583,41700,41701,41702,41703,41704,41705,41706,39423,41708,41709,41710,39844,41712,41713,41714,41715,41716,41717,41718,39861,41720,41721,41722,41723,41724,38673,41726,41727,41728,41729,41730,41731,41732,41733,41734,41735,39061,41737,41738,41739,41740,41741,39894,41743,41744,41745,41746,41747,41748,41749,41750,41751,41752,41753,41754,40666,41756,41757,41758,41759,40407,41761,41762,41763,41764,41765,41766,41767,41768,39765,41770,41771,41772,41773,41774,41775,41776,41777,41778,41779,41780,41781,41782,41783,39915,41785,41786,41787,41788,41789,41790,41791,41792,41793,41794,41759,41762,41797,41798,41799,41800,41801,41802,41770,41804,41805,41806,41807,41808,41809,41810,41811,38916,41813,41814,41815,41816,39989,41818,41819,41820,41821,39975,41823,41824,41825,41826,41827,41828,41829,40391,41831,41832,41833,41834,41835,41836,41837,41838,41839,39419,41841,41842,41843,41844,41845,41846,41847,39435,41849,41850,41851,41852,41853,41854,39474,41856,38658,41858,41859,41860,41861,41862,40346,41864,41865,41866,41867,41868,41869,39061,41871,41872,41873,41874,41875,41876,41877,41878,41879,41880,41881,41882,41883,41884,41885,41886,41887,41888,41889,41745,41891,41892,41893,41894,41895,41896,41897,41898,41899,41900,41901,41902,41903,39910,41905,41906,41907,41908,41909,40440,41911,41912,41913,41914,41915,41916,41917,39098,41919,41920,41921,41922,41923,41924,41925,41926,39637,41928,41929,41930,41931,41932,41933,41934,41935,39182,41937,41938,41939,40155,41941,41942,41943,41944,41945,39621,41947,41948,41949,41950,41951,41952,41953,39609,41955,41956,41957,41958,39172,41960,41961,41962,41963,41964,41965,41966,41967,41968,41969,41970,41971,41972,40259,41974,41975,41976,41977,41978,41979,41980,40507,41982,41983,41984,41985,41986,41987,41988,41989,41990,41991,38564,41993,41994,41995,41996,41997,39230,41999,42000,42001,42002,42003,42004,42005,42006,42007,40552,42009,42010,42011,42012,42013,42014,42015,42016,39251,42018,42019,42020,42021,42022,42023,42024,39261,42026,42027,42028,42029,42030,42031,42032,42033,42034,42035,42036,39271,42038,42039,42040,39290,42042,42043,42044,42045,42046,42047,42048,42049,42050,42051,42052,39306,42054,42055,42056,42057,42058,42059,42060,42061,39089,42063,42064,42065,42066,42067,42068,42069,42070,42071,38836,42073,42074,42075,42076,42077,42078,40491,42080,42081,42082,42083,42084,38841,42086,41072,42088,42089,42090,39326,42092,42093,42094,42095,42096,38857,42098,39358,42100,42101,42102,42103,40435,42105,42106,42107,42108,42109,39357,42111,42112,42113,42114,38928,42116,42117,42118,42119,42120,42121,42122,42123,42124,42125,38814,42127,42128,42129,42130,42131,42132,42133,40281,42135,42136,42137,42138,42139,42140,42141,42142,42143,42144,42145,42146,39815,42148,42149,42150,42151,42152,40026,42154,42155,42156,42157,42158,42159,42160,42161,42162,42163,42164,42165,40314,42167,42168,42169,42170,42171,42172,42173,42174,38604,42176,42177,42178,42179,42180,42038,42182,42183,42184,42185,39489,42187,42188,42189,42190,42191,42192,42193,42194,42195,42196,42197,39289,42199,42200,42201,42202,42203,42204,42205,42206,42207,42208,42209,42210,41871,42212,42213,42214,42215,42216,42217,42218,42219,42220,42221,42222,42223,42224,42225,38718,42227,42228,42229,42230,42231,42232,42233,39990,42235,39396,42237,42238,39183,42240,42241,42242,38768,42244,42245,39543,42247,42248,42249,42250,42251,42252,42253,42254,39607,42256,42257,42258,42259,42260,42261,42262,42263,39524,42265,42266,42267,42268,42269,42270,42271,42065,42273,42274,42275,42276,42277,42278,39100,42280,42281,42282,42283,42284,42285,42286,42287,42288,42289,39940,42291,42292,42293,42294,42295,42296,42297,42298,42299,42300,42301,42302,42093,42304,40524,42306,42307,42308,42309,42310,42311,38546,42313,42314,42315,42316,42317,42318,42319,42320,42321,42322,42323,42324,38608,42326,42327,42328,42329,42330,38634,42332,42333,42334,42335,42336,42337,42338,42339,42340,42341,42342,42343,42344,42345,42346,42347,39490,42349,42350,42351,42352,42353,42354,42355,42356,38691,42358,42359,42360,42361,42362,42363,42364,42365,42366,42367,42368,38723,42370,38756,42372,42373,42374,42375,42376,42377,42378,42379,42380,42381,42382,42383,42384,40731,42386,42387,42388,42389,42390,42391,42392,42393,42394,42395,42396,42397,39799,42399,42400,42401,42402,42403,42404,42405,42406,42407,42408,42409,42410,42411,42412,42413,39328,42415,42416,42417,38755,42419,42420,42421,42422,42423,42424,42425,42426,42427,42428,42429,42430,42431,42432,42433,42434,42435,42436,42437,42438,42439,42440,42441,42442,42443,42444,42445,42446,42447,42448,42449,42450,42451,42452,42453,42454,42455,42456,42457,42458,42459,42460,42461,42462,42463,42464,42465,42466,42467,42468,42469,42470,42471,42472,42473,42474,42475,42476,42477,42478,42479,42480,42481,42482,42483,42484,42485,42486,42487,42488,42489,42490,42491,42492,42493,42494,42495,42496,42497,42498,42499,38796,39389,42502,42503,42504,42505,42506,42507,42508,42509,38838,42511,42512,42513,42514,42515,39196,42517,42518,42519,42520,42521,42513,42523,42524,42525,42526,42527,40460,42529,42530,42531,42532,42533,42534,42535,42536,42537,42538,42539,42540,42541,42542,39420,42544,42545,42546,39813,42548,42549,42550,42551,42552,42553,42554,42555,41150,42557,42558,42559,42337,42561,42562,42563,42564,42565,42566,42567,39706,42569,42570,42571,42572,42573,42574,39713,42576,42577,42578,42579,42580,42581,42582,42583,42584,42585,42586,38724,42588,42589,42590,42591,42592,42593,42594,42595,42596,41240,42598,42599,42600,42601,42602,42603,42604,42387,42606,42607,42608,42609,42610,42611,42612,42613,42614,42615,40005,42617,42618,42619,42620,42621,42622,39988,42624,42625,42626,42627,38785,42629,42630,42631,42632,42633,42634,42635,42636,42637,42638,42639,42640,39120,42642,42643,42644,39371,42646,42647,38853,39804,42650,42651,42652,39328,42654,42655,42656,42657,39421,42659,42660,42661,42662,42663,42664,42665,40296,42667,42668,42669,42670,42671,42672,42673,42674,42675,42676,40314,42678,42679,42680,42681,42682,42683,39476,42685,42686,42687,42688,42689,42690,42691,42692,42693,42694,39271,42696,42697,42698,42699,42700,39501,42702,42703,42704,42705,42706,42707,39515,42709,42710,42711,42712,42713,42714,42715,42716,42717,39172,42719,42720,42721,42722,42723,42724,42725,42726,39089,42728,42729,40128,42731,42732,40811,42734,42735,42736,42737,42738,42739,42740,42741,41816,42743,42744,42745,42746,42747,40665,42749,42750,42751,42752,42753,42754,39993,42756,42757,42758,42759,42760,42761,42762,42763,42764,42765,42766,42767,40833,42769,42770,42771,42772,42773,42774,42775,42776,42777,42778,42602,42780,42781,42782,42073,42784,42785,42786,42787,42788,39921,42790,42791,42792,42793,42794,42795,42796,42797,42798,42799,42800,42801,42802,42803,42804,42805,42806,42807,42808,42809,42810,42811,42812,42813,42814,42815,42816,42817,42818,42819,42820,42821,42822,42823,42824,42825,42826,40263,42828,42829,42830,38615,42832,40980,42834,42835,42836,42837,38541,40559,42840,42841,42842,42843,42844,42845,42846,42847,42848,42849,42850,41004,42852,42853,42854,42855,42856,42857,42858,42859,42860,42861,42862,42863,40091,41020,42866,41372,42868,42869,42870,42871,42872,42873,39988,42875,42876,42877,42878,41429,42880,42881,42882,42883,42884,42885,42886,42887,42888,42889,42890,39583,42892,42893,42894,40378,42896,42897,39357,42899,42900,42901,42902,41593,42904,42905,42906,42907,42908,42909,42910,42911,42912,42913,42914,42915,42916,39906,42918,42919,42920,42921,42922,38834,42924,42925,42926,42927,42928,39919,42930,42931,42932,42933,42934,42935,42936,41775,42938,42939,42940,42941,42942,42943,38778,42945,42946,42947,42948,42949,42950,42951,42952,42953,42148,42955,42956,42957,42958,42959,42960,42961,42155,38975,42964,42965,42966,42967,42968,42969,42970,42971,42972,42973,42176,42975,42976,41006,42978,42979,42980,42981,42982,42983,42984,42985,42986,42987,42988,42989,42990,42991,42705,42993,39877,42995,42996,42997,42998,42999,43000,39305,43002,43003,43004,43005,43006,43007,43008,43009,41909,39092,43012,40383,43014,43015,43016,43017,43018,43019,41219,43021,43022,43023,43024,43025,43026,43027,43028,43029,43030,43031,43032,43033,43034,42112,43036,43037,42235,43039,43040,42372,40383,43043,43044,43045,43046,39343,43048,43049,43050,43051,43052,43053,43054,40832,43056,43057,43058,43059,43060,43061,43062,42073,43064,43065,43066,43067,39328,43069,43070,43071,43072,40458,43074,43075,43076,43077,43078,43079,43080,43081,43082,43083,43084,43085,38937,43087,43088,43089,43090,43091,43092,43093,43094,43095,41996,43097,43098,43099,43100,43101,43102,43103,43104,43105,43106,43107,43108,43109,43110,43111,43112,43113,43114,43115,43116,43117,43118,43119,43120,43121,43122,43123,43124,43125,43126,43127,43128,43129,43130,43131,43132,43133,43134,43135,43136,43137,43138,43139,43140,43141,43142,43143,43144,41999,43146,43147,41481,43149,42680,43151,43152,40323,43154,43155,43156,43157,43158,43159,43160,43161,43162,43163,43164,43165,43166,43167,40064,43169,43170,43171,43172,43173,38689,43175,43176,43177,43178,43179,38718,43181,43182,43183,43184,43185,43186,43187,43188,43189,43190,43191,43192,41074,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,41070,39592,43208,43209,43210,43211,43212,43213,43214,43215,43216,39123,43218,43219,43220,43221,43222,43223,43224,43225,43226,43227,43228,43229,40858,43231,43232,43233,43234,43235,43236,43237,43238,42876,40846,43241,43242,43243,43244,43245,39804,43247,43248,43249,43250,43251,43252,43253,43254,43255,43256,42075,43258,39908,43260,43261,43262,43263,43264,43265,42728,43267,43268,43269,43270,43271,43272,43273,43015,43275,43276,39120,43278,43279,43280,43281,43282,43283,38780,43285,43286,43287,42956,43289,43290,43291,43292,43293,43294,43295,40980,43297,43298,43299,43300,43301,38532,43303,43304,40990,43306,43307,43308,43309,43310,43311,43312,43313,43314,43315,43316,42984,43318,43319,43320,43321,43322,43323,43324,39489,43326,43327,43328,43329,43330,43331,43332,43333,41871,43335,43336,43337,43338,43339,43340,43341,38717,43343,43344,43345,43346,43347,43348,43349,43350,43351,43352,43353,43354,43355,43356,43268,43358,43359,43360,43361,43362,41411,43364,43365,39151,43367,43368,43369,43370,43371,43372,43373,43374,43375,43376,43377,43378,43379,40264,43381,43382,43383,43384,43385,43386,43387,43388,43389,40846,43391,43392,43393,43394,43395,43396,43397,43398,43399,43400,43401,39071,43403,43404,43405,43406,43407,43408,43409,43410,43411,43412,39089,43414,43415,43416,43417,43418,43419,42793,43421,43422,43423,43424,40266,43426,43427,38735,43429,43430,43431,43432,43433,43434,43435,43436,43437,43438,43439,43440,43441,43442,43443,43444,43445,43446,40377,43448,43449,43450,39993,43452,41776,43454,43455,43456,43457,43458,43459,43460,43461,39974,43463,43464,43465,43466,43467,43468,43469,43470,43471,43472,43289,43474,43475,43476,43477,43478,43479,43480,40298,43482,43483,43484,43485,43486,43487,43488,43152,39474,43491,43492,43493,43494,43495,43496,43497,43498,39274,43500,41520,43502,43503,43504,43505,39516,43507,43508,43509,43510,43511,43512,42875,43514,43515,43516,43464,43518,43519,43520,43521,43522,43523,43524,43525,41833,43527,43528,43529,43530,43531,43532,43533,43534,43535,43536,43537,40121,41411,43540,43541,43542,38929,43544,43545,43546,43547,39608,43549,43550,43551,43552,43553,39528,43555,43556,43557,43558,43559,43560,43561,39196,43563,43564,43565,43566,43567,43568,43569,43570,39102,43572,43573,43574,43575,43576,40809,43578,43579,43580,43581,43582,43583,43584,43585,39096,43587,43588,43589,43590,43591,43592,43593,43594,43595,43596,43597,43598,43599,43600,43601,39815,43603,43604,43605,43606,43607,43608,38514,43610,43611,43612,40312,43614,43615,43616,40327,43618,43619,43620,41858,43622,43623,43624,43625,43626,43627,43628,43629,43630,39034,43632,43633,43634,43635,43636,39065,43638,43639,43640,43641,39892,43643,43644,43645,43646,43647,43648,43649,43650,39366,43652,43653,43654,43655,43656,43657,43658,43659,43660,43661,43662,43287,43664,43665,43666,43667,41599,43669,43670,43671,40437,38834,43674,43675,43676,43677,43678,42531,43680,43681,43682,43683,43684,43685,43686,43687,43540,43689,43690,41759,41412,43693,43694,38914,43696,43697,43698,43699,43700,43701,43702,43703,43704,41130,43706,43707,43708,43709,43710,43711,43712,43713,43714,39815,43716,43717,43718,43719,43720,43721,39825,43723,43724,43725,43726,39000,43728,43729,43730,43731,43732,43733,43734,43735,39860,43737,43738,43739,43740,43741,43742,43743,43744,43745,43746,39872,43748,43749,43750,39877,43752,43753,43754,43755,43756,43757,43758,43759,43760,43761,43762,43763,39893,43765,43766,43767,43768,43769,43770,43771,43772,43773,43774,43775,43776,43777,41606,43779,43780,43781,43782,43783,40382,43785,41777,43787,43788,43789,43790,43791,43792,43793,43794,43391,43796,43797,40376,43799,43800,43801,43802,39993,41833,43805,43806,43807,43808,43809,43810,43811,43812,43813,40731,43815,43816,43817,43818,43819,43820,40159,43822,43823,43824,38844,43826,43827,43828,43829,43830,43831,43832,43833,43834,43835,43836,39801,43838,43839,43840,43841,43842,43843,39413,43845,43846,43847,42307,43849,43850,38514,43852,43853,42168,43855,43856,43857,43858,40327,43860,43861,43862,43863,43864,43865,43866,43867,39271,43869,43870,43871,40593,43873,43874,43875,43876,43877,43878,43879,40342,43881,43882,43883,43884,43885,43886,43887,43888,43889,43890,43891,43892,43893,43894,43895,43896,43897,43898,43899,43900,42200,43902,43903,43904,43905,43906,39514,43908,43909,43910,43911,43912,43913,43914,43915,43916,43917,43918,43919,43920,43921,43922,42721,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934,43935,43936,40015,43938,43939,43940,43941,43942,43943,43944,43945,43946,40016,43948,43949,43950,43951,43952,40644,43954,43955,43956,43957,43958,40005,43960,43961,43962,43963,43964,42114,43966,41962,40674,43969,43970,43971,43972,43973,43974,43975,43976,42404,43978,43979,43980,43981,39181,43983,43984,43985,43986,43987,43988,43989,43990,43991,39370,43993,43994,43995,43996,43997,43998,43942,44000,38920,44002,44003,44004,44005,44006,44007,44008,42132,44010,44011,44012,38579,44014,44015,44016,44017,44018,38963,44020,44021,44022,44023,44024,44025,44026,40304,44028,39479,44030,44031,44032,44033,39267,44035,44036,44037,44038,39062,44040,44041,44042,44043,44044,44045,44046,44047,44048,44049,40117,44051,39908,44053,44054,44055,44056,44057,44058,44059,44060,41295,44062,44063,44064,44065,44066,44067,42292,44069,44070,44071,44072,44073,44074,44075,44076,44077,44078,44079,39621,44081,44082,44083,44084,44085,44086,40666,44088,44089,44090,44091,40828,44093,44094,44095,43454,44097,44098,44099,44100,44101,44102,43598,44104,44105,44106,44107,44108,39984,44110,39973,44112,44113,44114,44115,41221,44117,44118,44119,44120,44121,44122,44123,44124,44125,44126,44127,42076,44129,42956,44131,44132,44133,44134,44135,44136,44137,44138,38964,44140,38586,44142,44143,44144,44145,44146,44147,44148,44149,44150,44151,42857,44153,44154,44155,44156,44157,44158,44159,44160,44161,44162,44163,38663,44165,39504,44167,44168,44169,44170,44171,41528,44173,44174,44175,44176,44177,44178,44179,44180,44181,44182,44183,44184,44185,39186,44187,44188,44189,44190,44191,44192,44193,44194,44195,39151,44197,44198,44199,44200,44201,44202,44203,44204,44205,44206,44207,44208,44209,44210,40507,44212,44213,44214,44215,44216,44217,44218,44219,44220,39183,44222,44223,44224,44225,44226,43995,44228,44229,44230,41920,42259,44233,44234,41964,44236,44237,44238,44239,44240,44241,44242,39151,44244,44245,44246,44247,44248,40506,44250,44251,44252,44253,44254,44255,44256,44257,44258,44259,44260,44261,44262,44263,44264,44265,44266,44267,44268,43144,44270,44271,44272,44273,44274,44275,44276,44277,44278,44279,44280,44281,44282,44283,44284,44285,44286,44287,44288,44289,44290,44291,44292,44293,44294,44295,44296,44297,44298,44299,44300,44301,44302,44303,44304,44305,44306,44307,44308,44309,44310,44311,44312,44313,44314,44315,44316,44317,44318,44319,44320,44321,44322,44323,44022,44325,38533,44327,44328,44329,44330,44331,43315,44333,44334,44335,44336,44337,44338,42985,44340,44341,44342,44343,44344,44345,44346,44347,40593,44349,44350,44351,44352,44353,44354,41025,44356,44357,44358,44359,44360,44361,44362,44363,44364,44365,44366,44367,44368,44369,44370,44371,44372,44373,44374,44375,38716,44377,44378,44379,44380,44381,40377,44383,44384,44385,44386,44387,44388,44389,44390,39580,44392,44393,44394,44395,44396,44397,44398,44399,44400,44401,44402,44403,44404,38800,44406,44407,44408,40506,44410,44411,44412,44413,44414,44415,44416,44417,43927,44419,44420,44421,44422,44423,44424,44425,44426,44427,39196,44429,44430,44431,44432,44433,42790,44435,44436,44437,44438,44439,44440,44441,44442,44443,40810,44445,44446,44447,43231,44449,44450,44451,44452,44453,44454,44455,42876,44457,44458,44459,40658,44461,44462,44463,44464,44465,44466,40125,44468,44469,44470,44471,44472,44473,39124,44475,44476,44477,44478,44479,44480,44481,44482,44483,44484,44485,44486,44487,44488,38586,44490,44491,44492,44493,44494,44495,44496,44497,44498,44499,44500,44501,44502,44503,44504,44505,44506,44507,44508,44509,44510,44511,44512,39230,44514,44515,44516,44517,43313,44519,44520,44521,44522,44523,44524,44525,44526,44357,44528,44529,44530,44531,44532,44533,44534,44535,44536,44537,41370,44539,44540,44541,44542,44543,44544,44545,43039,41131,44548,44549,44550,44551,44552,38929,44554,44555,44556,44557,44558,44559,44560,44561,39581,44563,44564,44565,44566,39988,44568,44569,44570,44571,44572,44573,44574,44575,44576,44577,38780,44579,44580,42117,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44592,44593,44594,44392,44596,44597,38887,44599,44600,41139,39993,44603,44604,44605,44606,44607,44608,44609,44610,44611,43056,44613,44614,44615,44616,44617,44618,44619,43605,44621,42156,44623,44624,44625,44626,44627,38976,44629,44630,44631,39846,44633,44634,44635,44636,38636,44638,44639,44640,44641,44642,42183,44361,44645,44646,44647,44648,44649,44650,44651,44652,44653,44654,44655,44656,44657,44658,44659,44660,44661,44662,44663,44664,39514,44666,44667,44668,44669,44670,44671,44672,44673,44674,44675,44676,44677,44678,43436,44680,44681,44682,44683,44684,44685,44686,44687,39090,44689,44690,44691,44692,40672,44694,44695,44696,44697,44698,44699,41774,44701,44702,44703,44704,39790,44706,44707,44708,44709,44710,44711,39988,44713,44714,44715,44716,44717,44718,44719,44720,38800,44722,44723,44724,44725,44726,38929,44728,44729,44730,44731,44732,44733,44734,44735,44736,44737,39120,44739,44740,44741,44742,44743,44744,44745,44746,44747,44748,44749,43995,44751,44752,44753,44754,44755,44756,42399,44758,44759,44760,44761,44762,44763,44764,44765,44766,42661,44768,44769,44770,44771,42156,44773,44774,44775,44776,44777,44778,44779,44780,38998,44782,44783,44784,44785,44786,43743,44788,44789,39871,44791,44792,44793,44794,44795,39879,44797,44798,44799,44800,44801,44802,44803,41743,44805,44806,44807,44808,44809,44810,44811,44812,44813,44814,41417,44816,40382,44818,44819,44820,44821,44822,44823,43455,44825,44826,44827,44828,44829,44830,44831,41790,44833,44834,43260,44836,44837,44838,44839,42758,44841,44842,44843,44844,44845,41775,44847,44848,44849,44850,44851,44852,44853,38800,44855,44856,44857,44858,44859,38896,40856,44862,44863,44864,44865,44866,41225,44868,44869,44870,38956,44872,39437,44874,44875,44876,42678,44878,44879,44880,44881,43491,44883,44884,44885,44886,44887,44888,44889,44890,39271,44892,44893,44894,44895,40346,44897,44898,44899,44900,42711,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,43184,44913,44914,44915,44916,44917,44918,44919,44920,44921,44922,42067,44924,39370,44926,44927,44928,44929,44930,44931,44932,44933,40382,44935,44936,44937,44938,44939,44940,44941,44942,44943,40005,44945,44946,44947,38814,44949,44950,44951,44952,44953,44954,44955,44956,44957,44958,44959,44960,39743,44962,44963,44964,44965,44966,38772,44968,44969,41949,44971,44972,38876,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44984,38756,44986,44987,44988,41920,44990,44991,44992,44993,41928,44995,44996,44997,44998,38522,45000,45001,45002,45003,45004,45005,45006,45007,45008,45009,45010,45011,45012,45013,45014,45015,44022,45017,45018,45019,45020,45021,41332,45023,45024,45025,45026,45027,45028,39252,45030,45031,45032,39258,45034,45035,45036,45037,45038,45039,45040,45041,45042,45043,40336,45045,45046,45047,45048,42042,45050,45051,45052,45053,45054,45055,45056,45057,45058,38718,45060,45061,45062,45063,45064,45065,45066,45067,39092,39358,45070,43078,45072,45073,45074,41906,45076,45077,41386,45079,45080,45081,45082,45083,45084,41114,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45096,45097,45098,45099,45100,45101,45102,39357,45104,45105,45106,45107,42900,45109,41688,45111,45112,45113,45114,45115,45116,45117,45118,45119,40738,45121,45122,40542,45124,45125,45126,45127,40045,45129,45130,45131,45132,45133,45134,45135,45136,45137,39861,45139,40081,45141,45142,45143,45144,45145,45146,45147,45148,45149,45150,45151,45152,45153,45154,45155,45156,40094,45158,45159,45160,45161,45162,45163,45164,45165,45166,43347,45168,45169,45170,45171,45172,39172,45174,45175,45176,45177,45178,45179,45180,45181,45182,45183,44714,45185,45186,45187,44583,45189,45190,45191,45192,45193,45194,45195,45196,45197,45198,45199,38773,45201,45202,45203,45204,45205,45206,45207,45208,45209,45210,45211,45212,45213,45214,41416,45216,45217,45218,45219,45220,43542,43669,45223,45224,45225,45226,45227,45228,41137,45230,45231,45232,41204,45234,42892,45236,45237,45238,45239,45240,45241,38928,45243,45244,45245,45246,45247,45248,45249,43088,45251,45252,45253,45254,45255,45256,45257,45258,45259,45260,39814,45262,45263,45264,45265,45266,45267,45268,45269,45270,45271,45272,45017,45274,45275,45276,45277,42324,45279,45280,45281,45282,38602,45284,45285,45286,45287,45288,45289,45290,45291,39258,45293,45294,45295,45296,45297,45298,45299,45300,45301,42697,45303,45304,45305,39294,45307,45308,45309,45310,45311,45312,45313,42054,45315,45316,45317,45318,45319,45320,45321,45322,45323,45324,41072,45326,45327,45328,45329,45330,45331,45332,40401,45334,45335,45336,45337,41113,45339,45340,43262,45342,45343,41412,41689,45346,45347,45348,45349,45350,45351,45352,45353,45354,45355,45356,39581,45358,45359,45360,39370,45362,45363,45364,39151,45366,45367,45368,45369,45370,45371,45372,45373,45374,45375,45376,45377,43218,45379,45380,45381,45382,45383,45384,45385,45386,45387,45388,44495,45390,45391,45392,38962,45394,45395,45396,45397,45398,45399,45400,45401,45402,45403,40990,45405,45406,45407,45408,45409,45410,45411,41350,39015,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,39892,45431,45432,45433,45434,45435,45436,45437,45438,45439,45440,45441,45442,39989,45444,45445,41430,45447,45448,45449,45450,45451,45452,41701,45454,45455,45456,45219,41411,45459,45460,45461,45462,44729,45464,45465,45466,45467,45468,45469,39581,45471,45472,43415,45474,45475,45476,45477,45478,45479,44228,45481,45482,39927,45484,45485,45486,45487,45488,45489,45490,45491,45492,44847,45494,45495,45496,45497,45498,45499,45500,43816,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,39815,45515,45516,45517,45518,45286,45520,45521,45035,45523,45524,45525,45526,45527,45528,45529,45530,45531,45532,45533,45534,43503,45536,39062,45538,45539,45540,45541,45542,45543,45544,45545,45546,45547,38720,45549,45550,45551,45552,45553,45554,45555,45556,45557,45558,44751,45560,45561,45562,45563,45564,45565,45566,41053,45568,45569,45570,45571,45572,45573,45574,45575,45576,45577,45578,45579,43260,45581,45582,45583,45584,45585,45586,43690,45588,45589,45590,44558,45592,45593,45594,45595,45596,45597,38874,45599,45600,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,39574,45613,45614,45615,39091,45617,43969,45619,45620,45621,45622,45623,45624,43458,45626,45627,45628,45629,45630,45631,43393,45633,45634,45635,45636,45637,45638,40975,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45656,45657,45658,45659,45660,45661,40980,45663,45664,38521,45666,45667,45668,45669,45670,45671,45672,38985,42177,45675,45676,45677,45678,45294,45680,45681,45682,45683,45684,45685,45686,45687,45688,43630,42205,45691,45692,45693,45694,45695,45696,38717,45698,45699,45700,45701,45702,45703,45704,45705,45706,45707,45708,45709,45710,45711,45712,45713,39089,45715,45716,45717,45718,45719,45720,41100,45722,45723,45724,42530,45726,45727,45728,45729,45730,45731,45732,45733,45734,45735,45736,45737,43364,45739,45740,45741,39085,45743,45744,45745,45746,45747,41102,45749,45750,40470,45105,45753,45754,45755,45756,43260,45758,45759,45760,45754,45762,45111,45764,45765,45766,45767,45768,45769,45770,45771,45772,45773,45774,45775,44394,45777,45778,45779,45780,45781,42662,45783,45784,40290,45786,45787,45788,38549,45790,45791,45792,45793,45794,45795,38604,45797,45798,45799,45800,45801,45802,39690,45804,45805,45806,45807,45808,45809,45810,45811,45812,45813,39486,45815,45816,39293,45818,45819,45820,45821,45822,45823,42059,45825,45826,45827,45828,41072,45830,45831,42657,39345,45834,45835,45836,45837,45838,41068,45840,45841,40435,45843,45844,45845,45846,45847,41094,45849,45850,38928,45852,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,38904,45867,45868,45869,45870,45871,45872,43822,45874,45875,45876,45877,45878,45879,44129,40486,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45908,45909,45910,45911,45912,45913,45914,45915,45916,45917,45918,45919,45920,45921,45922,45923,45924,45925,45926,45927,45928,45929,45930,45931,45932,45933,45934,45935,45936,45937,45938,45939,45940,45941,45942,45943,45944,45945,45946,45947,45948,45949,45950,45951,45952,45953,45954,45955,45956,45957,45958,45959,45960,45961,45962,45963,45964,45965,45966,45967,45968,45969,45970,45971,45972,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45984,45985,45986,45987,45988,45989,45990,45991,45992,45993,45994,45995,45996,45997,45998,42515,42551,46001,46002,42157,42969,46005,46006,46007,38593,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,39020,46021,46022,46023,46024,46025,46026,46027,46028,46029,46030,46031,46032,46033,46034,46035,46036,46037,46038,46039,46040,46041,46042,46043,46044,46045,46046,46047,46048,46049,46050,46051,46052,46053,46054,46055,46056,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46076,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46096,46097,46098,46099,40094,46101,46102,46103,46104,46105,46106,46107,46108,46109,40615,46111,46112,46113,46114,46115,46116,46117,46118,46119,42876,41823,46122,46123,46124,46125,46126,44760,46128,46129,46130,46131,41412,46133,46134,38741,46136,46137,46138,46139,46140,44582,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,42502,46153,46154,46155,46156,46157,46158,43394,46160,46161,46162,46163,41139,43372,46166,46167,46168,46169,46170,46171,46172,46173,46174,39123,46176,46177,46178,46179,46180,46181,46182,46183,46184,46185,46186,46187,46188,46189,46190,46191,46192,42135,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46208,46209,44021,46211,46212,46213,46214,46215,46216,40549,46218,46219,46220,46221,46222,46223,46224,46225,40755,46227,46228,46229,45815,46231,46232,46233,46234,42704,46236,46237,46238,46239,46240,46241,46242,44905,46244,46245,46246,46247,46248,46249,39143,46251,46252,46253,43569,46255,44062,46257,46258,46259,46260,46261,46262,46263,40808,46265,46266,46267,46268,46269,46270,46271,46272,46273,46274,46275,46276,46277,46278,40821,46280,46281,46282,46283,40665,46285,46286,46287,46288,46289,40384,46291,46292,46293,46294,46295,46296,46297,46298,44202,46300,46301,46302,46303,46304,46305,46306,39337,46308,46309,46310,46311,46312,46313,46314,46315,41615,42920,46318,46319,46320,44730,46322,46323,46324,46325,46326,46327,46328,46329,46330,39736,46332,46333,41841,46335,46336,46337,46338,46339,38969,46341,42010,46343,46344,41340,42986,46347,46348,46349,46350,46351,46352,41352,46354,46355,46356,46357,39509,42714,46360,46361,46362,46363,42720,46365,46366,46367,46368,46369,44714,46371,46372,46373,46374,43014,46376,46377,46378,46379,46380,46381,46382,46383,46384,46385,46386,46387,46388,43528,46390,43659,46392,46393,46394,42785,46396,46397,46398,46399,46400,40458,46402,46403,46404,46405,46406,46407,46408,46409,46410,38757,46412,46413,46259,46415,46416,46417,46418,46419,40686,46421,46422,46423,46424,46425,46426,46427,46428,46429,46430,46431,46432,39813,46434,42157,46436,46437,46438,38975,46440,46441,46442,46443,42179,42337,46446,46447,44895,46449,42200,46451,46452,46453,46454,46455,46456,46457,46458,38717,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,39172,46476,46477,46478,46479,38756,46481,46482,46483,40803,46485,46486,46487,46488,46489,46490,46491,44760,46493,46494,46495,46496,46497,46498,46499,46500,46501,46502,46503,46504,46505,46506,46507,46508,46509,46510,41222,46512,46513,46514,46515,46516,46517,46518,46519,46520,39357,46522,46523,46524,46525,46526,46527,40635,46529,46530,46531,46532,46533,43012,44818,46536,46537,46538,46539,41305,46541,46542,46543,46544,46545,38853,40401,46548,46549,46550,46551,40461,46553,46554,46555,46556,46557,46558,46559,43711,46561,46562,46563,46564,46565,46566,46567,38948,46569,46570,46571,46572,46573,46574,46575,46576,40290,46578,46579,46580,46581,46582,38541,39449,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,39476,46601,46602,46603,46604,46605,46606,46607,41352,46609,46610,46611,38691,46613,46614,46615,46616,46617,46618,46619,46620,46621,46622,45316,46624,46625,46626,46627,46628,46629,46630,46631,46632,46633,46634,46635,46636,40669,46638,40121,45485,46641,46642,46643,46644,39553,46646,46647,46648,46649,46650,39182,46652,46653,46654,46655,43417,46657,46658,46659,46660,46661,40732,46663,46664,46665,46666,46667,42503,46669,46670,46671,46672,46673,46674,43985,46676,46677,46678,39988,46680,46681,46682,46683,46684,46685,46554,46687,46688,46689,46690,46691,46692,46693,46694,46695,46696,46697,42629,46699,46700,39815,46702,46703,46704,46705,46706,46707,46708,38514,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,39251,46723,46724,46725,46726,46727,39836,46729,39022,46731,46732,46733,46734,46735,46736,46737,46738,42044,46740,46741,46742,46743,46744,46745,46746,46747,46748,46749,46750,46751,46752,46753,46754,46755,46756,38713,46758,46759,42058,46761,46762,46763,46764,46765,46766,46767,46768,39906,46770,39912,46772,46773,38794,45886,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46804,46805,39906,46807,46808,46809,46810,46811,46812,46813,39627,40506,46816,46817,46818,46819,46820,46821,46822,46823,46824,39070,46826,46827,46828,46829,46830,46831,46832,46833,46834,46835,46836,46837,43516,40486,46840,46841,42901,46843,46844,41710,46846,46847,39658,46849,46850,46851,40987,46853,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,42176,46873,46874,46875,46876,46877,45806,46879,46880,46881,46882,46883,46884,46885,46886,46887,46888,46889,46890,46891,45815,46893,46894,46895,46896,42042,46898,46899,46900,46901,46902,46903,46904,46905,46906,39306,46908,46909,46910,46911,46912,46913,46914,46915,46916,46917,46918,46919,46920,46921,46922,39361,42523,46925,45726,46927,46928,46929,46930,46931,46932,46933,46934,46935,46936,46937,46938,46939,46940,46941,46813,39591,46944,46945,46946,44261,46948,46949,46950,46951,46952,46953,43430,46955,46956,46957,46958,46959,46960,41207,43242,46963,46964,46965,46966,39554,46968,46969,46970,46971,46972,46973,46974,46975,46976,46977,46978,46979,46980,46981,46982,46523,46984,46985,41709,46987,46988,46989,38551,46991,46992,46993,46994,46995,46996,46997,46998,46999,47000,47001,38601,47003,47004,47005,47006,47007,47008,47009,39258,47011,47012,47013,47014,47015,47016,47017,47018,47019,47020,47021,47022,47023,47024,47025,47026,45806,47028,47029,47030,47031,47032,47033,47034,47035,47036,47037,44349,47039,47040,47041,47042,47043,44649,47045,47046,46460,47048,47049,47050,47051,47052,47053,47054,47055,47056,43260,47058,47059,47060,43364,45854,47063,47064,47065,47066,39581,41819,47069,38929,47071,47072,47073,45601,39187,47076,47077,40666,47079,47080,47081,47082,45488,47084,47085,47086,40652,47088,47089,47090,47091,38793,47093,39426,47095,47096,40302,47098,47099,47100,47101,47102,47103,47104,47105,47106,40312,47108,47109,47110,47111,47112,46011,47114,47115,47116,47117,47118,47119,47120,39017,47122,47123,47124,47125,47126,47127,47128,41354,47130,47131,47132,47133,47134,47135,40094,47137,47138,47139,47140,47141,47142,47143,47144,47145,47146,47147,47148,47149,43345,47151,47152,47153,47154,47155,47156,47157,47158,47159,41239,47161,47162,47163,47164,47165,47166,47167,47168,47169,47170,46804,47172,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,47190,47191,47192,47193,47194,47195,47196,47197,42625,47199,47200,46530,47202,47203,47204,47205,47206,47207,42101,47209,47210,45854,47212,47213,47214,47215,47216,47217,47218,47219,47220,47221,47222,46666,47224,38928,47226,47227,40378,40016,47230,47231,47232,47233,47063,47235,47236,47237,47238,47239,47240,44701,47242,47243,47244,47245,47246,47247,47248,47249,47250,47251,47252,47253,47254,44097,47256,47257,47258,47259,47260,38773,47262,47263,47264,47265,39651,47267,47268,43297,47270,47271,47272,47273,41483,47275,47276,47277,47278,47279,47280,47281,47282,47283,47284,41500,47286,47287,47288,47289,47290,47291,47292,47293,47294,40570,47296,47297,47298,47299,47300,42698,47302,47303,47304,40346,47306,47307,47308,47309,47310,39061,47312,47313,47314,47315,47316,47317,47318,47319,47320,46831,47322,47323,47324,47325,43416,47327,47328,47329,40672,47331,47332,47333,47334,47335,40808,47337,47338,47339,44833,47341,47342,47343,47344,47345,47346,41907,47348,47349,47350,47351,47352,47353,39993,47355,47356,47357,47088,47359,47360,47361,47362,47363,47364,47365,42784,47367,47368,47369,47370,38840,47372,41113,47374,39818,47376,44021,42318,47379,47380,47381,47382,38604,39260,47385,47386,47387,47388,47389,47390,47391,47392,47393,47394,42182,47396,47397,42042,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,45698,47413,47414,47415,47416,47417,47418,47419,47420,47421,47422,47423,47424,45475,47426,47427,47428,47429,47430,47431,47432,40517,47434,47435,43704,47437,42920,47439,47440,47441,47442,47443,45464,47445,47446,47447,47448,47449,47450,47451,47452,47453,47454,41267,47456,47457,47458,43984,47460,47461,47462,47463,47464,47465,47466,47467,47468,47469,43260,47471,47472,47473,47474,45219,44114,47477,47478,47479,47480,47481,47482,47483,47484,47485,47486,47487,42769,43817,47490,47491,47492,47493,47494,47495,47496,39424,47498,41480,41500,47501,47502,47503,40999,47505,47506,47507,47508,47509,47510,43327,47512,47513,47514,47515,47516,41525,47518,44666,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47532,40176,47534,47535,47536,47537,47538,47539,47540,47541,47542,42244,47544,47545,47546,47547,47548,47549,47550,41920,47552,47553,47554,47555,47556,47557,47558,39555,47560,47561,47562,47563,47564,47565,47566,47567,47568,43436,47570,47571,47427,47573,47574,47575,40676,47577,47578,47579,47580,47581,47582,47583,47584,39967,47586,47587,47588,47589,39977,47591,47592,47593,47594,47595,39988,47597,47598,47599,47600,47601,45634,47603,47604,47605,47606,47607,47608,47609,39120,47611,39413,47613,47614,47615,43289,47617,47618,47619,47620,47621,42163,47623,47624,42970,47626,47627,47628,38999,47630,47631,47632,47633,47634,47635,47636,41160,47638,47639,47640,47641,47642,47643,46614,47645,47646,47647,47648,47649,47650,47651,47652,47653,38721,47655,47656,47657,47658,47659,47660,47661,47662,47663,39405,43049,47666,47667,47668,47669,43365,47671,41606,47673,47674,47675,44579,47677,47678,39993,47680,47681,47682,47683,47684,47685,47686,47687,44618,47689,47690,47691,47692,42388,47694,47695,47696,47697,43994,47699,47700,47701,47702,47703,40488,47705,47706,43951,39815,47709,38515,47711,47712,42969,47714,47715,47716,47717,39005,47719,47720,47721,47722,40066,47724,47725,47726,47513,39290,47729,47730,47731,47732,47733,47734,47735,47736,47737,47738,47739,39303,47741,47742,47743,47744,42273,47746,47747,47748,47749,47750,45334,40458,47753,47754,47755,47756,39358,47758,47759,41586,40405,47762,47763,47764,47765,47766,47767,47768,47769,47770,47771,40127,47773,47774,47775,47776,47777,47778,44212,47780,47781,47782,47783,47784,47785,47786,47787,47788,47789,47790,47791,38925,47793,47794,47795,47796,47797,47798,47799,47800,47801,47802,44751,47804,47805,47806,47807,47808,47809,44580,41921,47812,47813,47814,47815,43280,47817,40015,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,46699,47830,39813,47832,47833,47834,39669,47836,47837,47838,47839,47840,47841,47842,47843,41338,47845,47846,44167,47848,47849,47850,44906,47852,47853,46958,47855,47856,47857,47858,47859,40823,39995,47862,47863,47864,47865,47866,47867,47868,47869,41117,47871,47872,47873,47874,47875,47876,47877,47878,47879,41400,47881,47882,47883,47884,47471,47886,47887,42900,47889,47890,47891,47445,47893,47894,47895,47896,47897,47898,38812,47900,47901,47902,47903,47904,47905,40176,47907,47908,39361,41295,47911,47912,47913,47914,47915,47916,47917,47918,47919,39944,47921,47922,46124,47924,47925,47926,45517,47928,47929,47930,47284,43497,47933,38658,47935,47936,47937,47938,47939,47940,42215,47942,47943,47944,47945,44806,47947,47948,47949,47950,47951,47952,47953,47954,47955,47956,47957,47958,47959,47960,47961,39905,47963,47964,47965,47966,47967,47968,47969,47591,47971,47972,47973,47974,47975,47976,47977,47978,47979,47980,42644,47982,47161,47984,47985,47986,47987,47988,47989,46310,47991,47992,47993,45070,40666,47996,47997,47998,44730,48000,48001,48002,48003,48004,44995,48006,48007,48008,48009,48010,48011,48012,48013,48014,48015,38579,48017,48018,48019,48020,48021,45396,48023,48024,48025,48026,48027,48028,48029,45405,48031,48032,48033,48034,48035,48036,48037,48038,48039,42858,48041,48042,48043,48044,48045,43329,48047,48048,48049,48050,44171,41528,48053,48054,48055,48056,48057,38721,48059,48060,48061,48062,48063,48064,48065,43064,48067,48068,48069,48070,48071,48072,46840,48074,48075,48076,46925,48078,48079,48080,43067,39343,48083,48084,48085,48086,47210,40435,48089,48090,48091,48092,48093,48094,48095,48096,41682,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48120,48121,48122,48123,48124,48125,48126,48127,39545,48129,48130,48131,48132,48133,41435,48135,48136,48137,48138,48139,48140,48141,48142,48143,45004,48145,48146,48147,48148,48149,48150,48151,48152,48153,48154,48155,48156,48157,48158,48159,48160,48161,48162,48163,48164,48165,48166,48167,48168,48169,48170,48171,48172,48173,48174,48175,39233,48177,48178,48179,42011,48181,48182,48183,48184,48185,39251,48187,48188,48189,48190,48191,38618,48193,48194,48195,48196,48197,48198,48199,48200,48201,48202,48203,40079,48205,48206,48207,48208,48209,48210,48211,48212,48213,48214,48215,48216,48217,48218,48219,48220,48221,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,44652,48249,48250,48251,48252,44378,48254,48255,48256,48257,48258,48259,48260,48261,48262,48263,48264,48265,48266,48267,48268,42875,48270,48271,48272,48273,45203,48275,48276,39622,48278,48279,48280,48281,48282,48283,48284,48285,48286,39639,48288,48289,48290,48291,48292,41278,48294,48295,48296,48297,48298,48299,47773,48301,48302,48303,48304,48305,48306,48307,48308,48309,42828,48311,48312,48313,40860,48315,48316,48317,48318,38743,48320,48321,48322,48323,43394,48325,48326,48327,48328,48329,48330,48331,46130,48333,48334,48335,43951,44771,42179,48339,48340,42853,48342,48343,48344,48345,48346,48347,48348,48349,48350,48351,41871,48353,48354,48355,48356,48357,48358,48359,48360,48361,39074,48363,48364,48365,48366,48367,48368,48369,48370,48371,48372,48373,48374,48375,48376,48377,39908,48379,48380,48381,48382,48383,48384,48385,48386,42758,48388,48389,48390,48391,48392,44475,48394,46663,48396,48397,48398,48399,43039,47971,48402,48403,48404,48405,48406,48407,48408,48083,48410,48411,48412,48413,48414,48415,48416,39179,48418,48419,48420,48421,39373,48423,48424,48425,48426,48427,48428,48429,48430,47232,48432,38929,48434,48435,45383,48437,48438,48439,48440,48441,48442,48131,48444,48445,48446,48447,42309,48449,41150,48451,48452,42176,48454,48455,48456,48457,47030,48459,48460,48461,48462,48463,45815,48465,48466,48467,42045,48469,48470,48471,48472,48473,48474,47416,48476,48477,48478,48479,48480,48481,48482,48483,48484,48485,48486,48487,48488,40437,46133,47213,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,38768,41205,48506,48507,42892,48509,48510,48511,48512,48513,40821,48515,48516,48517,48518,48519,48520,48521,48522,48523,48524,48525,46153,48527,48528,48529,48530,48531,48532,48533,48534,41546,48536,48537,48538,48539,48540,47081,48542,39994,48544,48545,48546,48547,48548,43805,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48560,48561,48562,44254,48564,48565,48566,48567,38579,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,39232,48592,48593,48594,48595,45405,48597,48598,48599,48600,48601,48602,48603,48604,48605,48606,48607,40781,48609,48610,48611,48612,48613,48614,48615,48616,48617,48618,48619,39138,48621,48622,48623,48624,48625,48626,48627,48628,48629,48630,48631,38898,48633,43367,48635,48636,48637,48638,48639,48640,48641,48642,48643,48644,39391,48646,48647,48648,48649,48650,48651,48652,48653,48654,48655,48656,48657,48658,48659,48660,48661,48662,48663,48664,48665,48666,48667,48668,48669,48670,48671,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,44189,44469,48686,48687,48688,48689,48690,48691,48692,48693,40263,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,43231,48706,48707,48708,48709,48710,48711,43516,47604,48714,48715,48716,44945,48718,48719,48720,48721,48722,39815,48724,39433,48726,48727,48728,48729,48730,48731,48732,48733,48734,48735,40314,48737,48738,48739,48740,48741,48742,48743,43618,48745,48746,48747,38678,48749,41871,48751,48752,48753,48754,48755,45433,48757,48758,48759,48760,48761,48762,48763,48764,48765,48766,48767,48768,48769,45444,48771,48772,40846,48774,48775,48776,43021,48778,48779,48780,48781,48782,48783,48784,48785,48786,48787,48788,48789,48790,48791,40458,48793,48794,48795,48796,48797,48798,43036,46281,48801,48802,43927,48804,48805,47887,40644,48808,48809,48810,48811,41777,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,40657,48824,48825,40737,48827,48828,48829,48830,48731,48832,48833,48834,48738,48836,48837,48838,48839,48840,48841,39844,48843,48844,48845,48846,48847,42333,48849,48850,48851,48852,48853,48854,48855,48856,48857,48858,48859,40337,48861,48862,41026,48254,48865,48866,48867,48868,48869,48870,48871,48872,48873,48874,48875,48876,44457,48878,48879,40644,48881,43530,48883,48884,48885,48886,48887,48888,48889,48890,48891,48892,45445,48894,38773,48896,39589,48898,48899,48900,48901,48902,48903,48904,48905,48906,42258,48908,48909,48910,48911,48912,48913,48914,48915,41278,48917,48918,48919,48920,48921,48922,48923,48924,48925,48926,39993,48928,48929,48930,48931,48932,48933,48934,44097,48936,48937,48938,48939,48940,48941,48942,39791,48944,48945,48946,48947,39651,48949,48950,48951,43612,42969,48954,48955,48956,48957,48958,38994,48960,48961,48962,48963,48964,48965,48966,48967,39861,48969,48970,48971,48972,48973,48974,48975,48976,48977,48978,48979,48980,42358,48982,43183,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,39331,48999,45570,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,45230,46684,49014,41606,49016,49017,49018,49019,45634,49021,49022,49023,49024,49025,44708,49027,49028,49029,49030,49031,49032,44762,49034,49035,49036,49037,49038,38834,49040,49041,49042,49043,49044,49045,38747,49047,49048,49049,49050,49051,49052,49053,49054,49055,49056,49057,38902,41555,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,40714,49071,49072,49073,49074,49075,48950,49077,49078,49079,41481,49081,49082,49083,49084,49085,49086,49087,49088,42840,49090,42691,49092,39872,49094,49095,49096,49097,49098,49099,49100,49101,49102,40095,49104,49105,49106,49107,46112,49109,49110,49111,49112,49113,49114,49115,43515,49117,49118,40732,49120,43279,49122,49123,49124,49125,49126,43065,49128,42598,49130,49131,49132,40498,49134,49135,49136,43675,49138,49139,49140,49141,38749,49143,43037,45464,49146,49147,49148,49149,49150,49151,49152,49153,49154,47904,49156,49157,49158,49159,49160,49161,49162,49163,41474,49165,49166,49167,49168,49169,49170,41174,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,42866,48611,49184,49185,49186,49187,49188,49189,49190,49191,40794,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,39151,49204,49205,49206,49207,41114,49209,49210,49211,49212,49213,49214,49215,45462,41687,49218,49219,49220,38773,44245,49223,49224,49225,49226,49227,49228,39391,49230,49231,41996,49233,49234,40290,49236,49237,49238,49239,49240,49241,47837,49243,49244,49245,49246,49247,49248,39253,49250,42027,49252,49253,49254,44365,46462,49257,49258,49259,49260,49261,49262,49263,49264,40666,49266,49267,49268,49269,49270,43541,43074,49273,49274,49275,49276,49277,49278,49279,49280,41608,49282,41130,49284,49285,42116,49287,49288,49289,49290,49291,47549,49293,49294,49295,42932,49297,49298,49299,49300,49301,49302,49303,49304,49305,49306,49307,49308,49309,49310,49311,49312,49313,49314,49315,49316,49317,49318,49319,49320,49321,49322,49323,49324,49325,49326,49327,49328,49329,49330,49331,49332,49333,49334,49335,49336,49337,49338,49339,49340,49341,49342,49343,49344,39939,49346,49347,49348,49349,49350,49351,49352,49353,49354,49355,39977,49357,39657,49359,49360,49361,46866,49363,49364,49365,39478,49367,49368,49369,49370,49371,41015,49373,49374,49375,40346,49377,49378,49379,49380,49381,49382,42215,49384,49385,49386,49387,49388,49389,49390,49391,49392,48054,49394,49395,49396,49397,49398,49399,41533,49401,49402,49403,49404,49405,49406,49407,49408,49409,49410,49411,48760,49413,49414,49415,49416,49417,49418,49419,49420,43951,41690,49423,49424,49425,49426,49427,49428,40440,49430,49431,44574,48896,39622,49435,49436,49437,49438,49439,39608,49441,49442,49443,49444,49445,49446,49447,49448,49449,49450,49451,49452,49453,49454,49455,49456,49457,39527,49459,49460,49461,49462,40437,49464,49465,49466,47863,49468,49469,49470,49471,49472,49473,40420,49475,49476,49477,49478,49479,49480,49481,49482,40845,49484,49485,49486,49487,49488,47267,39435,49491,49492,49493,49494,49495,46006,49497,49498,49499,49500,39000,49502,44788,49504,40588,40606,49507,49508,49509,49510,49511,49512,48759,49514,49515,49516,49517,49518,49519,49520,49521,49522,43039,40846,49525,49526,49527,49528,49529,49530,49531,44119,49533,49534,49535,49536,49537,49538,49539,46308,49541,49542,49543,49544,49545,49546,49547,49548,49549,49550,49551,49552,49553,49554,49555,45070,49557,38748,49559,49560,49561,49562,49563,49564,49565,49566,49567,43209,49569,49570,49571,49572,49573,49574,38814,48154,49577,49578,49579,49580,49581,49582,49583,49584,43298,49586,49587,42009,49589,49590,49591,42840,49593,49594,49595,49596,49597,45797,49599,49600,49601,49602,49603,49604,45294,49606,49607,49608,49609,49610,49611,49612,49613,42038,49615,49616,49617,49618,42207,49620,49621,49622,49623,45701,49625,49626,49627,49628,49629,49630,49631,49632,49633,46524,49635,49636,49637,49638,49639,47871,49641,49642,49643,49644,49645,49646,45231,42105,49649,49650,42900,42914,49653,49654,49655,47069,38902,49658,49659,49660,49661,48636,49663,49664,49665,49666,39552,49668,49669,49670,49671,41993,40981,49674,49675,38531,49677,49678,49679,49680,49681,49682,49683,49684,49685,49686,49687,49688,49689,49690,49691,49692,49693,49694,49695,49696,49697,49698,49699,49700,49701,49702,49703,49704,49705,49706,49707,49708,49709,49710,49711,49712,49713,49714,49715,49716,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,49734,49735,49736,49737,49738,49739,49740,49741,49742,49743,49744,49745,49746,49747,49748,49749,49750,49751,49752,40990,49754,49755,49756,49757,49758,49759,49760,49761,49762,49763,49764,49765,49766,49767,49768,49769,49770,49771,49772,49773,49774,49775,49776,49777,49778,49779,49780,49781,49782,49783,49784,49785,49786,49787,49788,49789,49790,49791,49792,49793,49794,49795,41006,49797,49798,49799,49800,49801,49802,49803,49804,49805,49806,49807,49808,49809,49810,49811,49812,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,49823,49824,49825,49826,49827,49828,49829,49830,49831,49832,49833,49834,49835,49836,49837,49838,49839,49840,49841,49842,49843,49844,49845,41352,49847,49848,49849,49850,49851,49852,49853,49854,49855,42869,49857,49858,49859,49860,49861,49862,49863,49864,49865,38743,49867,49868,49869,49870,38906,49872,49873,48635,49875,49876,49877,49878,49879,49880,49881,49882,49883,49884,49885,49886,39393,49888,49889,43929,49891,49892,49893,49894,49895,49896,38753,49898,49899,49900,43422,49902,49903,49904,49905,49906,49907,49908,39939,49910,49911,49912,49913,49914,49915,49916,49917,49918,49919,49920,49921,49922,49923,49924,49925,49926,40846,49928,49929,49930,49931,49932,49933,49934,47161,49936,49937,49938,49939,49940,49941,39328,49943,49944,49945,49946,49947,41400,49949,49950,49951,49952,49953,49954,49955,49956,46310,49958,49959,49960,49961,49962,49963,49964,49430,49966,49967,49968,49969,41708,49971,43297,49973,49974,49975,49976,38549,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49989,49990,49991,49992,49993,49994,49995,49996,38602,49998,39260,50000,50001,50002,43870,50004,50005,47400,50007,50008,50009,50010,50011,50012,50013,50014,42057,50016,50017,50018,50019,50020,50021,45327,50023,50024,50025,38834,50027,50028,50029,50030,50031,50032,40467,50034,50035,50036,50037,50038,50039,50040,50041,50042,43036,50044,50045,50046,40121,49557,50049,40458,50051,50052,50053,47968,50055,50056,42894,50058,50059,50060,50061,50062,48129,50064,45765,50066,50067,50068,50069,50070,50071,39358,50073,50074,50075,39437,50077,50078,50079,50080,50081,50082,50083,50084,39435,50086,43619,50088,49096,50090,50091,50092,50093,50094,50095,50096,50097,43754,50099,50100,50101,46113,50103,50104,50105,50106,50107,50108,50109,50110,50111,50112,42877,50114,50115,50116,50117,43816,44764,50120,50121,50122,50123,50124,50125,46551,42093,50128,49543,50130,50131,50132,50133,50134,50135,50136,50137,50138,49444,50140,50141,50142,50143,50144,50145,50146,50147,50148,50149,50150,50151,50152,50153,50154,50155,50156,50157,50158,50159,46680,50161,50162,50163,50164,50165,39581,50167,50168,50169,50170,38915,48136,50173,50174,50175,45010,46849,50178,50179,42314,50181,50182,50183,50184,50185,47007,50187,50188,50189,50190,50191,45041,50193,50004,43902,50196,50197,50198,50199,50200,50201,50202,50203,45701,50205,50206,50207,50208,50209,50210,50211,50212,39361,46526,50215,43697,50217,50218,39912,50220,42112,50222,44582,50224,38900,50226,39108,50228,50229,50230,50231,50232,50233,47586,50235,50236,44085,50238,50239,50240,39233,50242,50243,40562,50245,50246,50247,42857,50249,50250,50251,50252,43329,50254,50255,50256,50257,43505,50259,49396,50261,50262,50263,50264,50265,50266,47462,50268,50269,50270,50271,40800,50273,50274,41561,50276,50277,50278,50279,50280,38800,50282,50283,50284,50285,50286,50287,38765,44246,50290,50291,48530,50293,50294,50295,50296,50297,50298,50299,50300,50301,50302,41278,50304,50305,50306,50307,50308,50309,50310,47427,50312,50313,43969,50315,50316,50317,50318,50319,50320,50321,50322,50323,50324,50325,50277,50327,42143,50329,50330,50331,50332,50333,50334,50335,50336,50337,50338,50339,50340,40978,50342,50343,49686,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,44334,50357,50358,38614,50360,50361,50362,50363,50364,50365,50366,50367,50368,50369,50370,50371,50372,50373,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,50400,50401,50402,50403,50404,50405,50406,50407,50408,50409,50410,50411,50412,50413,50414,50415,50416,50417,50418,50419,50420,50421,50422,50423,50424,50425,50426,50427,50428,50429,50430,50431,50432,50433,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50444,50445,41020,50447,50448,50449,50450,50451,50452,50453,50454,50455,45701,50457,50458,50459,50460,50461,50462,50463,39958,50027,50466,50467,50468,50469,42537,50471,50472,50473,41907,46134,50476,45768,50478,50479,50480,50481,50482,50483,50484,42875,50486,50487,50488,50489,43994,50491,50492,50493,49223,50495,50496,50497,50498,50499,50500,50501,50502,50503,40506,50505,50506,50507,50508,44497,50510,50511,50512,50513,50514,50515,50516,50517,50518,50519,50520,50521,42000,50523,40765,41530,50526,50527,50528,50529,50530,50531,43986,50533,50534,50535,50536,47746,50538,47681,50540,50541,50542,50543,50544,41219,50546,50547,50548,50549,48090,50551,50552,39090,50554,50555,50556,50557,39594,50559,50560,50561,50562,50563,50564,50565,41773,50567,50568,50569,50570,50571,50572,50573,50574,50575,50576,50577,50578,50579,44965,50581,50582,42102,49138,50585,50586,50587,39596,50589,50590,39765,42955,50593,50594,50595,50596,50597,48950,50599,50600,50601,50602,50603,50604,47714,50606,50607,50608,50609,48187,50611,50612,50613,50614,41348,49381,39055,50618,50619,50620,50621,50622,50623,50624,50625,46831,50627,50628,50629,50630,50631,50632,40666,50634,50635,50636,47862,50638,50639,50640,50641,50642,50643,50644,50645,50646,50647,42770,50649,50650,50651,50652,50653,50654,50655,50656,39369,50658,50659,50660,50661,48083,50663,50664,50665,41070,43265,50668,50669,50670,50671,40444,50673,50674,47814,50676,41983,50678,50679,50680,50681,44504,50683,50684,50685,50686,50687,50688,50689,50690,38963,50692,49364,50694,50695,50696,50697,39454,50699,50700,50701,50702,50703,50704,50705,49367,50707,50708,50709,50710,50711,50712,44892,50714,50715,50716,40346,50718,50719,50720,50721,50722,40099,50724,50725,50726,44673,50728,50729,50730,50731,50732,41966,50734,50735,50736,50737,50738,38758,50740,50741,49060,50743,50744,50745,50746,50747,50748,50749,50750,50751,40505,50753,50754,50755,50756,50757,50758,50759,50760,50761,39140,50763,50764,50765,50766,50767,39093,41764,50770,50771,50772,50773,50774,50775,47338,50777,50778,50779,50780,50781,50782,50783,50784,50785,50786,50787,50788,50789,50790,50791,39926,42130,50794,50795,40016,50797,39814,50799,50800,50801,44641,50803,50804,50805,50806,50807,50808,50809,50810,39492,50812,50813,39291,50815,50816,50817,50818,42055,50820,50821,50822,50823,50824,50825,39092,38783,50828,41595,50830,50831,50832,50833,50834,50835,50836,50837,50838,50839,50840,50841,50842,50843,50844,50845,39581,50847,50848,48624,50850,50851,50852,50853,50854,38753,50856,50857,50858,40261,50860,50861,50862,50863,39123,50865,50866,50867,46829,50869,50870,50871,50872,50873,50874,47598,50876,50877,39343,50879,50880,50881,50882,50883,50884,41130,50886,50887,50888,39815,50890,38504,50892,40552,50894,50895,50896,50897,50898,50899,39672,50901,50902,50903,50904,50905,50906,50907,50908,50909,50910,38985,42179,45806,50914,50915,50916,50917,50918,50919,50920,50921,50922,50923,50924,38661,50926,47402,50928,50929,50930,50931,50932,50933,50934,50935,50936,50937,50938,50939,46909,50941,50942,50943,50944,50945,50946,50947,50948,50949,50950,50951,50952,50953,43268,50955,50956,50957,50958,50959,50960,50961,40401,50963,50964,50965,50966,50967,50968,41049,50970,50971,50972,50973,50974,50975,50976,50977,43694,50979,43414,50981,50982,50983,50984,50985,42102,42915,50988,50989,50990,50991,50992,42627,46413,39100,50996,50997,50998,50999,51000,51001,51002,51003,51004,48438,51006,46200,51008,51009,51010,42000,51012,51013,51014,51015,51016,51017,51018,46225,40327,51021,51022,51023,51024,39860,51026,51027,51028,51029,51030,51031,51032,51033,51034,51035,51036,42570,51038,51039,51040,51041,51042,51043,47045,51045,51046,51047,51048,51049,51050,51051,51052,51053,45549,51055,51056,51057,51058,51059,51060,51061,51062,51063,51064,51065,51066,51067,51068,44224,51070,51071,51072,51073,51074,39993,51076,51077,51078,51079,51080,51081,51082,51083,51084,51085,51086,42644,51088,42102,41965,51091,51092,51093,51094,51095,51096,43564,51098,51099,51100,43520,51102,51103,51104,51105,51106,50973,51108,51109,51110,51111,51112,51113,51114,51115,51116,51117,39572,51119,51120,51121,51122,51123,40442,51125,51126,51127,51128,51129,38930,51131,51132,51133,51133,41222,51136,51137,51138,51139,38583,46578,51142,40025,41496,51145,51146,51147,51148,51149,51150,51151,51152,51153,51154,51155,51156,47297,51158,51159,51160,51161,51162,44893,51164,51165,51166,43900,51168,51169,51170,51171,51172,45539,51174,51175,51176,43439,51178,51179,51180,51181,39093,40407,51184,51185,51186,51187,51188,51189,51190,41774,51192,51193,51194,51195,51196,51197,51198,51199,51200,51201,51202,51203,51204,51205,43242,51207,51208,51209,44714,51211,51212,46699,51214,51215,51216,51217,51218,51219,51220,42644,50956,51223,51224,51225,51226,40517,51228,51229,45346,51231,51232,51233,51234,51235,39581,51237,51238,51239,39652,51241,51242,51243,38964,51245,51246,51247,51248,51249,49365,50704,51252,46601,51254,51255,51256,51257,51258,39487,51260,51261,51262,51263,51264,51265,39033,51267,51268,51269,51270,51271,51272,51273,51274,51275,51276,51277,48354,51279,51280,51281,51282,51283,41747,51285,51286,51287,51288,51289,51290,41818,51292,51293,51294,49527,51296,51297,51298,51299,39801,51301,51302,51303,51304,51305,51306,51307,40016,51309,51310,51311,51312,51313,41074,51315,51316,51317,51318,51319,51320,41100,51322,51323,51324,51325,51326,51327,42910,51329,51330,51331,51332,51333,51334,51335,51336,51337,51338,51339,46545,51341,51342,51343,51344,51345,51346,51347,51348,48509,51350,51351,51352,38894,40126,51355,51356,51357,51358,51359,51360,51361,51362,51363,51364,51365,51366,51367,51368,43579,51370,51371,51372,51373,51374,51375,51376,51377,51378,41708,51380,42672,51382,51383,38606,51385,51386,39696,51388,51389,51390,51391,51392,51393,51394,51395,51396,48862,51398,41031,51400,51401,51402,51403,51404,41044,51406,51229,43699,51409,51410,51411,51412,51413,51414,46532,51416,38928,51418,51419,51420,39610,51422,51423,51424,51425,51426,51427,51428,51429,39743,51431,40405,51433,51434,51435,51436,51437,51438,51439,41773,51441,51442,51443,51444,51445,51446,51447,51448,51449,40843,51451,51452,51453,51454,51455,51456,51457,51458,51459,40738,51461,47280,51463,39474,51465,51466,51467,51468,51469,42996,51471,51472,51473,51474,51475,41369,51477,51478,51479,51480,51481,51482,51483,46138,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,39408,51497,51498,51499,42902,51501,46958,51503,51504,51505,51506,51507,51508,51509,51510,51511,45746,51513,51514,51515,43540,41686,51518,51519,51520,51521,51522,51523,51524,39209,51526,51527,51528,39160,51530,51531,51532,51533,51534,44496,51536,51537,51538,51539,51540,51541,51542,51543,51544,51545,51546,51547,39230,51549,50251,39271,51552,51553,51554,51555,51556,51557,41738,51559,44807,51561,51562,51563,51564,51565,51566,51567,51568,51569,51570,51571,51572,51573,51574,39906,51576,51577,51578,51579,51580,51581,51582,49945,51584,41920,51586,51587,51588,51589,51590,51591,51592,51593,51594,41770,51596,51597,51598,51599,51600,51601,51602,51603,51604,51605,51606,45502,51608,51609,51610,51611,51612,40137,51614,46553,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,42293,51629,51630,51631,51632,51633,51634,51635,51636,39413,51638,47471,51640,51641,51642,51643,44928,51645,51646,51647,51648,51649,51650,51651,51652,50273,51654,51655,51656,51657,51658,51659,41771,51661,51662,51663,51664,51665,51666,51667,51668,51669,51670,45517,51672,51673,51674,51675,51676,51677,51678,51679,51680,51681,44780,51386,51684,51685,51686,45294,51688,51689,51690,51691,51692,51693,51694,47045,51696,51697,51698,51699,51700,51701,51702,51703,48256,51705,51706,51707,51708,51709,51710,51711,51712,51713,51714,51715,42875,51717,51718,51719,51720,51721,39196,51723,51724,51725,51726,51727,41914,51729,51730,48278,51732,51733,51734,51735,51736,51737,51738,38936,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,51750,51751,50853,51753,51754,39747,51756,51757,51758,41922,51760,51761,51762,51763,43549,51765,51766,51767,51768,51769,51770,39526,51772,51773,51774,51775,51776,51777,39089,51779,51780,51781,41761,51783,51784,51785,51786,51787,51788,51789,51790,51791,51792,39939,51794,51795,51796,51797,51798,51799,51800,43594,51802,51803,51804,51805,51806,51807,44514,51809,51810,46859,51812,51813,51814,51815,51816,51817,51818,51819,38582,51821,51822,50252,43329,51825,51826,51827,51828,51829,39502,51831,51832,51833,39516,51835,51836,51837,51838,51839,43984,51841,51842,51843,51844,39089,51846,51847,51848,51849,51850,51851,41294,51853,51854,51855,51856,51857,51858,51859,51860,51861,40689,51863,51864,51865,43399,51867,51868,45444,51870,42606,51872,51873,51874,51875,44759,51877,51878,51879,51880,51881,51882,51883,51884,51885,51886,40016,51888,51889,44731,51891,51892,51893,51894,51895,51896,51897,51898,51899,51900,51901,38816,51903,51904,51905,51906,51907,51908,51909,51910,51911,51912,51913,38564,51915,51916,51917,51918,51919,51920,51921,51922,51923,51924,51925,51926,51927,51928,51929,51930,51931,51932,51933,51934,51935,51936,51937,51938,51939,51940,51941,51942,51943,51944,51945,49973,51947,51948,51949,51950,50812,44897,51953,51954,51955,51956,50200,51958,51959,51960,51961,51962,51963,51964,46463,51966,51967,51968,51969,51970,51971,51972,51973,51974,46958,51976,51977,50492,51979,51980,51981,51982,42932,51984,51985,45496,51987,51988,51989,51990,51991,51992,42076,39196,51995,51996,51997,51998,41068,44584,52001,52002,39524,52004,52005,52006,52007,52008,52009,47996,40658,52012,52013,52014,48778,52016,52017,52018,52019,52020,52021,40517,45263,52024,52025,52026,40543,39453,46602,52030,52031,52032,39706,52034,52035,52036,43754,52038,52039,52040,52041,52042,52043,52044,52045,52046,49413,52048,47699,52050,52051,52052,51616,52054,52055,52056,52057,52058,52059,52060,52061,52062,52063,52064,52065,40688,52067,52068,52069,48071,52071,52072,52073,45326,52075,52076,52077,50027,52079,52080,52081,52082,52083,39605,52085,52086,47338,52088,52089,52090,43835,50029,52093,52094,43701,52096,52097,52098,52099,52100,50800,52102,52103,52104,45263,52106,52107,52108,52109,52110,43146,52112,52113,40312,52115,52116,52117,52118,52119,52120,52121,39844,52123,52124,52125,48970,52127,52128,52129,52130,52131,42187,52133,52134,52135,52136,52137,39282,52139,52140,52141,52142,52143,43184,52145,52146,52147,52148,52149,52150,52151,52152,52153,52154,52155,42598,52157,52158,52159,52160,52161,52162,52163,52164,52165,52166,52167,52168,42073,52170,52171,52172,52173,48411,52175,52176,52177,52178,52179,52180,41069,39357,52183,52184,52185,52186,52187,52188,42912,52190,52191,52192,52193,52194,52195,52196,52197,52198,52199,52200,39200,52202,52203,52204,52205,52206,52207,51785,52209,52210,52211,42938,52213,52214,52215,52216,52217,52218,52219,52220,52221,52222,52223,52224,52225,52226,42608,52228,52229,52230,52231,52232,44768,52234,39437,52236,52237,52238,52239,52240,52241,46006,52243,52244,52245,52246,39004,52248,52249,44641,52251,52252,52253,39492,52255,42042,52257,52258,52259,52260,52261,52262,52263,52264,52265,46761,52267,52268,52269,52270,52271,52272,52273,52274,41074,52276,52277,52278,52279,45750,52281,52282,44004,52284,52285,52286,52287,52288,52289,52290,45237,52292,40700,40860,52295,52296,52297,52298,52299,52300,52301,52302,52303,42257,52305,52306,52307,52308,52309,52310,52311,52312,52313,52314,52315,52316,47462,52318,52319,52320,52321,52322,52323,52324,52325,52326,52327,52328,43263,52330,52331,43590,52333,52334,52335,52336,52337,52338,52339,44246,52341,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,38930,52359,52360,39737,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,48155,52373,52374,52375,52376,52377,52378,52379,52380,52381,52382,52383,52384,52385,52386,52387,52388,52389,52390,52391,52392,52393,52394,52395,52396,52397,52398,52399,52400,52401,52402,52403,51247,52405,52406,40552,52408,52409,52410,52411,52412,52413,52414,39247,52416,52417,52418,52419,52420,52421,52422,52423,41007,52425,52426,52427,52428,52429,52430,52431,52432,52433,52434,52435,40081,52437,52438,40762,52440,52441,52442,52443,40776,52445,52446,52447,52448,52449,52450,52451,52452,39569,52454,52455,52456,52457,52458,52459,52460,52461,52462,52463,46412,52465,41554,52467,52468,52469,52470,52471,45379,52473,52474,52475,52476,52477,52478,52479,52480,52481,46959,39993,52484,52485,41777,52487,52488,52489,52490,46965,52492,47699,52494,52495,52496,52497,52498,52499,52500,39327,52502,52503,52504,52505,52506,52507,52508,45573,52510,52511,52512,52513,52514,52515,42960,52517,52518,38504,52520,52521,52522,52523,38549,52525,52526,52527,52528,52529,39252,52531,52532,52533,47013,52535,52536,52537,52538,52539,52540,51698,52542,52543,52544,52545,52546,52547,48867,52549,52550,52551,52552,48272,39583,52555,52556,52557,52558,52559,52560,52561,50996,52563,52564,46177,52566,52567,52568,52569,52570,52571,52572,52573,52574,39927,52576,52577,52578,52579,52580,52581,52582,52583,52584,52585,52586,52587,52588,52589,52590,52591,52592,52593,52594,52595,52596,52597,52598,52599,52600,52601,52602,52603,52604,52605,52606,52607,52608,52609,52610,52611,52612,52613,52614,52615,52616,52617,52618,52619,52620,52621,52622,52623,41587,52625,40845,52627,52628,52629,52630,52631,52632,52633,52634,39116,52636,52637,52638,52639,52640,52641,44117,52643,52644,52645,52646,52647,52648,52649,52650,52651,52652,43677,52654,52655,45844,52657,44730,52659,52660,52661,52662,52663,52664,52665,52666,41708,52668,52669,52670,40978,52672,52673,52674,52675,52676,49245,52678,52679,52680,39249,52682,52683,52684,52685,52686,44341,52688,52689,52690,52691,41352,52693,52694,52695,52696,52697,52698,38712,52700,52701,52702,52703,52704,52705,52706,52707,52708,52709,52710,52711,48272,39098,52714,52715,52716,52717,40809,52719,52720,52721,52722,52723,52724,52725,52726,52727,52728,52729,52730,52731,39927,52733,43262,52735,47973,52737,52738,52739,52740,41834,52742,43541,52744,52745,43464,52747,52748,52749,52750,52751,52752,47072,52754,52755,52756,52757,52758,42294,52760,52761,52762,52763,43071,52765,51009,52767,52768,52769,52770,42663,52772,52773,49491,52775,52776,52777,52778,52779,52780,38595,52782,52783,46883,52785,52786,52787,52788,52789,52790,52791,52792,52793,52794,52795,52796,46101,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,47152,52810,52811,48079,41117,52814,52815,52816,52817,52818,52819,52820,52821,52822,45205,52748,52825,52826,52827,52828,42106,52830,52659,52832,52833,52834,52835,52836,44238,52838,52839,43414,52841,52842,52843,52844,52845,47863,52847,52848,52849,52850,52851,52852,52853,52854,52855,52856,40426,52858,52859,38851,45516,52862,52863,48727,49998,52866,39260,52868,52869,41016,52871,52872,52873,52874,52875,52876,52877,52878,52700,52880,52881,52882,46478,52884,44564,52886,52887,50501,52889,52890,52891,52892,52893,52894,52895,52896,52897,48682,52899,52900,52901,52902,52903,52904,52905,52906,52907,52908,52909,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,52923,52924,52925,52926,52927,52928,52929,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,43927,52942,52943,52944,39091,52946,48809,52948,52949,41773,52951,52952,52953,52954,38834,52956,52957,52958,52959,52960,40458,52962,52963,52964,52965,39816,52967,52968,52969,52970,52971,52523,52973,38554,52975,52976,52977,52978,52979,52980,52981,52982,48187,52984,52985,52986,50365,52988,52989,40590,52991,52992,52993,52994,52995,52996,52441,52998,52999,53000,53001,48055,53003,53004,53005,53006,53007,53008,53009,53010,53011,53012,46831,53014,53015,53016,53017,53018,53019,53020,47886,53022,40123,53024,53025,53026,53027,53028,40505,53030,53031,53032,53033,53034,53035,43433,53037,53038,53039,47427,53041,53042,44818,53044,53045,53046,53047,53048,53049,53050,53051,53052,53053,49912,53055,53056,53057,46963,53059,53060,47370,53062,46840,53064,53065,53066,53067,53068,53069,53070,53071,53072,45082,53074,53075,53076,53077,41142,53079,53080,53081,53082,53083,53084,45797,53086,53087,53088,45806,53090,53091,53092,53093,53094,53095,39266,53097,53098,53099,53100,38687,53102,53103,53104,53105,53106,53107,53108,53109,53110,53111,53112,41043,53114,45846,42113,53117,53118,53119,44584,53121,53122,53123,53124,53125,53126,46333,44110,53129,53130,53131,53132,53133,53134,39373,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,39211,53147,53148,53149,53150,53151,53152,53153,53154,53155,44475,53157,53158,53159,53160,53161,38734,46969,53164,53165,53166,53167,53168,53169,53170,53171,53172,53173,53174,53175,53176,53177,47434,51380,53180,40036,53182,53183,53184,53087,49607,53187,53188,53189,53190,53191,53192,53193,53194,51696,53196,53197,53198,53199,49106,53201,53202,45433,53204,53205,53206,53207,53208,53209,53210,53211,50877,42403,53214,53215,53216,53217,53218,53219,53220,53221,50966,41053,53224,53225,53226,53227,53228,53229,53230,53231,53232,41069,48542,53235,44090,53237,43422,53239,53240,53241,53242,53243,53244,46425,53246,45724,53248,39652,53250,53251,53252,40547,53254,53255,53256,53257,53258,53259,53260,53261,53262,42976,53264,53265,45806,53267,53268,53269,53270,53271,53272,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,47039,53285,53286,53287,53288,53289,53290,53291,53292,53293,39502,53295,53296,53297,53298,53299,53300,53301,50624,53303,53304,53305,53306,53307,41744,53309,53310,53311,53312,53313,53314,53315,53316,53317,53318,53319,53320,53321,53322,48072,52833,41931,53326,53327,53328,53329,39074,53331,53332,53333,53334,50220,53336,47972,53338,53339,53340,43032,53342,53343,53344,41320,53346,40121,41920,53349,40506,53351,53352,53353,53354,53355,53356,46209,53358,53359,53360,53361,53362,53363,53364,42150,53366,53367,40543,49689,53370,53371,53372,53373,53374,53375,45405,53377,53378,53379,53380,53381,41521,53383,53384,53385,53386,53387,53388,53389,48055,53391,53392,53393,53394,53395,53396,53397,53398,53399,53400,53401,53402,44224,53404,53405,39103,53407,53408,53409,53410,53411,53412,53413,53414,53415,53416,53417,50866,53419,53420,53421,53017,53423,53424,53425,53426,53427,53428,39927,53430,53431,53432,53433,53434,53435,53436,53437,39765,53439,53440,53441,53442,53443,53444,53445,53446,53447,42381,41320,53450,46688,53452,53453,53454,53455,53456,53457,53458,40533,53460,53461,40537,53463,40040,53465,38604,53467,53468,53469,53470,53471,45035,53473,53474,53475,53476,53477,53478,41031,53480,53481,53482,53483,53484,53485,53486,51967,53488,53489,53490,53491,53492,53493,41609,39543,53496,53497,41929,53499,53500,53501,53502,53503,53504,48621,53506,53507,53508,53509,53510,53511,53512,53513,53514,53515,53516,43012,47863,53519,53520,53521,53522,53523,53524,53525,53526,53527,40834,53529,53530,53531,53532,43360,53534,53535,53536,45741,47972,53539,53540,53541,53542,53543,53544,53545,42644,53547,42078,51681,46715,53551,53552,42969,53554,53555,53556,53557,53558,50803,53560,53561,53562,53563,53564,53565,53566,51260,53568,53569,53570,53571,53572,42042,53574,53575,42056,53577,53578,53579,53580,53581,53582,53583,53584,53585,53586,43012,50074,53589,42914,53591,53592,53593,48896,46371,53596,53597,53598,53599,43367,53601,53602,53603,48528,53605,53606,53607,43926,53609,53610,53611,53612,53613,53614,40846,53616,53617,53618,39800,53620,53621,53622,53623,53624,53625,53626,53627,53628,53629,53630,40016,53632,53633,53634,53635,49077,40025,53638,38982,53640,44638,53642,53643,53644,53645,42570,53647,53648,53649,53650,53651,42044,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,39305,53664,53665,53666,53667,53668,53669,53670,53671,53672,53673,53674,52744,46142,53677,53678,53679,53680,53681,53682,53683,53684,53685,38741,53687,53688,53689,53690,44237,53692,53693,53694,39372,53696,53697,40128,53699,53700,53701,53702,53703,53704,41111,53706,53707,53708,53709,53710,53711,53712,53713,53714,53715,53716,53717,53718,53719,53720,53721,52059,53723,53724,38812,53726,53727,53728,53729,53730,53731,53732,53733,43983,53735,53736,53737,53738,47203,53740,53741,47604,53743,53744,53745,53746,44120,53748,53749,53750,53751,53752,38836,53754,53755,53756,53757,53758,53759,53760,53761,39815,53763,53764,38513,53766,53767,53768,53769,53770,53771,39013,53773,53774,53775,53776,53777,53778,53779,53780,41514,47045,53783,53784,45549,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,49867,53800,53801,53802,47963,53804,53805,41591,48075,53808,39738,52334,53811,53812,53813,53814,53815,49047,53817,42932,53819,53820,53821,53822,53823,53824,51193,53826,53827,53828,53829,53830,53831,53832,47614,53834,53835,53836,43564,43592,53839,53840,53841,53842,49034,53844,53845,53846,53847,53848,53849,53850,53851,42100,53853,45267,53855,38964,53857,53858,46589,53860,53861,46601,53863,53864,42038,53866,43752,53868,53869,53870,53871,53872,53873,53874,40615,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53888,45876,53890,53891,53892,39342,53894,53895,53896,53897,53898,53899,53900,41773,53902,53903,53904,53905,53906,53907,53908,40730,39983,53911,53912,53913,40732,53915,53916,53917,53918,53919,53920,53921,49534,53923,53924,53925,53926,53927,42785,53929,39589,53931,43094,44015,53934,49360,53936,53937,41482,53939,53940,53941,53942,53943,53944,53945,53946,42170,53948,53949,53950,53951,40327,53953,53954,53955,53956,45418,53958,53959,53960,53961,53962,53963,53964,53965,53966,53967,40091,46615,53970,53971,53972,53973,53974,43185,53976,53977,53978,53979,53980,53981,53982,53983,53984,53985,53986,53987,52173,53989,41400,53991,53992,53993,53994,53995,53996,53997,53998,53999,54000,46133,49269,39590,54004,54005,54006,54007,54008,54009,54010,54011,54012,54013,52306,54015,54016,54017,54018,54019,54020,54021,43925,54023,54024,54025,54026,54027,45186,54029,53916,54031,54032,54033,54034,54035,54036,54037,39800,54039,54040,54041,54042,54043,54044,53346,54046,54047,47709,54049,53470,54051,54052,47017,54054,54055,54056,54057,54058,54059,54060,54061,40593,54063,54064,54065,54066,54067,54068,54069,54070,40786,54072,54073,54074,54075,54076,54077,54078,54079,54080,54081,54082,46111,54084,54085,54086,54087,41545,54089,54090,54091,54092,42106,54094,54095,54096,54097,54098,47863,54100,54101,54102,54103,54104,54105,47243,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,53633,54118,47573,44200,54121,54122,54123,39162,54125,54126,54127,45337,39908,54130,54131,54132,54133,54134,54135,44930,54137,54138,54139,52470,54141,54142,54143,54144,54145,54146,54147,52473,54149,54150,54151,54152,54153,54154,54155,54156,54157,53359,54159,42000,40302,54162,54163,54164,54165,54166,54167,54168,48739,38999,54171,54172,54173,54174,54175,39863,54177,54178,54179,54180,54181,54182,54183,54184,54185,54186,42189,47731,54189,54190,54191,54192,54193,54194,54195,45549,54197,54198,54199,43414,54201,54202,44548,54204,54205,51900,41435,54208,54209,54210,54211,54212,44224,54214,54215,54216,54217,54218,54219,49907,54221,54222,54223,54224,54225,40688,54227,54228,54229,54230,54231,54232,54233,40846,54235,54236,54237,54238,52157,54240,54241,54242,54243,54244,45337,42533,54247,54248,54249,54250,54251,54252,46332,54254,54255,54256,54257,54258,54259,54260,54261,54262,54263,38574,54265,54266,54267,54268,54269,54270,54271,54272,54273,54274,54275,54276,54277,54278,54279,54280,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,54295,54296,54297,54298,54299,54300,54301,54302,44020,54304,54305,50704,54307,54308,54309,54310,54311,54312,54313,46606,54315,54316,41013,54318,54319,54320,54321,54322,54322,52440,54325,54326,54327,54328,54329,54330,43345,54332,54333,54334,54335,54336,54337,54338,54339,54340,54341,54342,54343,54344,54337,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,54356,39581,54358,54359,54360,40402,54362,54363,54364,54365,53218,38938,54368,54369,54370,54371,54372,54373,54374,54375,54376,54377,54378,54379,51103,45760,54382,52171,54384,51901,44251,54387,54388,54389,54390,54391,54392,54393,54394,54395,52335,54397,54398,54399,54400,54401,52158,54403,54404,54405,54406,54407,42512,54409,54410,54411,45111,54413,54414,54415,54416,54417,54418,54419,54420,38770,54422,54423,38511,54425,54426,54427,54428,54429,54430,54431,54432,54433,54434,54435,47271,54437,54438,54439,54440,46854,54442,39473,54444,54445,43630,38673,54448,54449,54450,54451,54452,54453,54454,54455,54456,54457,54458,54459,43176,54461,54462,54463,54464,54465,54466,54467,54468,47154,54470,54471,54472,54473,54474,54475,54476,50128,54478,54479,41400,54481,54482,54483,54484,54485,54486,54487,54488,54489,54490,54491,41139,48894,54494,40441,54496,54497,54498,54499,54500,50861,54502,39765,54504,54505,54506,54507,54508,54509,54510,51322,54512,54513,54514,54515,54516,49867,54518,54519,39993,54521,54522,54523,54524,51088,45336,48168,54528,54529,54530,54531,54532,47709,54534,54535,54536,54537,54538,54539,41332,54541,54542,54543,54544,54545,54546,54547,54548,43309,54550,54551,54552,44897,54554,54555,54556,50620,54558,54559,54560,54561,54562,54563,54564,54565,54566,46958,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,50313,54584,54585,46378,44702,54588,54589,54590,54591,54592,54593,54594,54595,54596,54597,38844,54599,54600,48320,46310,54603,54604,54605,54606,54607,54608,54609,54610,54611,54612,54613,54614,54615,54616,46524,54618,54619,54620,44090,54622,48516,54624,54625,54626,54627,54628,54629,54630,39552,54632,54633,54634,54635,51542,54637,54638,54639,54640,54641,54642,54643,54644,54645,54646,54647,54648,54649,44515,54651,38581,54653,54654,54655,54656,54657,54658,54659,54660,54661,54662,49368,54664,54665,54666,54667,51552,54669,54670,54671,54672,54673,54674,41031,54676,54677,54678,54679,54680,54681,54682,54683,48255,54685,41969,54687,54688,54689,54690,40124,54692,54693,52719,54695,54696,54697,54698,54699,54700,54701,54702,54236,54704,54705,54706,54707,54708,54709,48771,54711,45504,54713,54714,54715,54716,54717,54718,44759,54720,54721,54722,54723,54724,54725,54726,54727,54728,54729,54730,52187,54732,46807,54734,54735,54736,54737,54738,54739,42244,54741,42390,54743,54744,54745,54746,39595,54748,54749,54750,41993,54752,54753,54754,40981,54756,54757,54758,54759,46864,54761,54762,54763,54764,54765,54766,54767,54768,54769,54770,54771,54772,54773,54774,54775,54776,54777,54778,54779,54780,54781,51152,54783,54784,54785,54786,54787,42688,54789,54790,54791,48861,39877,54794,54795,54796,54797,41743,54799,54800,54801,54802,54803,43801,38792,54806,52643,54808,54809,54810,54811,54812,54813,52173,42094,54816,49003,54818,54819,54820,54821,54822,54823,54824,54825,40636,54827,54828,54829,54830,54831,54832,39370,54834,54835,54836,39211,54838,54839,54840,54841,54842,54843,39765,54845,54846,54847,54848,54849,54850,54851,54852,54853,54854,54855,54856,52750,54858,54859,54860,39232,54862,54863,54864,46854,54866,54867,51021,54869,54870,54871,54872,45423,54874,54875,42362,54877,54878,54879,54880,38718,54882,49223,54884,54885,54886,54887,54888,54889,54890,54891,46177,54893,54894,54895,54896,54897,45326,54899,54900,54901,54902,54903,54904,54905,54906,39927,54908,54909,54910,54911,43231,54913,54914,54915,54916,54917,54918,54919,54920,54921,52359,54923,54924,54925,44566,39141,54928,54929,54930,54931,54932,54933,54934,54935,54936,54937,54938,54939,54940,54941,54942,54943,54944,54945,54946,54947,54948,54949,54950,54951,54952,54953,54954,54955,54956,54957,54958,54959,54960,54961,54962,54963,54964,54965,54966,54967,54968,54969,54970,54971,54972,54973,54974,54975,54976,54977,54978,54979,54980,54981,54982,54983,54984,54985,54986,54987,54988,54989,54990,54991,54992,54993,54994,54995,54996,54997,52157,54999,55000,55001,45206,55003,55004,55005,55006,41974,55008,55009,55010,55011,55012,43219,55014,55015,55016,55017,55018,55019,55020,55021,55022,55023,47796,55025,42661,55027,55028,55029,38515,55031,55032,45290,39256,55035,55036,55037,55038,55039,55040,55041,47039,55043,55044,55045,55046,55047,55048,55049,54072,55051,55052,55053,49193,55055,55056,55057,55058,55059,39917,55061,55062,50278,55064,55065,55066,55067,55068,55069,42950,55071,55072,55073,55074,44573,55076,38853,54041,55079,55080,55081,55082,55083,40019,45844,55086,48281,55088,55089,55090,55091,55092,55093,46968,45391,55096,55097,44514,55099,55100,53860,55102,55103,55104,55105,55106,52030,55108,55109,55110,55111,55112,42039,55114,49095,55116,55117,55118,55119,55120,47645,55122,55123,55124,55125,55126,55127,55128,55129,55130,55131,55132,54197,55134,55135,55136,55137,55138,55139,39958,52833,55142,55143,55144,55145,55146,55147,55148,53531,55150,55151,55152,55153,55154,55155,55156,55157,44410,55159,55160,55161,55162,48367,55164,55165,55166,55167,55168,55169,55170,55171,55172,46657,55174,40645,55176,55177,55178,55179,55180,47359,55182,55183,55184,38756,55186,55187,55188,55189,54046,40464,55192,55193,39815,55195,55196,38513,52410,55199,55200,55201,54550,55203,55204,55205,55206,55207,55208,55209,55210,55211,55212,53295,55214,55215,55216,55217,55218,39514,55220,55221,55222,55223,55224,55225,55226,55227,50767,55229,55230,55231,43415,55233,55234,55235,55236,55237,39995,55239,55240,55241,55242,41304,55244,55245,55246,55247,46413,55249,39327,55251,55252,55253,55254,55255,55256,41116,55258,55259,38896,51995,55262,55263,55264,55265,55266,48389,55268,55269,55270,55271,55272,55273,55274,51441,55276,39815,55278,55279,55280,55281,39437,55283,55284,42970,55286,55287,55288,42342,55290,55291,55292,55293,55294,55295,44892,55297,55298,55299,50197,55301,55302,55303,55304,55305,55306,51966,55308,55309,55310,55311,55312,55313,55314,55315,40617,55317,55318,55319,55320,55321,55322,55323,55324,55325,55326,55327,55328,48758,55330,55331,55332,55333,55334,55335,55336,55337,55338,55339,55340,48507,55342,55343,55344,47700,55346,55347,55348,41553,55350,55351,40509,55353,55354,55355,55356,55357,55358,55359,55360,39143,55362,55363,55364,55365,55366,55367,55368,55369,55370,55371,55372,55373,55374,55375,55376,52848,55378,55379,55380,55381,55382,55383,55384,51661,55386,55387,55388,55389,55390,55391,55392,54512,55394,55395,55396,55397,49277,44768,55400,55401,46578,55403,55404,47837,55406,55407,55408,55409,55410,55411,52782,45155,55414,55415,55416,55417,55418,55419,55420,55421,55422,55423,55424,55425,55426,55427,55428,55429,55430,55431,55432,55433,55434,55435,55436,55437,55438,55439,55440,55441,55442,55443,55444,55445,55446,55447,55448,55449,55450,55451,55452,55453,55454,55455,55456,55457,55458,55459,55460,55461,55462,55463,55464,55465,55466,55467,55468,55469,52441,55471,55472,55473,47400,55475,55476,55477,55478,55479,55480,55481,55482,46462,55484,55485,55486,44421,55488,55489,55490,55491,55492,55493,55494,39370,55496,55497,38928,55499,55500,55501,55502,55503,55504,52754,55506,55507,55508,44392,55510,55511,55512,55513,51103,55515,50486,55517,55518,52080,55520,55521,55522,55523,55524,49146,55526,55527,55528,55529,47900,55531,42086,55533,39986,55535,48091,47592,55538,55539,55540,55541,55542,55543,55544,52018,55546,38834,55548,55549,41841,55551,55552,55553,55554,40980,55556,55557,55558,40750,55560,55561,55562,43861,55564,55565,55566,55567,40062,55569,55570,55571,55572,55573,55574,54452,55576,55577,55578,55579,47138,55581,55582,55583,55584,55585,55586,55587,55588,55589,39892,55591,55592,55593,44458,38935,55596,55597,41094,55599,43012,45741,41429,55603,55604,55605,55606,55607,39581,55609,55610,39958,43043,55613,55614,55615,55616,55617,47088,55619,55620,55621,45516,55623,55624,55625,52238,55627,55628,55629,55630,46443,46879,55633,55634,55635,55636,55637,55638,55639,55640,55641,55642,42040,53105,55645,55646,55647,55648,55649,55650,55651,41045,45846,39591,55655,55656,55657,55658,55659,55660,55661,55662,55663,55664,55665,55666,55667,43087,55669,55670,55671,55672,55673,55674,55675,55676,43927,55678,55679,43015,55681,55682,55683,55684,55685,44616,55687,55688,55689,55690,55691,43267,44549,55694,44730,55696,55697,51903,55699,55700,55701,55702,55703,55704,55705,55706,55707,55708,55709,55710,55711,55712,55713,55714,55715,55716,55717,43540,55719,45516,55721,55722,55723,55724,55725,55726,55727,47003,55729,48197,55731,55732,55733,55734,54063,55736,55737,55738,55739,55740,55741,55742,44670,55744,55745,55746,55747,55748,55749,55750,55751,55752,55753,48917,55755,55756,55757,55758,46255,55760,51086,40872,55763,55764,55765,55766,55767,55768,55769,43394,55771,55772,55773,55774,55775,54494,38844,55778,55779,44763,55781,55782,55783,55784,42926,55786,45845,48275,55789,55790,55791,55792,55793,55794,55795,46166,55797,55798,55799,41982,55801,55802,55803,55804,55805,55806,55807,50330,55809,46579,55811,55812,55813,55814,36053,55816,55817,55818,55819,55820,55821,55822,55823,55824,55825,55826,55827,55828,55829,55830,55831,55832,55833,55834,55835,55836,55837,55838,55839,55840,55841,55842,55843,55844,55845,55846,55847,55848,55849,55850,55851,55852,55853,55854,55855,55856,55857,55858,55859,55860,55861,55862,55863,55864,55865,55866,55867,55868,55869,55870,55871,55872,55873,55874,55875,55876,55877,55878,55879,55880,55881,55882,55883,55884,55885,55886,55887,55888,55889,55890,55891,55892,55893,55894,55895,55896,55897,55898,55899,55900,55901,55902,55903,55904,55905,55906,55907,55908,55909,55910,55911,55912,55913,55914,55915,55916,55917,55918,55919,55920,55921,55922,55923,55924,55925,55926,55927,55928,55929,55930,55931,55932,55933,55934,55935,55858,55937,55938,55939,55940,55941,55942,55943,55944,55945,55946,55947,55948,55949,55950,55951,55952,55953,55954,55955,55956,55957,55958,55959,55960,55961,55962,55963,55964,55965,55966,55967,55968,55969,55970,55971,55972,55973,55974,55975,55976,55977,55978,55979,55980,55981,55982,55983,55984,55985,55986,55987,55988,55989,55990,55991,55992,55993,55994,55995,55996,55997,55998,55999,56000,56001,56002,56003,56004,56005,56006,56007,56008,56009,56010,56011,56012,56013,56014,56015,56016,56017,56018,56019,56020,56021,56022,56023,56024,56025,56026,56027,56028,55960,56030,56031,56032,56033,56034,56035,56036,56037,56038,56039,56040,56041,56042,56043,56044,56045,56046,56047,56048,56049,56050,56051,56052,55853,56054,56055,56056,56057,56058,56059,56060,56061,56062,56063,56064,56065,56066,56067,56068,56069,56070,56071,56072,56073,56074,56075,56076,56077,56078,56079,56080,56081,56082,56083,56084,56085,56086,56087,56088,56089,56090,56091,56092,56093,56094,56095,56096,56097,56098,56099,56100,56101,56102,56103,56104,56105,56106,56107,56108,56109,56110,56111,56112,56113,56114,56115,56116,56117,56118,56119,56120,56121,56122,56123,56124,56125,56126,56127,56128,56129,56130,56131,56132,56133,56134,56135,56136,56137,56138,56139,56140,56128,56142,56143,56144,56145,56146,56147,56148,56149,56082,56151,56152,56153,56154,56155,56156,56157,56158,56159,56160,56161,56162,56163,56164,56165,56166,56167,56168,56169,56170,56171,56172,56173,56174,56175,56176,56177,56178,56179,56180,56181,56182,56183,56184,56185,56186,56187,56188,56189,56190,56191,56192,56193,56194,56195,56196,56197,56198,56199,56200,56201,56202,56155,56204,56205,56206,56207,56208,56209,56210,56211,56212,56213,56214,56215,56216,56217,56218,56219,56220,56221,56222,56223,56224,56225,56226,56227,56228,56229,56230,56231,56232,56233,56234,56235,56236,56237,56238,56239,56240,56241,56242,56243,56244,56245,56246,56247,56248,56249,56250,56251,56252,56253,56254,56151,56256,56257,56258,56259,56260,56261,56262,56263,56264,56265,56266,56267,56268,56269,56270,56271,56272,56273,56274,56275,56276,56277,56278,56279,56280,56281,56282,56283,56284,56285,56286,56287,56288,56289,56290,56291,56292,56293,56294,56295,56296,56297,56298,56299,56300,56301,56302,56303,56304,56305,56306,56307,56308,56309,56310,56259,56312,56313,56314,56315,56316,56317,56318,56319,56320,56321,56322,56323,56324,56325,56326,56327,56328,56329,56330,56331,56332,56333,56334,56335,56336,56337,56338,56339,56340,56341,56342,56343,56344,56345,56058,56347,56348,56349,56350,56351,56352,56353,56354,56355,56356,56357,56358,56359,56360,56361,56362,56363,56364,56365,56366,56367,56368,56369,56370,56371,56372,56373,56374,56375,56376,56377,56378,56379,56380,56381,56382,56383,56384,56385,56386,56387,56388,56389,56390,56391,56392,56393,56394,56395,56396,56397,56398,56399,56400,56401,56402,56403,56404,56405,56406,56407,56408,56409,56410,56411,56412,56413,56414,56415,56416,56417,56418,56419,56420,56421,56422,56423,56424,56425,56426,56427,56428,56429,56430,56431,56432,56433,56434,56435,56436,56437,56438,56439,56440,56441,56442,56443,56444,56445,56446,56447,56448,56449,56450,56391,56452,56453,56454,56455,56456,56457,56458,56459,56460,56461,56462,56463,56464,56465,56466,56467,56468,56469,56470,56471,56472,56473,56474,56475,56476,56477,56478,56479,56480,56481,56482,56483,56484,56485,56486,56487,56488,56489,56490,56491,56492,56493,56494,56495,56496,56497,56498,56499,56500,56501,56502,56503,56504,56505,56506,56507,56508,56471,56510,56511,56512,56513,56514,56515,56375,56517,56518,56519,56520,56521,56522,56523,56524,56525,56526,56527,56528,56529,56530,56531,56532,56533,56534,56535,56536,56537,56538,56539,56540,56541,56542,56543,56544,56545,56546,56547,56548,56549,56550,56551,56552,56553,56554,56555,56556,56557,56558,56559,56560,56561,56562,56563,56564,56565,56566,56567,56568,56569,56570,56571,56572,56573,56574,56575,56576,56577,56370,56579,56580,56581,56582,56583,56584,56585,56586,56587,56588,56589,56590,56591,56592,56593,56594,56595,56596,56597,56598,56599,56600,56601,56602,56603,56604,56605,56606,56607,56608,56609,56610,56611,56612,56613,56614,56615,56616,56617,56618,56619,56620,56621,56622,56623,56624,56625,56626,56627,56628,56629,55837,56631,56632,56633,56634,56635,56636,56637,56638,56639,56640,56641,56642,56643,56644,56645,56646,56647,56648,56649,56650,56651,56652,56653,56654,56655,56656,56657,56658,56659,56660,56661,56662,56663,56664,56665,56666,56667,56668,56669,56670,56671,56672,56673,56674,56675,56676,56677,56678,56679,56680,56681,56682,56683,56684,56685,56686,56687,56688,56689,56690,56691,56692,56693,56694,56695,56696,56697,56698,56699,56700,56701,56702,56703,56704,56705,56706,56707,56708,56709,56710,56711,56712,56713,56714,56715,56716,56717,56718,56719,56720,56721,56722,56723,56724,56725,56726,56727,56728,56729,56730,56731,56732,56733,56645,56735,56736,56737,56738,56739,56740,56741,56742,56743,56744,56745,56746,56747,56748,56749,56750,56751,56752,56753,56754,56755,56756,56757,56758,56759,56760,56761,56762,56763,56764,56765,56766,56767,56768,56769,56770,56771,56772,56773,56774,56775,56776,56777,56778,56779,56780,56781,56782,56783,56784,56785,56786,56787,56788,56789,56790,56791,56792,56793,56794,56795,56796,56797,56798,56799,56800,56801,56802,56803,56804,56805,56806,56807,56808,56809,56810,56811,56812,56640,56814,56815,56816,56817,56818,56819,56820,56821,56822,56823,56824,56825,56826,56827,56828,56829,56830,56831,56832,56833,56834,56835,56836,56837,56838,56839,56840,56841,56842,56843,56844,56845,56846,56847,56848,56849,56850,56851,56852,56853,56854,56855,56856,56857,56858,56859,56860,56861,56862,56863,56864,56865,56866,56867,56868,56869,56870,56871,56872,56873,56874,56875,56876,56877,56878,56879,56880,56881,56882,56883,56884,56885,56886,56847,56888,56889,56890,56891,56892,56893,56894,56895,56896,56897,56898,56899,56900,56901,56902,56903,56904,56905,56906,56907,56908,56909,56910,56911,56912,56913,56914,56915,56916,56917,56918,56919,56920,56921,56922,56923,56924,56925,56926,56927,56928,56929,56930,56931,56932,56933,55826,56935,56936,56937,56938,56939,56940,56941,56942,56943,56944,56945,56946,56947,56948,56949,56950,56951,56952,56953,56954,56955,56956,56957,56958,56959,56960,56961,56962,56963,56964,56965,56966,56967,56968,56969,56970,56971,56972,56973,56974,56975,56976,56977,56978,56979,56980,56981,56982,56983,56984,56985,56986,56987,56988,56989,56990,56991,56992,56993,56994,56995,56996,56997,56998,56999,57000,57001,57002,57003,57004,57005,57006,57007,57008,57009,57010,57011,57012,57013,57014,57015,57016,57017,57018,57019,57020,57021,57022,57023,57024,57025,57026,57027,57028,57029,57030,57031,57032,57033,57034,57035,57036,57037,57038,57039,57040,56968,57042,57043,57044,57045,57046,57047,57048,57049,57050,57051,57052,57053,57054,57055,57056,57057,57058,57059,57060,57061,57062,57063,57064,57065,57066,57067,57068,57069,57070,57071,57072,57073,57074,57075,57076,57077,57078,57079,57080,57081,57082,56939,57084,57085,57086,57087,57088,57089,57090,57091,57092,57093,57094,57095,57096,57097,57098,57099,57100,57101,57102,57103,57104,57105,57106,57107,57108,57109,57110,57111,57112,57113,57114,57115,57116,57117,57118,57119,57120,57121,57122,57123,57124,57125,57126,57127,57128,57129,57130,57131,57132,57133,57134,57135,57136,57137,57138,57139,57140,57141,57142,57143,57144,57145,57146,57147,57148,57149,57150,57151,57152,57153,57154,57155,57156,57157,57158,57159,57160,57161,57162,57163,57164,57165,57166,57167,57168,57169,57170,57171,57172,57173,57174,57088,57176,57177,57178,57179,57180,57181,57182,57183,57184,57185,57186,57187,57188,57189,57190,57191,57192,57193,57194,57195,57196,57197,57198,57199,57200,57201,57202,57203,57204,57205,57206,57207,57208,57209,57210,57211,57212,57213,57214,57215,57216,57217,57218,57219,57220,57221,57222,57223,57224,57225,57226,57227,57228,57229,57230,57231,57232,57233,57234,57235,57236,57237,57238,57239,57240,57241,57242,57243,57244,57245,56935,57247,57248,57249,57250,57251,57252,57253,57254,57255,57256,57257,57258,57259,57260,57261,57262,57263,57264,57265,57266,57267,57268,57269,57270,57271,57272,57273,57274,57275,57276,57277,57278,57279,57280,57281,57282,57283,57284,57285,57286,57287,57288,57289,57290,57291,57292,57293,57294,57295,57296,57297,57298,57299,57300,57301,57302,57303,57304,57305,57306,57307,57308,57309,57310,57311,57312,57313,57314,57315,57316,57317,57318,57255,57320,57321,57322,57323,57324,57325,57326,57327,57328,57329,57330,57331,57332,57333,57334,57335,57336,57337,57338,57339,57340,57341,57342,57343,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57250,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57396,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,57532,57533,57534,57535,57536,57537,57538,57539,57540,122,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57553,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57658,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,35796,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,35914,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,14012,58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,3814,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58024,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58056,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58091,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58085,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58045,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,58190,58191,58192,58193,58194,58195,58196,58197,58198,58171,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58212,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58200,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58248,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,58284,58285,58286,58287,58288,58244,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58169,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58200,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58212,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58275,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58246,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58294,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58200,58434,58435,58326,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58354,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,58472,58473,58474,58475,58476,58477,58478,58342,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58370,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58294,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58238,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58180,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58220,58557,58558,58559,58560,58561,58562,58563,58564,58565,58566,58567,58568,58569,58570,58382,58572,58573,58574,58575,58576,58577,58578,58278,58580,58581,58582,58583,58584,58585,58393,58587,58588,58589,58590,58237,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,14132,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58627,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58657,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,14130,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58734,58755,58756,58757,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58757,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58756,58792,58793,58794,58795,58796,58797,58798,58799,58782,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58757,58813,58814,58792,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58804,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,58853,58854,58855,58856,58857,58858,58717,58860,58861,58862,58863,58864,58865,58866,58867,58822,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58847,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58630,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58674,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58687,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,58950,58951,58952,58953,58954,58725,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58763,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58775,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58737,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,58804,59010,59011,58787,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,58824,59029,59030,59031,59032,58847,59034,59035,59036,59037,58987,59039,59040,59041,59042,59043,59044,59045,59046,59047,59048,59049,59050,58776,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,58816,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,58836,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,58641,59094,59095,59096,58940,59098,59099,59100,59101,59102,59103,58735,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,58759,59128,59129,59130,59131,59132,59133,59134,59135,59136,58757,59138,59139,58794,59141,59142,59143,59144,59145,58805,59147,59148,59149,59150,59151,59152,58730,59154,59136,59156,59157,58757,59159,59160,59161,59162,59163,59164,59165,59166,59167,58798,59169,58806,59171,59172,59173,59174,59175,59176,59177,59178,58630,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,58658,59196,59197,59198,59199,59200,59201,59202,59203,59204,58928,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,58725,59220,59221,59222,59223,59224,59129,59226,58776,59228,58796,58847,59231,59232,59233,59234,59235,59236,59237,59238,59013,59240,59241,59242,59243,59244,59245,59246,59247,59248,59249,59250,59251,59252,59253,58881,59255,59256,59257,59258,59259,59084,59261,59262,59263,59264,59265,59266,58741,59268,59269,59270,59271,58787,59273,59274,59275,59276,59277,59278,59279,59280,59281,59282,59283,59284,58651,59286,59287,59288,59289,59290,59291,59292,59293,59294,59295,59296,59297,59298,59299,59300,59301,59302,59303,58692,59305,59306,59307,59308,59309,59310,58689,59312,59313,59314,59315,59316,59317,59318,59319,59320,58792,59322,59323,59324,59325,59326,58889,59328,59329,59330,59331,59332,59333,59334,59335,58734,59337,59338,59339,59340,59341,59342,59343,59344,59345,59346,58755,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,59362,59363,59364,59365,59366,59367,59368,59369,59370,59371,59372,59373,59374,59375,59376,59377,59378,59379,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,59408,59409,59410,59411,59412,59413,59414,59415,59416,59417,59418,59419,59420,59421,59422,59423,59424,59425,59426,59427,59428,59429,59430,59431,58847,59433,59434,59435,59436,59437,59438,58741,59440,59441,59442,59443,59444,59445,59446,59447,59448,58972,59450,59451,59452,59453,59454,59455,59456,59457,59458,59459,59460,59461,59462,59463,59464,59465,59466,59467,59468,59469,59470,59471,58790,59473,58794,59475,58757,59477,59478,59479,59480,59481,59482,59483,59484,59485,59486,59487,59488,59489,59490,59491,59492,59493,59349,59495,59496,59497,59498,59499,59500,59501,59502,59503,59504,59505,59506,58639,59508,59509,59510,59511,59512,59513,58677,59515,59516,59517,59518,59519,59520,59521,59522,59523,59524,59525,59526,59441,59528,59529,59530,59531,59532,59533,59534,59470,59536,59537,59538,59539,59540,59541,59542,59543,59544,59545,59546,59547,59548,59549,59550,59551,59552,59553,58790,59555,58793,59557,59558,59559,59560,59561,59562,59563,59564,59565,59566,59567,59568,59569,58844,59571,59572,59573,59574,59575,59576,59577,59578,59579,59580,58735,59582,59583,59584,59585,59586,59587,59588,59589,59590,59591,59592,59593,59594,59595,59596,59597,59598,58759,59600,59601,59602,59603,59604,58790,59606,58792,59608,59609,59610,59611,59612,59613,59614,59615,59616,59617,59034,59619,59620,59621,58911,59623,59624,59625,58949,59627,59628,59629,58725,59631,59632,59633,59634,59635,59636,59637,59638,59639,59640,59641,59642,59501,59644,59645,59646,59019,59648,59649,59650,58819,59652,59653,59654,59089,59656,59221,59658,59659,59601,59052,59662,59663,59664,59665,59666,59667,59668,59669,59670,59671,59672,59673,59000,59675,59676,59677,59678,59679,59680,59681,59682,59683,59684,59685,59686,59687,59688,58807,59690,59691,59692,59014,59694,59695,59696,59697,59698,59699,59700,59701,59702,59703,59704,59705,59706,59707,59708,59709,59296,59711,59712,59713,59714,59715,59716,59717,58660,59719,59720,59721,59722,59723,59724,59725,59726,59727,59728,59729,59730,58690,59732,59733,59734,59735,59736,59737,59738,59739,59740,59741,59742,59743,59744,59745,59746,59747,59748,59749,59750,59751,59752,59753,59754,59755,59756,59757,59758,59759,59760,59761,59762,59763,59764,59765,59766,59767,59768,59769,59770,59771,59772,59773,59774,59775,59142,59777,59778,59779,59780,59781,59036,58755,59784,59785,59786,59787,59788,59789,59790,59791,59792,59793,59794,59795,59796,59797,59798,58881,59800,59801,59802,59803,59804,59805,59806,59807,59041,59809,59810,59811,59812,59813,59814,59815,59816,59817,59818,59819,59443,59821,59822,59823,59824,59825,59826,59827,59130,59829,59830,59831,59832,59833,59834,59017,59836,59837,59838,59839,59840,59841,59842,59843,59844,59845,59846,59847,59848,59849,59850,59142,59852,59853,59056,59855,59856,59857,59858,59859,59860,59861,59862,59863,59864,59865,59866,59867,58643,59869,59870,59871,59872,58649,59874,59875,59876,59877,59878,59879,59880,59881,59882,59883,59884,59885,59886,59887,59888,59889,59890,58674,59892,59893,59894,59895,59896,59897,59898,59899,59900,59901,58934,59903,59904,59905,59906,59907,59908,59909,59910,59911,59912,59913,59914,59658,59916,59917,59918,59919,59667,59921,59922,59923,59924,59675,59926,59927,59928,59929,59930,59931,59932,59933,59934,59935,59936,59937,58832,59939,59940,59941,59942,59943,59944,59013,59946,59947,59948,59949,59950,59951,59952,59800,59954,59955,59956,59957,59329,59959,59444,59961,59962,59963,59964,59965,58801,59967,59968,59969,59970,59971,59972,59973,59974,59975,59836,59977,59978,59979,59980,59981,59982,59983,59984,59985,58651,59987,59988,59989,59990,59991,59992,59993,59994,59995,59996,59997,59998,59999,60000,60001,58936,60003,60004,60005,60006,60007,60008,60009,60010,60011,60012,59779,60014,60015,60016,60017,60018,60019,60020,60021,58729,60023,60024,60025,60026,60027,59129,60029,59505,60031,60032,60033,60034,60035,60036,60037,60038,60039,60040,58796,60042,59632,60044,60045,60046,60047,60048,60049,60050,60051,59478,60053,60054,59241,60056,60057,60058,60059,60060,59875,60062,60063,60064,60065,60066,60067,60068,60069,60070,60071,60072,60073,60074,60075,58677,60077,60078,60079,60080,60081,60082,60083,60084,60085,60086,60087,60088,60089,60090,60091,60092,60093,60094,58704,60096,60097,60098,60099,60100,60101,60102,60103,60104,60105,60106,60107,60108,60109,60110,60111,60112,60113,60114,59682,60116,60117,60118,60119,60120,60121,60122,60123,60124,59013,60126,60127,60128,60129,60130,60131,60132,60133,60134,60135,58818,60137,60138,60139,60140,60141,60142,60143,59232,60145,60146,60147,60148,60149,60150,60151,60152,60153,60154,60155,59584,60157,60158,60159,60160,60161,60162,60163,60164,60165,60166,60167,60168,60169,60170,60171,60172,58787,60174,60175,60176,60177,60178,60179,60180,60181,60182,60183,60184,59029,60186,60187,60188,60189,60190,58888,60192,60193,14350,60195,60196,60197,59991,60199,60200,60201,60202,60203,60204,60205,60206,60207,60208,59200,60210,60211,60212,60213,60214,60215,60216,60217,60218,59521,60220,60221,60222,60223,60224,60225,60226,60227,60228,60229,60230,60231,60232,60233,60234,60235,60236,60237,60238,58704,60240,60241,60242,60243,60244,60245,60246,60247,60248,60249,59269,60251,60252,60253,60254,60255,60256,60257,60258,60259,59601,60261,60262,60263,59166,60265,60015,60267,60268,60269,60270,60271,60272,60273,60274,59178,60047,60277,58766,60279,60280,60281,60282,60283,60284,60285,60126,60287,59323,60289,59621,60291,60176,60293,60294,59879,60296,60297,60298,60299,60300,60301,60302,60303,60304,60305,60306,60307,60308,60309,60231,60311,60312,60313,60314,58685,60316,60317,60318,60319,60320,60321,59916,60323,59129,60325,60326,60327,60328,60329,60330,60331,60332,59261,60334,60335,60336,60337,60338,60339,60340,60341,60342,60343,60344,60345,59221,60347,60348,60349,60350,60351,60352,60353,60354,58869,60356,58802,60358,60359,60360,60361,60362,60363,60364,60365,60366,60367,60368,60369,60370,60371,58718,60373,60374,60375,60376,60377,59800,60379,60380,60381,60382,60383,60384,60385,60386,59690,59221,60389,60390,59834,58892,60393,60394,60395,60396,58656,60398,60399,60400,60401,60402,60403,60404,60405,60406,60407,60408,60409,60410,60411,60412,60413,60414,58714,59316,60417,60418,60419,60420,60421,58997,60423,60424,60425,60426,60427,60428,60429,60430,60431,60432,60433,60434,60435,60436,60437,60438,60439,59013,60441,60442,60443,60444,60445,60446,60447,60448,60449,60450,60451,60452,59323,60454,60455,59329,60457,60458,60459,60460,60461,60462,60463,60464,60465,58861,60467,60468,60469,60326,60471,60472,58814,60424,60475,60476,60477,60478,60479,60480,60481,60482,60483,60484,59473,59291,60487,60488,60489,60490,60491,59722,60493,60494,60495,60496,60497,60498,60499,60500,60501,60502,58690,60504,60505,58651,60507,60508,60509,60510,60511,60512,60513,60514,60515,60516,60517,60518,60519,60520,60521,60522,60523,60524,60525,60526,60527,58741,60529,60530,60531,60532,60533,60534,60535,60536,59157,59855,60539,60540,59169,59125,60543,60544,60545,60546,60547,59160,60549,60550,60551,60552,59779,60554,60555,60556,60557,60558,60559,60560,60561,60562,59176,60564,60565,60566,60567,59184,58662,60570,60571,60572,60573,60574,60575,60576,59658,60578,60579,59273,60581,60582,60583,58794,60457,60586,60587,60588,59919,60590,60591,60592,60593,60594,60595,60596,60597,59157,58986,60600,60601,60602,60434,60604,59696,60606,60607,60608,60609,60610,60611,60612,60613,60614,60615,60616,60617,60618,60619,60620,59990,60622,60623,60624,59778,60626,60627,60628,60047,60630,60631,60632,60633,60634,60635,60636,60637,60638,60639,60640,60053,60642,60643,60644,60645,60646,60647,59020,60649,60137,60651,59434,60653,59919,60655,60656,60657,60658,60659,60660,60661,59606,3809,60664,60665,60666,60667,60668,60669,60670,60671,60672,60673,60674,60675,60676,60677,60678,60679,60680,60681,60682,60683,60684,60685,60686,60687,60688,60689,60690,60691,60692,60693,60694,60695,60696,60697,60698,60699,60700,60701,60702,60703,60704,60705,60706,60707,60708,60709,60710,60711,60712,60713,60714,60715,60716,60717,60718,60719,60720,60721,60722,60723,60724,60725,60726,60727,60728,60729,60730,60731,60732,60733,60734,60735,60736,60737,60738,60739,60740,60741,60742,60743,60744,60745,60746,3809,60748,60749,60750,60751,60752,60753,60754,4420,60756,60757,60758,60759,60760,60761,60762,60763,60764,60765,60766,60767,60768,60769,60770,60771,60772,60773,60774,60775,60776,60777,60778,60779,60780,60781,60782,60783,60769,60785,60786,60787,60788,60789,60790,60791,60792,60793,60794,60795,60796,60797,60798,60799,60800,60801,60802,60803,60804,60805,60806,60807,60808,60809,60810,60811,60812,60813,60814,60815,60816,60817,60818,60805,60820,60821,60822,60823,60824,60825,60826,60827,60828,60829,60830,60831,60832,60833,60834,60835,60836,60837,60838,60839,60840,60841,60842,60843,60844,60845,60846,60847,60848,60849,60850,60831,60852,60853,60854,60855,60856,60857,60858,60859,60860,60861,60862,60863,60864,60865,60866,60867,60868,60869,60870,60871,60872,60873,60874,60866,60876,60877,60878,60879,60880,60881,60882,60883,60884,60885,60886,60887,60888,60889,60890,60891,60892,60893,60894,60895,60896,60897,60898,60899,60900,60901,60889,60903,60904,60905,60906,60907,60908,60909,60910,60911,60912,60913,60914,60915,60916,60917,60918,60919,60920,60921,60922,60923,60924,60925,60926,60927,60928,60929,60930,60931,60932,60933,60934,60935,60936,60937,60938,60913,60940,60941,60942,60943,60944,60945,60946,60947,60948,60949,60950,60951,60952,60953,60954,60955,60956,60957,60958,60959,60960,60961,60962,60963,60964,60965,60966,60967,60968,60969,60970,60971,60972,60973,60942,60975,60976,60977,60978,60979,60980,60981,60982,60983,60984,60985,60986,60987,60988,60880,60990,60991,60992,60993,60994,60995,60996,60997,60998,60999,61000,61001,61002,61003,61004,61005,61006,61007,61008,61009,61010,61011,61012,61013,61014,61015,60997,61017,61018,61019,61020,61021,61022,61023,61024,61025,61026,61027,61028,61029,61030,61031,61032,61033,61034,61035,61036,61037,61038,61039,61040,61041,61017,61043,61044,61045,61046,61047,61048,61049,61050,61051,61052,61053,61054,61055,61056,61057,61058,61059,61060,61061,61062,61063,61064,61065,61066,61067,61068,61069,61070,61071,61072,61073,61074,61075,61076,61077,61078,61079,61080,61081,61056,61083,61084,61085,61086,61087,61088,61089,61090,61091,61092,61093,61094,61095,61096,61097,61098,61099,61100,61101,61102,61103,61104,61105,61106,61107,61108,61109,61110,61111,61053,61113,61114,61115,61116,61117,61118,61119,61120,61121,61122,61123,61124,61125,61126,61127,61128,61129,61019,61131,61132,61133,61134,61135,61136,61137,61138,61139,61140,61125,61142,61143,61144,61145,61146,61147,61148,61149,61150,61151,61152,61153,61095,61155,61156,61157,61158,61159,61160,61161,61162,61163,61164,61165,61166,61167,61168,61169,61119,61171,61172,61173,61174,61175,61176,61177,61178,61179,61180,61181,61182,61029,61184,61185,61186,61187,61188,61189,61190,61191,61192,61193,61194,61115,61196,61197,61198,61199,61200,61201,61202,61203,61204,61205,61059,61207,61208,61209,61210,61211,61212,61213,61214,61215,61216,61217,61096,61219,61220,61221,61222,61223,61096,61225,61226,61227,61228,61229,61126,61231,61232,61233,61234,61235,61236,61237,61238,61239,61240,61241,60757,61243,61244,61245,61246,61247,61248,61249,61250,61251,61252,61253,61254,61255,61256,61257,61258,61259,61260,61261,61262,60768,61264,61265,61266,61267,61268,61269,61270,61271,61272,61273,61274,60822,61276,61277,61278,61279,61280,61281,61282,61283,61284,61285,61286,61287,61288,61289,61290,61291,61292,61293,61294,61295,61296,61297,61298,61299,61300,61301,61302,61303,61304,61305,61306,61307,61308,61309,61310,61311,61312,61313,61314,61315,61316,61317,61318,61319,61320,61321,61322,61323,61324,61325,61326,61327,61328,61329,61330,61331,61332,61333,61334,61335,60853,61337,61338,61339,61340,61341,61342,61343,61344,61345,61346,61347,61348,61349,60883,61351,61352,61353,61354,61355,61356,61357,61358,61359,61360,61361,61362,61363,61364,60891,61366,61367,61368,61369,61370,61371,61372,61373,61374,61375,61376,61377,61378,61379,61380,61381,61382,61383,61384,61385,61386,61387,61369,61389,61390,61391,60960,61393,61394,61395,61396,61397,61398,61399,60942,61401,61402,61403,61404,61405,61406,61407,61408,61409,61410,61411,61412,61413,61414,61415,61416,61417,61418,61419,61420,61421,61422,61423,61424,61425,61426,61427,61428,61005,61430,61431,61432,61433,61434,61435,61436,61437,61438,61439,61440,61441,61442,61443,61444,61445,61446,61023,61448,61449,61450,61451,61452,61453,61454,61455,61456,61457,61458,61459,61460,61143,61462,61463,61464,61465,61466,61467,61468,61469,61470,61471,61472,61473,61156,61475,61476,61477,61478,61479,61480,61481,61482,61483,61484,61485,61172,61487,61488,61489,61490,61189,61492,61493,61494,61495,61496,61056,61498,61499,61500,61501,61502,61503,61504,61505,61506,61507,61508,61509,61510,61511,61512,61513,61514,61515,61516,61517,61518,61519,61520,61521,61522,61523,61090,61525,61526,61527,61528,61529,61530,61531,61532,61533,61534,61535,61536,61537,61538,61539,61540,61541,61542,61543,61544,61545,61546,61547,61548,61434,61550,61551,61450,61553,61554,61555,61556,61557,61468,61559,61560,61561,61562,61563,61564,61565,61566,61567,61092,61569,61570,61571,61572,61573,61574,61575,61576,61115,61578,61579,61580,61581,61582,61583,61584,61585,61586,61587,61588,61589,61251,61591,61592,61593,61594,61595,61596,61597,60759,61599,61600,61601,60786,61603,61604,61605,61606,61607,61608,61609,61610,61611,61612,61613,61614,61615,61616,61617,60808,61619,61620,61621,61622,61623,61624,61625,61626,61627,61628,61629,61630,60833,61632,61633,61634,61635,61636,61637,61638,61639,61640,61641,61642,61343,61644,61645,61646,61647,61648,61649,61650,61651,61652,61653,61654,61655,61656,61657,61658,61659,61660,61661,61662,61391,61664,61665,61666,61667,61668,61669,60916,61671,61672,61673,61674,61675,61676,61677,61678,61679,61680,60942,61682,61683,61684,61685,61686,61687,61688,61689,61690,61691,61692,61693,61694,61695,61696,61697,61698,61699,61700,61701,61702,61703,61704,61136,61706,61707,61708,61709,61041,61207,61712,61713,61714,61715,61716,61717,61718,61719,61720,61721,61722,61723,61724,61725,61726,61727,61728,61729,61730,61731,61096,61733,61734,61735,61736,61737,61738,61739,61740,61741,61742,61512,61744,61745,61746,61747,61748,61749,61750,61751,61752,61753,61754,61452,61756,61757,61758,61759,61760,61761,61762,61763,61764,61765,61058,61767,61768,61769,61770,61771,61772,61773,61774,61775,61776,61777,61096,61779,61780,61781,61782,61783,61784,61785,61786,61787,61788,61789,61790,61791,61792,61793,61794,61175,61796,61797,61798,61799,61800,61492,61802,61803,61514,61805,61806,61807,61808,61809,61810,61811,61812,61813,61814,61815,61816,61525,61818,61819,61820,61821,61822,61823,61824,61825,61826,61827,61828,61829,61830,61831,61832,61833,60827,61835,61836,61837,61838,61839,61840,61841,61842,61843,61844,61845,61846,61847,61848,61849,61850,61851,61852,61853,61600,61855,61856,61857,61858,61859,61860,61861,61862,61863,61864,61865,61866,61867,60796,61869,61870,61871,61872,61873,61874,61875,61876,61877,61878,60843,61880,61881,61882,61883,61884,61337,61886,61887,61888,61889,61890,61891,61892,61893,61894,61895,61896,61375,61898,61899,61900,61901,61902,61903,61904,61905,61906,61907,61908,61909,61676,61911,61912,61913,61914,61915,60976,61917,61918,61919,61920,61921,61922,61923,61924,61925,61926,61927,61928,61929,61930,61931,61932,61933,61934,61935,61936,61937,61938,61939,61940,61941,61942,61943,60909,61945,61946,61947,61948,61949,61450,61951,61952,61953,61954,61955,61465,61957,61958,61959,61960,61961,61962,61963,61964,61965,61966,61967,61157,61969,61970,61971,61972,61973,61176,61975,61976,61977,61978,61979,61189,61981,61982,61983,61984,61985,61986,61987,61988,61583,61990,61991,61992,61516,61994,61995,61996,61997,61535,61999,62000,62001,62002,62003,62004,62005,62006,62007,61001,62009,62010,62011,62012,62013,62014,62015,62016,62017,62018,62019,61019,62021,62022,62023,62024,62025,62026,62027,62028,62029,62030,61796,62032,62033,62034,62035,62036,61499,62038,62039,62040,62041,62042,62043,62044,62045,62046,62047,62048,62049,62050,62051,61097,62053,62054,62055,62056,62057,62058,61796,62060,62061,62062,62063,4415,62065,62066,62067,62068,62069,62070,62071,62072,60783,60826,62075,62076,62077,62078,62079,62080,62081,62082,62083,61655,62085,62086,62087,61665,62089,62090,62091,62092,62093,60916,62095,62096,62097,62098,62099,62100,62101,61933,62103,62104,62105,62106,62107,62108,62109,62110,62111,62112,62113,62114,62115,62116,61947,62118,62119,61758,62121,62122,62123,62124,62125,62126,61775,62128,62129,62130,62131,62132,62133,62134,61779,62136,62137,62138,62139,62140,62141,62142,62143,61153,61031,62146,62147,62148,62149,62150,62151,62152,62153,62154,62155,62156,62157,62158,62159,62160,61120,62162,61056,62164,62165,62166,62167,62168,62169,62170,62171,62172,62173,62174,62175,62176,62177,62178,62179,62180,62181,62182,62183,62184,62185,62186,62187,62188,62189,62190,61583,62192,62193,62194,62195,62196,61021,62198,62199,62200,61041,61715,62203,62204,62205,62206,62207,62208,62209,62210,62211,61100,62213,62214,62215,62216,62217,62218,61559,62220,62221,62222,62223,62224,62225,62226,62227,62228,62229,62230,62231,62066,62233,62234,62235,62236,62237,62238,60786,62240,62241,62242,62243,62244,62245,62246,62247,62248,62249,61632,62251,62252,62253,62254,62255,62256,62257,62258,62259,62260,62261,62262,62263,62264,61649,62266,62267,62268,62269,62270,62271,62272,62273,62274,62275,62276,62277,60917,62279,62280,62281,61926,62283,62284,62285,62286,62287,62288,62289,60992,62291,62292,62293,62294,62295,62296,62297,62298,62299,62300,62301,62302,62303,62304,62305,62306,62307,62308,61452,62310,62311,62312,62313,61530,62315,62316,62192,62318,62319,62320,62321,62310,62323,62324,62325,62326,62327,62328,62329,61806,62331,62332,62333,62334,62335,62336,62337,62338,62339,61096,62341,62342,62343,62344,62345,62346,62347,62296,62349,62350,62351,61802,62353,61073,62355,62356,62357,62358,62359,62360,62361,62362,62363,62364,62365,61097,62367,62368,62369,62370,62371,62372,62373,62374,62375,62376,62377,62378,62379,62380,4420,62382,62383,62384,62385,62386,62387,62388,62389,62390,62391,62392,62393,62394,62395,62396,62397,62398,62399,62400,62401,62402,62403,62404,62405,62406,62407,62408,60840,62410,62411,62412,62413,62414,62415,62416,62417,62418,62419,62420,62421,62422,62423,62424,62425,62426,62427,62428,62429,62430,62431,62432,62433,62415,62435,62436,62437,62438,62439,62440,62441,60945,62443,62444,62445,62446,62104,62448,62449,62450,62451,62452,62453,62454,60979,62456,62457,62458,62459,62460,62461,62462,62463,62464,62465,62466,61001,62468,62469,62470,62471,62472,62473,62474,62475,62476,62477,62478,62479,62480,62481,62482,61452,62484,62485,62486,62487,62488,61958,62490,62491,62492,62493,62494,61509,62496,62497,62498,62499,62500,61044,62502,62503,62504,62505,62506,62507,62508,62509,62510,62511,62512,62513,62514,61435,62516,62517,62518,62519,62520,62521,62522,61029,62524,62525,62526,62527,62528,62529,62530,62531,62532,62533,62534,62535,62536,62355,62538,62539,62540,62541,62542,62543,62370,62545,62546,62547,62548,62549,62550,62551,62552,61990,62554,62555,62556,62557,61515,62559,62560,62561,62562,62563,62564,62565,62566,62567,62568,61049,62570,62571,62572,62573,62574,60769,62576,62577,62578,62579,62580,62581,62582,62583,61867,60838,62586,62587,60858,62589,62590,62591,62592,62593,62594,62595,62596,62597,61382,62599,62600,62601,62602,62603,62604,62605,60920,62607,62608,62609,62610,62611,62612,62613,62614,62615,62616,60979,62618,62619,62620,62621,62622,62623,62624,61551,62626,62627,62628,62629,62630,62631,62632,62633,62634,62635,62636,62637,62638,61803,62359,62641,62642,62643,62644,62645,62646,62647,62648,62649,62650,62651,61783,62653,62654,62655,62656,62657,62658,62659,62660,61175,62662,62663,62664,62665,62666,62667,62668,62192,62670,62671,62672,61808,62674,62675,62676,62677,62678,62679,62680,62038,62682,61205,62518,62685,62686,62687,62688,62689,62690,62691,62692,61456,62694,62695,62696,61961,62698,62699,62700,62701,62702,62703,62704,62705,62706,61229,62708,62709,62710,61173,62712,62713,62714,62715,62716,62717,61591,62719,62720,62721,62722,62723,62724,62725,62726,61264,62728,62729,62730,62731,62732,62733,62734,62735,62736,62737,62738,62739,62740,62741,62742,62743,61622,62745,62746,62747,62748,62749,62750,62751,62752,62753,62754,62755,62756,62757,62758,62759,62760,62761,62762,61339,62764,62765,62766,62767,62768,62769,62770,62771,62772,60953,62774,62775,62776,62777,62778,62779,62780,62781,62782,62783,61694,62785,62786,62787,62788,62789,62790,62791,62792,62793,62794,62795,62796,62797,62798,62799,62800,62801,62802,62803,62804,62805,62806,62807,62808,62809,62810,62811,62812,61189,62814,62815,62816,62817,62818,62819,62820,62821,62822,62823,61487,62825,62826,62827,62828,62829,61515,62831,62832,62833,61136,62835,62836,62837,62838,62506,62840,61713,62842,62843,62844,62845,62846,62847,62848,62849,62850,62851,62852,62853,61734,62855,62856,62857,62858,62859,62860,62861,62862,62863,62864,62865,62866,62867,62868,62869,62870,61069,62872,62873,62874,62875,62876,61024,62878,62879,62880,62881,62882,62883,62884,62885,62886,62887,62888,62889,61177,62891,62892,62893,62894,62040,62896,62897,62898,62899,62900,62901,62902,62903,62904,62905,62906,62907,62908,61049,62910,61592,62912,62913,62914,62915,62916,62917,62918,62919,60759,62921,62922,62923,62924,62925,62926,62927,62928,62929,62930,62931,60808,62933,62934,62935,62936,62937,62938,62939,62940,62941,62942,62417,62944,62945,62946,62947,62948,62949,62950,62951,62952,62953,60866,62955,62956,62957,62958,62959,62960,62961,62962,62963,62964,62965,62966,62967,62968,62969,62970,62971,62972,62973,60891,62975,62976,60928,62978,62979,62980,62981,62982,62983,62984,62985,62986,62987,62988,62989,62990,62991,62992,62993,62994,62995,62996,62997,62998,62999,63000,61689,63002,63003,63004,63005,63006,63007,63008,63009,63010,62472,63012,63013,63014,63015,61073,63017,63018,63019,63020,62373,63022,63023,63024,63025,63026,63027,63028,63029,62015,63031,63032,63033,63034,63035,63036,63037,63038,63039,61024,63041,62359,63043,63044,63045,62369,63047,63048,63049,63050,63051,63052,63053,63054,63055,63056,63057,63058,63059,63060,62555,63062,63063,63064,63065,63066,61516,63068,63069,63070,63071,63072,63073,63074,63075,63076,63077,63078,63079,63080,62508,63082,60764,63084,63085,63086,63087,61855,63089,63090,63091,63092,63093,63094,63095,63096,62959,63098,63099,63100,63101,63102,63103,63104,63105,63106,63107,63108,60929,63110,63111,61699,63113,63114,63115,63116,63117,63118,63119,61136,63121,63122,63123,63124,63125,63126,61048,63128,63129,63130,63131,63132,63133,63134,63135,61713,63137,63138,63139,63140,63141,62855,63143,63144,63145,63146,63147,63148,63149,63150,63151,61072,63153,63154,63155,63156,63157,63158,63159,63160,63161,63162,61951,63164,63165,61143,63167,63168,63169,63170,63171,63172,61477,63174,63175,63176,63177,63178,63179,63180,63181,63182,63183,63184,63185,63186,63187,63188,63189,61173,63191,63192,63193,63194,63195,63196,62484,63198,63199,63200,63201,63202,62153,63204,63205,63206,63207,63208,63209,61065,63211,63212,63213,63214,63215,63216,63217,63218,63219,61097,63221,63222,63223,63224,63225,63226,63227,63228,63172,63230,63231,63232,63233,63234,63235,63236,63237,63238,63239,63240,63241,63242,63243,63244,63245,63246,63247,63248,63249,63250,63251,63252,63253,63254,63255,63256,63257,63258,63259,63260,63261,63262,63263,63264,63265,63266,63267,63268,63269,63270,63271,63272,63273,63274,63275,63276,63277,63278,63279,63280,63281,63282,63283,63284,63285,63286,63287,63288,63289,63290,63291,63292,63293,63294,63295,63296,63297,63298,63299,63300,63301,63302,63303,63304,63305,63306,63307,63308,63309,63310,63311,63312,63313,63314,63315,63316,63317,63318,63319,63320,63321,63322,63323,63324,63325,63326,63327,63328,63329,63330,63331,62066,63333,63334,63335,63336,63337,63338,60786,63340,63341,63342,62087,63344,61391,63346,63347,63348,63349,61390,63351,63352,63353,60958,63355,63356,63357,63358,63359,63360,63361,63362,63363,63364,62785,63366,63367,63368,63369,63370,63371,63372,63373,63374,63375,63376,63377,63378,63007,63380,63381,63382,63383,63384,63385,63386,63387,63388,63389,63390,63391,62554,63393,63394,63395,62664,63397,63398,63399,63400,63401,63402,62355,63404,63405,63406,63407,63408,63409,63410,63411,63412,63413,61516,63415,63416,63417,63418,63419,63420,63421,63422,63423,63424,63425,63426,63129,63428,63429,63430,63431,61145,63433,63434,63435,61118,63437,63438,61516,63440,63441,63442,63443,63444,63445,63446,62343,63448,63449,63450,63451,63452,63453,63454,63455,63456,63457,63458,63459,63460,63461,63462,63463,63464,63465,63466,63467,63468,62310,63470,63471,61235,63473,61096,63475,63476,63477,63478,63479,63480,63481,63482,63483,63484,63485,63486,63487,61176,63489,63490,63491,63492,61251,63494,63495,63496,63497,63498,63499,63500,62924,63502,63503,63504,63505,63506,63507,63508,63509,63510,63511,63512,63513,62938,63515,63516,63517,63518,63519,63520,63521,62953,60883,63524,63525,63526,63527,63528,63529,63530,63531,63532,63533,63534,63535,63536,63537,60891,63539,63540,63541,63542,63543,63544,63545,63546,63547,63548,63549,60926,63551,63552,63553,63554,63555,63556,63557,63558,63559,63560,63561,63562,62785,63564,63565,63566,63567,63568,63569,63570,63571,63572,61454,63574,63575,63576,63577,63578,63428,63580,63581,63582,63583,63584,63585,63586,61207,63588,63589,63590,63591,63592,63593,63594,63595,62341,63597,63598,63599,63600,63601,63602,63603,63604,63605,63606,63607,63608,61061,63610,63611,63612,63613,63614,63615,63616,63617,63618,63619,61449,63621,63622,63623,63624,63625,63626,63627,63628,63629,63630,63631,63632,61143,63634,63635,63636,63637,61477,63639,63640,63641,63642,63643,63644,63645,63646,63647,63648,63649,63650,63651,63652,63653,63654,63655,63656,63657,61173,63659,63660,63661,63662,62484,63664,63665,63666,63667,63668,61044,63670,63671,63672,63673,63139,63675,63676,63677,63678,63679,63680,63681,63682,63683,63684,63685,62855,63687,63688,63689,63690,63691,63692,63693,63694,61120,63696,63697,63698,63699,63700,63701,63702,63703,63704,63705,63706,63707,63708,63709,63710,63711,63336,63713,63714,63715,62243,63717,63718,63719,63720,63721,63722,63723,63724,63725,63726,61634,63728,63729,63730,61655,63732,63733,63734,63735,63736,63737,63738,63739,63740,63741,62089,63743,63744,63745,63746,63747,63748,63749,62095,63751,63752,63753,63754,63755,61933,63757,63758,63759,63760,63761,63762,63380,63764,63765,63766,63767,63768,63769,63770,63771,63772,63773,63774,63775,63776,63369,63778,63779,63780,63781,63782,63783,63784,63785,63786,63665,63788,62152,63790,63791,63792,63793,63794,63795,63796,61718,63798,63799,63800,63801,63802,63803,63804,63805,63806,63807,62855,63809,63810,63811,61806,63813,63814,63815,63816,63817,63818,61456,63820,63821,63822,63823,63824,63825,61466,63827,63828,63829,63830,63831,63832,63482,63834,63835,63836,63837,63838,63839,63840,61173,63842,63843,63844,63845,63846,61454,63848,63849,63850,63851,63852,63853,63854,63855,63017,63857,63858,63859,63860,63861,63862,63863,63864,63223,63866,63867,63868,63869,63870,63871,63872,63873,63874,63333,63876,63877,63878,63879,63718,63881,63882,63883,63884,63885,63886,62258,63888,61676,63890,63891,63892,63893,63894,63895,63896,61932,63898,63899,63900,63901,63902,63903,63904,63905,63906,63907,63908,63909,63910,63911,63912,63913,63914,60909,63916,63917,63918,63822,63920,61559,63922,63923,63924,63925,63478,63927,63928,63929,63930,63931,63932,63933,61176,63935,63936,61983,63938,63939,63940,63941,63942,63943,63944,63945,61990,63947,63417,63949,63950,63951,63952,63953,63954,63955,63956,63957,61541,63959,63960,61550,63962,63963,63964,63965,63966,63967,61136,63969,63970,63971,63972,63973,63974,61150,61530,63977,63978,63979,63980,63981,63982,63983,63984,63985,63986,63987,63988,63989,63990,63991,63992,63993,63994,63995,63996,63997,63998,63999,64000,64001,64002,64003,64004,64005,64006,64007,64008,64009,64010,64011,64012,64013,64014,64015,64016,64017,64018,64019,64020,64021,64022,64023,64024,64025,64026,64027,64028,64029,64030,64031,64032,64033,64034,64035,64036,64037,64038,64039,64040,64041,64042,64043,64044,64045,64046,64047,64048,64049,64050,64051,64052,64053,64054,64055,64056,64057,64058,64059,64060,64061,64062,64063,64064,64065,64066,64067,64068,64069,64070,64071,64072,64073,64074,64075,64076,64077,64078,64079,64080,64081,64082,61583,64084,64085,64086,64087,61243,64089,64090,64091,64092,64093,64094,64095,64096,63506,64098,64099,64100,64101,64102,64103,64104,64105,64106,64107,61624,64109,64110,64111,64112,64113,64114,64115,64116,62417,64118,64119,64120,64121,60888,64123,64124,64125,64126,64127,64128,64129,64130,64131,64132,64133,64134,64135,64136,64137,64138,64139,64126,64141,64142,64143,64144,64145,64146,64147,64148,64149,64150,64151,64152,64153,61665,64155,64156,64157,64158,64159,63356,64161,64162,64163,64164,64165,62785,64167,64168,64169,64170,64171,64172,64173,64174,64175,64176,64177,64178,64179,64180,61803,61583,64183,64184,64185,64186,64187,64188,62559,64190,64191,64192,64193,64194,64195,62508,64197,64198,64199,64200,63012,64202,64203,64204,64205,64206,64207,64208,64209,61075,64211,64212,64213,64214,64215,64216,63222,64218,64219,64220,64221,64222,64223,64224,64225,64226,64227,64228,64229,64230,64231,61562,64233,64234,64235,64236,64237,64238,61032,64240,64241,64242,64243,64244,62318,62832,64247,64248,64249,64250,64251,64252,64253,64254,64255,64256,63133,64258,64259,64260,60764,64262,64263,64264,64265,64266,64267,64268,64269,64270,64271,64272,64273,64274,64275,64276,64277,64278,64279,64280,64281,64282,64283,64284,64285,61855,64287,60818,60845,64290,64291,64292,64293,64294,64295,64296,64297,60870,64299,64300,64301,64302,64303,64304,64305,64306,64307,64308,64309,61419,64311,64312,64313,61435,64315,64316,64317,64318,64319,64320,64321,64322,62698,64324,64325,64326,61087,64328,63664,64330,64331,64332,62121,64334,64335,64336,64337,62040,64339,64340,64341,64342,64343,64344,64345,64346,64347,64348,64349,64350,63696,64352,64353,61435,64355,64356,64357,64358,64359,64360,64361,64362,64363,64364,64365,64366,64367,61131,64369,64370,62033,62899,64373,64374,64375,64376,64377,64378,64379,61820,64381,64382,64383,64384,64385,64386,64387,64388,64389,64390,63267,64392,61774,64394,64395,64396,64397,64398,64399,64400,61591,64402,64403,64404,64405,64406,61859,64408,64409,64410,64411,64412,64413,64414,64415,64416,63719,64418,64419,64420,64421,64422,64423,64424,64425,61644,64427,63544,64429,64430,64431,64432,64433,60908,64435,64436,64437,64438,64439,64440,64441,64442,64443,64444,62443,64446,64447,64448,64449,64450,64451,64452,64453,64454,63005,64456,64457,64458,64459,64460,64461,64462,64463,64464,64465,64466,62153,64468,64469,64470,61120,64472,64473,64474,64475,64476,62183,64478,64479,64480,64481,64482,64483,64484,64485,64486,64487,64488,64489,64184,64491,64492,64493,64337,64495,61207,64497,64498,64499,64500,64501,64502,64503,64504,64505,64506,64507,61534,64509,64510,64511,64512,64513,64514,64515,64516,64517,64518,64519,64520,64521,64522,61001,64524,64525,64526,64527,64528,64529,64530,64531,64532,64533,61138,61505,64536,64537,64538,61976,62914,64541,64542,64543,64544,64545,64546,60764,64548,64549,64550,64551,64552,64553,64554,64555,64109,64557,64558,64559,64560,64561,64562,62425,64564,64565,64566,64567,64568,64569,64570,64571,64572,64573,64133,64575,64576,64432,63556,64579,64580,61696,64582,64583,64584,64585,64586,62835,64588,64589,64590,62878,64592,64593,64594,64595,64596,63676,64598,64599,64600,64601,64602,64603,61097,64605,64606,64607,64608,63473,64610,64611,64612,64613,64614,64615,61708,64617,61175,64619,64620,64621,64622,64623,64624,64625,62042,64627,64628,64629,64630,64631,64632,64633,64634,64635,62474,64637,64638,64639,64640,64641,62121,64643,64644,64645,64646,61566,64648,64649,64650,62846,64652,64653,64654,64655,64656,64657,62855,64659,64660,64661,64662,64663,64664,64665,61116,62068,64668,61610,64670,64671,64672,64673,64674,64675,64676,60836,64678,64679,64680,64681,64682,64683,64684,64685,64686,64687,64688,62267,64690,64691,64692,64693,64694,64695,64696,64697,64698,64699,64700,64701,64702,64703,64704,64705,62611,64707,64708,64709,64710,64711,64712,62283,64714,64715,64716,64717,64718,64719,64720,60992,64722,64723,64724,64725,64726,64727,64728,64729,64730,64731,64732,64733,64734,64735,64736,64737,64738,61952,64740,64741,61961,64743,64744,64745,64746,64747,64748,64749,64750,64751,64752,63477,64754,64755,64756,64757,64758,64759,64760,64761,64762,64763,64764,64765,64766,64767,62663,64769,64770,64771,64772,62713,64774,64775,64776,64777,62496,64779,64780,64781,64782,64783,64784,64785,64786,64787,64788,62910,64202,64791,61024,64793,64395,64795,64796,64797,64798,64799,64800,64801,61096,64803,64804,64805,64806,62033,64092,64809,64810,62752,64812,64813,64814,64815,64816,64817,64818,64819,64820,64821,64822,64823,64824,64825,64826,64827,61346,64829,64830,64831,64150,64833,64834,64835,64836,64837,64838,64839,64840,64841,64842,64843,61665,64845,64846,64847,64848,64849,64850,64851,63358,64853,64854,64855,64856,64857,64858,64859,64860,64861,64862,64863,62786,64865,64866,64867,64868,64869,64870,64871,64872,64873,64874,64875,64876,61981,64878,64879,64880,61990,64882,64883,64884,63416,64886,64887,64888,64889,64890,64891,64892,64893,64894,64895,64896,64382,64898,64899,64900,64901,64902,64903,64904,64905,64906,64907,64908,64909,64910,64911,64912,62011,64914,64915,64916,64917,61803,64919,63044,64921,64922,64923,64924,64925,62137,64927,64928,64929,64930,64931,64932,64933,64934,64935,64936,64937,64938,64509,64940,64941,64942,64943,64944,64945,64946,64947,62296,64949,64950,64951,62668,64953,64954,62498,64956,64957,64958,64959,64960,64961,64962,64963,64964,64965,63581,64967,64968,64969,64970,61515,64972,64973,64974,64975,64976,61600,64978,64979,64980,64981,64982,64983,64984,64985,62765,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64124,64999,65000,65001,65002,65003,65004,65005,65006,65007,65008,65009,65010,65011,63544,65013,65014,65015,60979,65017,65018,65019,65020,61009,65022,65023,65024,65025,65026,65027,61073,65029,65030,62371,65032,65033,65034,65035,65036,65037,65038,65039,65040,65041,65042,65043,65044,65045,61799,65047,65048,62192,65050,65051,65052,61515,65054,65055,65056,65057,65058,65059,65060,65061,65062,65063,65064,63130,65066,65023,65068,65069,65070,65071,65072,65073,65074,65075,65076,65077,65078,65079,65080,65081,65082,65083,65084,65085,65086,65087,65088,65089,65090,65091,65092,65093,65094,65095,65096,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65107,65108,65109,65110,65111,65112,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65127,65128,65129,65130,65131,65132,65133,65134,65135,65136,65137,65138,65139,65140,65141,65142,65143,65144,65145,65146,65147,65148,65149,65150,65151,65152,65153,65154,65155,65156,65157,65158,65159,65160,65161,65162,65163,65164,65165,65166,65167,65168,65169,65170,65171,65172,65173,65174,65175,63849,65177,62701,65179,65180,65181,65182,65183,65184,65185,64898,65187,65188,65189,65190,65191,65192,65193,65194,65195,65196,65197,65198,65199,65200,61585,65202,65203,65204,65205,65206,64095,65208,62730,65210,65211,65212,65213,65214,65215,62770,65217,65218,65219,65220,64126,65222,65223,65224,65225,65226,65227,65228,65229,65230,65231,65232,65233,65234,65235,65236,65237,65238,65239,62444,65241,65242,62448,65244,65245,65246,65247,65248,65249,64315,65251,65252,65253,65254,65255,65256,65257,64337,62670,65260,65261,65262,64498,65264,65265,65266,65267,65268,65269,64220,65271,65272,65273,65274,65275,65276,65277,65278,62665,65280,65281,65282,65283,61136,65285,65286,65287,65288,65289,65290,65291,61803,65293,63428,65295,65296,65297,65298,65299,62843,65301,65302,65303,65304,65305,61102,65307,65308,65309,65310,65311,64234,65313,65314,65315,65316,65317,65318,65319,61583,65321,65322,65323,65324,65325,64886,65327,65328,65329,65330,60801,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,64983,61607,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,62258,65374,65375,65376,65377,65378,61668,65380,61676,65382,65383,65384,62449,65386,65387,65388,65389,65390,63005,65392,65393,65394,65395,65396,65397,65398,65399,65400,65401,62835,65403,65404,61159,65406,65407,65408,65409,65410,65411,65412,65413,65414,65415,61175,65417,65418,65419,65420,65421,65422,65423,63939,65425,65426,64498,65428,65429,65430,65431,65432,65433,65434,64659,65436,65437,65438,65439,65440,65441,62230,65443,62154,65445,65446,65447,65448,65449,65450,65451,65452,61583,65454,65455,65456,65457,65458,65459,65460,65461,65462,64247,65464,65465,65466,65467,65468,65469,65470,63132,65472,65473,65474,65475,65476,65477,64276,65479,65480,65481,65482,65483,65484,65485,65486,65487,64683,65489,65490,65491,65492,65493,65494,65495,65496,61644,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,61907,65510,65511,65512,62609,65514,65515,65516,62286,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,65536,64458,65538,65539,65540,65541,65542,65543,65544,65545,65546,65547,65548,65549,65550,65551,65552,61553,65554,65555,65556,65557,65558,65559,65560,65561,65562,65563,65564,65565,61153,62185,65568,65569,65570,65571,61091,65573,65574,65575,65576,65577,65578,65579,65580,65581,65582,65583,65584,65585,65586,64491,65588,65589,62696,65591,65592,61210,65594,65595,65596,65597,65598,65599,65600,65601,65602,65603,65604,65605,61528,65607,65608,65609,65610,65611,65612,65613,65614,65615,65616,65617,62292,65619,65620,65621,65622,65623,65624,65625,65626,65627,65628,65629,61173,65631,65632,65633,65634,65635,65636,65637,63416,65359,65640,65641,64291,65643,65644,65645,65646,64300,65648,65649,62611,65651,65652,65653,65654,65655,65656,61419,65658,65659,65660,65661,65662,65663,65664,65665,65666,64355,65668,65669,65670,65671,65672,62355,65674,65675,65676,65677,65678,65679,65680,65681,63022,65683,65684,65685,65686,65687,65688,65689,65690,65282,65692,62896,65694,65695,65696,65697,65698,60998,65700,65701,65702,65703,65704,65705,65706,65707,62310,65709,65710,65711,65712,64610,65714,65715,65716,65717,65718,65719,65720,65721,63480,65723,65724,65725,65726,65727,65728,65729,63491,62913,65732,65733,65734,65735,65736,65737,65738,62729,65740,65741,65742,65743,65744,65745,65746,65747,65748,65749,65750,65751,65752,65753,65754,65755,65756,65757,65758,65759,62769,65761,65762,65763,65764,65765,63355,65767,65768,65769,65770,65771,65772,65773,64868,65775,65776,65777,65778,65779,65780,65781,65782,65783,65784,65785,62516,65787,65788,65789,65790,65791,65792,65793,65794,63791,65796,65797,65798,65799,62668,65801,64482,63041,61205,61519,65806,65807,65808,65809,65810,65811,65812,65813,65814,61435,65816,65817,65818,65819,61452,65821,65822,65823,65824,65825,65826,62699,63927,65829,65830,65831,65832,65833,65834,65835,65836,65837,62893,61248,65840,65841,65842,65843,65844,65845,65846,65847,64815,65849,65850,65851,65852,65853,61346,65855,65856,65857,65858,65859,65860,62777,65862,65863,65864,65865,65866,65867,65868,65869,65870,65871,65872,65873,65874,65875,65876,65877,65878,65879,65880,65881,65882,65883,65884,65885,65886,65887,65888,65889,65890,65891,65892,65893,65894,65895,65896,65897,65898,65899,65900,65901,65902,65903,65904,65905,65906,65907,65908,65909,62788,65911,65912,65913,65914,65915,65916,65917,65918,65919,65920,65921,61982,65923,65924,65925,65926,65927,65928,65589,61517,65931,65932,65933,65934,65935,65936,65937,64899,65939,65940,65941,65942,65943,60999,65945,65946,65947,65948,65949,65950,65951,65952,63156,65954,65955,65956,65957,65958,65959,65960,65961,64805,62323,65964,65965,65966,65967,63582,65969,65970,65971,65972,65973,65974,65975,65976,65723,65978,65979,65980,65981,65982,64221,65984,65985,65986,65987,65988,60859,65990,65991,65992,65993,65994,61247,65996,65997,62242,65999,66000,66001,66002,66003,66004,66005,66006,66007,66008,66009,66010,64558,66012,66013,66014,66015,66016,66017,66018,66019,60872,66021,66022,66023,66024,66025,66026,66027,61909,63751,66030,66031,66032,66033,66034,66035,66036,66037,63356,66039,66040,66041,66042,66043,66044,62108,66046,66047,66048,66049,66050,66051,66052,62785,66054,66055,66056,66057,66058,66059,66060,66061,66062,66063,63938,66065,66066,66067,66068,66069,66070,66071,62153,66073,66074,66075,66076,63017,66078,66079,66080,66081,66082,64219,66084,66085,66086,66087,66088,66089,66090,66091,66092,66093,66094,63433,66096,66097,66098,66099,66100,62886,66102,66103,61122,66105,62176,66107,66108,66109,66110,66111,66112,66113,66114,66115,66116,66117,66118,66119,66120,66121,66122,66123,66124,66125,66126,66127,64086,66129,62835,66131,66132,63858,66134,66135,66136,66137,66138,66139,66140,66141,66142,66143,65985,66145,66146,66147,66148,66149,66150,66151,62700,66153,66154,66155,66156,63333,66158,66159,66160,66161,65749,66163,66164,66165,66166,66167,62770,66169,66170,65228,66172,66173,66174,66175,66176,66177,66178,65770,65775,66181,66182,66183,66184,66185,66186,66187,66188,66189,66190,66191,66192,66193,66194,66195,66196,61189,66198,66199,66200,66201,66202,61583,66204,66205,66206,66207,66208,64886,66210,66211,66212,66213,62516,66215,66216,66217,66218,66219,66220,66221,66222,62355,66224,66225,66226,66227,66228,66229,66230,66231,66232,66233,66234,66235,66236,61097,66238,66239,66240,66241,66242,66243,66244,61189,66246,66247,66248,66249,66250,66251,61209,66253,66254,66255,66256,66257,66258,66259,66260,66261,66262,66263,66264,66265,66266,66267,66268,66269,66270,64659,66272,66273,66274,66275,66276,66277,66278,66279,63923,66281,66282,66283,66284,66285,63336,66287,66288,66289,66290,61612,66292,66293,66294,66295,66296,65853,66298,66299,66300,66301,66302,66303,66304,66305,66306,66307,66298,66309,66310,66311,66312,66313,66314,66315,62960,66317,66318,66319,66320,66321,66322,66323,66324,66325,66326,66327,66328,66329,66330,66331,66332,66333,66334,63114,66336,66337,66338,66339,66340,66341,66342,66343,61557,66345,65474,66347,66348,66349,66350,66351,66352,63589,66354,66355,66356,66357,66358,66359,66360,62347,66362,66363,66364,66365,66366,66367,66368,66369,66370,62678,66372,66373,62487,66375,62224,66377,66378,63929,66380,66381,64771,65970,66384,66385,63681,66387,66388,66389,66390,66391,66273,66393,66394,66395,66396,63613,66398,66399,66400,63335,66402,66403,66404,62243,66406,66407,66408,66409,61655,66411,66412,66413,66414,66415,66416,63544,66418,66419,66420,66421,66422,60909,66424,64447,66426,66427,66428,66429,66430,66431,66432,66433,66434,66435,62785,66437,66438,66439,66440,66441,66442,66443,66444,66445,66446,66447,66448,66449,64468,66451,66452,66453,66454,66455,66456,66457,65418,66459,66460,66461,66462,66463,66464,66465,66466,66467,62498,66469,66470,66471,66472,66473,66474,66475,66476,63130,66478,66479,66480,62688,66482,66483,61981,66485,66486,66487,66488,66489,66490,66491,66492,63043,66494,66495,66496,66497,66498,66499,66500,66501,61782,66503,66504,66505,66506,66507,62121,66509,66510,66511,66512,62153,66514,66515,66516,66517,66518,66519,61716,66521,66522,66523,66524,66525,66526,61527,66528,66529,66530,66531,66532,66533,66534,66535,66536,62572,66538,66539,65350,66541,66542,66543,66544,66545,66546,66547,66548,66549,66550,66551,66552,66553,66554,66555,66556,64290,66558,66559,66560,66561,60872,66563,66564,66565,66566,66567,66568,66569,66570,66571,60938,61690,66574,66575,66576,66577,66578,66579,66580,66581,66582,66583,66584,66585,61137,66587,62149,66589,66590,66591,66592,66593,61714,66595,66596,66597,66598,66599,66600,66601,66602,66603,61096,66605,66606,61113,66608,66609,66610,66611,66612,66613,66614,66615,66616,66617,66618,63122,66620,65575,66622,66623,66624,66625,66626,66627,66628,66629,66630,66631,66632,66633,66634,66635,66636,62318,66638,61450,66640,61067,66642,66643,66644,66645,66646,66647,66648,66649,66650,66651,63223,66653,66654,66655,66656,66657,66658,66659,61962,66661,66662,66663,66664,66665,66666,66667,66668,62258,66670,66671,66672,66673,66674,66675,66676,63344,63346,66679,66680,66681,66682,66037,65768,66685,66686,66687,66688,66689,66690,66691,65777,66693,66694,66695,66696,66697,66698,66699,61139,66701,65293,61059,66704,63478,66706,66707,66708,66709,66710,66711,66712,66713,64727,66715,66716,66717,66718,66719,66720,63623,66722,66723,66724,66109,66726,66727,66728,66729,66730,66731,61197,66733,66734,66735,66736,66737,61551,66739,66740,66741,66742,66743,66744,66745,61125,66747,66748,66749,66750,66751,66752,66753,66754,66755,66756,66757,66758,66759,66760,66761,66762,66763,66764,66765,66766,66767,66768,63476,66770,66771,66772,66773,66774,66775,66776,66777,66778,66779,63492,63497,66782,60766,66784,61625,66786,60883,66788,66789,63544,66791,66792,66793,66794,61703,66796,66797,66798,66799,66800,66801,66802,66803,63971,66805,66806,66807,62504,66809,66810,66811,66812,62843,66814,66272,66816,66817,66818,66819,66820,66821,61070,66823,66824,66825,66826,66827,63623,66829,66830,66831,66832,66833,65607,66835,66836,66837,66838,66839,66840,66841,66842,65052,62021,66845,66846,66847,66848,66849,66850,66225,66852,66853,66854,66855,66856,66857,66858,66859,66860,66861,62368,66863,66864,66865,66866,66867,66868,66869,66870,66871,66872,63876,66874,66875,66876,60773,66878,66879,66880,66881,66882,66883,66884,66885,66886,66887,66888,66889,66890,66891,66892,66893,66894,66895,66896,66897,66898,66899,66412,66901,66902,66903,66904,66905,64429,66907,66908,66424,66426,66911,66912,66913,66914,66915,66916,66917,66440,66919,66920,66921,66922,66923,66924,66925,66926,66927,62156,66929,66930,66931,66932,66933,66934,66935,66936,66937,62061,66939,66940,66941,66942,64342,66944,66945,66946,66947,66948,66949,66950,66951,66952,66953,66954,63971,66956,66957,61048,66959,63801,66961,66962,66963,66964,66965,66966,66967,66968,61807,66970,66971,66972,66973,66974,66975,66976,62899,66978,66979,66980,66981,66982,66983,61003,66985,66986,66987,66988,66989,66990,66991,66992,66993,66994,66995,66996,66997,66998,66999,67000,67001,67002,67003,67004,67005,67006,67007,67008,67009,67010,67011,67012,67013,67014,67015,67016,67017,67018,67019,61455,67021,67022,67023,67024,63168,67026,67027,67028,63477,67030,67031,67032,67033,67034,61253,67036,67037,67038,67039,67040,67041,62753,67043,67044,67045,67046,67047,67048,67049,67050,67051,61346,67053,67054,67055,67056,67057,67058,67059,67060,67061,61900,67063,67064,67065,67066,67067,67068,62445,67070,67071,67072,67073,67074,67075,67076,62786,67078,67079,67080,67081,67082,67083,67084,63844,67086,67087,65466,67089,67090,67091,67092,67093,67094,63428,67096,67097,67098,64202,67100,67101,67102,67103,67104,67105,61713,67107,67108,67109,67110,67111,67112,67113,67114,67115,67116,61100,67118,67119,67120,67121,67122,67123,67124,67125,67126,67127,67128,67129,61236,67131,67132,67133,67134,67135,67136,67137,61032,67139,67140,67141,67142,67143,67144,67145,62319,67147,67148,64190,67150,67151,67152,67153,67154,67155,67156,67157,67158,67159,67160,67161,67162,67163,65341,67165,67166,67167,67168,67169,67170,67171,67172,67173,67174,67175,67176,67177,67178,67179,67180,67181,61880,67183,67184,67185,67186,67187,67188,60854,67190,67191,67192,67193,67194,67195,67196,67197,67198,67199,67200,67201,67202,67203,61899,67205,67206,67207,67208,67209,67210,67211,67212,67213,67214,67215,67216,67217,67218,67219,67220,64710,67222,67223,67224,61932,67226,67227,67228,67229,67230,67231,67232,67233,67234,65624,67236,67237,67238,67239,67240,62121,67242,67243,67244,66281,67246,67247,61157,67249,67250,67251,67252,67253,67254,67255,67256,67257,67258,61586,67260,67261,67262,62128,67264,67265,67266,67267,67268,67269,67270,65669,67272,67273,67274,66246,67276,67277,67278,67279,67280,67281,67282,62356,67284,67285,67286,67287,62545,67289,67290,67291,67292,67293,67294,67295,67296,61516,67298,67299,67300,67301,67302,61820,67304,67305,67306,67307,67308,67309,67310,67311,67312,67165,67314,67315,67316,67317,67318,67319,67320,67321,67322,67323,67324,67325,67326,67327,67328,61870,67330,67331,67332,67333,67334,65490,67336,66022,67338,67339,67340,67341,67213,67343,67344,67345,67346,67347,67348,67349,67350,67351,67352,61676,67354,67355,67356,63759,67358,67359,62785,67361,67362,67363,67364,67365,67366,67367,67368,67369,67370,67371,67372,67373,67374,67375,67376,67377,67378,61981,67380,67381,67382,67383,67384,67385,63476,67387,67388,67389,67390,67391,67392,67393,67394,61991,67396,62313,67398,64499,67400,67401,67402,67403,67404,67405,67406,67407,67408,67409,67410,67411,67412,65612,67414,67415,67416,61808,67418,67419,67420,67421,61976,67423,67424,67425,67426,67427,67428,65694,67430,67431,67432,67433,67434,61199,67436,67437,67438,67439,67440,67441,67442,67443,64277,67445,67446,67447,67448,67449,67450,67451,67452,67453,67454,67455,67456,67457,67458,67459,67460,67461,67462,67463,67464,67465,67466,67467,67468,67469,67470,67471,61867,65490,67474,67475,67476,67477,65502,67479,67480,67481,67482,67483,67484,62611,67486,67487,67488,67489,67490,67491,67492,67493,67494,67495,67229,67497,67498,67499,67500,67501,67502,62296,67504,67505,67506,67507,67508,63201,63433,67511,67512,61075,67514,67515,67516,67517,67518,67519,63866,67521,67522,67523,67524,67525,67526,67527,67528,67529,62157,67531,67532,67533,67534,67535,67536,67537,67538,61796,67540,67541,67542,67543,67544,62181,67546,67547,67548,67549,67550,67551,67552,64087,67554,62835,67556,67557,67558,67559,61076,67561,67562,67563,67564,67565,67566,67567,67568,67569,67570,67571,63866,67573,67574,67575,67576,61559,67578,67579,67580,67581,67582,62066,61604,67585,67586,67587,67588,67589,67590,67591,67592,67593,67594,67595,61642,63732,67598,67599,67600,67601,67602,67603,67604,61391,67606,67607,67608,67609,67610,66037,66911,67613,67614,67615,67616,67617,63002,67619,67620,67621,67622,67623,67624,65446,67626,67627,67628,67629,67630,67631,67632,67633,67634,67635,61176,67637,67638,67639,67640,67641,62902,67643,67644,67645,67646,67647,67648,61132,67650,67651,67652,67653,67654,67655,67656,66642,67658,67659,67660,67661,67662,67663,67664,67665,67666,67667,67668,67669,66084,67671,67672,67673,67674,67675,67676,67677,67678,64491,67680,67681,67420,67683,67684,62346,67686,67687,67688,67689,67690,67691,67692,67693,62333,67695,67696,67697,67698,67699,67700,66158,67702,67703,67704,62240,67706,67707,67708,67709,67710,61655,67712,67713,67714,67715,67716,67717,63544,67719,67720,67721,67722,67723,67724,60904,67726,67727,67728,67729,67730,67731,67732,67733,62445,67735,67736,67737,67738,67739,67740,67741,67742,67743,67744,67745,67623,67747,67748,67749,67750,67751,67752,67753,67754,62296,67756,67757,67758,67759,67760,67761,64588,67763,67764,65188,67766,67767,67768,67769,67770,67771,67772,67773,61487,67775,67776,67777,67778,67779,67780,67781,67782,67783,67784,62487,62540,67787,67788,67789,67790,67791,67792,67793,67794,65032,67796,67797,67798,67799,67800,67801,67802,67803,61515,67805,67806,67807,67808,67809,67810,67811,67812,65187,67814,67815,67816,67817,67818,67819,67820,67821,67822,67823,67824,67825,67826,67827,67828,60859,67830,67831,67832,67833,67834,67835,67836,67837,61607,61632,67840,67841,67842,67843,67844,67845,67846,67847,67848,67849,67850,67851,67852,67853,67854,67855,67856,67857,67858,67859,67860,67861,67862,67863,67864,67865,67866,67867,67868,67869,67870,67871,61370,67873,60916,67875,67876,67877,67878,61933,67880,67881,67882,67883,67884,67885,67886,67887,67888,67889,67890,67891,67892,67893,63764,67895,67896,67897,61137,67899,67900,67901,67902,67903,67904,67905,62162,62040,67908,67909,67910,67911,67912,63849,67914,67915,67916,63130,67918,67919,67920,67921,67922,67923,61716,67925,67926,67927,67928,67929,61104,67931,67932,61240,67934,61991,67936,67937,67938,61520,67940,67941,67942,67943,67944,67945,64898,67947,67948,67949,67950,67951,67952,67953,67954,67955,67956,67957,67958,67959,67960,61841,67962,67963,67964,67965,67966,67967,67968,67969,67970,67971,67972,67973,67974,67975,67976,67977,67978,67979,67980,67981,63333,67983,61607,67985,67986,67987,67988,67989,67990,67991,67992,67993,67994,67995,67996,62254,67998,67999,68000,68001,68002,68003,68004,68005,68006,68007,68008,68009,68010,68011,68012,68013,63344,64131,68016,68017,68018,68019,68020,68021,68022,68023,68024,68025,68026,68027,64833,68029,68030,68031,68032,68033,61899,68035,68036,60920,68038,68039,68040,68041,68042,68043,68044,68045,68046,68047,62105,68049,68050,68051,68052,68053,68054,68055,68056,68057,68058,68059,68060,68061,68062,68063,63382,68065,68066,68067,68068,68069,68070,68071,68072,68073,68074,68075,68076,61192,68078,68079,68080,68081,63418,68083,68084,68085,68086,68087,68088,63867,68090,68091,68092,68093,68094,63155,68096,68097,68098,68099,68100,68101,68102,68103,68104,68105,68106,66451,68108,68109,68110,68111,68112,68113,68114,68115,62033,68117,67300,68119,68120,68121,68122,64727,68124,65418,68126,68127,68128,68129,68130,64786,68132,68133,65476,68135,65348,68137,68138,68139,68140,68141,68142,68143,68144,68145,68146,68147,68148,68149,68150,68151,68152,68153,68154,68155,68156,68157,61857,68159,68160,61878,64684,68163,68164,68165,61676,68167,68168,68169,68170,68171,68172,68173,63900,68175,68176,68177,68178,68179,68180,68181,68182,68183,68184,68185,68186,61949,61450,68189,68190,63178,68192,68193,68194,68195,68196,68197,68198,61579,68200,68201,68202,68203,68204,68205,68206,68207,68208,68209,68210,68211,68212,68213,68214,68215,68216,68217,68218,68219,68220,68221,68222,68223,68224,68225,68226,68227,68228,68229,68230,66131,68232,68233,66225,68235,68236,68237,68238,68239,68240,68241,68242,68243,68244,68245,61097,68247,68248,68249,68250,68251,68252,68253,68254,68255,68256,62665,68258,68259,68260,61451,68262,68263,66812,65301,68266,68267,68268,68269,67574,68271,68272,68273,68274,68275,68276,62699,68278,68279,68280,68281,68282,68283,68284,63154,68286,68287,68288,68289,68290,68291,68292,68293,68294,68295,68296,62068,68298,60822,68300,68301,68302,68303,67054,68305,68306,68307,68308,68309,68310,67212,68312,68313,67739,68315,68316,68317,68318,68319,68320,68321,66437,68323,68324,68325,68326,61031,68328,68329,67638,68331,64627,68333,68334,68335,68336,61136,68338,68339,68340,61032,68342,68343,62203,68345,68346,61733,68348,68349,68350,65716,63791,68353,68354,68355,62318,68357,68358,68359,65054,68361,68362,68363,68364,68365,68366,68367,68368,68369,68370,68371,61049,68373,68374,60820,68376,68377,68378,64985,68164,61931,68382,68383,68384,68385,68386,68387,68388,68389,68390,68391,63005,68393,68394,68395,68396,68397,68398,68399,63947,68401,68402,63418,68404,68405,68406,68407,68408,64900,68410,68411,68412,68413,68414,62013,68416,68417,68418,68419,68420,68421,68422,68423,66768,68425,68426,68427,68428,68429,68430,68431,68432,68433,68434,68435,68436,68437,68438,68439,68440,68441,68442,68443,68444,68445,68446,68447,68448,68449,68450,68451,68452,68453,68454,68455,68456,68457,68458,68459,68460,68461,68462,68463,68464,68465,68466,68467,68468,68469,68470,68471,68472,68473,68474,68475,68476,68477,68478,68479,68480,68481,68482,68483,68484,68485,68486,68487,68488,68489,68490,68491,68492,68493,68494,68495,68496,68497,68498,68499,68500,68501,68502,68503,68504,68505,68506,68507,68508,68509,68510,68511,68512,68513,68514,68515,68516,68517,68518,68519,68520,68521,68522,68523,68524,68525,68526,68527,68528,68529,63174,68531,68532,68533,68534,68535,68536,68537,68538,68539,68540,68541,68542,68543,68544,68204,68546,68547,62324,68549,68550,68551,68552,64751,68554,67561,68556,68557,68558,68559,68560,67574,68562,68563,68564,68565,68566,68567,68568,68569,68570,68571,62066,68573,68574,68575,60775,68577,68578,68579,68580,68581,61335,68583,68584,68585,68586,68587,68588,68589,68590,68591,68592,68593,68594,68595,68596,68597,68598,68599,68600,68601,68602,68603,68305,68605,68606,68607,65863,68609,68610,68611,68612,68613,68614,62789,68616,68617,68618,68619,68620,68621,68622,68623,68624,68625,68626,62192,68628,68629,68630,63072,68632,61001,68634,68635,68636,68637,68638,68639,68640,68641,68642,65718,68644,68645,68646,68647,68648,63475,68650,68651,68652,68653,68654,68655,68656,68657,68658,68659,66460,68661,68662,68663,62488,61147,61530,68667,68668,68669,68670,68671,68672,68673,68674,68675,68676,68677,68678,68679,61255,68681,68682,68683,68684,61859,61609,68687,68688,68689,68690,68691,64686,68693,68694,67192,68696,68697,68698,68699,63544,68701,68702,68703,68704,68705,68706,62445,68708,68709,68710,68711,68712,64171,68714,68715,68716,68717,68718,68719,68720,68721,68722,68723,61757,68725,68726,68727,67279,68729,68730,68731,68235,68733,68734,68735,68736,68737,68738,68739,68740,68741,68742,66944,68744,68745,68746,68747,68748,68749,68750,68751,68752,68753,62516,68755,68756,68757,68758,65956,68760,68761,68762,68763,68764,68765,68766,68767,63479,68769,68770,68771,68772,68773,68774,67796,68776,68777,68778,68779,68780,68781,65033,68783,68784,68785,68786,68787,68788,68789,68790,68791,68792,61585,68794,68795,68796,68797,68798,68799,61707,68801,68802,68803,68804,68805,62361,68807,68808,68809,68810,64927,68812,68813,68814,68815,68816,68817,68818,68819,68820,68821,63335,68823,68824,68825,60771,62415,68828,68829,68830,68831,68832,68833,68834,68835,68836,68837,68838,68839,68840,68841,64833,68843,68844,68845,68846,68847,68848,68849,68850,68851,64159,68853,63556,68855,68856,68857,68858,68859,68860,63368,68862,68863,68864,68865,68866,68867,68868,68869,68870,64506,68872,68873,61825,68875,68876,68877,68878,68879,68880,68881,60992,68883,61553,68885,68886,68887,68888,68889,68890,66632,68892,66638,67557,68895,68896,66235,68898,68899,68900,62367,68902,68903,68904,68905,68906,68907,68908,68909,68910,68911,68912,62912,68914,68915,68916,68917,62762,65763,65228,68921,68922,68923,68924,68925,68926,61665,68928,68929,68930,68931,68932,68933,64854,68935,68936,68937,68938,68939,68940,68941,68942,64167,68944,68945,68946,68947,68948,68949,68950,68951,62310,68953,68954,68955,68956,64968,68958,68959,61714,68961,68962,68963,68964,63222,68966,68967,68968,68969,68970,68971,63194,68973,68974,68975,68976,68977,68978,68979,68980,64610,68982,68983,68984,68985,68986,64799,68988,68989,66624,68991,68992,68993,68994,68995,68996,61503,68998,68999,69000,69001,69002,69003,69004,69005,69006,69007,63583,69009,69010,69011,66644,69013,69014,69015,69016,69017,69018,69019,69020,69021,69022,69023,69024,68090,69026,69027,69028,69029,69030,69031,69032,69033,62233,69035,69036,69037,69038,60806,69040,69041,69042,69043,69044,69045,69046,69047,69048,69049,69050,69051,69052,67054,69054,69055,69056,69057,69058,69059,69060,69061,69062,63356,69064,69065,69066,69067,69068,69069,69070,69071,69072,69073,69074,69075,69076,69077,62786,69079,69080,69081,69082,69083,69084,69085,69086,69087,69088,69089,61189,69091,69092,69093,69094,69095,69096,69097,63814,69099,69100,69101,61823,69103,69104,69105,69106,69107,69108,69109,69110,69111,69112,69113,62297,69115,69116,69117,69118,69119,69120,69121,69122,69123,69124,69125,64337,68280,69128,69129,69130,69131,69132,69133,69134,69135,61477,69137,69138,69139,69140,69141,69142,69143,69144,65051,65403,69147,69148,69149,69150,69151,62540,69153,69154,69155,69156,69157,69158,69159,69160,69161,69162,69163,69164,69165,69166,62374,69168,69169,69170,69171,69172,69173,69174,69175,61591,69177,69178,69179,69180,69181,65853,69183,69184,69185,69186,65761,69188,69189,65226,69191,69192,69193,69194,69195,69196,69197,69198,67873,69065,69201,69202,69203,69204,69080,69206,69207,63198,69209,69210,63428,69212,69213,69214,69215,66814,69217,69218,69219,69220,69221,69222,69223,69224,69225,69226,68532,69228,69229,69230,69231,69232,69233,69234,69235,69236,69237,69238,69239,64754,69241,69242,69243,69244,69245,69246,69247,69248,69249,69250,69251,63012,69253,69254,69255,69256,69257,69258,63858,69260,69261,69262,69263,69264,65984,69266,69267,69268,69269,69270,69271,69272,69273,69274,63444,69276,69277,69278,69279,69280,69105,69282,69283,69284,69285,69286,67977,69288,69289,69290,69291,61856,69293,69294,69295,69296,69297,69298,69299,69300,64683,69302,69303,69304,64431,67354,69307,69308,69309,69310,61928,69312,69313,69314,69315,69316,69317,63380,69319,69320,69321,69322,69323,69324,63971,69326,69327,63429,62645,69330,63481,69332,69333,69334,69335,69336,69337,61436,69339,69340,69341,69342,69343,69344,69345,61073,69347,69348,69349,69350,69351,69352,68531,69354,69355,69356,69357,69358,62311,69360,69361,69362,69363,69364,62174,69366,69367,69368,69369,69370,69371,69372,69373,69374,69375,69376,69377,69378,69379,69380,69381,69382,69383,69384,69385,69386,69387,69388,69389,69390,69391,69392,69393,69394,69395,69396,69397,69398,69399,69400,69401,69402,69403,69404,69405,69406,69407,69408,69409,69410,69411,69412,64085,69414,69415,69416,69417,61591,69419,69420,69421,64416,67330,69424,60843,69426,69427,61645,67354,69430,69431,69432,69433,62106,69435,69436,69437,69438,69439,63380,69441,69442,69443,69444,69445,69446,69447,69448,69449,69450,69451,61982,69453,69454,69455,69456,63041,64746,69459,69460,69461,69462,69463,61229,69465,69466,69467,69468,68127,69470,69100,69472,69473,69474,61535,69476,69477,69478,69479,69480,69481,69482,69483,69484,69485,64727,69487,69488,69489,69490,69491,69492,62030,62062,62040,69496,69497,69498,69499,69500,69501,69502,69503,69504,69505,69506,69507,69508,61245,69510,69511,69512,69513,69514,69515,69516,69517,69518,60843,69520,69521,69522,67194,69524,69525,69526,62095,69528,69529,69530,69531,61932,69533,69534,65541,69536,69537,69538,69539,69540,69541,61136,69543,69544,69545,69546,69547,61175,69549,69550,69551,69552,69553,69554,69555,69556,69557,69558,68333,69560,69561,69562,69563,69564,61709,69566,69567,69568,69569,69570,69571,66134,69573,69574,69575,69576,69577,69578,69579,68783,69581,69582,69583,69584,69585,69586,65925,69588,69589,69590,69591,69592,69593,66254,69595,69596,69597,69598,69599,64660,69601,69602,69603,69604,69605,69606,67132,69608,69609,69610,69611,69612,69035,69614,69615,69616,69617,66407,69619,66901,69621,69622,69623,69624,69625,69626,63545,69628,69629,69630,69631,61378,69633,69634,69635,69636,69637,69638,69639,69640,69641,65242,69643,69644,69645,69646,69647,69648,69649,69650,69651,69652,69653,63898,69655,69656,69657,69658,69659,69660,69661,62293,69663,69664,69665,69666,69667,69668,69669,69670,66451,69672,69673,64771,69675,64627,69677,69678,69679,69680,69681,69682,69683,68885,69685,69686,69687,69688,69689,69690,63428,69692,69693,61719,69695,69696,69697,69698,69699,61101,69701,69702,69703,69704,69705,69706,69707,69708,69709,61559,69711,69712,69713,69714,69414,69716,69717,67941,69719,69720,69721,69722,69723,69724,61823,69726,69727,69728,69729,69730,69731,69732,65991,69734,69735,69736,69737,69738,69739,69740,69741,69742,69743,69744,69745,69746,69747,69748,61878,64683,69751,69752,69753,69754,69755,61665,69757,69758,69759,69760,69761,69762,69763,68386,69765,69766,69767,69768,69769,69770,69771,69772,64458,69774,69775,69776,69777,69778,69779,69780,69781,69782,69783,69784,69785,69786,68109,69788,69789,69790,69791,62665,69793,69794,69795,69796,69797,62899,69799,69800,69801,69802,69803,69804,69805,69806,69807,69808,69809,69810,69811,69812,69813,69814,63580,69816,64358,69818,69819,69820,62819,61073,69823,69824,69825,62654,69827,69828,69829,69830,69831,69832,69833,69834,69835,69795,69837,69838,69839,69840,64337,67144,69843,69844,69845,69846,63859,69848,69849,69850,69851,69852,69853,69854,69855,69856,63027,69858,69859,69860,69861,69862,61591,69864,69865,69866,69867,69868,65748,69870,69871,69872,69873,69874,69875,69876,69877,69878,69879,69880,62262,69882,69883,69884,68834,69886,69887,69888,69889,68845,69891,69892,69893,64159,69895,69896,69897,60947,69899,69900,69901,69902,69903,69904,69905,69906,69907,69908,69909,69910,69911,69912,68946,69914,69915,69916,69917,69918,69919,69920,69921,69922,69923,69924,69925,61495,67787,69928,69929,69930,69931,66863,69933,69934,69935,69936,62155,69938,69939,69940,69941,69576,69943,69944,69945,69946,62857,69948,69949,69950,69951,69952,69953,69954,69955,69956,69957,69958,69959,66722,69961,69962,61803,69964,62335,69966,69967,69968,69969,69970,61501,69972,69973,69974,69975,69976,69977,69978,66478,69980,69981,60852,64985,62750,69985,69986,69987,69988,69989,69990,69991,64829,69993,69994,69995,69996,69997,69998,61666,70000,70001,70002,70003,70004,70005,63361,69919,70008,70009,70010,61450,70012,70013,70014,70015,70016,70017,70018,70019,62504,70021,70022,70023,70024,61720,70026,70027,70028,70029,70030,70031,70032,67573,70034,70035,70036,70037,70038,70039,70040,70041,67396,65597,70044,62347,70046,70047,70048,70049,70050,70051,66617,70053,70054,70055,70056,70057,64085,65932,70060,70061,63174,70063,70064,70065,70066,70067,70068,70069,69104,70071,70072,70073,70074,70075,70076,61805,70078,70079,70080,70081,70082,70083,70084,70085,70086,67592,68003,70089,70090,70091,70092,70093,70094,70095,70096,70097,61649,70099,70100,70101,70102,70103,70104,70105,62089,70107,70108,70109,70110,70111,64447,70113,70114,70115,70116,70117,70118,65540,70120,70121,70122,70123,70124,70125,70126,70127,70128,70129,61017,70131,70132,70133,70134,70135,70136,70137,70138,70139,70140,70141,70142,70143,70144,70145,70146,70147,62062,64627,70150,61450,70152,70153,70154,70155,69009,70157,70158,70159,70160,70161,70162,61715,70164,70165,70166,70167,70168,67521,70170,70171,70172,70173,70174,61962,70176,61196,70178,70179,70180,70181,70182,70183,70184,70185,62331,70187,70188,70189,70190,70191,70192,70193,70194,69106,70196,70197,68374,70199,70200,70201,70202,70203,70204,70205,61607,70207,70208,70209,70210,70211,70212,70213,70214,70215,70216,70217,70218,70219,70220,70221,70222,70223,65374,70225,70226,63743,70228,70229,70230,64446,70232,70233,70234,67363,70236,70237,70238,70239,70240,70241,70242,65594,70244,70245,70246,70247,70248,70249,70250,70251,63449,70253,70254,70255,70256,70257,70258,70259,70260,70261,70262,70263,70264,70265,70266,70267,70268,61770,66701,70271,69561,70273,70274,70275,70276,70277,70278,70279,70280,70281,70282,70283,70284,70285,70286,70287,70288,64202,70290,66249,70292,70293,70294,70295,70296,65926,70298,70299,70300,70301,70302,70303,70304,70305,70306,70307,61029,68097,70310,70311,70312,70313,70314,69830,70316,69549,70318,70319,70320,70321,70322,70323,70324,70325,61591,70327,70328,70329,70330,70331,70332,62753,70334,70335,70336,70337,65765,63357,70340,70341,70342,64866,70344,70345,70346,70347,70348,70349,70350,61210,70352,70353,70354,69728,70356,70357,70358,70359,70360,61515,70362,70363,61456,70365,70366,70367,70368,66107,70370,70371,70372,70373,70374,70375,70376,70377,70378,61115,70380,70381,70382,70383,66512,68280,70386,70387,70388,69354,70390,70391,70392,70393,70394,70395,62671,70397,70398,64092,70400,70401,70402,70403,70404,62736,70406,70407,70408,70409,70410,70411,70412,70413,63515,70415,70416,70417,70418,70419,70420,70421,70422,62959,70424,70425,70426,70427,70428,70429,70430,70431,70432,70433,70434,70435,70436,62612,70438,70439,70440,62619,70442,70443,70444,70445,70446,70447,70448,70449,70450,70451,70452,70453,70454,70455,70456,62118,70458,70459,70460,70461,70462,70463,70464,70465,70466,70467,61137,70469,70470,70471,61994,70473,70474,70475,70476,70477,67147,61233,70480,70481,70482,68108,70484,70485,70486,70487,70488,70489,61520,70491,70492,70493,70494,70495,70496,70497,70498,70499,70500,70501,70502,70503,70504,70505,70506,70507,66981,70509,70510,70511,70512,70513,70514,70515,70516,70517,70518,70519,70520,62902,70522,70523,70524,70525,70526,70527,70528,70529,70530,70531,70532,62033,70534,61803,70536,61073,70538,70539,70540,70541,70542,70543,70544,64803,70546,70547,70548,70549,62892,70551,70552,70553,69865,70555,70556,70557,70558,70559,70560,61856,60849,70563,70564,70565,68696,70567,70568,70569,70570,70571,70572,70573,70574,70575,70576,70577,70578,70579,70580,70581,70582,70583,70584,70585,70586,70587,70588,70589,70590,70591,70592,70593,70594,70595,70596,70597,70598,70599,70600,70601,70602,70603,70604,70605,70606,70607,70608,70609,70610,70611,70612,70613,70614,70615,70616,70617,70618,70619,70620,70621,70622,70623,70624,70625,70626,70627,70628,70629,70630,70631,70632,70633,70634,70635,70636,70637,70638,70639,70640,70641,70642,70643,70644,70645,70646,70647,70648,70649,70650,70651,70652,70653,70654,70655,70656,70657,70658,70659,70660,70661,70662,70663,70664,70665,70666,70667,70668,61676,70670,70671,70672,70673,70674,70675,67226,70677,70678,70679,69118,70681,70682,70683,70684,70685,68890,70687,70688,61824,70690,70691,70692,63947,61757,70695,70696,70697,64654,70699,70700,70701,70702,66272,70704,70705,66377,70707,70708,70709,61578,64976,70712,70713,70714,70715,70716,70717,61821,70719,67697,70721,70722,70723,70724,68573,70726,70727,70728,70729,70730,70731,70732,70733,70734,62245,70736,70737,67212,70739,70740,70741,70742,70743,70744,70745,70746,70747,70748,70749,70750,63355,70752,70753,70754,70755,70756,70757,70758,70759,70760,70761,70762,70763,70764,70765,70766,70767,70768,70347,70770,70771,70772,70773,70774,61452,70776,70777,70778,70779,70780,70781,70782,70783,64599,70785,70786,70787,70788,70789,70790,70791,70792,70793,61100,70795,70796,70797,70798,70799,70800,70801,70802,70803,70804,70805,64732,70807,70808,70809,70810,70811,70812,68726,70814,70815,61044,70817,70818,70819,70820,67659,70822,70823,70824,70825,70826,70827,70828,70829,70830,70831,70832,70833,70834,70835,70836,70837,70838,70839,70840,70841,70842,70843,70844,70845,70846,70847,70848,70849,70850,70851,70852,70853,70854,70855,70856,70857,70858,70859,70860,70861,70862,70863,70864,70865,70866,70867,70868,70869,70870,70871,70872,70873,70874,70875,70876,70877,70878,70879,70880,70881,70882,70883,70884,70885,70886,70887,70888,70889,70890,70891,70892,70893,70894,70895,70896,70897,70898,70899,70900,70901,70902,70903,70904,70905,70906,70907,70908,70909,70910,70911,70912,70913,70914,70915,70916,70917,70918,70919,70920,70921,70922,69702,70924,70925,70926,70927,70928,70929,70930,70931,70932,61963,70934,70935,70936,70937,70938,70939,70940,70941,67680,70943,70944,70945,70946,61519,70948,70949,70950,70951,70952,70953,70954,70955,64898,70957,70958,70959,70960,70961,70962,70963,70964,70965,70966,69291,64679,70969,70970,70971,70972,70973,70974,70975,70976,70977,70978,65380,67885,70981,70982,70983,70984,70985,70986,70987,70988,70989,68066,70991,70992,70993,70994,70995,70996,70469,70998,70999,62182,71001,71002,71003,70380,71005,71006,61450,71008,71009,71010,70140,71012,66647,71014,71015,71016,71017,71018,71019,71020,64218,71022,71023,71024,71025,71026,71027,71028,71029,71030,67380,71032,71033,71034,67442,71036,66357,71038,71039,71040,67524,71042,71043,69128,71045,71046,71047,62235,71049,69879,71051,64558,71053,71054,71055,62595,71057,71058,61909,69432,67883,71062,71063,71064,71065,71066,71067,71068,71069,65539,71071,71072,71073,63206,71075,71076,71077,71078,71079,71080,71081,64953,66966,71084,71085,71086,69245,71088,62670,71090,65710,61209,71093,71094,71095,71096,71097,71098,64509,71100,71101,71102,71103,71104,71105,64723,71107,71108,71109,71110,71111,71112,71113,71114,71115,71116,71117,71118,71119,71120,71121,71122,62663,71124,71125,71126,71127,71128,64628,71130,71131,71132,71133,65733,71135,71136,71137,71138,71139,60845,71141,71142,71143,71144,71145,71146,62590,71148,71149,71150,71151,71152,71153,71154,71155,71156,71157,71158,71159,71160,67352,71162,62609,71164,71165,71166,71167,71168,67497,71170,71171,71172,71173,71174,62119,69209,71177,71178,71179,71180,71181,71182,71183,69354,71185,71186,71187,71188,71189,71190,71191,71192,71193,71194,61488,71196,71197,71198,69092,65429,71201,65612,71203,71204,71205,71206,71207,71208,71209,65624,71211,71212,61976,62898,71215,71216,71217,71218,69693,71220,71221,71222,60791,71224,71225,71226,71227,71228,71229,71230,71231,71232,71233,71234,71235,71236,71237,71238,71239,71240,71241,71242,71243,71244,71245,71246,71247,71248,71249,71250,71251,71252,71253,71254,71255,71256,71257,71258,71259,71260,71261,71262,71263,71264,71265,71266,71267,71268,71269,71270,71271,71272,71273,71274,71275,71276,71277,71278,71279,71280,71281,71282,71283,71284,71285,71286,71287,71288,71289,71290,71291,71292,71293,71294,71295,61882,71297,71298,71299,71300,71301,71302,64699,71304,71305,71306,71307,71308,71309,62600,71311,71312,71313,71314,71315,71316,71317,71318,71319,71320,62443,71322,71323,71324,71325,68862,71327,71328,71329,71330,71331,71332,71333,71334,71335,71336,69915,71338,71339,71340,71341,71342,71343,71344,71345,71346,71347,64867,71349,71350,71351,71352,71353,71354,71355,66992,71357,71358,71359,71360,71361,71362,71363,71364,71365,71366,71367,71368,71369,71370,71371,71372,71373,71374,71375,71376,71377,71378,71379,71380,71381,71382,71383,71384,71385,71386,71387,71388,71389,71390,71391,71392,71393,71394,71395,71396,71397,71398,71399,71400,71401,71402,71403,71404,71405,71406,71407,71408,71409,71410,71411,71412,67899,71414,71415,70553,71417,65430,71419,71420,71421,71422,71423,65437,71425,71426,71427,71428,61057,71430,71431,71432,71433,71434,71435,71436,71437,71438,71439,71440,63154,71442,71443,71444,71445,71446,71447,71180,71449,61800,62042,71452,71453,71454,71455,71456,71457,71458,71459,71460,71461,71462,71463,71464,64208,71466,63973,71468,71469,65569,71471,71472,71473,71474,62724,71476,71477,70970,71479,71480,71481,71482,71483,71484,71485,61666,71487,71488,71489,71490,66912,71492,71493,71494,71495,67623,71497,71498,71499,71500,71501,71502,71503,71504,71505,71506,71507,71508,71509,71510,71511,71512,71513,71514,71515,71516,71517,71518,71519,71520,71521,71522,71523,71524,71525,71526,71527,71528,71529,71530,71531,71532,71533,71534,71535,71536,71537,71538,71539,71540,71541,71542,71543,71544,71545,71546,71547,71548,71549,71550,71551,71552,71553,71554,71555,71556,71557,71558,71559,71560,71561,71562,71563,71564,71565,71566,71567,71568,71569,71570,71571,71572,71573,71574,71575,71576,71577,71578,71579,71580,71581,71582,71583,71584,71585,71586,71587,71588,71589,71590,71591,71592,71593,71594,71595,71596,71597,71598,71599,71600,62154,71602,71603,71604,71605,71606,71607,62555,64888,71610,71611,71612,71613,71614,71615,71616,71617,71618,71619,64901,71621,71622,71623,71624,71625,71626,71627,71628,71629,71630,71631,64727,71633,71634,71635,71636,71637,71638,71639,71640,61452,71642,71643,71644,71645,71646,71647,71648,61962,71650,71651,71652,71653,61533,71655,71656,71657,62194,71659,69547,66246,71662,71663,61775,71665,71666,71667,66706,71669,71670,71671,71672,71673,71674,71675,71676,71677,71678,71679,71680,71681,71682,71683,61173,71685,71686,71687,64543,71689,71690,71691,71692,60764,71694,62938,71696,71697,71698,60870,71700,71701,71702,71703,71704,71705,71706,71707,68845,71709,71710,71711,71712,71713,60892,71715,71716,71717,65767,71719,71720,71721,71722,71723,65913,71725,71726,71727,71728,71729,71730,71731,65925,71733,71734,71735,71736,70187,71738,71739,71740,71741,71742,71743,71744,64900,71746,71747,71748,71749,71750,71751,71752,71753,71754,62016,71756,71757,71758,71759,71760,71761,71762,71763,61235,71765,71766,71767,71768,71769,71770,71771,71670,71773,67423,71775,71776,62484,71778,71779,71780,71781,71782,65029,71784,71785,71786,71787,71788,71789,71790,71791,62369,71793,71794,71795,71796,71797,71798,71799,71800,71801,71802,66159,71804,71805,71806,71807,71808,71809,71810,71811,67051,71813,71814,71815,71816,65761,71818,71819,71820,64144,71822,71823,71824,71825,71826,71827,70110,60942,71830,71831,62785,71833,71834,71835,71836,64336,71838,63132,71840,61713,71842,61097,71844,71845,71846,71847,71848,63634,71850,66451,71852,71853,71854,71855,71856,71857,71858,71126,64376,71861,71862,71863,71864,61011,71866,71867,71868,71869,63623,71871,71872,71873,71874,71875,71876,71877,71878,67549,71880,71881,71882,71883,71884,71885,71886,63428,71888,71889,71890,71891,71892,71893,68287,71895,71896,71897,71898,71899,71900,71901,71902,68145,71904,71905,71906,71907,71908,71909,71910,71911,71912,71913,71914,71915,71916,71917,71918,61591,71920,71921,71922,71923,71924,66406,71926,71927,71928,71929,71930,71931,67054,71933,71934,71935,71936,71937,66792,71939,71940,71941,68935,71943,71944,71945,71946,71947,71948,71949,71950,71951,71952,71953,71835,65969,71956,70787,71958,69701,71960,71961,71962,71963,71964,71965,71966,71967,61964,71969,71970,71971,71972,64617,71974,71975,71976,71977,62061,64627,71980,71981,71982,71983,71984,71985,71986,71987,71988,71989,71990,71991,65712,71993,66662,71995,71996,71997,71998,71999,72000,72001,61969,72003,72004,72005,72006,72007,72008,72009,68127,69868,72012,62729,72014,72015,72016,72017,72018,72019,72020,72021,72022,72023,72024,72025,72026,72027,72028,72029,72030,72031,72032,72033,72034,72035,72036,72037,72038,72039,72040,64558,72042,72043,72044,61352,72046,72047,72048,72049,72050,72051,72052,63542,72054,72055,72056,72057,72058,72059,72060,72061,72062,72063,61413,72065,72066,72067,72068,72069,72070,72071,72072,64357,72074,72075,72076,69611,63835,72079,72080,72081,67776,63678,61733,72085,72086,72087,72088,72089,72090,66661,72092,72093,72094,72095,62153,72097,72098,72099,72100,67109,72102,72103,68961,72105,72106,72107,72108,61990,72110,72111,72112,72113,63923,72115,72116,69866,72118,72119,72120,72121,72122,63505,72124,72125,64688,68606,72128,62611,72130,72131,72132,72133,72134,72135,72136,72137,72138,60979,72140,72141,72142,72143,72144,64917,72146,72147,72148,72149,67244,72151,61823,72153,72154,72155,72156,72157,62555,70158,72160,72161,72162,66524,72164,72165,70795,72167,72168,72169,72170,72171,72172,63636,72174,65594,72176,72177,72178,69104,72180,72181,72182,72183,72184,72185,72186,72187,72188,72189,72190,72191,61749,72193,72194,72195,72196,62070,72198,72199,72200,69183,72202,72203,72204,72205,72206,72207,72208,72209,72210,72211,72212,69188,65228,72215,72216,72217,72218,72219,62089,72221,72222,72223,72224,72225,60944,72227,72228,72229,72230,72231,72232,72233,72234,72235,72236,72237,72238,72239,71835,72241,61708,72243,72244,62125,62061,64248,72248,72249,72250,72251,72252,70023,72254,61435,72256,72257,72258,72259,72260,72261,72262,72263,61802,72265,64750,68532,72268,65610,72270,72271,72272,72273,72274,72275,72276,72277,72278,72279,72280,72281,72282,72283,72284,72285,63195,61131,72288,72289,72290,72291,72292,72293,72294,72295,62642,72297,72298,72299,72300,72301,72302,72303,69934,72305,72306,72307,72308,61591,72310,72311,72312,72313,62734,72315,61625,72317,72318,72319,72320,72321,63099,72323,72324,72325,72326,72327,72328,72329,72330,72331,72332,72333,72334,62612,72336,72337,72338,72339,72340,72341,60982,72343,72344,72345,72346,72347,72348,72349,72350,72351,72352,72353,72354,72355,72356,72357,72358,72359,72360,62519,72362,72363,72364,72365,72366,72367,72368,61803,61056,72371,64805,68331,65293,61209,72376,72377,72378,72379,72380,72381,72382,72383,72384,72385,72386,62346,72388,72389,72390,72391,72392,72393,72394,72395,72396,72397,72398,61770,72400,72401,72402,72403,72404,72405,72406,72407,72408,72409,72410,68343,70497,72413,72414,70071,72416,72417,72418,72419,72420,72421,72422,72423,61056,72425,72426,72427,72428,72429,72430,72431,72432,72433,72434,72435,72436,72437,72438,72439,72440,72441,72442,72443,72444,72445,72446,72447,72448,72449,72450,72451,72452,72453,72454,72455,72456,72457,72458,72459,72460,72461,72462,72463,72464,72465,72466,72467,72468,72469,72470,72471,72472,72473,72474,72475,72476,72477,72478,72479,72480,72481,72482,72483,72484,72485,72486,72487,72488,72489,72490,72491,72492,72493,72494,72495,62245,72497,72498,72499,72500,72501,71933,72503,72504,72505,72506,63356,72508,72509,72510,72511,72512,72513,72514,72515,72516,71338,72518,72519,72520,72521,72522,72523,72524,72525,72526,72527,72528,61456,72530,72531,72532,72533,62508,72535,72536,72537,66135,72539,72540,72541,72542,62371,72544,72545,72546,72547,72548,72549,72550,64493,63154,72553,72554,72555,64341,72557,72558,72559,72560,62474,72562,72563,72564,72565,67900,72567,72568,69796,71980,72571,72572,72573,72574,72575,72576,72577,72578,72579,72580,72581,72582,72583,72584,69177,72586,72587,72588,72589,72590,72591,60759,72593,72594,72595,72596,60845,72598,72599,72600,72601,72602,72603,72604,71150,72606,72607,72608,72609,72610,61900,72612,72613,62609,72615,72616,72617,72618,72619,62105,72621,72622,72623,65538,72625,72626,72627,72628,72629,72630,72631,72632,72633,72634,72635,69544,72637,72638,64766,72640,72641,72642,72643,61782,72645,72646,72647,72648,72649,64953,72651,61454,72653,62358,72655,72656,72657,72658,72659,72660,72661,72662,72663,72664,62182,72666,72667,72668,72669,72670,72671,72672,72673,61044,72675,72676,64724,72678,72679,72680,72681,72682,72683,72684,65447,72686,72687,72688,72689,72690,63616,72692,72693,72694,67030,72696,67261,72698,61591,72700,72701,72702,72703,72704,72705,72706,72707,72708,72709,61632,72711,72712,72713,72714,64156,72716,72717,64437,72719,72720,72721,72722,72723,62443,72725,72726,72727,72728,72729,72730,72731,65912,72733,72734,72735,72736,72737,72738,62817,72740,72741,72742,72743,72744,72745,72746,72747,72748,65433,72750,66238,72752,72753,72754,72755,72756,72757,72758,72759,72760,71840,72762,72763,72764,72765,72766,62296,72768,70697,72770,66622,72772,72773,72774,72775,62554,61191,72778,72779,72780,72781,72782,61236,72784,72785,72786,72787,72788,72789,72790,63835,72792,72793,72794,72795,72796,72797,72798,72799,69470,72801,72802,70328,69878,71053,72806,72807,72808,72809,72810,62424,72812,72813,72814,72815,72816,61355,72818,72819,72820,65015,72822,64456,72824,72825,72826,72827,69545,62357,72830,72831,72832,72833,72834,64927,64953,61191,72838,72839,72840,72841,72842,61208,72844,72845,72846,62341,72848,72849,72850,72851,61126,62331,72854,72855,72856,72857,72858,72859,72860,72861,72862,72863,61821,72865,72866,72867,71898,72869,72870,72871,72872,69037,72874,72875,72876,72877,62243,72879,72880,72881,72882,72883,72884,72885,60818,62752,72888,72889,72890,72891,72892,72893,66170,71710,72896,72897,72898,72899,72900,66419,72065,72903,72904,72905,72906,72907,72908,72909,72910,72911,72912,72913,62626,72915,72916,72917,72918,72919,72920,72921,72922,72923,72924,71607,72926,72927,72928,62883,72930,72931,72932,72933,72934,72935,72936,72937,72938,62844,72940,72941,72942,72943,72944,72945,72946,72947,72948,72949,72950,72951,72952,72953,63689,72955,72956,72957,72958,72959,66661,72961,72962,68108,72964,72965,72966,72967,64770,72969,72970,72971,62043,72973,72974,72975,72976,72977,72978,72979,72980,71009,72982,72983,72984,72985,72986,72987,70375,72989,72990,69716,72992,69865,72994,72995,72996,72997,72998,72999,73000,73001,64985,68833,73004,73005,73006,73007,73008,73009,73010,73011,64575,73013,73014,73015,73016,73017,73018,73019,73020,63545,73022,73023,73024,73025,66574,73027,73028,73029,73030,73031,73032,73033,73034,73035,73036,73037,73038,73039,73040,73041,73042,73043,73044,73045,73046,73047,73048,73049,73050,73051,73052,73053,73054,73055,73056,73057,73058,73059,73060,73061,73062,73063,73064,73065,73066,73067,73068,73069,73070,73071,73072,73073,73074,73075,73076,73077,73078,73079,73080,73081,73082,73083,73084,73085,73086,73087,73088,73089,73090,73091,73092,73093,72562,73095,73096,68290,73098,73099,72645,73101,73102,63492,61803,61208,73106,73107,73108,73109,73110,63144,73112,61147,73114,73115,73116,73117,65029,73119,73120,73121,73122,62368,73124,73125,73126,73127,73128,73129,73130,73131,73132,73133,62665,73135,73136,73137,69419,73139,73140,73141,62730,73143,73144,73145,73146,73147,73148,73149,73150,73151,73152,64558,73154,73155,73156,73157,73158,73159,73160,73161,73162,63100,73164,73165,73166,73167,73168,73169,73170,73171,73172,73173,73174,73175,72132,73177,73178,73179,73180,73181,66432,73183,73184,73185,73186,73187,64456,73189,73190,73191,73192,61138,73194,61234,61780,73197,73198,73199,73200,62665,73202,73203,73204,73205,66198,73207,73208,73209,73210,73211,73212,73213,73214,70825,73216,73217,72005,73219,73220,73221,73222,73223,69717,66645,73226,73227,73228,73229,73230,73231,73232,73233,68813,73235,73236,73237,73238,73239,73240,67637,73242,73243,73244,73245,73246,73247,72586,73249,73250,73251,73252,73253,72880,73255,73256,73257,73258,73259,60827,73261,73262,73263,73264,73265,73266,73267,73268,73269,73270,73271,73272,65855,73274,73275,71701,73277,73278,73279,73280,73281,73282,61381,73284,73285,73286,73287,73288,73289,73290,73291,61676,73293,73294,73295,73296,73297,73298,73299,69658,73301,73302,73303,73304,73305,63621,73307,73308,73309,73310,64478,73312,72637,73314,68733,73316,73317,73318,73319,73320,73321,62055,73323,73324,73325,73326,73327,73328,73329,70322,73331,73332,69094,73334,73335,66516,73337,73338,73339,73340,73341,71785,73343,73344,73345,73346,73347,73348,73349,73350,62368,73352,73353,73354,73355,73356,73357,73358,73359,73360,73204,61250,73363,73364,73365,73366,62734,73368,73369,62942,62410,73372,73004,73374,73375,73376,73377,62959,73379,73380,73381,73382,73383,73384,73385,73386,73387,73388,73389,73390,73391,73392,62612,73394,73395,73396,73397,73398,62619,73400,73401,73402,73403,73404,73405,73406,73407,73408,61438,73410,73411,73412,73413,73414,73415,73416,61981,73418,73419,73420,73421,73422,73423,73424,73425,73426,73427,64613,73429,73430,73431,64806,61800,73434,70179,73436,73437,64974,73439,73440,73441,73442,73443,61540,73445,73446,73447,67757,73449,73450,73451,73452,73453,73454,66737,61811,73457,64381,73459,73460,73461,73462,73463,73464,73465,73466,73467,73468,62875,73470,73471,73472,73473,62236,66890,73476,73477,73478,73479,73480,73481,73482,73483,69990,73485,73486,73487,73488,73489,73490,73491,73492,73493,73494,61345,73496,73497,73498,73499,73500,73501,73502,73503,64848,73505,69906,73507,68862,73509,73510,73511,73512,73513,73514,73515,63970,73517,73518,73519,73343,73521,73522,73523,67796,73525,73526,73527,73528,73529,73530,73531,73114,73533,67396,71740,73536,73537,62345,73539,73540,73541,71443,73543,73544,73545,73546,64498,73548,73549,73550,68812,73552,73553,73554,73555,73556,73557,73558,73559,73560,73561,73562,61101,73564,73565,73566,73567,73568,73569,73570,73571,73572,62068,66169,73575,73576,64150,73578,73579,73580,73581,73582,73583,73584,73585,64158,73587,73588,62986,73590,73591,73592,73593,73594,73595,73596,73509,73598,73599,73600,73601,73602,73603,73604,62694,73337,73607,66134,73609,73610,73611,73612,73613,73614,69029,73616,73617,61798,73619,61209,73621,73622,73623,73624,73625,65608,73627,73628,73629,73630,73631,66827,62334,73634,69282,73636,73637,73638,73639,73640,73641,65993,73643,73644,73645,73646,73647,73648,73649,73650,73651,73652,73653,73654,73655,73656,73657,73658,73659,67586,73661,73662,73663,73664,73665,73666,73667,71937,73669,63355,73671,73672,66181,73674,73675,73676,73677,73678,73679,73680,73681,73682,66249,73684,73685,73686,73687,64498,73689,73690,73691,73692,73693,72388,73695,73696,73697,73698,73699,73700,73701,73702,71765,73704,73705,73706,73707,73708,69973,73710,73711,73712,73713,73714,73715,73716,73717,73718,73719,73720,73721,69213,73723,73410,73725,73726,73727,66592,73729,73730,73731,73732,73733,73734,73735,71075,73737,73738,73739,73740,73741,73742,73743,62557,63949,73746,73747,73748,73749,73750,73751,73752,73753,62574,66971,73756,73757,73758,62066,73760,72035,73762,68163,73764,73765,73766,73767,73768,71701,73770,73771,73772,73773,73774,73775,62774,73777,73778,73779,73780,73781,65776,73783,73784,73785,73786,71075,73788,73789,73790,73791,73792,73793,73794,61516,73796,73797,73798,73799,73800,73801,73802,73803,73804,63222,73806,73807,73808,73809,73810,73811,73812,73813,73814,73815,73816,73817,73818,73819,73820,73821,62629,73823,73824,73825,73826,73827,73828,73829,61189,73831,73832,73833,73834,73835,73836,73837,73838,61144,73840,73841,73842,73843,73844,73845,73846,66622,73848,73849,73850,73851,73852,73853,73854,65576,73856,61991,73858,67038,73860,64416,64684,73863,73864,73865,70002,73867,64447,73869,73870,73871,73872,73873,73874,73875,73876,73877,73878,66439,73880,73881,73882,73883,73884,63191,73886,73887,73888,73889,73890,73891,72250,73893,73894,62628,73896,73897,73898,73899,73900,73901,73902,73903,73904,73905,73906,65964,73908,66096,73910,70510,73912,73913,70523,73915,73916,73917,73918,73919,73920,73921,73922,68784,73924,73925,73926,73927,73928,73929,73930,73931,61173,73933,73934,73935,73936,73937,73938,70153,62645,73941,73526,73943,73944,73945,73946,73947,73948,62068,68833,73951,73952,73953,73954,73955,73956,73957,64149,73959,73960,73961,73962,73963,73964,73965,73966,73967,73968,73969,67724,73971,61411,73973,73974,73975,73976,73977,73978,73979,73980,73981,73982,73983,73984,73985,73986,73987,73988,73989,73990,73991,73992,73993,73994,73995,73996,73997,73998,73999,74000,74001,74002,74003,74004,74005,74006,74007,74008,74009,74010,74011,62478,74013,74014,74015,68103,74017,74018,64805,61977,74021,74022,74023,61193,74025,74026,65301,74028,74029,74030,74031,74032,74033,74034,68790,74036,74037,74038,62121,74040,74041,74042,74043,74044,67787,74046,74047,74048,74049,74050,74051,74052,74053,74054,74055,74056,63048,74058,74059,74060,74061,74062,74063,67542,74065,74066,61591,74068,60847,74070,74071,74072,74073,74074,74075,60870,74077,74078,68035,74080,74081,74082,67356,74084,74085,74086,71062,74088,74089,74090,74091,74092,74093,74094,74095,74096,65541,74098,74099,74100,74101,74102,62153,74104,74105,74106,74107,73933,74109,74110,74111,74112,67153,74114,74115,74116,74117,74118,74119,67306,74121,74122,74123,74124,65948,74126,74127,74128,74129,74130,74131,74132,74133,74134,74135,74136,74137,74138,74139,74140,74141,74142,74143,74144,74145,74146,74147,74148,74149,74150,74151,74152,74153,74154,74155,74156,74157,74158,74159,74160,74161,74162,74163,74164,74165,74166,74167,74168,74169,74170,74171,62516,74173,74174,74175,74176,74177,70136,74179,74180,74181,74182,61076,74184,74185,74186,74187,74188,74189,74190,74191,74192,74193,63225,74195,74196,74197,74198,74199,74200,74201,74202,74203,74204,74205,74206,74207,74208,61981,74210,74211,74212,74213,74214,74215,74216,74217,63428,74219,74220,74221,74222,74223,74224,74225,66647,74227,74228,74229,74230,70039,74232,74233,74234,74235,74236,69510,74238,74239,73006,74241,74242,74243,74244,74245,74246,74247,73962,74249,74250,74251,74252,74253,74254,74255,74256,63540,74258,60983,74260,74261,74262,61551,74264,74265,74266,74267,74268,74269,74270,74271,74272,74273,74274,68753,74276,62469,74278,74279,74280,74281,74282,62355,74284,62140,74286,74287,74288,74289,71127,63850,74292,74293,74294,74295,62357,74297,74298,74299,74300,74301,74302,74303,62653,74305,74306,74307,65420,74309,74310,71231,69874,74313,74314,74315,74316,74317,69990,74319,74320,74321,74322,74323,74324,74325,74326,61655,74328,74329,74330,74331,74332,66326,74334,74335,60889,74337,74338,74339,74340,74341,74342,74343,74344,74345,74346,74347,74348,74349,74350,74351,62611,74353,74354,74355,74356,74357,63899,74359,74360,74361,74362,74363,72733,74365,74366,74367,74368,74369,74370,74371,74372,74373,74374,74375,68963,74377,74378,74379,74380,74381,74382,74383,66961,74385,74386,74387,74388,74389,74390,74391,61719,74393,74394,74395,74396,74397,74398,74399,74400,74401,74402,64484,74404,74405,74406,74407,61962,74409,74410,74411,74412,74413,74414,66806,74416,74417,74418,67546,74420,74421,74422,74423,74424,71005,74426,74427,62701,74429,65831,74431,74432,74433,74434,74435,74436,61173,74438,74439,74440,74441,74442,74443,61591,64408,74446,74447,74448,74449,74450,74451,74452,74453,74454,69302,74456,74457,74458,62277,71323,74461,74462,74463,74464,74465,74466,74467,74468,74469,74470,69778,74472,74473,74474,74475,69845,74477,61175,74479,74480,74481,74482,74483,74484,68362,74486,74487,74488,74489,74490,74491,74492,74493,74494,74495,74496,63133,74498,74499,74500,74501,74502,74503,74504,74505,66217,74507,74508,74509,74510,74511,74512,65293,64234,74515,74516,74517,74518,74519,74520,61156,74522,74523,74524,74525,74526,74527,74528,74529,74530,74531,66208,74533,74534,62021,74536,74537,74538,74539,74540,74541,74542,74543,74544,74545,74546,74547,65293,71995,74550,74551,74552,74553,74554,74555,70390,74557,74558,74559,74560,74561,74562,62555,68916,74565,74566,69302,74568,74569,62443,74571,74572,74573,74574,74575,74576,66337,74578,74579,74580,74581,74582,74583,74584,74585,74586,68946,74588,74589,74590,74591,74592,74593,74594,68718,74596,74597,61583,74599,74600,74601,74602,74603,74604,74605,67153,74607,74608,74609,74610,74611,74612,74613,74614,74615,74616,63589,74618,74619,74620,62344,74622,74623,74624,74625,74626,74627,74628,67899,66723,74631,74632,74633,74634,61796,74636,74637,74638,74639,74640,73716,74642,74643,74644,74645,74646,63130,74648,74649,67971,74651,74652,74653,74654,74655,74656,62068,74658,74659,74660,74661,74662,74663,74664,74665,74662,74667,74668,74669,74670,74671,61600,74673,74674,74675,62745,74677,62769,74679,74680,74681,74682,74683,64150,74685,74686,74687,74688,74689,74690,74691,74692,74693,74694,74695,74696,74697,72717,74699,62981,74701,74702,74703,74704,74705,74706,72241,65710,74709,66254,74711,74712,74713,74714,74715,72153,74717,74718,74719,74720,74721,74722,74723,74724,74725,74726,74727,74728,74729,61963,69545,69244,74733,74734,74735,74736,74737,74738,74739,74740,74741,65324,66131,74744,74745,61803,72571,74748,74749,74750,74751,74752,74753,74754,74755,74756,74757,64968,74759,65990,74761,74762,74763,74764,74765,74766,74767,74768,74769,74770,74771,63503,74773,74774,74775,72025,74777,72880,74779,74780,74781,74782,74783,74784,74785,74786,61639,74788,61894,74790,74791,74792,74793,74794,67212,74796,74797,74798,74799,74800,74801,74802,60901,67228,74805,74806,74807,74808,74809,74810,74811,74812,74813,61136,74815,74816,74817,74818,74819,70310,74821,74822,74823,74824,74825,74826,74827,74828,63928,74830,74831,74832,74833,74834,65946,74836,74837,74838,74839,74840,74841,74842,74749,74844,74845,74846,74847,74848,74849,74850,74851,74852,72261,74854,74855,62030,70551,74858,61507,74860,74861,74862,74863,74864,60805,74866,74867,74868,74869,74870,74871,74872,74873,74874,74875,74876,74877,74878,74879,74880,74881,74882,74883,71815,74885,60834,74887,74888,74889,74890,74891,74892,74893,74894,74895,74896,74897,74898,74899,74900,74901,74902,64833,74904,74905,74906,74907,66907,74909,63115,74911,74912,74913,74914,74915,74916,61137,74918,74919,74920,74921,62182,74923,74924,74925,74926,74927,63428,74929,74930,74931,74932,61235,74934,74935,74936,65447,74938,74939,74940,74941,74942,74943,74944,74945,74946,62321,73227,61097,74950,74951,74952,74953,74954,72273,74956,74957,74958,61758,74960,74961,74962,61520,74964,74965,74966,74967,74968,74969,74970,74971,74622,74973,74974,74975,74976,74977,74978,74979,74980,74981,74982,74983,70320,74985,74986,65735,74988,61593,74990,74991,74992,62923,67333,74995,71053,74997,74998,74999,75000,70424,75002,75003,75004,75005,75006,75007,75008,75009,75010,62615,73401,75013,75014,75015,75016,75017,75018,75019,75020,75021,75022,75023,62516,75025,75026,75027,75028,75029,75030,75031,75032,75033,75034,75035,61455,75037,75038,75039,75040,75041,75042,75043,75044,75045,75046,62060,75048,75049,75050,75051,75052,75053,62898,75055,75056,75057,75058,75059,75060,75061,66478,75063,67381,75065,75066,75067,75068,63131,75070,75071,75072,75073,75074,75075,63017,75077,75078,75079,75080,75081,75082,62374,75084,75085,75086,75087,61203,75089,75090,75091,75092,67420,75094,75095,66066,75097,75098,75099,75100,75101,75102,75103,75104,63159,75106,75107,75108,75109,75110,72079,75112,75113,75114,62337,75116,75117,75118,63715,69878,75121,75122,75123,75124,72498,75126,75127,75128,75129,75130,75131,75132,75133,66300,75135,62770,75137,75138,75139,72049,75141,75142,75143,75144,75145,75146,75147,75148,75149,75150,61382,75152,75153,75154,75155,75156,75157,69307,75159,75160,66430,75162,67361,75164,75165,75166,75167,71778,75169,75170,75171,75172,75173,68117,75175,75176,65464,75178,75179,62892,63849,75182,64627,75184,75185,75186,75187,75188,75189,75190,75191,62508,75193,75194,75195,75196,75197,75198,71776,74541,75201,75202,72770,61216,75205,75206,75207,75208,75209,69333,75211,75212,75213,75214,75215,75216,65323,75218,72704,75220,75221,75222,61859,75224,75225,75226,60800,75228,75229,75230,75231,75232,75233,75234,75235,64684,75237,75238,75239,64696,75241,75242,75243,75244,75245,75246,74909,72131,75249,75250,75251,75252,61399,75254,75255,75256,65775,75258,75259,75260,75261,75262,75263,75264,75265,75266,61981,75268,67381,75270,75271,75272,75273,75274,75275,64340,75277,75278,75279,75280,75281,62343,75283,75284,75285,75286,75287,75288,75289,75290,75291,69128,75293,62814,75295,75296,75297,75298,72940,62341,75301,75302,75303,75304,75305,75306,75307,75308,75309,75310,75311,75312,75313,68278,75315,75316,75317,63141,75319,75320,75321,75322,75323,75324,75325,75326,75327,75328,75329,75330,75331,75332,75333,61097,75335,75336,75337,75338,75339,75340,75341,75342,75343,75344,75345,67512,66013,75348,75349,75350,64290,75352,75353,75354,75355,64697,75357,75358,75359,67873,60908,75362,75363,75364,75365,75366,62986,75368,75369,75370,75371,75372,75373,75374,75375,75376,60981,75378,75379,75380,75381,71112,75383,75384,75385,75386,75387,75388,75389,63139,75391,75392,75393,75394,75395,75396,75397,75398,70924,75400,75401,75402,75403,75404,75405,75406,73832,75408,75391,75410,75411,75412,75413,61737,75415,75416,75417,75418,61537,75420,75421,75422,75423,75424,75425,75426,75427,75428,75429,75430,61436,75432,75433,75434,75435,75436,64589,75438,75439,75440,65575,75442,75443,75444,75445,75446,68402,61591,75449,75450,75451,75452,75453,62923,75455,75456,75457,75229,75459,75460,75461,75462,75463,64679,75465,75466,75467,61666,75469,75470,75471,75472,75473,74462,75475,75476,75477,75478,75479,75480,75481,75482,70120,75484,75485,75486,75487,75488,75489,70139,75491,68260,64341,75494,75495,75496,75497,75498,63125,75500,73730,75502,75503,69848,75505,75506,75507,64222,75509,75510,75511,75512,75513,75514,62815,75516,75517,75518,75519,75520,75521,75522,75523,75524,62910,63678,75527,75528,75529,75530,75531,75532,75533,75534,63143,75536,75537,75538,75539,75540,62236,75542,61339,75544,75545,75546,64833,75548,75549,75550,75551,75552,75553,75554,75555,75556,75557,75558,63351,75560,75561,75562,75563,60930,75565,75566,75567,75568,75569,61697,75571,75572,75573,75574,75575,75576,69327,75578,75579,74046,75581,75582,75583,75584,75585,75586,75403,75588,75589,75590,75591,70704,75593,75594,75595,75596,75597,75598,69669,75600,75601,75602,62882,75604,75605,75606,75607,75608,75609,75610,74821,75612,75613,75614,75615,75616,75617,75618,75619,75620,75621,75622,62355,75624,75625,75626,75627,75628,75629,75630,70493,75632,62014,75634,75635,75636,61008,75638,75639,75640,75641,75642,75643,75644,75645,75646,75647,75500,75649,61033,75651,75652,75653,75654,75655,61976,62336,75658,75659,75660,74625,75662,75663,75664,75665,75666,75667,62914,75669,75670,75671,75672,74675,75674,75675,66881,75677,75678,75679,75680,75681,75682,75683,75684,75349,75686,75687,67183,75689,75690,75691,75692,75693,75694,75695,75696,66420,75698,75699,62984,75701,75702,75703,61692,75705,75706,75707,75708,75709,75710,75711,75712,75713,75714,75715,75716,69819,75718,75719,75720,75721,75722,75723,75724,61719,75726,75727,75728,75729,75730,75731,75732,75733,75734,75735,63224,75737,75738,75739,75740,75741,75742,75743,62193,75745,75746,63622,75748,75749,75750,75751,71872,75753,75754,75755,75756,75757,75758,64770,63074,75761,75762,75763,75764,75765,75766,61820,75768,75769,75770,75771,75772,75773,75774,75775,75776,67696,75778,75779,75780,75781,75782,75783,63794,75785,75786,75787,75788,65266,75790,75791,68875,75793,75794,75795,75796,75797,75798,75799,75800,62873,75802,75803,75804,66875,75806,69879,64109,75809,75810,75811,75812,75813,75814,75815,75816,60872,75818,75819,75820,75821,67344,75823,75824,75825,75826,75827,75828,69431,67882,75831,75832,75833,75834,75835,63380,75837,75838,75839,75840,75841,75842,65450,75844,75845,61586,75847,75848,75849,63417,75851,75852,75853,75854,75855,73553,75857,75858,75859,75860,75861,75862,75863,75864,75865,75866,75867,69705,75869,75870,75871,75872,75873,75874,75875,61039,75877,75878,75879,62196,63070,75882,75883,75884,75885,75886,75887,75888,64200,75890,75891,75892,75893,74264,75895,75896,75897,75898,66460,75900,75901,75902,72249,75904,75905,75906,75907,75908,75909,60768,75911,75912,75913,75914,75915,75916,75917,75918,75919,75920,75921,75922,75923,75924,75925,75926,75927,75928,75929,75930,75931,75932,75933,75934,75935,75936,62258,75938,75939,75940,75941,75942,75943,75944,75945,61655,64429,75948,75949,75950,65512,70752,75953,75954,75955,65918,75957,75958,75959,75960,65924,75962,75963,75964,75965,75966,75967,75968,75969,61976,75971,61747,75973,75974,75975,75976,75977,75978,62858,75980,74270,75982,61019,75984,75985,75986,75987,67396,75989,75990,62898,75992,75993,67311,75995,75996,75997,75998,75999,67638,76001,76002,76003,74938,76005,76006,76007,76008,76009,76010,76011,76012,66522,76014,76015,76016,76017,76018,76019,62369,76021,76022,76023,76024,76025,76026,76027,76028,76029,76030,76031,64899,76033,76034,76035,76036,76037,76038,76039,76040,76041,76042,66460,76044,76045,76046,76047,76048,65847,76050,76051,76052,76053,74673,76055,76056,76057,72039,76059,73764,76061,76062,64846,76064,76065,76066,76067,76068,76069,76070,67071,76072,76073,76074,76075,76076,76077,76078,76079,76080,76081,76082,76083,76084,76085,76086,64865,76088,76089,76090,76091,76092,76093,76094,67627,76096,76097,76098,76099,76100,76101,76102,67276,76104,76105,76106,76107,76108,76109,61585,76111,76112,76113,76114,66255,76116,76117,76118,76119,76120,76121,76122,76123,76124,76125,76126,63599,76128,65293,73610,76131,76132,76133,74951,76135,76136,76137,68238,76139,76140,68784,76142,76143,76144,66159,76146,76147,76148,76149,75455,76151,76152,76153,76154,76155,76156,73863,76158,76159,64156,76161,76162,76163,76164,76165,76166,76167,64437,76169,76170,76171,76074,76173,76174,76175,67363,76177,76178,76179,76180,76181,76182,76183,76184,76185,76186,76187,62671,63070,76190,76191,76192,76193,76194,76195,61833,76197,62063,63798,76200,76201,76202,76203,76204,76205,76206,76207,76208,61097,76210,76211,76212,76213,69964,66517,76216,76217,76218,76219,76220,74185,76222,76223,76224,76225,64219,76227,76228,76229,76230,76231,76232,76233,76234,76235,76236,69177,76238,76239,76240,76241,64414,76243,76244,76245,60809,76247,76248,76249,76250,76251,76252,76253,76254,65646,65380,76257,76258,64442,76260,76261,76262,76263,76264,76265,65863,76267,76268,66431,76270,76271,76272,69916,76274,76275,76276,76277,76278,76279,76280,76281,73207,76283,76284,76285,76286,61821,76288,76289,76290,75175,61709,62047,69209,76295,76296,68675,76298,76299,76300,76301,65322,76303,76304,76305,62914,76307,76308,76309,76310,75457,76312,76313,76314,76315,76316,76317,76318,76319,73004,76321,76322,76323,76324,76325,62277,69201,76328,76329,76330,76331,76332,74588,76334,76335,76336,62518,76338,76339,76340,76341,76342,63200,76344,76345,63979,76347,76348,76349,76350,76351,76352,76353,76354,76355,76356,76357,76358,76359,76360,76361,76362,76363,76364,76365,76366,76367,76368,76369,76370,76371,76372,76373,76374,76375,76376,76377,76378,76379,76380,76381,76382,76383,76384,76385,76386,76387,76388,76389,76390,76391,76392,76393,76394,76395,76396,76397,76398,76399,76400,76401,76402,76403,76404,76405,76406,76407,76408,76409,76410,76411,76412,76413,76414,76415,76416,76417,76418,76419,76420,76421,76422,76423,76424,66459,76426,76427,76428,76429,76430,76431,76432,76433,61983,76435,76436,76437,67382,76439,76440,76441,76442,76443,76444,76445,76446,76447,76448,62062,76450,76451,74967,76453,76454,61175,76456,76457,76458,71852,76460,76461,76462,62508,62040,76465,76466,76467,76468,76469,76470,76471,76472,76473,76474,76475,76476,76477,69703,76479,76480,76481,76482,76483,76484,76485,76486,76487,76488,76489,75449,76491,76492,76493,76494,76495,72593,76497,76498,76499,76500,76501,76502,62938,76504,76505,76506,76507,76508,62953,73005,76511,76512,76513,76514,76515,76516,76517,76518,61655,74077,76521,76522,76523,76524,61909,62095,76527,76528,76529,76530,76531,76532,76533,68383,76535,76536,76537,76538,76539,76540,76541,76542,76543,76544,76545,76546,76547,68065,76549,76550,76551,76552,76553,76554,72964,76556,76557,76558,76559,76560,76561,76562,76563,76564,68127,76566,76567,66475,76569,76570,76571,76572,76573,76574,76575,76576,76577,76578,76579,76580,76581,76582,76583,76584,76585,76586,76587,76588,76589,76590,76591,76592,76593,76594,76595,76596,76597,76598,76599,76600,76601,76602,76603,76604,76605,76606,76607,76608,76609,76610,76611,76612,76613,65251,76615,76616,76617,76618,67278,76620,76621,61235,76623,76624,76625,76626,62664,76628,76629,76630,76631,76632,76633,76634,63199,76636,76637,76638,72841,76640,76641,62032,76643,76644,76645,68363,76647,76648,76649,76650,76651,76652,76653,76654,76655,76656,76657,61966,76659,76660,76661,76662,76663,66158,76665,76666,76667,76668,65743,76670,76671,76672,76673,76674,76675,76676,76677,63519,76679,60845,76681,76682,76683,76684,76685,76686,60854,76688,64439,76690,76691,76692,76693,76694,76695,63355,76697,76698,76699,76700,76701,76702,76703,76704,76705,62786,76707,76708,76709,76710,76711,76712,76713,61494,76715,76716,76201,76718,76719,76720,76721,76722,62215,76724,76725,76726,74484,76728,76729,67150,76731,76732,76733,76734,76735,76736,76737,76738,76739,74837,76741,76742,76743,76744,76745,76746,76747,76748,76749,76750,76751,76752,76753,76754,76755,76756,76757,76758,76759,76760,76761,76762,72112,73748,76765,76766,76767,76768,76769,76770,76771,76772,76773,76774,72753,76776,76777,76778,76779,76780,76781,76782,76783,60820,76785,76786,76787,76788,76789,76790,76791,76792,76793,76794,76795,76796,76797,64685,76799,76800,64848,76802,76803,76804,76805,67728,76807,76808,76174,76810,76811,76812,76813,76814,70236,76816,76817,76818,76819,76820,76821,76111,76823,76824,76825,62831,76827,76828,76829,76830,76831,76832,76833,63582,76835,76836,76837,74173,69964,62701,76841,76842,76843,76844,76845,76846,76847,76848,76849,61096,76851,76852,76853,76854,76855,76113,76857,65403,76859,75270,76861,76862,76863,76864,76865,63613,76867,61783,76869,76870,61176,76872,76873,76874,76875,65845,76877,76878,76879,76880,76059,76882,76883,76884,62938,76886,76887,76888,76889,76681,76891,76892,76893,76894,76895,60869,76897,76898,76899,76900,76901,76902,76903,76904,76905,76906,76907,76908,61899,76910,76911,76912,76913,61677,76915,76916,68386,76918,76919,76920,76921,76922,76923,76924,67623,76926,68328,76928,76929,74438,76931,76932,76933,76934,76935,76936,61515,76938,76939,76940,76941,66538,76943,76944,76945,76946,76947,76948,76949,76950,76951,76952,64727,76954,76955,76956,76957,74961,76959,76960,76961,76962,62042,76964,76965,76966,76967,76968,76969,76970,76971,66482,76973,70536,70144,76976,76977,76978,61186,76980,76981,76982,76983,76984,76985,76986,76987,76988,76989,75746,76991,64886,76993,76994,76995,76996,76997,76998,76999,77000,77001,77002,61840,77004,77005,77006,61855,77008,77009,60794,77011,77012,77013,77014,77015,77016,77017,77018,77019,77020,62087,77022,63545,77024,77025,77026,63356,77028,77029,77030,77031,77032,77033,77034,77035,75259,77037,77038,77039,77040,77041,77042,77043,61985,74711,77046,77047,77048,77049,77050,77051,77052,77053,75283,77055,77056,77057,77058,77059,77060,77061,77062,77063,77064,77065,77066,77067,77068,74935,77070,77071,77072,77073,66587,77075,77076,77077,62896,77079,77080,77081,77082,77083,77084,77085,73411,77087,77088,77089,68802,77091,64770,62038,77094,77095,77096,61049,77098,77099,77100,77101,77102,77103,60792,77105,64561,77107,77108,77109,77110,77111,61356,77113,77114,77115,77116,77117,77118,77119,67873,71323,77122,77123,77124,77125,77126,77127,77128,77129,77130,77131,77132,61023,77134,77135,77136,77137,77138,77139,77140,72765,77142,77143,77144,77145,71897,61485,77148,77149,66733,77151,77152,75898,77154,77155,69545,77157,77158,73623,77160,77161,77162,77163,77164,77165,77166,77167,77168,77169,77170,66116,77172,77173,77174,77175,77176,77177,77178,77179,77180,77181,77182,66534,77184,77185,77186,69664,77188,77189,77190,71852,77192,77193,77194,77195,77196,77197,69004,77199,72182,77201,77202,77203,77204,77205,77206,77207,77208,77209,77210,71446,77212,77213,62069,69880,66014,77217,77218,77219,77220,77221,77222,71702,77224,77225,77226,77227,77228,77229,77230,77231,61381,77233,77234,77235,77236,77237,62609,77239,77240,77241,77242,77243,77244,77245,77246,77247,77248,67230,77250,77251,77252,77253,77254,65948,77256,77257,77258,77259,77260,77261,77262,77263,72151,66628,77266,77267,77268,77269,65589,77271,74292,76216,77274,73343,77276,77277,77278,77279,77280,77281,77282,69266,77284,77285,77286,77287,77288,70536,62153,63858,77292,77293,77294,77295,77296,77297,77298,62367,77300,77301,77302,77303,77304,77305,61591,77307,77308,77309,77310,77311,77312,77313,77314,77315,77316,69879,64110,77319,77320,77321,77322,77323,77324,76681,77326,77327,77328,77329,76521,77331,77332,77333,77334,77335,77336,61920,77338,77339,77340,77341,77342,77343,77344,77345,63005,68121,77348,76347,77350,77351,63924,77353,77354,77355,77356,77357,64202,77359,77360,77361,77362,77363,77364,77365,75322,77367,77368,77369,77370,77371,77372,77373,77374,77375,77376,77377,77378,77379,77380,77381,64660,77383,77384,77385,77386,77387,77388,77389,77390,77391,77392,77393,77394,77395,61559,77397,77398,77399,70700,77401,77402,77403,77404,77055,77406,77407,77408,77409,77410,61237,77412,77413,77414,77415,77416,77417,77418,77419,62233,77421,77422,77423,77221,77425,76681,77427,77428,77429,77430,61665,77432,77433,77434,77435,77436,77437,77438,60908,67071,77441,77442,77443,77444,77445,77446,77447,77448,68618,77450,77451,77452,77453,77454,77455,76861,77457,77458,77459,77460,77461,77462,70249,77464,77465,61820,77467,77468,63615,77470,77471,61136,77473,77474,77475,72584,77477,62474,77479,77480,77481,77482,77483,77484,77485,77486,77487,77474,77489,77490,77491,77492,77493,75176,62043,77496,77497,77498,77499,77500,77501,77502,77503,77504,77505,71295,77507,77508,77509,77510,77511,77512,77513,77514,77515,77516,77517,77518,77519,77520,77521,77522,77523,65363,77525,77526,77527,77528,71933,77530,77531,77532,69902,77534,71327,77536,77537,77538,77539,67914,77541,62355,77543,77544,77545,77546,63815,77548,77549,77550,66835,77552,77553,77554,77555,77556,77557,77558,77559,66587,77561,77562,77563,72833,77565,77566,62370,77568,77569,77570,77571,77572,77573,61800,68729,77576,77577,75625,77579,77580,77581,77582,77583,61228,77585,77586,77587,77588,61144,77590,77591,77592,77593,77594,77595,62914,77597,77598,61858,77600,60836,77602,77603,77604,77605,61657,74797,77608,77609,77610,77611,77612,77613,77614,72140,77616,77617,77618,77619,77620,77621,77622,77623,77624,77625,77626,77627,77628,65945,77630,77631,77632,77633,63576,77635,77636,64480,77638,77639,77640,77641,77642,77643,77644,77645,62476,77647,77648,77649,67382,77651,77652,77653,72115,77655,69245,77657,77658,77659,65050,77661,77662,77663,62313,69496,77666,77667,77668,77669,77670,77671,77672,63670,77674,77675,77676,77677,77678,77679,66015,77681,77682,77683,77684,62956,77686,77687,77688,77689,77690,77691,77692,77693,77694,77695,77696,77697,77698,77699,77700,77701,61382,77703,77704,77705,77706,77707,77708,77709,77710,77711,77712,61680,68383,77715,77716,77717,64868,77719,77720,77721,77722,77723,77724,77725,77726,77727,77728,77729,77730,77731,77732,77733,77734,77735,77736,77737,77738,77739,77740,66693,77742,77743,77744,77745,77746,77747,77748,77749,77750,65911,77752,77753,77754,77755,77756,77757,76140,77759,77760,77761,77762,62374,77764,77765,77766,77767,77768,77769,77770,77771,77772,77773,77774,77775,62334,77777,77778,77779,77780,77781,77782,77783,77784,77785,64940,77787,77788,77789,77790,77791,77792,77793,77794,71898,77796,75652,72196,77799,77800,61823,77802,77803,77804,77805,77806,77807,77808,77809,77810,61752,77812,60783,61339,77815,77816,73960,77818,77819,77820,77821,77822,77823,77824,77825,60901,65017,77828,77829,77830,77831,77832,77833,77834,64315,77836,77837,77838,77839,77840,77841,73845,61093,77844,77845,77846,77847,77848,77849,77850,77851,77852,77853,69414,77855,61951,68734,77858,77859,77860,77861,77862,77863,68250,77865,77866,77867,77868,77869,77870,77871,77872,62194,75041,77875,77876,77877,62046,77879,77880,77881,77882,77883,77884,77885,77886,77887,77888,77889,77890,66554,77892,77893,77894,77895,77896,77897,77898,70211,77900,77901,77902,77903,77904,77905,77906,77907,67056,77909,77910,77911,77912,77913,77914,67218,77916,77917,77918,77919,63356,77921,66693,77923,77924,77925,77926,77927,77928,64598,77930,62343,77932,77933,77934,77935,77936,77937,77938,74550,77940,77941,71076,77943,77944,77945,74309,64247,77948,77949,77950,77951,77952,74930,77954,71112,77956,77957,77958,77959,77960,63205,65595,77963,77964,77965,77966,77967,77968,70357,77970,77971,77972,77973,66616,77975,77976,77977,67704,77979,77980,77981,77982,73164,77984,74348,64708,77987,77988,77989,77990,61932,77992,77993,77994,77995,77996,77997,77998,77999,78000,78001,78002,78003,78004,78005,78006,78007,61031,78009,78010,78011,78012,78013,78014,78015,78016,78017,78018,78019,78020,78021,78022,78023,78024,78025,78026,78027,78028,78029,78030,78031,78032,78033,78034,78035,78036,78037,78038,78039,78040,78041,78042,78043,78044,78045,78046,78047,78048,78049,78050,78051,78052,78053,78054,78055,78056,78057,78058,78059,78060,78061,78062,78063,78064,78065,78066,78067,78068,78069,78070,78071,78072,78073,78074,78075,78076,78077,78078,78079,78080,78081,78082,78083,78084,78085,78086,78087,78088,78089,62557,61713,78092,78093,78094,78095,62344,78097,78098,78099,78100,78101,78102,78103,78104,78105,78106,78107,78108,78109,73137,78111,64086,64976,78114,78115,78116,78117,71100,78119,78120,78121,78122,61235,78124,78125,78126,78127,78128,78129,78130,78131,74385,78133,78134,78135,78136,78137,78138,63222,78140,78141,78142,69796,61592,78145,78146,78147,72312,78149,78150,76152,78152,78153,78154,78155,78156,78157,77014,60892,78160,78161,78162,78163,78164,78165,78166,78167,78168,78169,60960,78171,78172,78173,78174,78175,74589,78177,78178,78179,78180,78181,78182,78183,78184,78185,63576,77858,78188,78189,78190,78191,77568,78193,78194,78195,63041,71125,78198,68287,78200,78201,78202,78203,78204,78205,78206,78207,75768,78209,78210,78211,78212,78213,78214,78215,75746,63788,78218,61192,78220,78221,78222,78223,77669,78225,78226,78227,78228,78229,78230,78231,78232,78233,78234,78235,78236,66533,78238,78239,78240,71045,69037,78243,76152,78245,78246,78247,78248,78249,78250,78251,78252,66407,78254,78255,78256,78257,78258,78259,78260,78261,78262,78263,62760,78265,68829,78267,78268,78269,78270,78271,78272,78273,78274,78275,78276,78277,63529,78279,78280,78281,73294,78283,78284,78285,78286,78287,72621,78289,78290,78291,78292,63006,78294,78295,78296,67680,70352,78299,78300,78301,78302,78303,61092,66281,78306,78307,78308,78309,78310,63208,78312,78313,65633,78315,64888,78317,78318,78319,78320,78321,64940,78323,78324,78325,78326,71767,78328,78329,78330,78331,76203,78333,78334,78335,78336,78337,63442,78339,78340,69829,78342,78343,78344,78345,61258,78347,61858,78349,72711,78351,78352,61655,78354,78355,78356,78357,78358,78359,66419,65769,78362,78363,78364,78365,78366,78367,78368,78369,78370,76088,78372,78373,64879,78375,78376,78377,74394,78379,78380,78381,78382,78383,78384,78385,72169,78387,78388,78389,78390,78391,78392,78393,78394,78395,78396,78397,78398,65323,68233,78401,78402,78403,77457,78405,72667,78407,78408,78409,78410,78411,78412,78413,78414,71116,78416,78417,64240,66852,78420,78421,78422,78423,78424,78425,61477,78427,78428,78429,78430,78431,78432,78433,78434,78435,78436,78437,61511,78439,78440,78441,78442,78443,62076,78445,78446,78447,78448,78449,78450,78451,78452,78453,73005,78455,78456,78457,78458,78459,78460,64300,78462,78463,78464,78465,78466,78467,78468,77446,65911,78471,78472,78473,78474,69009,78476,78477,78478,78479,61074,78481,78482,78483,78484,78485,69581,78487,78488,78489,78490,78491,78492,78493,78494,72110,78496,78497,61139,64919,62042,78501,78502,78503,78504,78505,78506,78507,78508,78509,78510,78511,78512,78513,78514,78515,78210,78517,78518,78519,78520,78521,73887,78523,78524,78525,78526,61240,78528,78529,78530,64396,78532,78533,66198,78535,78536,73543,78538,78539,78540,78541,78542,63799,78544,78545,78546,78547,71128,77073,78550,4415,78552,78553,78554,78555,78556,65363,78558,78559,78560,78561,78562,78563,78564,78565,61607,78567,78568,78569,78570,78571,78572,78573,78574,78575,60831,78577,74889,78579,78580,78581,78582,78583,60868,78585,78586,78587,78588,78589,78590,78591,63547,70741,78594,78595,78596,78597,78598,78599,78600,78601,67736,78603,78604,78605,78606,78607,78608,78609,78610,76088,78612,78613,62486,69500,78616,78617,78618,78619,78620,78621,78622,78623,78624,78625,78626,78627,78628,78629,63581,78631,78632,67541,78634,67650,67144,66609,78638,78639,78640,78641,78642,78643,74558,78645,78646,78647,78648,78649,78650,63125,64629,78653,61578,78655,61591,78657,75942,78659,78660,78661,78662,78663,78664,62087,78666,63351,78668,78669,78670,78671,78672,78673,78674,78675,60921,78677,72140,78679,78680,78681,78682,78683,78684,78685,78686,78687,78688,78689,78690,78691,74648,78693,78694,66853,78696,78697,78698,78699,78700,78701,78702,78703,78704,78705,61782,78707,78708,78709,78710,78711,78712,78713,78714,78715,78716,69001,78718,78719,78720,78721,61041,62153,78724,78725,78726,78727,78728,78729,78730,78731,78732,63154,78734,78735,78736,78737,78738,78739,68235,78741,78742,78743,78744,78745,78746,78747,66355,78749,78750,78751,78752,78753,74625,78755,78756,72111,65711,62171,78760,78761,78762,78763,78764,78765,78766,78767,73647,78769,78770,78771,78772,78773,78774,78775,78776,78777,78778,78779,78780,64109,78782,78783,78784,78785,78786,78787,76891,78789,78790,78791,78792,78793,78794,68698,78796,78797,78798,60909,78800,78801,78802,78803,78804,78805,78806,76329,78808,65778,78810,78811,78812,78813,78814,78815,78816,78817,61190,78819,78820,78821,78822,77100,78824,78825,78826,78827,78828,78829,78830,61717,78832,78833,78834,78835,78836,78837,78838,78839,78840,78841,78842,78843,78844,61100,78846,78847,78848,78849,78850,78851,78852,78853,78854,72112,61516,78857,78858,78859,78860,78861,61536,78863,78864,78865,78866,78867,78868,61113,78870,65447,78872,75790,66531,78875,78876,78877,67136,78879,78880,62070,78882,64564,78884,78885,78886,78887,78888,78889,78890,78891,63529,78893,78894,78895,75250,78897,78898,78899,71172,78901,78902,78903,78904,62119,74744,78907,78908,64953,78910,78911,78912,62040,78914,78915,78916,68769,78918,78919,78920,78921,62546,78923,78924,78925,78926,78927,78928,78929,78930,78931,78932,78933,78934,78935,78936,78937,78938,61182,78940,77493,68287,78943,78944,78945,78946,78947,61475,78949,78950,78951,78952,78953,78954,78955,78956,78957,67915,62891,78960,78961,78962,78963,78964,64503,78966,78967,78968,78969,78970,78971,78972,78973,78974,70924,78976,78977,78978,78979,78980,78981,78982,78983,74605,74239,78986,78987,78988,78989,78990,78991,78992,76056,64112,78995,78996,78997,78998,78999,64302,79001,79002,79003,79004,67212,79006,79007,79008,79009,79010,79011,79012,79013,79014,79015,61680,79017,67881,79019,79020,79021,79022,79023,69444,79025,79026,79027,79028,68329,79030,65051,63069,79033,79034,79035,68413,79037,79038,79039,79040,61808,79042,79043,79044,79045,79046,79047,79048,79049,65403,62033,74644,79053,79054,79055,79056,79057,79058,79059,79060,79061,79062,79063,72915,79065,79066,79067,79068,79069,79070,79071,61586,79073,79074,76996,79076,79077,79078,79079,73649,79081,79082,62245,79084,79085,79086,79087,74680,79089,79090,79091,68017,79093,79094,79095,79096,79097,79098,79099,79100,79101,79102,73177,79104,79105,79106,79107,79108,77992,79110,79111,79112,79113,79114,79115,79116,70998,63428,79119,79120,79121,79122,79123,63492,62896,79126,79127,79128,79129,79130,79131,79132,61196,79134,62519,79136,79137,79138,79139,62182,79141,79142,79143,79144,79145,79146,79147,70012,79149,79150,78111,79130,79153,79154,79155,67172,79157,79158,79159,79160,79161,79162,79163,79164,79165,79166,79167,79168,79169,79170,79171,79172,79173,79174,79175,73662,79177,79178,79179,79180,61642,68305,79183,79184,79185,79186,66681,79188,79189,77618,79191,79192,79193,79194,79195,79196,79197,79198,79199,79200,69488,79202,79203,79204,75750,62035,79207,79208,77881,79210,79211,79212,79213,79214,79215,79216,79217,79218,79219,79220,79221,79222,79223,79224,79225,79226,79227,64967,79229,79230,79231,79232,62626,79234,79235,79236,79237,70531,62627,79240,79241,79242,74029,79244,79245,79246,79247,79248,79249,79250,79251,79252,79253,79254,79255,68091,79257,79258,79259,79260,79261,79262,79263,67541,79265,79266,79267,79268,79269,72119,79271,79272,79273,62731,79275,79276,79277,79278,79279,79280,79281,79282,79283,79284,79285,79286,79287,79288,75237,79290,79291,79292,66420,63358,79295,79296,79297,79298,79299,79300,63759,79302,79303,79304,79305,74371,66495,79308,79309,79310,79311,79312,79313,79314,79315,73237,79317,69964,74378,79320,61102,79322,79323,79324,79325,77565,76777,79328,71126,79330,79331,62913,79333,79334,79335,79336,65743,79338,66786,79340,79341,64698,79343,79344,79345,79346,79347,79348,79349,62445,79351,79352,79353,79354,79355,79356,79357,79358,79359,79360,79361,79362,79363,67366,79365,79366,79367,79368,79369,79370,79371,79372,79373,61115,79375,79376,79377,79378,61073,79380,79381,73552,79383,79384,79385,79386,79387,79388,79389,79390,79391,79392,77662,79394,65822,79396,79397,61173,79399,61059,79401,66647,79403,79404,79405,79406,79407,79408,79409,79410,79411,79412,79413,79414,79415,79416,79417,74832,79419,79420,62022,79422,79423,79424,79425,79426,69213,79428,79429,74553,79431,72006,79433,79434,79435,79436,79437,61853,66287,79440,79441,71696,79443,79444,60847,79446,79447,79448,79449,61346,79451,79452,79453,79454,79455,62087,64150,79458,79459,79460,79461,79462,79463,79464,63547,79466,79467,62456,79469,79470,79471,79472,79473,79474,79475,79476,79477,79478,79479,79480,79481,79482,79483,79484,79485,79486,62516,79488,61186,79490,79491,79492,65188,79494,79495,79496,79497,79498,79499,79500,79501,79502,78698,79504,79505,79506,73130,79508,71125,79510,79511,79512,63970,79514,79515,79516,64381,79518,79519,79520,79521,70402,79523,79524,74446,79526,79527,79528,79529,79530,71933,79532,79533,79534,79535,79536,79537,61907,60921,79540,79541,79542,79543,63368,79545,79546,79547,79548,79549,74819,61189,67511,61825,74816,79555,79556,68429,78949,61991,63625,79561,79562,79563,79564,79565,79566,79567,68260,79569,73713,79571,79572,68902,79574,79575,77777,79577,79578,60773,79580,79581,79582,79583,79584,79585,79586,79587,79588,79589,79590,79591,79592,79593,79594,62754,79596,79597,79598,79599,62769,79601,79602,79603,79095,79605,79606,79607,79608,79609,79610,78677,60979,79613,79136,79615,79616,79617,79618,79619,79620,61024,79622,79623,79624,65573,79626,79627,79628,79629,79630,79631,79632,67650,79634,79635,79636,79637,79638,79639,79640,67247,79642,68651,79644,79645,79646,64771,62498,79649,79650,79651,79652,79653,79654,79655,79656,79657,79658,79659,62506,67968,79662,79663,79664,79665,79666,79667,79668,79669,79670,79671,79672,79673,79674,79675,79676,79677,79678,63096,74784,79681,79682,79683,79684,79685,64819,79687,79688,79689,79690,79691,65218,79693,79694,64833,79696,79697,79698,79699,79700,78677,77617,79703,79704,79705,79706,79707,79708,79709,79710,79711,79712,60992,79714,79715,79716,79717,79718,79719,63470,79721,73717,79723,79724,77100,79726,79727,64357,79729,79730,79731,79732,79733,79734,79735,67556,67420,79738,79739,79740,79741,79742,78953,79744,79745,79746,79747,61563,79749,79750,79751,79752,79753,79754,79755,61029,79757,79758,79759,79760,79761,79762,79763,79764,79765,79766,79767,61981,79769,79770,79771,79772,79773,79774,79775,73337,79777,79778,79779,79780,79781,79782,79783,63581,79785,79786,79787,79788,66747,62136,79791,79792,79793,79794,79795,79796,61260,79798,61857,79800,68003,79802,79803,79804,79805,79806,77022,69628,79541,79810,71835,66375,79813,72299,73327,79816,79817,79818,79819,79820,79821,61983,79823,79824,79825,79826,79827,61712,79829,79830,69703,79832,79833,79834,79835,79836,79837,79838,79839,79840,79841,79842,73211,79844,79845,79846,79847,66518,79849,79850,65029,79852,79853,79854,79855,79856,79857,79858,79859,62372,79861,79862,79863,79864,79865,79866,61798,79868,79869,69177,79871,65740,79873,79874,79875,62940,79877,79878,74071,79880,79881,79882,79883,79884,79885,61888,79887,79888,79889,79890,79891,60951,79893,79894,79895,79896,79897,75260,79899,79900,79901,79902,79903,79904,79905,79906,79907,79908,70536,76835,79911,79912,79913,79914,79915,79916,79917,79918,79919,67561,79921,79922,79923,79924,79925,79926,79927,79928,62367,73434,69964,78094,79933,61482,79935,79936,65617,79938,79939,79940,79941,79942,70542,79944,79945,79946,79947,68906,79949,79950,79951,79952,64541,79954,76670,79956,62939,79958,79959,79885,79961,64700,79963,79964,79965,79966,79967,79968,79969,79970,76073,79972,79973,79974,79975,79976,79977,79978,67080,79980,79981,79982,79983,79984,79985,73689,79987,79988,69109,79990,79991,61562,79993,79994,79995,79996,79997,79998,62157,80000,80001,80002,80003,80004,80005,62714,80007,80008,76192,80010,80011,80012,80013,80014,62307,80016,70485,80018,80019,70245,80021,68668,80023,80024,80025,80026,67135,80028,62236,80030,62425,80032,80033,80034,80035,63532,80037,80038,77988,63898,80041,77077,74534,61713,80045,80046,80047,80048,80049,80050,80051,80052,70928,80054,80055,80056,80057,63634,80059,64330,80061,80062,63939,80064,80065,80066,80067,80068,80069,80070,70298,80072,80073,80074,80075,80076,80077,80078,74604,63676,80081,80082,80083,69476,80085,80086,80087,80088,80089,80090,80091,80092,80093,80094,80095,80096,80097,80098,80099,80100,80101,80102,80103,80104,80105,67102,80107,80108,80109,80110,80111,70999,80113,71125,80115,63477,80117,80118,80119,80120,62508,80122,80123,80124,80125,80126,61849,80128,80129,80130,80131,72022,80133,62939,80135,80136,64683,80138,80139,80140,80141,80142,61933,80144,80145,80146,65912,80148,80149,80150,80151,80152,80153,80154,77541,80156,66826,80158,80159,80160,80161,73220,80163,80164,80165,70382,65554,80168,78640,66381,74533,64740,80173,80174,72248,80176,80177,80178,80179,80180,80181,80182,80183,80184,80185,80186,80187,80188,80189,63130,80191,60852,80193,80194,80195,80196,80197,80198,80199,80200,80201,80202,80203,80204,80205,80206,77691,80208,80209,80210,80211,80212,80213,80214,80215,80216,80217,62599,80219,80220,80221,80222,80223,80224,80225,61677,80227,80228,80229,80230,67887,80232,80233,80234,63383,80236,80237,80238,80239,80240,74939,80242,80243,80244,80245,80246,80247,80248,80249,63947,80251,80252,80253,72376,80255,80256,80257,80258,80259,80260,80261,80262,80263,77777,80265,80266,80267,80268,80269,80270,80271,80272,80273,80274,80275,72157,80277,80278,80279,80280,66110,80282,80283,80284,80285,80286,80287,80288,80289,73840,80291,62844,80293,80294,80295,80296,80297,80298,80299,80300,80301,80302,78097,80304,80305,80306,80307,80308,80309,80310,80311,61235,80313,80314,80315,80316,62068,80318,66015,80320,80321,80322,80323,62959,80325,80326,80327,80328,80329,80330,80331,80332,80333,71311,80335,80336,80337,80338,80339,80340,67354,80342,80343,61933,80345,80346,80347,80348,80349,80350,66921,80352,80353,80354,80355,80356,61803,62311,80359,80360,80361,80362,62183,80364,80365,80366,80367,80368,80369,80370,80371,80372,80373,64919,79723,80376,67781,80378,66216,80380,80381,80382,80383,80384,63128,67265,80387,80388,80389,80390,80391,77267,80393,80394,80395,80396,80397,80398,71224,80400,80401,80402,35786,80404,80405,80406,80407,80408,80409,80410,80411,80412,80413,80414,80415,80416,80417,80418,80419,80420,80421,80422,80423,80424,80425,80426,80427,80428,80429,80430,80431,80432,80433,80434,80435,80436,80437,80438,80439,80440,80441,80442,80443,80444,80445,80446,80447,80448,80449,80450,80451,80452,80453,80454,80455,80456,80457,80458,80459,80460,80461,80462,80463,80464,80465,80466,80467,80468,80469,80470,80471,80472,80473,80474,80475,80476,80477,80478,80479,80480,80481,80482,80483,80484,80485,80486,80487,80488,80489,80490,80491,80492,80493,80494,80495,80496,80497,80498,80499,80500,80501,80502,80503,80504,80505,80506,80507,80508,80509,80510,80511,80512,80513,80514,80515,80516,80517,80518,80519,80520,80521,80522,80523,80524,80525,80526,80527,80528,80529,80530,80531,80532,80533,80534,80535,80536,80537,80538,80539,80540,80541,80542,80475,80544,80545,80546,80547,80548,80549,80550,80551,80552,80553,80554,80555,80556,80557,80558,80559,80560,80561,80562,80563,80564,80565,80566,80567,80568,80569,80570,80571,80572,80573,80574,80575,80576,80577,80578,80579,80580,80581,80582,80583,80584,80585,80586,80587,80470,80589,80590,80591,80592,80593,80594,80595,80596,80597,80598,80599,80600,80601,80602,80603,80604,80605,80606,80607,80608,80609,80610,80611,80612,80613,80614,80615,80616,80617,80618,80619,80620,80621,80622,80623,80624,80625,80626,80627,80628,80629,80630,80631,80632,80633,80634,80635,80636,80637,80589,80639,80640,80641,80642,80643,80644,80645,80646,80647,80648,80649,80650,80651,80652,80653,80654,80655,80656,80657,80658,80659,80660,80661,80662,80663,80664,80665,80666,80667,80668,80669,80670,80671,80672,80673,80674,80675,80676,80462,80678,80679,80680,80681,80682,80683,80684,80685,80686,80687,80688,80689,80690,80691,80692,80693,80694,80695,80696,80697,80698,80699,80700,80445,80702,80703,80704,80705,80706,80707,80708,80709,80710,80711,80712,80713,80714,80715,80716,80717,80718,80719,80720,80721,80722,80723,80724,80725,80726,80727,80728,80729,80730,80731,80732,80733,80734,80735,80736,80737,80738,80739,80740,80741,80742,80743,80744,80745,80746,80747,80748,80749,80750,80751,80752,80753,80754,80755,80756,80757,80758,80759,80760,80761,80762,80763,80764,80765,80766,80767,80768,80769,80770,80771,80772,80773,80774,80775,80776,80777,80778,80779,80780,80781,80782,80783,80784,80785,80786,80787,80788,80789,80731,80791,80792,80793,80794,80795,80796,80797,80796,80799,80800,80801,80802,80803,80804,80805,80806,80807,80808,80809,80810,80811,80812,80813,80814,80815,80816,80817,80818,80819,80820,80821,80822,80823,80824,80825,80826,80827,80828,80829,80830,80831,80832,80833,80834,80835,80836,80837,80802,80839,80840,80841,80842,80843,80844,80845,80846,80847,80848,80849,80850,80851,80852,80853,80854,80855,80856,80857,80858,80859,80860,80861,80862,80863,80864,80865,80866,80867,80868,80869,80870,80871,80872,80873,80874,80875,80876,80877,80878,80879,80880,80881,80882,80726,80884,80885,80886,80887,80888,80889,80890,80891,80892,80893,80894,80895,80896,80897,80898,80899,80900,80901,80902,80903,80904,80905,80906,80907,80908,80909,80910,80911,80912,80913,80914,80915,80916,80917,80918,80919,80920,80921,80922,80923,80924,80925,80926,80927,80928,80929,80930,80931,80932,80933,80888,80935,80936,80937,80938,80939,80940,80941,80942,80943,80944,80945,80946,80947,80948,80949,80950,80951,80952,80953,80954,80955,80956,80957,80958,80959,80960,80961,80962,80963,80964,80963,80966,80967,80968,80969,80970,80971,80972,80973,80974,80975,80976,80977,80978,80979,80980,80981,80982,80983,80884,80985,80986,80987,80988,80989,80990,80991,80992,80993,80994,80995,80996,80997,80998,80999,81000,81001,81002,81003,81004,81005,81006,81007,81008,81009,81010,81011,81012,81013,81014,81015,81016,81017,81018,81019,81020,81021,81022,81023,81024,81019,81026,81027,81028,81029,81030,81031,81032,81033,81034,81035,81036,81037,81038,81039,81040,80440,81042,81043,81044,81045,81046,81047,81048,81049,81050,81051,81052,81053,81054,81055,81056,81057,81058,81059,81060,81061,81062,81063,81064,81065,81066,81067,81068,81069,81070,81071,81072,81073,81074,81075,81076,81077,81078,81079,81080,81081,81082,81083,81084,81085,81086,81087,81088,81089,81090,81091,81092,81093,81094,81095,81096,81097,81098,81099,81100,81101,81102,81103,81104,81105,81106,81107,81108,81109,81110,81111,81112,81113,81114,81115,81116,81117,81118,81119,81120,81121,81122,81123,81124,81125,81126,81127,81128,81129,81130,81131,81132,81133,81134,81135,81136,81137,81092,81139,81140,81141,81142,81143,81144,81145,81146,81147,81148,81149,81150,81151,81152,81153,81154,81155,81156,81157,81158,81159,81160,81161,81162,81163,81164,81165,81166,81167,81168,81169,81170,81171,81172,81173,81174,81175,81176,81076,81178,81179,81180,81181,81182,81183,81184,81185,81186,81187,81188,81189,81190,81191,81192,81193,81194,81195,81196,81197,81198,81199,81200,81201,81202,81203,81204,81205,81206,81207,81208,81209,81210,81211,81212,81213,81214,81215,81216,81217,81218,81219,81220,81221,81222,81223,81224,81225,81226,81227,81228,81229,81230,81071,81232,81233,81234,81235,81236,81237,81238,81239,81240,81241,81242,81243,81244,81245,81246,81247,81248,81249,81250,81251,81252,81253,81254,81255,81256,81257,81258,81259,81260,81261,81262,81263,81264,81265,81266,81267,81268,81269,81270,81271,81272,81273,81274,81275,81276,81277,81278,81279,81280,81281,81282,81046,81284,81285,81286,81287,81288,81289,81290,81291,81292,81293,81294,81295,81296,81297,81298,81299,81300,81301,81302,81303,81304,81305,81306,81307,81308,81309,81310,81311,81312,81313,81314,81315,81316,81317,81318,81319,81320,81321,81322,81323,81324,81325,81326,81327,81328,81329,81330,81331,81332,81333,81334,81335,81336,81337,81338,81339,81340,81341,81342,81343,81344,81345,81346,81347,81348,81349,81350,81351,81352,81353,81354,81355,81356,80424,81358,81359,81360,81361,81362,81363,81364,81365,81366,81367,81368,81369,81370,81371,81372,81373,81374,81375,81376,81377,81378,81379,81380,81381,81382,81383,81384,81385,81386,81387,81388,81389,81390,81391,81392,81393,81394,81395,81396,81397,81398,81399,81400,81401,81402,81403,81404,81405,81406,81407,81408,81409,81410,81411,81412,81413,81414,81415,81416,81417,81418,81419,81420,81421,81422,81423,81424,81425,81426,81427,81428,81429,81430,81431,81432,81433,81434,81435,81436,81437,81438,81439,81440,81441,81442,81443,81444,81445,81446,81447,81448,81449,81450,81451,81452,81453,81454,81455,81456,81397,81458,81459,81460,81461,81462,81463,81464,81465,81466,81467,81468,81469,81470,81471,81472,81473,81474,81475,81476,81477,81478,81479,81480,81481,81482,81483,81484,81485,81486,81487,81488,81489,81490,81491,81492,81493,81494,81495,81496,81497,81498,81499,81500,81501,81502,81503,81504,81505,81506,81507,81508,81372,81510,81511,81512,81513,81514,81515,81516,81517,81518,81519,81520,81521,81522,81523,81524,81525,81526,81527,81528,81529,81530,81531,81532,81533,81534,81535,81536,81537,81538,81539,81540,81541,81542,81543,81544,81545,81546,81547,81548,81549,81550,81551,81552,81553,81554,81555,81556,81557,81558,81559,81560,81561,81562,81563,81564,81565,81566,81567,81568,81569,81570,81571,81572,81573,81574,81367,81576,81577,81578,81579,81580,81581,81582,81583,81584,81585,81586,81587,81588,81589,81590,81591,81592,81593,81594,81595,81596,81597,81598,81599,81600,81601,81602,81603,81604,81605,81606,81607,81608,81609,81610,81611,81612,81613,81614,81615,81616,81617,81618,81619,81620,81621,81622,81605,81624,81625,81626,81627,81628,81629,81630,81631,81632,81633,81634,81635,81636,81637,81638,81639,81640,81641,81642,81643,81644,81645,81646,81647,81648,81649,81650,81651,81652,81653,81654,81655,81656,81657,81658,81659,81660,81661,81662,81663,81664,81665,81666,81580,81668,81669,81670,81671,81672,81673,81674,81675,81676,81677,81678,81679,81680,81681,81682,81683,81684,81685,81686,81687,81688,81689,81690,81691,81692,81693,81694,81695,81696,81697,81698,81699,81700,81701,81702,81703,81704,81705,81706,81707,81708,81709,81710,81711,81712,81713,81714,81715,81716,81717,81718,81719,81720,81721,81722,81723,81724,81725,81726,81727,81728,81729,81730,81731,81732,81733,81734,81735,81736,81737,81738,81739,81740,81741,81742,81743,80413,81745,81746,81747,81748,81749,81750,81751,81752,81753,81754,81755,81756,81757,81758,81759,81760,81761,81762,81763,81764,81765,81766,81767,81768,81769,81770,81771,81772,81773,81774,81775,81776,81777,81778,81779,81780,81781,81782,81783,81784,81785,81786,81787,81788,81789,81790,81791,81792,81793,81794,81795,81796,81797,81798,81799,81800,81801,81802,81803,81804,81805,81806,81807,81808,81809,81810,81811,81812,81813,81814,81815,81816,81817,81818,81819,81820,81754,81822,81823,81824,81825,81826,81827,81828,81829,81830,81831,81832,81833,81834,81835,81836,81837,81838,81839,81840,81841,81842,81843,81844,81845,81846,81847,81848,81849,81850,81851,81852,81853,81854,81855,81856,81857,81858,81859,81860,81861,81862,81863,81864,81865,81866,81867,81868,81869,81870,81871,81872,81873,81874,81875,81876,81877,81878,81879,81880,81881,81882,81883,81884,81885,81886,81887,81888,81889,81890,81891,81892,81893,81894,81895,81896,81897,81898,81899,81900,81901,81902,81903,81904,81905,81906,81907,81908,81909,81910,81911,81912,81913,81914,81846,81916,81917,81918,81919,81920,81921,81922,81923,81924,81925,81926,81927,81928,81929,81930,81931,81932,81933,81934,81935,81936,81937,81938,81939,81940,81941,81942,81943,81944,81945,81946,81947,81948,81949,81950,81951,81952,81953,81954,81749,81956,81957,81958,81959,81960,81961,81962,81963,81964,81965,81966,81967,81968,81969,81970,81971,81972,81973,81974,81975,81976,81977,81978,81979,81980,81981,81982,81983,81984,81985,81986,81987,81988,81989,81990,81991,81992,81993,81994,81995,81996,81997,81998,81999,82000,82001,82002,82003,82004,82005,82006,82007,82008,82009,82010,82011,82012,82013,82014,82015,82016,82017,82018,82019,82020,82021,82022,82023,82024,82025,82026,82027,82028,82029,82030,82031,82032,82033,82034,82035,82036,82037,82038,82039,82040,82041,82042,82043,82044,82043,82046,82047,82048,82049,82050,82051,82052,82053,81985,82055,82056,82057,82058,82059,82060,82061,82062,82063,82064,82065,82066,82067,82068,82069,82070,82071,82072,82073,82074,82075,82076,82077,82078,82079,82080,82081,82082,82083,82084,82085,82086,82087,82088,82089,82090,82091,82092,82093,82094,82059,82096,82097,82098,82099,82100,82101,82102,82103,82104,82105,82106,82107,82108,82109,82110,82111,82055,82113,82114,82115,82116,82117,82118,82119,82120,82121,82122,82123,82124,82125,82126,82127,82128,82129,82130,82131,82132,82133,82134,82135,82136,82137,82138,82139,82140,82141,82142,82143,82144,82145,82146,82147,82148,82149,82150,82116,82152,82153,82154,82155,82156,82157,82158,82159,82160,82161,82162,82163,82164,82165,82166,82167,82168,82169,82170,82171,82172,82173,82174,82175,82176,82177,82178,82179,82180,82181,82182,82183,82184,82185,82186,82187,82188,82189,82190,82191,82192,82193,82194,82195,81960,82197,82198,82199,82200,82201,82202,82203,82204,82205,82206,82207,82208,82209,82210,82211,82212,82213,82214,82215,82216,82217,82218,82219,82220,82221,82222,82223,82224,82225,82226,82227,82228,82229,82230,82231,82232,82233,82234,82235,82236,82237,82238,82239,82240,82241,82242,82243,82244,82245,82246,82247,82248,82249,82250,82251,82252,82253,82254,82255,82256,82257,82258,82259,82260,82261,82262,82263,82264,82263,82266,82267,82268,82269,82270,82271,82272,82273,82274,82275,82276,82277,82278,82279,82280,82281,82282,82283,82284,82285,82286,82287,82288,82289,82290,82291,82292,82293,82294,82226,82296,82297,82298,82299,82300,82301,82302,82303,82304,82305,82306,82307,82308,82309,82310,82311,82312,82313,82314,82315,82316,82317,82318,82319,82320,82321,82322,82323,82324,82325,82326,82327,82328,82329,82330,82331,82332,82333,82334,82335,82336,82337,82338,82339,82340,82341,82342,82343,82344,82345,82346,82347,82348,82349,82350,81745,82352,82353,82354,82355,82356,82357,82358,82359,82360,82361,82362,82363,82364,82365,82366,82367,82368,82369,82370,82371,82372,82373,82374,82375,82376,82377,82378,82379,82380,82381,82382,82383,82384,82385,82386,82387,82388,82389,82390,82391,82392,82393,82394,82395,82396,82397,82398,82399,82400,82401,82402,82403,82404,82405,82406,82407,82408,82409,82410,82411,82412,82413,82414,82415,82416,82417,82418,82419,82420,82421,82422,82423,82424,82425,82426,82427,82428,82429,82430,82431,82432,82433,82434,82435,82436,82437,82438,82439,82360,82441,82442,82443,82444,82445,82446,82447,82448,82449,82450,82451,82452,82453,82454,82455,82456,82457,82458,82459,82460,82461,82462,82463,82464,82465,82466,82467,82468,82469,82470,82471,82472,82473,82474,82475,82476,82477,82478,82479,82480,82481,82482,82483,82484,82485,82486,82487,82488,82489,82490,82491,82492,82493,82494,82495,82496,82497,82498,82499,82500,82501,82502,82503,82504,82505,82506,82507,82508,82509,82510,82511,82512,82513,82355,82515,82516,82517,82518,82519,82520,82521,82522,82523,82524,82525,82526,82527,82528,82529,82530,82531,82532,82533,82534,82535,82536,82537,82538,82539,82540,82541,82542,82543,82544,82545,82546,82547,82548,82549,82550,82551,82552,82553,82554,82555,82556,82557,82558,82559,82560,82561,82562,82563,82564,82565,82566,35786,82568,82569,82570,82571,82572,82573,82574,82575,82576,82577,82578,82579,82580,82581,82582,82583,82584,82585,82586,82587,82588,82589,82590,82591,82592,82593,82594,82595,82596,82597,82598,82599,82600,82601,82602,82603,82604,82605,82606,82607,82608,82609,82610,82611,82612,82613,82614,82615,82616,82617,82618,82619,82620,82621,82622,82623,82624,82625,82626,82627,82628,82629,82630,82631,82632,82633,82634,82635,35904,82637,82638,82639,82640,82641,82642,82643,82644,82645,82646,82647,82648,82649,82650,82651,82652,82653,82654,82655,82656,82657,82658,82659,82660,82661,82662,82663,82664,82665,82666,82667,82668,82669,82670,82671,82672,82673,82674,82675,82676,82677,82678,82679,82680,82681,82682,82683,82684,82685,82686,82687,82688,82689,82690,82691,82692,82693,82694,82695,82696,82697,82698,82699,82700,82701,82702,82703,82704,82705,82706,82707,82708,82709,82710,82711,82712,82713,82714,82715,82716,82717,82718,82719,82720,82721,82657,82723,82724,82725,82726,82727,82728,82729,82730,82731,82732,82733,82734,82735,82736,82737,82738,82739,82740,82741,82742,82743,82744,82745,82746,82747,82748,82749,82750,82751,82752,82753,82754,82755,82756,82757,82758,82759,82760,82761,82762,82763,82764,82765,82766,82767,82768,82769,82770,82771,82772,82773,82774,82775,82776,82777,82778,82779,82780,82781,82782,82783,82784,82785,82786,82787,82788,82789,82790,82791,82792,82793,82794,82795,82796,82797,82798,82799,82800,82801,82802,82803,82804,82805,82806,82807,82808,82809,82810,82811,82812,82813,82814,82815,82816,82817,82818,82819,82820,82821,82822,82823,82824,82825,82826,82827,82828,82646,82830,82831,82832,82833,82834,82835,82836,82837,82838,82839,82840,82841,82842,82843,82844,82845,82846,82847,82848,82849,82850,82851,82852,82853,82854,82855,82856,82857,82858,82859,82860,82861,82862,82863,82864,82865,82866,82867,82868,82869,82870,82871,82872,82873,82874,82875,82876,82877,82878,82879,82880,82881,82882,82883,82884,82885,82886,82887,82888,82889,82890,82891,82892,82893,82894,82895,82896,82897,82898,82899,82900,82901,82902,82903,82904,82905,82906,82907,82908,82909,82910,82911,82912,82913,82914,82915,82916,82917,82918,82919,82920,82921,82830,82923,82924,82925,82926,82927,82928,82929,82930,82931,82932,82933,82934,82935,82936,82937,82938,82939,82940,82941,82942,82943,82944,82945,82946,82947,82948,82949,82950,82951,82952,82953,82954,82955,82956,82957,82958,82959,82960,82961,82962,82963,82964,82965,82966,82967,82968,82969,82970,82971,82972,82973,82974,82975,82976,82977,82978,82979,82980,82981,82982,82983,82984,82985,82986,82987,82988,82989,82990,82991,82992,82993,744,10475,82996,82997,82998,82999,83000,83001,83002,83003,83004,83005,1106,83007,83008,83009,83010,83011,83012,83013,83014,83015,83016,83017,83018,83019,83020,83021,83022,83023,83024,83025,83026,83027,83028,83029,83030,83031,83032,83017,83034,83035,83036,83037,83038,83039,83040,83041,83042,83043,83044,83045,83046,83047,83048,83049,83050,83051,83052,83053,83054,83055,83056,83057,83058,83059,83060,83061,83062,83063,83064,83065,83066,83067,83045,83069,83070,83071,83072,83073,83074,83075,83076,83077,83078,83079,83080,83081,83082,83083,83084,83085,83086,83087,83088,83089,83090,83091,83092,83093,83070,83095,83096,83097,83098,83099,83100,83101,83102,83103,83104,83105,83106,83107,83108,83109,83110,83111,83112,83113,83114,83115,83116,83117,83118,83119,83120,83121,83122,83123,83124,83125,83126,83127,83128,83129,83130,83131,83132,83133,83134,83135,83136,83121,83138,83139,83140,83141,83142,83143,83144,83145,83146,83147,83148,83149,83150,83151,83152,83153,83154,83155,83143,83157,83158,83159,83160,83161,83162,83163,83164,83165,83166,83167,83168,83169,83170,83171,83172,83173,83174,83175,83176,83177,83178,83179,83180,83181,83182,83183,83184,83185,83186,83187,83188,83189,83164,83191,83192,83193,83194,83195,83196,83197,83198,83199,83200,83201,83202,83203,83204,83205,83206,83207,83208,83209,83210,83211,83212,83213,83214,83215,83216,83217,83218,83219,83220,83221,83212,83223,83224,83225,83226,83227,83228,83229,83230,83231,83232,83112,83234,83235,83236,83237,83238,83239,83240,83241,83242,83243,83244,83245,83246,83247,83248,83249,83250,83251,83252,83253,83250,83255,83256,83257,83258,83242,83260,83261,83262,83263,83264,83265,83266,83267,83268,83269,83270,83271,83272,83273,83274,83275,83276,83277,83278,83279,83280,83281,83282,83283,83284,83285,83286,83287,83270,83289,83290,83291,83292,83293,83294,83295,83296,83297,83298,83299,83300,83301,83302,83303,83304,83305,83306,83307,83308,83309,83310,83311,83312,83313,83261,83315,83316,83317,83318,83319,83320,83321,83322,83323,83324,83325,83326,83327,83236,83329,83330,83331,83332,83333,83334,83335,83336,83337,83338,83339,83244,83341,83342,83343,83344,83345,83346,83347,83348,83349,83350,83351,83352,83353,83354,83355,83356,83277,83358,83359,83360,83361,83362,83363,83364,83365,83366,83367,83368,83369,83370,83371,83372,83373,83374,83375,83291,83377,83378,83379,83380,83381,83382,83383,83384,83385,83386,83387,83388,83389,83390,83391,83392,83393,83394,83395,83396,83397,83273,83399,83400,83401,83402,83403,83404,83405,83406,83407,83408,83244,83410,83411,83412,83413,83414,83415,83416,83417,83418,83419,83347,83421,83422,83423,83424,83280,83426,83427,83428,83429,83430,83431,83432,83293,83434,83435,83436,83437,83438,83439,83440,83441,83442,83443,83444,83445,1049,83447,83448,4232,83450,83451,83452,83453,83454,83455,83456,83457,83458,83459,83460,83461,4232,83463,83464,83465,83466,83467,83468,83469,83470,83471,83472,83473,83474,83475,83476,83477,83478,83479,83480,83481,83482,83483,83484,83485,83486,83487,83488,83489,83490,83491,83492,83493,83494,83495,83496,83497,83498,83499,83500,83501,83502,83481,83504,83505,83506,83507,83508,83509,83510,83511,83512,83513,83514,83515,83516,83517,83518,83519,83520,83521,83522,83523,83524,83525,83526,83527,83528,83529,83530,83531,83517,83533,83534,83535,83536,83537,83538,83539,83540,83541,83542,83543,83544,83545,83546,83547,83548,83549,83550,83551,83552,83553,83554,83555,83556,83557,83558,83559,83560,83561,83562,83563,83564,83565,83566,83567,83568,83569,83570,83571,83572,83573,83574,83575,83576,83577,83578,83579,83580,83581,83582,83583,83558,83585,83586,83587,83588,83589,83590,83591,83592,83593,83594,83595,83596,83597,83598,83585,83600,83601,83602,83603,83604,83605,83606,83607,83608,83609,83610,83611,83612,83613,83614,83615,83616,83617,83618,83619,83620,83621,83622,83623,83624,83625,83626,83627,83628,83629,83630,83631,83632,83633,83634,83635,83610,83637,83638,83639,83640,83641,83642,83643,83644,83645,83646,83647,83648,83649,83650,83651,83652,83653,83654,83655,83656,83657,83658,83659,83660,83661,83662,83663,83664,83665,83666,83667,83550,83669,83670,83671,83672,83673,83674,83675,83676,83677,83678,83679,83680,83681,83682,83683,83684,83685,83686,83687,83688,83689,83690,83691,83692,83693,83694,83695,83696,83697,83698,83699,83700,83676,83702,83703,83704,83705,83706,83707,83708,83709,83710,83711,83712,83713,83714,83715,83716,83717,83718,83719,83720,83721,83722,83702,83724,83725,83726,83727,83728,83729,83730,83731,83732,83733,83734,83735,83736,83737,83738,83739,83740,83741,83742,83743,83744,83745,83746,83747,83748,83749,83750,83751,83752,83753,83754,83755,83756,83757,83758,83759,83734,83761,83762,83763,83764,83765,83766,83767,83768,83769,83770,83771,83772,83773,83774,83775,83776,83777,83778,83737,83780,83781,83782,83783,83784,83785,83786,83787,83788,83789,83704,83791,83792,83793,83794,83795,83796,83797,83798,83799,83714,83801,83802,83803,83804,83805,83806,83807,83808,83809,83810,83811,83812,83763,83814,83815,83816,83817,83818,83819,83820,83821,83822,83823,83824,83825,83826,83827,83828,83829,83772,83831,83832,83833,83834,83835,83836,83837,83838,83741,83840,83841,83842,83843,83844,83845,83846,83847,83848,83796,83850,83851,83852,83853,83854,83708,83856,83857,83858,83859,83860,83861,83862,83863,83864,83865,83763,83867,83868,83869,83870,83871,83872,83873,83874,83875,83876,4251,83878,267,83880,83881,83882,83883,83884,83885,83886,83887,83888,83889,60756,83891,83892,83893,83894,83895,83896,83897,83898,83899,83900,83901,83902,83903,83904,83905,83906,83907,83908,83909,83910,83911,83912,83913,83914,83915,83916,83917,83918,83919,83920,83921,83922,83923,83924,83925,83926,83927,83928,83929,83930,83931,83932,83933,83934,83935,83936,83937,83938,83939,83940,83927,83942,83943,83944,83945,83946,83947,83948,83949,83950,83951,83952,83953,83954,83955,83956,83957,83958,83959,83920,83961,83962,83963,83964,83965,83966,83967,83968,83969,83970,83971,83972,83973,83974,83975,83976,83977,83978,83979,83980,83981,83982,83983,83984,83985,83986,83987,83988,83989,83990,83991,83969,83993,83994,83995,83996,83997,83998,83999,84000,84001,84002,84003,84004,84005,84006,84007,83963,84009,84010,84011,84012,84013,84014,84015,84016,84017,84018,84019,84020,84021,84022,84023,84024,84025,84026,84027,84028,84029,83900,84031,84032,84033,84034,84035,84036,84037,84038,84039,84040,84041,84042,84043,84044,84045,84046,84047,84048,84049,84050,84051,84052,84053,84054,84055,84056,84057,84058,84059,84060,84061,84062,84063,84064,84065,84066,84067,84068,84069,84070,84071,84072,84073,84074,84050,84076,84077,84078,84079,84080,84081,84082,84083,84084,84085,84086,84087,84088,84089,84090,84091,84092,84093,84094,84086,84096,84097,84098,84099,84100,84101,84102,84103,84104,84105,84106,84107,84108,84109,84110,84111,84112,84113,84114,84115,84116,84117,84118,84119,84120,84121,84122,84123,84124,84083,84126,84127,84128,84129,84130,84131,84132,84133,84134,84135,84136,84137,84138,84139,84140,84141,84142,84143,84144,84145,84146,84147,84148,84126,84150,84151,84152,84153,84033,84155,84156,84157,84158,84159,84160,84161,84162,84163,84164,84078,84166,84167,84168,84169,84170,84171,84172,84173,84174,84175,84176,84146,84178,84179,84180,84181,84182,84183,84184,84185,84186,84187,84188,84151,84190,84191,84192,84193,84194,84195,84196,84197,84198,84199,84200,84201,84202,84203,84204,84205,84206,84036,84208,84078,84210,84211,84212,84213,84214,84215,84216,84217,84184,84219,84220,84221,84222,84223,84224,84225,84226,84227,84228,84229,84230,84231,84232,84233,84234,84235,84236,84237,84238,84239,84196,84241,84242,84243,84244,84245,84246,84247,84248,84249,84250,84251,84252,84253,84254,84255,84256,84038,84258,84259,84260,84261,84262,84263,84264,84265,84266,84267,84268,84269,84270,84271,84272,84273,84274,84275,84276,84277,84089,84279,84280,84281,84282,84283,84284,84285,84286,84146,84288,84289,84290,84291,84292,84293,84294,84295,84296,84297,84298,84299,84300,84301,84302,84303,84304,84305,84306,84307,84308,84309,84310,84311,84312,84313,84252,84315,84316,84317,84318,84319,84320,84321,84322,84323,84324,84325,84326,84327,84328,84329,84330,84331,84332,84333,84334,84335,84336,84337,84268,84339,84340,84341,84342,84343,84344,84345,84346,84285,84348,84349,84350,84351,84352,84353,84129,84355,84356,84357,84322,84359,84360,84361,84362,84363,84364,84365,84366,84367,228,84369,84370,84371,84372,84373,84374,84375,84376,84377,84378,84379,84380,84381,84382,84383,84384,84385,84386,84387,280,84389,84390,84391,84392,84393,84394,84395,84396,84397,84398,84399,84400,4,84402,84403,84404,84405,4,84407,84408,84409,84410,84409,84412,84413,84414,84415,84416,84409,84409,84419,84409,84421,84422,84409,84424,84409,84426,84427,84428,84429,84429,84424,84432,84409,84434,84409,84421,84437,84438,84439,84440,84409,84442,84443,84444,84415,84446,84412,84448,84449,84450,84451,84452,84421,84454,84455,84456,84421,84458,84459,84460,84461,84462,84412,84464,84465,84466,84467,84468,84421,84470,84471,84421,84473,84474,84475,84476,84477,84422,84412,84480,84481,84482,84460,84484,84485,84456,84487,84488,84409,84490,84491,84492,84480,84461,84495,84458,84484,84498,84499,84500,84501,84502,84503,84504,84505,84409,84507,84480,84409,84510,84511,84467,84513,84409,84515,84516,84517,84518,84519,84520,84521,84522,84412,84524,84525,84526,84527,84528,84529,84413,84422,84532,84533,84534,84535,84536,84537,84444,84412,84473,84474,84542,84543,84544,84533,84546,84547,84548,84549,84550,84412,84552,84553,84554,84555,84556,84557,84558,84559,84560,84561,84442,84409,84409,84565,84444,84434,84516,84569,84570,84571,84409,84573,84409,84414,84412,84577,84409,84579,84422,84466,84421,84409,84577,84585,84473,84587,84588,84589,84480,84591,84432,84485,84594,84595,84596,84597,84598,84599,84600,84409,84602,84603,84546,84605,84606,84607,84608,84609,84610,84611,84612,84613,84614,84615,84616,84424,84618,84597,84421,84448,84459,84409,84624,84625,84565,84412,84628,84629,84630,84631,84632,84573,84510,84464,84565,84482,84507,84434,84640,84524,84642,84643,84644,84645,84646,84460,84510,84409,84650,84466,84652,84653,84654,84655,84656,84657,84658,84659,84660,84450,84662,84663,84664,84665,84666,84667,84668,84669,84670,84671,84672,84673,84674,84675,84676,84677,84678,84679,84680,84681,84682,84683,84684,84685,84686,84687,84688,84689,84587,84691,84692,84693,84694,84524,84696,84697,84409,84409,84466,84603,84603,84412,84427,84507,84449,84707,84708,84709,84710,84711,84712,84713,84602,84422,84716,84717,84718,84414,84720,84721,84448,84723,84724,84725,84421,84727,84728,84729,84473,84731,84732,84733,84696,84735,84470,84737,84738,84739,84548,84741,84742,84743,84744,84745,84746,84747,84511,84602,84409,84751,84752,84753,84754,84755,84465,84757,84758,84759,84760,84761,84603,84427,84764,84681,84602,84767,84464,84628,84770,84771,84772,84432,84470,84775,84776,84777,84778,84779,84454,84781,84782,84413,84784,84785,84428,84587,84788,84464,84790,84791,84792,84515,84794,84795,84796,84533,84480,84491,84800,84473,84802,84803,84804,84471,84806,84510,84412,84809,84810,84811,84525,84813,84814,84815,84816,84817,84818,84535,84645,84546,84822,84409,84470,84825,84826,84827,84428,84829,84480,84424,84832,84532,84834,84835,84836,84837,84838,84421,84840,84841,84427,84424,84707,84845,84846,84847,84848,84849,84850,84851,84852,84853,84854,84855,84856,84857,84409,84548,84860,84697,84466,84863,84532,84421,84866,84498,84868,84869,84870,84871,84872,84758,84640,84459,84602,84413,84878,84784,84458,84881,84882,84883,84412,84532,84413,84887,84888,84889,84890,84891,84421,84428,84603,84731,84896,84507,84898,84421,84459,84813,84745,84460,84534,84905,84480,84907,84908,84909,84910,84911,84912,84913,84914,84448,84464,84838,84918,84710,84920,84909,84922,84923,84924,84524,84415,84547,84664,84929,84930,84931,84442,84933,84731,84935,84468,84409,84866,84887,84940,84434,84474,84943,84944,84945,84565,84947,84948,84949,84434,84813,84952,84953,84409,84409,84956,84757,84958,84959,84960,84961,84443,84490,84964,84965,84966,84967,84968,84495,84970,84971,84484,84973,84974,84975,84409,84977,84978,84979,84980,84981,84982,84909,84984,84794,84986,84987,84988,84642,84990,84426,84866,84993,84994,84995,84996,84997,84998,84999,85000,85001,84646,84909,85004,85005,85006,84471,85008,85009,85010,85011,85012,85013,85014,84491,84510,84524,85018,85019,85020,84794,85022,85023,84890,85025,84642,85027,85028,85029,85030,85031,84732,84471,85034,84424,85036,84909,85038,85039,85040,84642,85042,84454,85044,85045,85046,85047,85048,85049,84910,85051,85052,84988,85054,84504,85056,85057,84465,84896,85060,85061,85062,84449,85008,85065,84999,85044,85068,85069,85070,84454,85072,85068,85074,85075,84495,84547,84474,85079,85080,85081,84781,85083,85084,84459,85086,85087,85088,85089,84579,85091,84653,85054,85094,84455,85096,85042,84458,85099,84595,84424,84424,84462,84965,85105,85106,85107,84521,85109,85110,85111,84986,85113,84986,84733,84602,84654,85118,85119,84491,85121,84652,85123,85124,85125,84516,84662,84424,84455,85130,84524,84944,85133,85134,85135,84546,84656,85138,85139,85140,85141,85142,85143,84468,85145,85146,84516,85148,85149,85150,84767,84845,84603,84491,85155,85156,85157,84758,85046,85160,85161,85162,84888,85164,85165,85166,85167,85168,85169,84409,85171,84474,85173,85173,84448,84840,85177,85178,85179,85180,84988,84965,85183,85184,85185,84424,85187,85188,84467,85190,84510,84516,85193,85194,85195,85196,85086,85198,85199,85200,85201,85202,85203,85204,85205,85206,85207,85208,85209,84492,84409,84442,84533,84443,84923,85029,84735,84452,85219,85220,84645,85222,85223,85188,85046,85226,85227,84958,85229,85230,85231,85232,85233,85234,84958,85236,85237,85238,85239,85240,84421,85242,84473,85244,85245,85246,85247,85177,84579,85250,85251,85252,85253,84409,84412,85256,85257,84565,84515,84510,85261,85262,84691,85264,84421,84426,84482,85268,85269,84451,85271,84770,85273,85274,85275,85276,85277,85278,85279,84534,85281,84413,85283,85284,84751,84995,85287,85028,85289,84840,85291,84487,85293,84987,85295,85148,85297,85298,84510,84429,85145,84659,84977,85304,85305,84412,84412,85308,85309,85310,85311,84424,85313,85030,84532,85316,85130,84452,84412,85320,85321,84524,85123,85324,85325,85326,85327,85328,84753,85330,84515,84697,84990,85334,85335,84458,85150,85338,85339,85340,85341,85342,85343,85344,85345,85346,85347,84697,85273,85350,85351,85352,84911,85354,84978,85356,85357,85358,85359,85069,84461,85362,84500,84475,85365,85366,84958,84437,85369,85370,85371,85372,84492,84784,85375,85376,85377,84515,84481,85380,84599,85382,85383,85384,84522,85386,85387,85388,85389,85390,85391,84923,85393,85394,85268,85396,84409,84526,84451,85400,85237,85402,85403,85404,85405,85406,85407,85408,84646,85410,84409,84432,84412,85396,84465,84516,85417,84424,85087,85420,85421,85422,85423,85424,85029,85426,85427,84642,85429,85430,85431,84758,84645,85434,85435,85088,85437,85438,85439,85440,85145,85442,84987,85444,84490,85446,85447,85448,84456,84481,85451,84475,85250,84980,85455,84656,84421,85237,85459,85460,85461,85462,84412,84794,84888,85466,84409,85468,85145,85304,85471,85472,85473,85474,85475,84979,85477,85478,85479,85480,85481,84432,84421,85484,85485,85486,85487,85488,85489,84476,84554,85492,84448,84988,85495,85496,85497,85498,84587,85500,85501,84477,85250,84907,85505,85506,85507,85508,85509,85510,84534,85512,85284,85514,85515,85516,84888,85518,85519,85369,84988,85522,85523,85524,85525,84599,84524,85268,85529,85229,85531,85532,85533,85534,84428,85536,85133,84518,84421,84965,85541,85542,85543,85344,85545,84866,84442,85548,85298,85550,85551,85552,85553,84652,84754,85556,84454,84827,85559,85560,84432,84775,84451,85564,84652,84587,85567,85568,85569,85570,85571,84543,85573,85574,85575,85576,85335,85365,85579,85400,85406,85582,85583,85584,85573,84697,84602,85588,85589,85590,85089,84628,85593,85594,85595,85596,85597,85598,84460,85600,85601,85602,85603,84474,85605,85606,85607,84414,85609,85610,85611,84887,85335,84990,85615,85616,84535,85618,84597,85468,85621,84437,85250,85624,85625,85626,84461,85628,85268,84434,85030,85632,85633,84480,85030,85636,85637,85638,84535,84909,84428,85642,85643,85644,85057,85646,85647,85648,85649,84443,85651,85652,85653,85297,85655,84579,84468,85658,84644,85660,85380,84944,85054,85664,85665,85666,84602,84485,85669,85046,85671,85672,85673,84409,85556,85676,84970,85678,85679,85680,84646,85682,85683,85684,84424,84654,85222,84448,85689,84510,84487,85692,85693,85694,84502,84565,84424,85698,85028,85700,84646,85702,85703,84525,85705,84424,84458,84587,85709,85710,85711,84510,85713,85714,85715,84460,85459,85072,85573,85237,85155,84624,85171,85556,84434,84434,85148,85698,85729,85730,84967,85732,84412,84428,84986,84473,85573,85738,85739,84421,84473,84602,85743,84421,84421,84412,84409,84628,85749,85750,85751,85752,85753,85754,85755,85756,85757,85758,85759,85760,85008,85762,85763,85764,84495,85766,85767,85768,84533,85770,85771,84473,84834,84432,85149,85776,85777,85778,85779,85780,85781,85782,84958,84409,84480,84697,84549,85788,85789,85790,84970,85618,85618,85794,85795,85796,84409,84987,85799,84655,85801,84495,85803,85804,84513,85442,84654,84424,85133,85810,85811,84696,84517,85814,85815,85816,85817,85818,85819,85820,85821,85822,85823,85824,85825,84488,84409,84448,85829,85618,85831,85815,85833,85834,85835,85836,85837,85838,85839,85840,85841,84482,84995,85844,85845,85846,85847,85848,84510,84544,85219,84475,85853,85854,85423,85856,84487,85858,85655,85660,85113,85862,84657,84697,84448,84428,85867,84415,85869,85870,85871,84658,84474,85874,84532,84438,85478,85878,84491,85369,85881,85882,85883,85884,85885,85472,85887,84450,85810,85890,85891,85892,85262,84953,85145,85054,85897,85898,84412,84967,85901,85902,85903,85904,84499,85906,85907,84979,85909,85910,85911,85271,85047,85914,85915,84847,85430,85918,84565,84565,84490,84464,84409,84944,85925,85874,85155,85928,85929,85930,85931,85008,85933,85934,85935,85936,85937,85938,85328,85940,84424,84993,85943,85944,85945,85946,85947,85948,85949,84565,84834,85404,85134,85925,85382,84548,84535,85958,85959,85034,85961,85962,85963,85236,84751,85966,85738,85268,85969,85970,85971,85334,85973,84426,85975,85976,85977,85978,84466,85980,85935,85982,84986,85984,85985,85986,85338,85988,85989,85990,85991,85992,85993,85994,85995,85996,85997,85998,85999,84602,86001,86002,84434,84424,85038,86006,86007,86008,86009,84409,84439,84524,84451,85375,86015,86016,86017,84444,84465,86020,86021,86022,85472,86024,86025,84498,85155,85471,86029,86030,86031,86032,84794,86034,86035,86036,84409,85750,86039,86040,86041,86042,86043,86044,85810,84526,84599,84644,86049,84956,85980,86052,84652,85045,86055,86056,86057,86058,85856,86060,86061,86062,86063,85518,86065,86066,86067,86068,86069,86070,85766,86072,86073,86074,84995,84511,85382,84480,85177,86080,84775,86082,86083,86084,86085,86086,86087,85022,84981,86090,86091,86092,86093,84606,85048,84533,84573,84826,84524,84449,85615,86102,86103,86104,84422,84434,85991,86108,86109,84438,86111,86112,86113,86114,85304,86116,84485,84644,86119,85009,86121,86122,84525,85298,86125,84977,85738,86128,86042,86130,86131,85029,85298,84535,85304,86111,86137,86138,86139,86140,86141,84654,84424,84834,84775,86146,86147,86148,85056,84602,86151,84602,85789,86154,86155,86156,86157,86158,86159,86160,86161,86162,86163,86164,84747,86166,86167,86168,84426,86170,86171,84414,84454,84448,84628,86176,86177,84565,86179,84442,86181,86182,86183,84739,84449,84424,86187,86121,86189,86190,86191,86192,86193,84594,84546,85978,86049,84465,84587,86200,86201,86202,84988,85145,86205,86206,86207,84434,84664,86210,86211,86212,86213,84450,86215,85698,84662,86218,84481,85906,86221,86222,86223,86224,86225,86226,86227,86228,86229,86230,85402,84464,86233,84826,84456,86236,85738,86238,86239,86240,84986,85250,86243,86244,86245,85155,85334,85803,86249,86250,86251,84482,84455,86254,84510,85335,86119,84434,84466,84618,85883,86262,86263,86264,86265,86266,86267,86268,86269,85550,85426,86272,86273,86274,84628,86276,86277,86278,84977,84888,84424,85261,86283,86284,86285,85564,84454,85256,86289,86290,86291,86292,86293,85710,85824,84993,85402,85320,86299,86300,86049,85943,86303,86304,85121,84840,84662,84510,85976,84986,86311,84596,86313,86314,86315,84434,84455,84665,84655,84464,86315,86322,86323,84548,86325,84482,86327,86328,86329,86330,85250,84424,84475,84526,86335,86336,85321,86338,86339,86340,85396,86190,86343,86344,86345,86346,86347,84977,84475,85814,86351,86352,86353,86354,86355,86356,86357,84834,86359,86360,86361,84458,84487,84656,84476,86366,84533,85156,86369,86370,86371,84480,84507,84660,85139,86376,85297,86378,84708,84415,85655,86254,85375,86384,84594,86386,84510,85365,86389,86218,86391,85751,86393,86394,86395,86396,86397,86398,86399,86400,86401,86402,86403,84510,84660,86406,86407,86408,86409,86410,86411,84464,84475,85119,84696,84448,85219,86418,86419,86420,85334,86422,86423,86424,85383,86190,84605,86428,84795,86430,84412,86029,86433,86434,86435,85273,86437,86438,86439,86440,85087,84940,86443,85298,85867,84442,86447,86448,84532,85009,86451,84565,85257,86454,86455,86456,86111,86458,86459,84504,84421,84825,84565,84532,84565,84473,84761,86468,86469,86470,86471,86472,85198,84784,84467,86476,84524,85289,85847,86480,86481,86482,86483,86484,86485,86486,84764,85118,86489,86490,86491,86492,86299,85471,86495,86496,85201,84646,85426,86500,85156,85156,86503,84511,84473,84443,84458,84424,85574,86510,86511,86512,84659,86514,85001,86516,86391,84428,86519,86520,86521,84905,85958,86524,86525,86526,85166,86528,86529,86530,86531,84409,86533,84990,84887,86536,85034,86265,86539,86540,85522,86542,86543,86544,86062,84466,86547,84691,84454,84414,85698,84412,86492,86554,86555,85709,84480,86558,86559,86560,84443,86562,84532,84458,85471,85574,86567,84408,86569,86570,86571,86572,86573,84408,86575],"frame":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,23,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,71,73,74,66,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,23,90,91,61,92,93,94,67,68,69,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,99,111,112,99,113,101,114,115,116,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,130,100,122,123,124,125,126,127,128,129,131,132,133,123,134,101,102,103,104,135,136,137,138,139,140,141,142,143,144,125,126,145,146,147,148,149,150,151,152,153,154,135,136,137,138,139,136,137,138,155,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,160,161,101,162,163,164,165,166,167,168,169,170,171,172,173,174,161,101,162,163,164,165,175,176,177,169,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,113,122,123,124,125,126,197,198,199,200,201,202,203,204,205,206,207,208,209,210,128,129,211,212,213,214,215,121,109,110,99,111,112,99,161,216,217,218,219,220,110,99,111,112,99,100,221,222,223,224,101,225,226,120,121,109,110,99,111,112,117,113,227,123,124,125,126,228,229,230,146,231,232,233,190,234,235,201,202,236,204,175,176,177,169,237,238,184,185,186,239,185,186,240,188,189,241,185,242,243,244,175,176,177,169,237,238,184,185,186,241,185,186,239,185,186,190,245,246,247,206,207,208,209,210,128,129,131,248,152,249,250,101,225,226,120,121,109,213,214,215,121,109,110,99,111,112,99,161,101,251,252,253,254,255,216,217,218,219,220,110,99,111,112,117,100,101,225,226,120,121,109,110,99,111,112,99,100,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,258,259,260,261,262,263,264,265,266,267,268,269,270,270,271,270,270,270,270,272,69,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,276,179,147,277,278,279,280,281,281,280,282,283,284,285,286,104,135,136,137,138,287,288,117,100,101,225,226,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,159,128,129,131,290,121,109,110,99,111,112,99,100,101,102,103,291,292,293,294,295,296,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,297,298,299,201,202,256,257,99,111,112,117,113,227,123,124,125,126,228,178,179,300,301,302,303,304,303,304,303,305,303,306,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,205,101,102,103,104,135,136,137,138,139,140,307,308,309,113,101,114,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,231,232,311,181,312,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,313,314,315,316,317,318,319,320,193,194,321,101,114,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,322,323,99,113,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,292,324,253,68,325,326,327,99,111,112,99,161,328,329,101,114,119,120,121,109,110,99,111,112,99,100,101,330,252,253,68,331,161,101,330,332,333,334,335,336,337,44,45,338,258,339,340,341,342,343,344,175,176,177,316,317,345,172,346,319,347,348,349,350,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,127,128,129,211,212,326,327,99,111,112,99,161,328,329,101,114,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,352,353,146,346,319,354,328,329,227,123,124,125,126,145,146,147,355,356,357,358,359,359,360,350,243,244,361,362,101,225,226,120,121,109,363,364,365,366,225,226,120,121,367,368,369,370,371,372,373,374,375,376,377,378,313,314,315,379,169,380,381,227,123,124,125,126,228,178,179,382,355,383,384,385,386,225,226,120,289,109,110,99,111,112,99,201,202,243,244,175,387,206,207,208,388,389,179,390,391,392,328,393,394,395,396,397,398,225,226,120,121,367,368,399,400,179,382,401,383,402,358,360,403,404,405,406,407,408,135,136,137,138,139,409,101,251,332,333,410,335,411,412,413,109,110,99,111,112,117,113,414,415,416,244,175,176,177,169,417,333,334,418,419,101,283,284,420,421,422,423,424,425,426,427,428,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,374,178,179,382,148,429,149,430,431,161,328,393,394,395,396,432,433,434,320,435,99,113,101,102,103,291,297,436,437,438,439,440,441,442,161,101,225,226,120,121,109,110,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,367,368,369,400,179,382,401,443,444,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,400,179,382,148,445,149,150,446,447,447,448,156,157,216,449,439,450,451,452,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,453,319,454,455,455,456,455,455,457,203,204,458,459,169,460,179,147,461,462,463,69,243,244,247,101,464,251,465,295,466,102,103,467,291,297,468,299,243,244,313,314,315,169,237,238,184,185,186,190,469,470,471,326,327,99,111,112,99,161,328,329,101,472,157,473,474,475,179,346,476,477,478,479,480,481,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,482,483,484,485,486,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,492,172,382,148,429,429,445,493,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,390,391,494,495,496,497,498,499,117,201,202,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,445,429,429,445,445,501,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,500,146,147,401,383,502,503,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,276,179,390,391,494,495,505,496,496,295,506,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,352,353,146,147,148,429,445,149,279,280,281,281,280,507,99,113,414,415,487,206,488,489,490,227,123,124,125,508,317,345,509,172,382,510,278,511,446,447,447,512,69,99,113,101,472,157,473,474,475,179,147,513,514,515,516,517,203,204,458,459,169,460,179,147,518,519,520,521,522,523,44,45,524,525,225,226,120,121,367,368,399,400,179,382,401,383,526,527,367,368,399,400,179,346,319,454,455,528,515,516,529,167,168,169,178,179,382,148,445,429,530,393,394,395,396,531,146,147,532,533,534,535,536,537,538,538,537,539,166,167,168,169,460,179,346,540,541,328,329,101,472,157,489,490,216,542,543,544,113,101,225,226,120,121,367,368,399,400,179,382,355,383,526,545,546,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,401,356,402,302,303,305,303,304,303,305,303,305,303,548,549,550,551,197,145,146,147,148,429,429,552,258,259,260,261,262,263,264,553,439,266,267,554,555,547,172,382,401,356,556,557,558,557,559,560,561,178,179,382,510,278,562,280,563,564,565,566,567,568,569,532,514,570,571,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,547,172,382,510,573,574,575,576,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,580,345,172,346,319,347,581,582,127,128,129,211,583,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,547,587,434,347,581,455,348,455,455,455,588,589,590,429,149,591,150,446,592,592,447,447,593,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,460,179,147,597,402,302,303,598,472,157,473,474,475,179,147,513,533,599,228,352,600,172,382,601,602,603,603,602,603,602,603,604,374,352,353,146,147,148,149,562,280,281,280,281,280,281,605,472,157,473,474,475,179,180,606,607,608,609,169,460,179,147,461,445,445,445,445,445,149,150,446,512,549,610,145,146,147,355,383,534,535,611,537,538,538,538,538,537,537,612,613,614,615,616,496,497,498,617,618,361,619,620,169,352,621,146,147,355,383,383,384,558,622,500,146,147,148,429,429,429,429,429,445,445,445,149,623,100,101,624,625,626,627,628,146,147,510,573,629,190,630,300,301,302,303,304,631,632,54,55,633,228,352,600,172,382,401,383,502,634,611,538,537,538,538,537,537,538,635,149,150,446,447,447,592,636,637,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,638,169,639,640,427,428,99,111,112,99,201,202,427,428,99,111,112,117,161,101,225,226,120,121,367,368,399,641,642,434,347,348,643,582,109,110,99,111,112,117,201,202,203,204,584,585,222,223,224,644,222,223,645,646,647,648,649,650,651,603,602,603,602,603,602,603,602,603,602,603,561,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,178,179,382,401,356,502,634,536,538,537,652,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,472,157,473,474,475,179,147,589,653,570,571,117,201,202,203,204,458,459,169,460,179,147,597,556,654,557,558,557,558,557,557,557,558,557,557,557,558,557,558,557,655,225,226,120,121,367,368,399,641,656,657,658,616,497,659,660,113,101,472,157,473,474,475,179,147,532,526,545,661,243,244,166,167,662,169,178,179,382,401,383,402,383,502,634,537,611,537,537,663,664,326,327,99,111,112,99,161,328,393,572,489,665,666,667,668,439,669,179,382,518,384,654,557,557,557,558,557,558,557,557,557,563,225,226,120,121,367,368,399,400,179,147,148,445,670,545,671,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,148,149,591,672,280,281,280,281,280,281,280,673,329,122,123,124,125,491,374,352,353,146,147,148,429,445,149,279,280,281,280,281,280,281,280,281,280,674,205,675,676,677,678,146,147,601,679,225,226,120,121,109,110,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,102,103,104,135,136,137,138,139,140,141,680,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,662,169,178,179,382,148,445,445,445,149,150,446,447,447,681,326,327,99,111,112,99,161,328,329,122,123,124,125,491,145,146,147,148,429,149,511,446,592,682,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,127,128,129,683,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,460,179,147,597,556,654,557,558,557,558,557,557,557,558,557,558,557,558,684,367,368,399,613,685,434,454,686,435,161,101,102,154,135,136,137,138,139,136,137,138,139,140,141,680,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,687,688,495,689,496,690,691,692,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,148,429,429,429,445,445,429,149,591,693,99,113,414,415,694,204,594,595,596,379,169,178,179,346,319,454,455,695,99,113,101,225,226,120,121,367,368,399,400,179,382,510,696,697,698,393,394,395,396,699,172,382,532,700,534,535,536,701,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,702,580,703,704,705,706,707,99,111,112,99,113,227,564,133,123,124,125,508,317,703,146,346,319,454,348,456,455,686,549,708,201,202,326,327,99,201,202,326,327,99,111,112,99,161,328,329,227,123,124,125,491,492,172,382,148,445,429,445,149,150,446,447,592,636,435,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,709,60,61,710,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,148,149,279,280,281,281,281,280,281,711,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,510,712,278,591,150,446,592,512,713,117,201,202,427,428,99,111,112,117,113,101,472,157,473,474,475,179,382,513,526,545,714,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,609,169,178,179,382,401,383,402,302,303,304,303,304,303,304,303,548,331,326,327,99,111,112,99,161,328,329,122,123,124,125,491,145,146,147,148,445,429,429,445,149,150,446,447,447,512,435,225,226,120,121,367,368,399,400,179,382,401,383,514,570,516,715,716,717,718,719,718,720,718,721,718,721,722,403,374,352,353,146,147,355,383,384,654,557,557,557,557,557,558,557,558,692,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,178,179,147,148,149,150,446,447,636,69,99,113,101,225,226,120,121,367,368,399,453,476,477,478,723,724,393,572,489,665,666,667,725,439,266,267,268,726,403,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,727,434,454,728,549,729,472,157,489,665,666,667,730,731,268,732,733,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,352,353,727,434,347,734,161,101,225,226,120,121,109,110,99,111,112,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,665,735,489,665,735,216,736,179,147,737,738,739,740,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,228,352,600,172,382,148,445,429,149,150,446,447,741,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,472,157,473,474,475,179,382,589,670,545,742,117,201,202,203,204,458,459,169,237,743,744,188,189,241,185,186,239,185,186,190,745,746,147,589,747,748,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,154,135,136,137,138,139,136,137,138,139,749,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,628,146,147,510,573,629,190,750,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,429,429,149,591,751,752,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,753,754,113,122,123,124,125,126,127,128,129,211,755,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,756,268,757,758,393,394,395,396,531,146,147,589,590,445,429,149,759,446,447,592,592,447,636,549,760,427,428,99,111,112,99,201,202,427,428,99,111,112,99,258,761,260,261,762,262,263,264,763,764,765,766,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,767,752,117,201,202,326,327,99,111,112,99,161,328,393,394,395,396,531,727,434,347,768,528,571,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,367,368,399,400,179,382,510,696,697,769,770,771,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,147,510,696,772,117,201,202,326,327,99,111,112,99,161,328,329,122,123,124,125,491,500,146,147,148,429,429,149,511,446,592,592,447,447,512,69,243,244,313,314,315,169,773,774,47,367,368,399,641,775,203,204,458,459,169,352,776,777,778,779,780,780,781,781,780,781,782,382,510,696,783,570,784,453,476,477,478,785,786,787,243,244,166,167,662,169,460,179,147,597,402,302,303,304,303,304,303,304,303,304,303,788,549,789,393,394,395,396,699,172,382,589,590,429,429,429,429,445,429,149,759,446,447,447,790,662,169,352,791,792,793,794,795,707,99,111,112,99,113,101,162,163,796,489,665,666,667,797,169,352,798,172,382,355,383,383,534,535,537,799,549,800,328,329,101,283,284,285,286,467,104,135,136,137,138,139,140,141,680,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,313,314,315,316,317,345,509,172,382,510,573,629,190,191,802,803,472,157,216,804,805,161,328,329,101,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,134,122,123,124,125,126,127,128,806,807,808,809,810,809,809,809,809,809,811,812,813,814,815,816,817,333,410,335,336,337,818,117,161,328,329,101,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,820,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,355,356,519,821,201,202,427,428,99,111,112,99,161,328,329,101,251,332,333,334,335,336,337,44,45,822,823,117,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,367,368,369,370,824,765,825,99,113,101,114,119,120,121,109,110,99,111,112,99,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,201,202,203,204,175,176,177,169,178,179,231,232,182,834,835,258,761,260,261,836,837,262,263,264,553,439,838,47,99,113,101,330,332,333,334,335,336,337,44,45,524,839,840,809,809,809,809,809,811,812,813,814,815,841,650,603,602,603,602,603,603,602,603,602,603,602,603,602,442,492,172,390,391,494,80,842,258,761,843,225,226,120,121,367,368,399,844,845,541,109,110,99,111,112,99,100,122,123,124,125,126,145,777,846,80,847,500,146,147,510,573,574,234,848,849,236,204,175,176,177,169,237,743,744,188,189,190,850,851,852,853,244,313,314,315,316,317,703,146,147,148,854,629,190,191,855,313,314,315,316,317,345,509,172,382,148,854,856,379,169,857,858,859,860,861,458,459,169,417,333,862,584,863,864,489,665,666,667,730,731,268,865,69,794,795,707,99,111,112,99,201,202,427,428,99,111,112,99,161,328,393,572,216,449,439,838,23,866,99,258,259,867,868,243,244,175,176,177,169,869,687,688,870,251,871,489,665,666,667,797,169,178,179,382,148,854,872,873,490,227,123,124,125,508,317,703,146,147,355,356,874,393,394,395,396,699,172,382,532,700,384,557,507,572,489,665,666,667,797,169,875,146,346,319,876,283,284,420,877,878,879,880,881,882,730,731,883,268,884,885,886,543,544,887,888,439,450,889,890,891,892,893,584,863,864,206,488,489,665,666,667,894,895,289,109,110,99,111,112,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,896,807,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,897,113,152,249,250,101,251,332,333,410,418,255,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,178,179,147,510,278,562,281,280,281,280,281,280,281,898,114,119,120,121,109,808,811,812,899,814,815,900,901,902,303,903,904,127,128,129,905,283,284,285,286,467,104,135,136,137,138,906,393,572,489,665,735,216,907,908,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,909,146,231,232,311,181,233,190,910,192,193,194,195,911,912,913,179,914,225,226,120,121,109,110,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,175,176,177,379,169,857,915,916,917,918,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,159,128,129,819,919,117,161,328,329,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,145,146,231,232,921,922,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,923,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,808,811,812,899,814,924,179,390,391,494,495,925,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,367,368,399,641,657,658,495,691,605,109,110,99,111,112,99,100,122,123,124,125,126,374,229,909,146,231,232,311,181,233,241,185,926,927,201,202,203,204,175,176,177,169,178,179,147,401,383,556,560,442,624,625,928,206,488,216,929,930,931,932,68,69,99,113,101,102,103,467,291,292,324,253,933,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,460,934,935,393,572,206,207,208,388,936,937,938,939,211,940,920,492,509,172,382,510,573,574,941,942,374,943,319,454,348,348,944,350,243,244,166,167,662,169,170,171,587,434,347,348,945,946,947,226,120,121,367,368,399,400,179,180,181,233,239,948,949,950,951,570,952,529,947,226,120,121,367,368,399,400,179,147,355,383,953,156,157,152,954,955,956,253,254,255,489,665,735,216,736,179,180,606,957,426,310,146,147,148,429,429,854,574,958,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,251,252,253,254,960,961,962,963,135,136,137,138,139,964,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,547,587,434,320,193,194,195,965,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,472,157,275,473,474,475,179,231,967,968,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,145,146,147,401,356,969,326,327,99,201,202,203,204,594,595,596,379,169,352,353,146,346,319,347,970,971,367,368,399,641,972,973,613,614,615,495,496,497,659,974,104,135,136,137,138,139,975,500,146,390,391,494,495,976,977,291,297,436,978,145,146,147,148,429,445,445,429,979,310,146,390,391,494,616,690,673,243,244,166,167,638,169,352,600,687,980,981,295,982,115,983,253,254,984,153,103,291,292,324,253,254,985,920,145,146,147,148,854,574,986,987,471,467,988,989,145,146,147,401,383,519,990,991,110,99,111,112,99,100,227,123,124,125,126,228,352,600,172,180,181,233,190,992,993,367,368,399,400,179,382,510,278,994,295,982,995,996,299,211,997,367,368,369,400,179,390,391,494,495,691,918,390,391,494,495,689,690,496,496,496,690,496,496,691,442,139,140,141,680,460,179,147,277,712,712,696,696,696,712,696,696,998,999,435,1000,522,523,1001,1002,1003,1004,1005,333,334,335,336,337,44,45,1006,835,808,810,809,809,809,809,809,809,809,809,809,809,1007,1008,1009,1010,1011,23,258,259,867,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1015,172,382,510,696,712,696,1016,168,169,237,743,744,188,189,190,575,802,1017,156,1018,1019,1020,423,424,1021,1022,1023,1024,161,328,393,394,395,396,265,838,23,401,383,519,990,1025,1026,319,347,455,1027,549,1028,1029,954,955,956,253,254,419,229,1015,1030,1007,1031,333,410,418,1032,369,400,179,231,232,233,190,986,1033,420,801,120,289,367,368,369,1034,80,1035,909,146,147,148,429,429,429,445,445,149,672,1036,1037,1031,333,410,418,23,461,149,562,281,281,280,281,280,281,1038,564,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1039,1040,216,449,439,266,1041,68,331,492,172,346,319,347,581,455,582,113,489,665,735,489,490,216,1042,439,1043,178,179,231,232,233,190,986,1044,1045,178,179,147,401,383,402,383,556,282,1046,1047,1048,1049,1050,1051,467,467,467,995,1052,510,696,712,998,463,835,467,467,104,135,136,137,138,139,140,141,680,197,145,146,147,510,712,696,696,696,278,1053,1054,1055,1056,330,1057,468,29,417,1058,102,1059,1060,1061,80,1062,206,1063,777,778,1064,561,203,204,584,585,222,223,224,221,222,223,645,646,647,1065,1066,1067,147,148,429,854,574,1068,1069,1070,1071,237,743,744,188,189,239,185,186,190,910,192,193,194,1072,1073,977,1074,1075,68,69,1076,726,435,1077,1078,1079,1080,1081,69,156,157,489,665,666,667,1082,774,23,624,625,626,627,628,777,846,616,1083,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,175,176,177,379,1084,439,1085,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,159,128,129,211,290,117,161,328,329,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,132,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,1086,333,410,335,336,337,44,45,524,561,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1087,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,1015,172,180,181,233,190,1088,1089,1090,1091,1090,1092,549,1093,117,100,101,118,119,120,121,1037,1031,333,410,418,23,175,176,177,169,943,319,1094,1010,102,103,467,104,135,140,141,1095,522,523,44,45,524,507,117,113,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,1096,227,123,124,125,126,228,1097,1098,203,204,175,176,177,379,169,1099,859,1100,1101,917,839,920,492,509,172,180,181,233,190,1102,178,179,147,401,356,502,634,538,1103,69,99,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,276,179,390,391,494,616,505,1083,351,237,743,744,188,189,190,910,1104,80,1105,117,201,202,326,327,99,111,112,99,100,273,274,227,123,124,125,126,228,229,1106,172,390,391,23,99,113,101,102,103,467,1107,1108,351,1026,319,347,1109,283,284,420,801,120,289,367,368,369,400,179,346,319,347,1110,367,368,399,641,657,658,616,1111,351,1112,1113,746,117,100,101,118,119,120,121,367,368,369,1114,23,109,110,99,111,112,99,100,122,123,124,125,126,374,1115,561,1116,572,273,1117,1118,1119,1120,1121,1122,1123,1124,1125,379,169,352,798,587,434,320,193,194,1126,594,1127,216,449,439,669,179,147,597,519,1128,1129,283,284,285,286,467,104,135,136,137,138,139,140,141,959,101,947,226,120,121,367,368,369,1130,1131,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,145,727,434,347,1132,69,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,243,244,166,167,638,169,352,1133,799,758,414,415,694,204,594,595,596,379,169,756,268,1134,1135,326,327,99,201,202,243,244,1123,1124,1125,379,169,178,179,180,181,233,190,1136,1137,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,145,727,434,347,455,944,69,947,226,120,121,367,368,399,400,179,231,232,233,241,948,949,1138,325,399,400,179,382,355,383,700,1139,487,101,225,226,120,121,109,110,99,111,112,99,100,152,153,154,135,136,137,138,139,1140,330,252,253,68,426,1141,1142,1143,1144,1145,1146,249,250,101,118,1141,1142,1147,1148,454,455,1149,435,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,1150,492,172,382,510,573,1151,873,156,157,101,283,284,285,286,467,467,1152,1153,374,229,909,146,147,401,383,519,520,521,522,1154,102,103,988,1155,1156,159,128,129,1002,156,157,152,249,1157,1158,396,265,266,1041,1122,1159,1160,1161,193,194,1162,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,231,232,1163,232,233,241,185,926,1164,275,473,474,475,179,147,589,670,698,203,204,458,459,169,237,238,184,185,186,240,188,189,239,185,186,239,1165,1166,156,157,206,207,208,388,1167,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1168,203,204,594,595,596,379,1169,439,266,1041,68,637,118,119,120,121,367,368,369,400,179,147,148,854,629,190,191,192,193,194,1170,102,103,104,135,136,137,138,139,140,141,1171,472,157,275,473,474,475,179,180,606,1172,416,244,1123,1124,1125,316,317,345,509,172,180,181,233,190,986,1044,849,1015,687,688,616,690,1173,662,169,237,743,744,188,189,187,188,189,239,185,186,187,1174,1175,1176,330,252,253,68,435,669,1120,1121,254,985,109,110,99,111,112,99,100,133,123,124,125,126,1177,172,390,391,494,495,1178,100,101,624,625,626,627,1179,1180,1181,1182,454,455,686,758,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,1150,145,146,147,510,573,574,1183,1184,1185,1186,1187,182,606,607,545,1188,1189,240,188,189,187,1174,744,188,189,190,1190,367,368,369,1191,145,146,147,355,356,519,1192,1193,1194,237,743,744,188,189,241,185,186,239,185,186,190,1195,1196,1197,1198,382,589,670,545,1188,1199,666,667,725,439,450,1200,1201,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,159,128,129,130,367,368,369,641,642,434,320,193,194,1202,1203,103,104,135,136,137,138,139,140,141,959,367,368,369,400,179,382,510,696,696,696,696,278,150,446,1204,492,172,382,401,356,556,654,557,558,557,558,561,458,459,169,1115,673,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,367,368,369,400,179,382,148,854,1205,1206,115,1207,1208,1209,1210,23,159,128,129,683,143,144,125,126,145,146,147,148,445,445,445,445,149,672,280,281,280,281,280,281,1211,492,172,382,510,278,430,280,281,280,281,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,373,229,1212,1213,267,554,1214,435,118,119,120,121,367,368,369,641,642,434,347,456,1215,1216,109,110,99,111,112,99,100,158,123,124,125,126,145,1217,346,319,454,348,348,1109,1218,1219,367,368,399,400,179,382,148,1220,602,1221,351,229,1015,587,434,347,348,1149,426,909,146,390,391,494,616,690,505,690,690,1222,777,778,779,780,780,780,780,780,780,781,1223,601,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,603,602,1224,510,696,278,511,446,447,447,636,69,252,1225,808,809,809,809,809,811,812,899,814,815,816,1226,1182,454,456,455,686,1227,109,110,99,111,112,99,100,133,123,124,125,126,145,146,231,232,233,187,1174,1228,977,251,332,1229,510,712,696,696,278,150,446,592,447,447,512,426,178,179,147,355,383,357,383,357,383,519,1230,1231,1037,1031,333,1232,335,336,337,1233,1234,102,154,135,136,137,138,139,1235,777,846,495,496,496,1236,1237,1037,1031,333,410,335,411,412,54,55,1238,712,278,562,281,280,281,280,281,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,752,816,1226,1182,454,1239,1240,492,687,688,495,496,505,496,691,622,399,400,179,147,355,443,463,1241,492,172,382,401,383,502,634,537,1242,69,172,382,510,712,712,696,696,278,1243,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,674,665,666,667,725,439,266,267,554,1244,69,492,172,390,391,494,1245,310,146,231,232,1163,232,233,190,1246,1247,987,1248,808,809,809,1007,1249,295,1250,346,319,454,348,455,1251,147,355,356,356,534,535,1103,549,1252,662,169,237,238,184,185,186,240,188,189,240,188,189,240,1174,1253,1254,1255,1256,1257,1258,1259,1260,44,45,46,1261,756,554,270,269,270,270,270,270,271,726,403,131,1262,382,401,356,556,557,558,559,560,605,102,103,104,135,136,137,138,139,140,141,680,1003,1263,1264,253,254,1032,808,811,812,899,814,815,900,901,1265,303,903,303,304,303,304,303,304,303,788,835,680,237,743,744,188,189,190,1266,1267,1268,1269,184,185,186,240,1174,744,188,189,240,1174,1270,492,687,980,981,711,103,104,135,136,137,138,139,140,141,680,778,781,781,781,1271,1272,1273,1274,390,391,494,616,505,691,1275,285,286,1107,299,467,104,135,136,137,138,139,140,141,959,157,216,1042,439,266,267,1276,1277,1278,1279,1280,811,812,899,814,924,179,390,391,494,616,505,690,496,496,496,1281,104,135,136,137,138,139,140,141,680,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1283,276,179,346,319,454,455,1284,147,401,443,1056,147,510,573,629,190,191,1285,1286,602,603,603,602,603,602,603,602,603,603,605,104,135,136,137,1287,139,140,141,680,351,352,353,146,231,232,311,181,233,187,188,507,920,492,1288,1289,1290,1291,1292,641,657,658,495,496,1293,1083,149,150,446,447,447,447,447,447,447,447,512,549,789,756,268,1294,726,69,1295,1296,422,1297,1046,1047,1298,333,334,335,336,337,1299,819,1300,253,68,1301,1302,467,104,135,140,141,1303,403,104,135,136,137,138,139,1304,1305,1306,637,332,333,410,335,411,412,758,346,1307,346,319,347,581,348,455,1215,426,1308,367,368,369,400,179,346,319,347,455,581,455,1309,390,391,494,495,690,1293,1111,148,445,445,445,445,445,149,1310,401,1311,510,712,712,696,696,696,278,430,280,281,280,281,280,281,280,281,280,281,280,281,1211,1171,1312,1156,346,319,347,456,455,455,455,1109,382,1286,602,603,602,603,604,712,712,696,696,696,278,591,150,446,447,447,447,447,447,447,592,512,549,1313,1314,567,1315,69,808,810,811,812,899,814,815,816,1226,1182,454,1316,1317,188,655,727,434,347,581,455,455,455,455,455,455,455,1318,1319,346,319,454,456,348,455,455,455,348,455,455,455,455,455,455,1215,435,1320,291,297,1321,134,216,1042,439,266,267,268,270,1294,1322,1323,1324,333,410,335,411,412,758,1325,1326,1327,1328,333,410,1329,687,688,495,689,496,496,496,496,496,690,496,496,496,690,1330,251,252,253,68,1216,597,519,520,1331,1331,1332,1332,1332,1332,1331,1333,959,1107,1334,1335,1336,1337,1050,977,429,429,149,591,150,446,447,447,447,447,447,447,447,447,447,447,447,636,549,1338,460,179,147,518,519,520,1331,1333,1339,463,758,100,133,123,124,125,126,1340,439,838,23,154,1341,510,696,278,672,280,281,280,281,280,281,281,280,281,280,281,674,352,353,146,390,391,494,616,690,496,1342,673,399,400,179,382,510,696,1343,1141,1142,1147,1148,454,1344,115,1345,333,410,335,336,337,44,45,1346,1347,355,383,384,557,1348,557,558,557,558,442,755,696,712,696,696,696,696,696,696,712,696,998,999,713,961,962,963,135,136,137,1287,139,140,141,680,777,778,1349,1350,310,146,147,355,383,384,558,1351,258,761,260,261,836,837,1352,1120,1121,254,724,148,149,591,672,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,281,280,1353,216,804,1354,1355,920,492,509,172,390,391,494,495,496,1111,211,132,1356,1357,299,587,434,454,455,455,970,971,510,712,712,278,150,446,447,447,592,447,447,447,447,447,447,1358,115,1046,1359,1350,460,179,147,277,696,696,696,278,279,561,159,128,129,1360,1361,977,355,356,357,302,303,548,713,252,253,1122,147,601,603,603,1362,99,201,202,243,244,175,176,177,379,169,352,776,146,147,597,519,1192,1363,332,333,334,1364,616,689,496,496,496,496,496,496,690,496,561,401,383,502,1365,252,253,254,255,156,157,216,449,439,266,1366,254,255,311,183,1367,231,232,311,181,1163,232,233,190,850,246,811,812,899,814,924,179,346,319,454,456,455,455,348,455,455,455,455,455,455,348,455,1215,1368,445,149,591,150,446,447,447,447,447,447,447,447,447,447,447,447,448,1369,308,1370,172,382,1286,602,603,602,603,602,603,603,602,603,602,431,400,179,147,510,696,696,712,696,278,672,1371,1372,1373,148,429,429,429,445,445,445,445,445,445,445,445,445,462,999,69,586,1374,222,223,645,646,1375,333,410,1364,105,294,295,982,300,1376,1377,130,1378,1379,1380,1081,664,1026,319,347,581,348,455,455,455,455,686,403,924,1120,1121,68,435,1177,172,382,510,573,574,745,80,1381,1382,1130,1383,1384,1385,1386,1385,1385,1385,1385,295,982,564,216,1042,439,266,267,1387,331,712,712,696,696,696,712,696,696,278,672,280,281,280,295,506,207,208,388,936,937,938,939,1388,203,204,313,314,1389,467,104,135,136,137,138,139,1390,233,190,1068,1069,1391,1260,44,45,1392,1393,370,433,434,347,455,456,455,455,455,455,455,582,355,356,534,535,611,537,537,537,537,537,537,537,537,537,537,537,537,1394,460,179,147,518,534,535,537,1395,549,800,172,382,401,356,402,1396,664,1397,1259,1260,44,45,1398,54,55,1399,1400,439,266,267,554,270,269,270,270,270,272,835,520,1332,1332,1332,1401,1402,150,446,447,447,447,447,447,447,512,69,547,172,390,391,494,616,505,1403,712,573,629,1404,1194,237,743,744,188,189,190,575,1405,1031,333,410,418,23,1406,557,557,558,557,558,557,558,557,557,558,557,558,557,558,557,558,557,558,557,655,382,355,383,357,383,1407,146,147,355,383,519,990,1408,382,148,854,629,190,245,1409,1044,849,1410,347,456,455,686,69,1411,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,1086,333,1232,418,255,1046,1047,1048,1336,1414,1050,1050,692,1002,401,383,519,520,1401,1402,393,394,395,396,397,23,178,179,300,301,1396,637,233,190,910,1415,1416,465,295,1250,147,510,278,591,150,446,447,636,403,69,1417,1418,23,709,60,61,1419,93,94,1420,1421,435,276,179,346,319,347,686,435,355,383,534,535,536,538,537,537,537,537,537,537,537,1422,640,297,1423,1424,905,262,263,264,265,266,267,554,1294,270,270,270,270,270,270,270,270,270,272,426,567,568,1425,1426,1427,322,1428,1429,1430,1431,1432,1178,756,554,1433,140,141,959,131,1434,211,1219,1424,687,980,779,1223,276,179,346,319,347,455,455,348,695,1435,1436,1437,1438,1439,69,492,172,382,355,383,519,520,1332,1332,1332,1332,1440,696,696,696,712,696,696,696,696,696,696,712,696,696,696,696,278,150,1441,1442,696,278,759,446,447,447,447,447,447,447,636,426,1037,1031,333,1232,335,336,337,44,45,1443,135,136,137,138,139,140,141,680,1444,148,429,445,445,445,445,445,445,445,445,149,150,446,447,447,636,435,352,791,172,147,401,356,402,383,519,990,1445,399,1446,1447,23,355,383,384,558,557,1348,557,558,557,558,557,558,557,558,557,557,1222,826,1282,829,830,831,832,832,832,832,1448,1413,696,696,696,278,430,280,281,280,281,280,281,280,281,280,281,280,281,281,280,295,982,467,104,135,136,137,138,139,140,141,1449,1450,1451,390,391,494,616,496,690,1452,355,383,357,302,303,304,303,304,303,304,303,304,303,304,303,305,303,304,303,304,303,1453,1454,463,1455,712,696,696,696,696,696,696,712,278,150,446,447,636,664,680,1456,101,251,332,333,410,335,411,412,69,347,456,455,455,348,455,455,455,348,1457,808,1458,1459,255,278,150,446,447,447,447,592,447,636,435,237,238,184,185,186,240,188,189,190,245,1409,1460,1177,172,180,181,1163,232,233,190,630,777,846,616,689,1461,1414,1050,1050,442,375,1462,1463,1464,1464,1464,1465,1466,1467,1467,1468,426,401,383,402,302,1469,1470,211,820,456,455,1215,549,610,777,778,1064,780,781,780,780,780,780,780,780,780,1223,357,302,303,304,303,304,303,304,303,305,303,304,303,304,303,788,403,712,696,696,696,278,150,446,447,447,592,447,447,1471,292,324,253,68,350,616,496,689,295,982,382,355,383,534,535,537,1472,549,1338,278,759,446,592,592,447,447,447,592,636,549,1338,934,1473,1474,1475,1476,154,135,136,137,138,139,136,137,138,139,1304,1477,1049,1414,1050,1050,1050,1050,1478,1479,1480,1281,346,1481,356,556,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1482,369,1435,1483,1484,905,315,316,317,345,172,346,319,1094,23,401,383,556,558,557,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,557,782,355,383,357,302,303,304,303,304,303,305,303,1485,1059,1361,295,466,178,179,382,1486,758,1487,268,269,270,270,271,270,270,270,270,270,270,271,270,270,270,270,270,1488,820,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,1489,1490,23,379,169,460,179,147,518,384,1348,557,752,367,368,369,641,642,1491,23,509,172,382,401,356,502,634,537,1492,554,269,270,270,272,758,1368,1493,1494,1074,1323,251,1073,386,180,181,233,190,1495,80,1496,1497,233,190,234,1498,1499,1500,453,319,347,1501,1502,780,1064,839,696,696,696,712,696,696,696,696,696,696,712,696,278,1503,815,900,901,1265,303,903,303,305,303,304,303,304,303,304,303,305,303,304,303,304,303,304,303,304,303,1504,370,371,1505,495,496,496,976,1178,1506,561,510,696,696,278,150,446,447,447,447,592,447,447,447,447,512,69,940,1507,563,1356,1508,1037,1031,333,410,335,411,412,54,1509,347,456,455,455,455,455,455,348,455,686,758,346,319,347,728,435,149,672,280,281,280,281,280,1510,1004,1264,253,254,419,637,148,854,574,745,1511,573,574,1512,429,149,672,280,281,280,281,280,281,280,281,1513,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1515,131,1516,258,339,1517,755,846,495,496,689,496,496,496,496,1222,255,1518,537,799,403,900,901,1265,303,1519,303,304,303,788,549,610,182,183,1520,1521,1413,460,179,147,277,696,696,696,696,696,696,278,1522,280,281,280,281,674,712,696,696,696,696,696,696,712,696,696,278,150,446,1523,1325,1524,1525,745,1526,982,357,302,303,1527,149,994,673,819,820,449,439,669,179,346,319,1528,1529,1530,1031,333,1232,335,336,337,44,45,1531,1532,467,291,292,324,253,254,984,390,391,494,495,1461,370,433,434,347,686,413,278,591,150,446,447,447,447,592,447,447,447,447,447,447,592,447,447,447,447,1533,178,179,147,355,383,519,990,1534,1535,23,1099,916,1101,917,386,1074,1536,1537,918,291,297,1538,29,291,292,324,1539,276,179,382,518,1540,1541,1542,1101,860,1101,1101,1543,1314,1544,333,334,335,336,337,44,45,1545,1077,1078,1078,1078,340,340,1546,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,1547,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,1546,1548,826,1282,829,830,831,832,832,832,832,832,832,966,146,147,510,573,629,190,1549,193,194,1072,148,149,759,1550,153,103,467,467,467,467,1152,1551,419,1552,1544,1229,1553,152,954,955,956,1225,628,146,147,148,854,629,190,1554,1196,1197,1555,211,212,1556,618,178,179,382,510,573,574,1557,1558,518,519,520,1559,640,148,429,149,562,281,280,281,280,281,280,281,280,281,280,281,622,180,181,921,1560,744,188,189,240,1174,744,188,189,239,1165,1561,1164,1323,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1562,1563,507,1564,859,1565,1566,640,390,391,494,80,1567,298,1568,1569,510,696,696,696,696,1570,510,696,696,696,696,278,511,446,447,447,447,512,549,1571,278,759,446,447,447,447,592,447,447,447,447,636,69,224,216,449,439,266,1366,68,350,115,1046,1047,1298,333,410,335,336,337,44,45,1346,1572,357,302,303,304,303,304,303,304,303,304,303,304,303,305,303,304,303,304,303,1504,1573,731,268,1294,270,270,270,270,270,270,270,270,270,270,1488,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,680,1574,99,111,112,99,161,328,329,101,225,226,120,289,109,110,99,111,112,99,100,101,102,103,104,135,136,137,1287,139,140,141,680,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,227,123,124,125,126,228,229,1106,687,688,495,505,690,1403,117,201,202,243,244,313,314,315,316,1575,902,303,1576,549,729,161,328,329,101,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,367,368,399,400,179,147,510,573,629,190,1549,193,194,1577,1578,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,1218,1087,1579,340,340,340,340,340,340,340,340,340,340,1580,427,428,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,178,179,382,401,356,519,1128,1581,367,368,399,1582,999,549,1571,117,201,202,326,327,99,111,112,99,826,1282,829,1583,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1584,117,201,202,243,244,175,176,177,379,169,170,1585,439,669,179,346,319,347,686,331,113,101,472,157,216,449,439,669,179,346,319,347,1215,403,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,920,492,509,172,1586,193,194,1577,1587,1588,99,111,112,99,161,101,162,163,164,165,1589,1590,1591,169,237,238,184,185,186,190,745,80,1592,134,122,123,124,125,126,374,178,179,382,355,383,384,1593,379,169,1026,319,454,348,455,944,835,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,905,1116,394,395,1594,396,1595,764,1596,1331,1597,99,113,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,102,103,291,297,298,29,127,128,129,1424,808,809,809,809,840,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,1007,1031,333,410,418,23,237,743,744,188,189,241,185,186,190,1598,1599,152,961,962,1600,1601,1602,105,1603,507,808,809,809,809,809,809,809,811,812,899,814,815,900,1604,68,69,1605,169,178,179,382,401,356,502,1606,650,1607,1608,1609,1610,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,203,204,584,585,222,223,224,644,222,223,224,216,449,439,669,179,147,1406,1482,145,146,147,401,383,502,634,536,1611,699,172,382,532,526,769,1612,1613,1614,1615,147,601,295,1616,147,148,854,629,190,1617,1618,390,391,494,495,505,496,640,260,261,262,263,264,432,371,1505,495,1619,504,1374,222,223,1620,1621,981,1245,727,434,347,581,455,348,455,455,1318,1622,1413,1130,1383,1623,1386,1385,1385,1385,1385,1386,1624,394,395,396,553,439,266,267,268,1625,271,270,270,270,1626,375,376,1627,1331,1332,1331,1628,355,383,383,1629,276,179,390,391,494,495,689,496,690,496,691,752,330,332,1630,616,689,496,691,1178,696,696,712,696,696,278,1243,280,281,280,281,280,561,1106,172,180,181,311,1631,248,1632,333,410,335,411,412,637,1633,712,696,696,696,712,696,696,696,1634,492,172,382,355,383,384,558,557,1348,557,1635,383,534,1636,1637,541,1638,172,382,510,1639,463,713,101,225,226,120,289,109,110,99,111,112,117,113,158,1640,227,123,134,122,123,124,125,126,500,146,231,1641,243,244,175,176,177,379,169,178,179,382,148,854,574,1598,1642,118,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1410,251,332,333,410,335,411,412,435,99,161,328,329,101,251,252,253,254,419,145,146,231,232,233,190,1643,1044,1045,127,128,129,819,919,1644,1645,1646,1647,23,467,467,1107,299,369,370,371,1505,495,655,140,141,959,156,157,101,624,625,626,627,628,146,346,319,454,1215,637,330,1073,752,1116,394,395,1594,396,1648,1649,1650,332,333,334,418,1651,369,400,179,382,510,573,1652,920,492,509,1288,1653,228,229,230,146,147,401,356,502,634,537,1242,758,954,955,1324,333,334,418,823,231,232,233,190,1654,848,1655,351,229,909,146,231,232,311,181,233,190,986,1044,1045,330,1073,442,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,460,1120,1121,1071,694,204,594,595,596,379,169,352,353,146,147,401,383,556,559,560,295,1616,162,163,164,165,361,619,620,169,460,179,147,597,556,558,1482,99,113,101,283,284,420,421,422,1023,1656,154,135,136,137,138,139,136,137,138,139,1657,300,301,302,303,304,631,570,1658,54,1659,1194,352,1660,1661,1662,495,976,622,275,473,474,475,179,147,1663,1664,1665,333,1666,1667,268,1294,272,403,383,519,990,1534,180,181,921,232,233,239,1668,1288,1289,1596,1332,521,1669,231,232,233,239,185,926,1670,756,268,269,271,1671,134,216,1042,439,266,267,554,270,1672,69,278,1522,280,281,280,281,280,281,918,1673,673,195,196,1506,295,466,1073,1178,436,978,587,434,454,686,549,1674,1141,1142,1147,1148,1528,1318,291,1675,1676,80,1381,1382,1677,826,827,828,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,609,169,460,179,147,597,402,1678,252,253,68,69,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,429,445,445,149,751,839,400,179,147,510,573,629,190,986,1044,1189,727,434,347,581,348,455,455,455,455,686,835,109,110,99,111,112,99,100,489,490,216,1042,439,266,267,554,270,1294,1680,902,303,903,303,305,303,788,835,410,418,419,357,302,303,304,303,304,303,304,303,305,303,304,303,304,303,788,549,1338,1681,300,301,711,665,666,667,725,439,266,267,554,269,1682,1462,1463,1683,1683,1464,1464,1464,1684,1685,1686,69,1687,1688,1689,1690,1100,1101,1101,1101,1100,1101,295,982,467,291,297,1538,1691,304,303,304,303,304,303,306,1456,101,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1694,401,383,402,302,303,788,758,1695,1696,1697,291,292,324,253,254,984,150,1698,230,146,147,355,356,534,535,611,1699,278,672,280,1281,988,1700,1701,1702,179,390,391,494,495,689,1703,148,429,445,445,445,1704,990,1705,1663,1706,1707,1708,736,179,173,948,949,950,1709,1037,1031,333,410,418,1710,180,181,233,190,191,1711,1141,1142,1147,1148,347,1109,179,346,319,1528,1712,1713,1714,330,332,333,410,335,411,1715,1037,1031,333,410,418,23,104,135,136,137,138,139,140,141,680,687,688,495,689,690,496,496,496,690,690,1083,1074,1323,1716,1130,1717,278,1243,280,281,1718,287,1719,1720,1721,68,1455,815,841,80,1592,666,667,1722,1723,613,614,615,1724,1286,602,603,603,602,603,602,603,603,602,603,602,603,602,603,603,602,603,605,1163,232,233,190,191,192,193,194,1725,712,696,278,1726,502,634,536,537,537,663,435,370,824,765,1727,148,429,149,759,446,447,447,447,1728,597,502,634,663,549,1313,399,400,179,180,181,233,241,1729,366,330,252,253,254,255,254,1032,1730,69,959,696,712,712,712,696,278,672,281,280,752,959,977,696,712,696,278,150,446,447,1731,162,163,796,216,449,439,450,1200,1732,1733,1734,1735,1218,1736,355,383,1737,668,439,669,179,382,597,402,402,302,303,305,303,304,303,304,303,548,549,610,554,1738,1739,687,688,495,689,496,690,711,467,291,1675,1740,1741,1742,278,150,446,592,447,447,592,447,447,1743,755,668,439,669,179,390,391,494,616,1744,497,498,1745,1746,1747,206,207,208,388,936,937,1748,777,846,616,689,496,690,496,691,673,756,554,1672,403,1749,383,534,535,611,537,538,663,549,1338,995,1052,980,780,1750,781,780,780,780,1751,1752,985,1753,696,696,712,696,696,696,278,591,672,442,1754,1060,1755,1756,696,696,712,696,696,278,150,446,592,447,512,426,1086,1757,846,495,689,496,1758,1294,270,270,271,272,549,800,460,179,147,518,534,535,611,538,1759,350,346,319,454,686,758,553,439,440,859,746,445,1760,685,434,347,455,945,686,435,959,1761,1762,1245,278,150,446,447,447,636,758,735,216,542,1012,1013,1763,1764,355,383,384,654,557,557,558,557,558,557,557,558,557,558,557,1635,300,301,302,303,304,303,788,549,610,502,634,537,1472,835,300,301,302,303,548,69,1765,507,1766,1767,1385,1385,1386,1385,1385,1385,1768,386,140,141,959,429,1769,291,292,324,253,254,255,147,148,854,629,190,1549,193,194,1577,1770,445,445,149,562,280,561,1771,278,759,446,592,447,1772,1773,562,1774,1775,1158,1594,396,1776,1777,352,791,172,231,1641,1778,276,179,346,319,347,455,1779,348,455,455,455,348,455,1215,549,610,1060,1755,80,1780,401,443,999,426,455,455,348,455,1781,1493,1305,1782,1783,355,383,384,1784,1275,241,1165,184,185,186,190,1785,597,519,520,521,1786,1573,731,268,269,270,271,270,270,270,726,549,1571,370,433,434,347,455,455,695,1424,510,696,712,712,278,591,150,446,447,447,1787,1012,1788,149,562,281,281,280,605,1789,1790,1791,454,728,435,149,150,446,447,592,447,447,447,636,664,1159,1160,1436,1792,1522,280,281,280,281,280,281,442,148,445,462,999,435,376,377,1793,1794,683,233,190,1795,147,518,357,534,535,536,538,537,537,663,1796,668,439,669,179,390,391,494,616,1797,690,496,496,496,496,1111,1286,602,603,603,602,603,602,603,603,602,603,602,603,602,603,602,295,982,154,105,1719,1074,1323,518,357,302,303,305,303,305,303,304,303,304,303,304,303,305,303,304,303,1798,442,502,634,537,799,549,708,352,791,1288,1799,510,573,574,941,1800,1801,495,496,1802,690,496,1803,382,355,383,519,990,1804,1804,1363,383,556,1348,557,558,557,557,558,752,445,445,462,1805,292,324,253,254,1402,943,319,454,581,348,348,455,455,455,455,1109,170,1585,439,266,267,554,1806,69,346,319,454,348,1110,130,564,216,1042,439,266,267,268,270,1807,69,519,1793,1808,572,489,665,666,667,725,439,440,859,1762,295,1616,366,1809,1810,816,1226,1182,347,1239,549,610,401,356,502,634,537,799,69,696,696,712,696,696,696,712,696,278,150,1811,170,171,687,688,495,691,839,254,1402,278,150,446,1812,553,439,669,179,390,391,494,1813,401,356,356,519,990,1804,1408,266,267,268,1814,1815,952,1816,496,1802,690,496,496,496,1222,782,613,614,615,495,496,1817,442,454,455,1779,1215,403,1317,188,386,1159,1160,1161,435,1818,422,1819,1435,1436,1437,1439,1216,147,148,445,429,445,445,149,994,386,1820,735,216,449,439,669,179,346,319,1821,454,1822,403,332,333,334,335,336,1823,454,456,455,348,348,348,455,686,637,1824,23,149,1825,355,383,534,535,611,537,538,537,1759,69,251,332,333,1826,149,759,446,592,1827,237,743,744,188,189,241,185,186,239,185,186,190,1828,802,80,1829,534,535,538,799,1216,554,270,1134,271,272,549,760,687,688,495,690,1342,711,1830,439,450,889,1831,1832,1832,1832,1833,265,266,267,883,1276,1834,1835,557,558,557,558,557,557,558,557,558,1836,468,1837,1838,685,434,347,1839,548,549,1338,1032,173,185,1222,347,1840,1822,69,346,319,454,455,728,758,278,562,1774,1265,303,305,1841,1216,462,463,435,696,712,278,672,280,281,281,280,1510,278,150,446,592,592,592,447,447,593,419,519,990,1804,1025,445,445,429,445,445,149,150,446,447,448,449,439,669,179,346,319,454,768,1822,403,278,562,281,281,280,281,280,281,280,281,280,605,340,1078,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,1078,340,340,340,340,340,340,340,340,1078,1078,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,1547,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1842,225,226,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,101,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1112,1843,1844,1845,549,610,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,467,104,135,136,137,138,139,140,141,959,117,161,328,329,101,283,284,420,801,120,289,367,368,369,400,179,382,510,573,629,190,245,1409,1044,1846,118,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,510,278,1847,145,146,147,355,356,519,1128,1848,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,1074,366,1074,1323,1116,394,395,1849,1850,396,1838,685,434,454,1215,69,794,795,707,99,111,112,99,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,101,225,226,120,289,109,110,99,111,112,117,113,158,123,134,206,207,208,388,1167,1693,1012,1851,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,99,113,101,102,103,291,292,324,253,254,419,117,161,328,329,152,249,1157,1158,396,265,266,267,554,1135,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,133,123,143,144,125,126,145,146,231,232,233,190,1852,193,194,195,1853,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1854,310,1562,1289,1855,1080,1856,201,202,427,428,99,111,112,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,99,161,328,329,101,225,226,120,121,109,110,99,111,112,99,113,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,1857,117,201,202,326,327,99,111,112,99,100,273,1117,1858,1859,117,113,158,123,124,125,126,159,128,129,1424,117,113,227,123,134,122,123,124,125,126,374,229,1015,172,382,510,696,696,712,1634,152,954,955,1324,1860,249,250,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,351,229,1015,172,382,510,573,574,575,1861,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,374,229,1015,587,434,454,455,944,69,1862,1121,68,758,117,100,101,118,119,120,121,367,368,399,400,179,382,148,854,629,190,1863,1196,1864,1865,489,665,666,667,797,169,1866,950,1867,950,1868,161,328,329,101,283,284,420,801,120,289,109,110,99,111,112,99,100,273,274,275,101,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,351,460,179,147,461,445,149,150,1869,117,161,328,329,152,153,103,467,467,467,467,467,467,1107,1702,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,330,1870,225,226,120,121,367,368,399,613,614,615,561,201,202,427,428,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,100,101,118,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,145,146,147,355,383,534,535,538,538,1759,664,127,128,129,130,100,273,274,227,123,124,125,126,228,229,230,146,147,148,854,1871,530,225,226,120,121,109,110,99,111,112,99,201,202,256,257,99,111,112,117,113,133,123,134,158,123,124,125,126,276,179,147,597,556,1348,557,558,557,558,557,557,557,1245,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,1424,100,101,102,103,467,467,467,467,467,467,1506,1872,1873,254,419,337,44,45,1346,1874,1875,393,572,489,490,101,624,625,928,489,665,1876,422,1023,1877,1878,1879,1880,169,237,238,184,185,186,241,185,186,190,1881,1044,1189,387,101,283,284,420,801,120,289,109,110,99,111,112,117,161,328,393,394,395,396,265,266,1882,243,244,1123,1124,1125,316,1575,902,1883,1884,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,154,135,136,137,138,139,136,137,138,139,1304,1885,117,201,202,427,428,99,111,112,117,113,414,415,487,101,251,1701,299,161,328,329,101,472,157,206,488,101,114,119,120,121,367,368,399,400,934,1886,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,117,201,202,427,428,99,111,112,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,961,962,963,135,136,137,138,139,140,141,680,326,327,99,201,202,243,244,1123,1124,1125,379,169,1887,859,1888,746,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,1562,765,1290,1291,523,44,45,524,1281,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,147,401,383,556,558,557,558,559,560,1245,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,99,113,101,472,157,101,251,332,333,410,418,984,258,761,260,261,836,837,1352,179,300,1889,947,226,120,121,367,368,399,400,179,231,232,921,967,1890,608,169,1086,333,410,1891,156,157,101,283,284,285,286,467,104,135,140,307,308,1892,373,330,252,253,68,435,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,460,179,147,597,502,634,537,799,1455,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,1893,774,23,153,1325,1894,959,947,226,120,121,367,368,399,400,179,382,148,445,670,545,1188,1199,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,1573,731,268,270,1895,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,211,820,472,157,275,473,474,475,179,147,589,670,545,1188,1846,158,123,124,125,126,351,1026,319,347,348,944,549,760,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,1084,439,440,859,1762,622,1107,1568,133,123,134,101,114,119,120,121,367,368,369,1896,23,1107,299,118,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1177,172,180,181,233,190,575,192,193,194,195,1897,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,158,123,124,125,126,310,727,434,454,456,455,455,455,455,455,348,455,455,455,455,1898,808,811,812,899,814,924,179,346,319,347,456,455,734,122,123,124,125,126,197,492,172,382,510,712,696,696,696,712,696,696,696,696,696,696,278,511,446,1444,500,146,147,401,356,356,519,520,1628,114,119,120,121,109,110,99,111,112,99,161,101,114,119,120,121,109,110,99,111,112,99,794,795,707,99,111,112,99,201,202,1899,1900,99,111,112,117,161,101,251,332,333,334,335,336,337,44,45,524,507,225,226,120,121,109,110,99,111,112,117,201,202,427,428,99,111,112,99,113,101,118,119,120,121,109,110,99,111,112,99,100,101,102,103,104,135,136,137,138,139,140,141,959,117,161,328,329,101,472,157,206,488,101,114,119,120,121,367,368,369,1159,1901,68,1902,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,1903,1904,1905,23,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,114,119,120,121,367,368,399,400,179,382,355,443,999,549,1338,101,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,225,226,120,289,109,110,99,111,112,117,113,158,123,124,125,126,351,229,1015,587,434,1821,347,1109,1003,1004,1264,253,68,69,118,119,120,121,109,110,99,111,112,99,100,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1906,333,1907,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,367,368,369,641,657,1908,1751,442,122,123,124,125,126,127,128,129,1424,258,761,260,261,836,837,262,263,264,1595,764,1596,1331,1332,1332,1331,1909,413,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,727,434,454,455,643,1318,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,819,1910,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,158,123,124,125,126,351,178,179,382,401,383,556,654,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1718,143,144,125,126,145,146,390,391,494,495,505,496,496,496,496,496,496,496,496,496,691,918,197,145,146,147,355,356,357,302,303,304,303,304,303,304,303,305,303,304,303,548,549,1338,1074,1323,367,368,369,400,179,382,401,383,302,1469,156,157,216,1042,439,266,267,554,1294,270,270,270,270,270,270,726,549,1338,229,909,146,147,510,278,591,150,446,447,447,447,447,447,447,1827,1218,290,367,368,369,400,179,382,148,854,629,190,986,1044,1189,99,201,202,203,204,313,314,315,379,169,460,179,147,518,534,535,538,1395,403,102,103,467,104,135,136,137,138,139,140,307,308,1892,295,1911,102,103,104,135,136,137,138,139,140,141,959,492,172,382,510,712,696,696,696,278,591,150,446,447,447,636,426,117,201,202,1899,1900,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,1254,1255,1256,1912,253,68,664,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,975,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,203,204,584,585,222,223,224,221,586,565,1913,117,113,101,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,131,132,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,1914,1915,442,1037,1916,746,152,249,250,101,251,332,1917,808,809,809,811,812,1918,1350,153,103,104,135,136,137,1287,287,1919,143,144,125,126,492,172,346,319,454,581,455,1318,103,104,135,136,137,1287,139,140,141,959,101,114,119,120,121,109,808,811,812,899,814,815,816,1226,1182,347,1132,1216,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,146,147,401,383,1733,472,157,489,665,735,216,449,439,266,267,1920,270,732,1921,549,1922,283,284,285,286,467,104,135,136,137,138,139,140,141,680,122,123,124,125,126,374,229,909,146,390,391,494,616,690,505,690,690,691,782,114,119,120,121,367,368,399,400,179,382,148,854,629,190,1554,1196,1197,1923,367,368,369,1924,1925,709,60,61,73,1926,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,725,439,440,859,1101,1927,1222,178,179,147,510,278,562,281,280,281,280,281,280,281,280,674,458,459,169,170,1928,146,390,391,494,870,1929,640,1761,1690,1930,203,204,458,459,169,237,743,744,188,189,190,1931,1932,1199,249,250,101,114,119,120,121,367,368,399,400,179,382,148,854,629,190,1933,326,327,99,201,202,203,204,594,595,596,316,317,345,509,172,382,601,507,1456,101,162,163,796,216,449,439,669,179,346,319,347,1934,500,146,147,401,356,356,556,654,557,558,557,558,557,558,557,558,557,558,1935,291,297,436,1936,1219,1107,299,291,292,324,253,68,664,367,368,399,400,1120,1121,68,426,109,1074,1323,370,824,765,1596,1332,521,522,523,44,45,1006,69,947,226,120,121,109,110,99,111,112,99,161,101,102,1059,1060,1937,249,250,101,118,119,120,121,367,368,399,400,179,231,232,182,181,233,239,1165,1938,1939,275,473,474,475,179,147,1663,697,698,1824,23,399,400,179,382,510,573,629,190,986,1940,161,328,393,394,395,396,531,777,846,80,1941,1942,156,157,216,1042,439,266,267,268,1294,1626,145,146,147,401,356,556,654,557,558,557,558,557,558,557,558,752,291,297,1943,127,128,129,683,178,179,382,401,383,402,383,519,520,521,1944,102,103,104,135,136,137,138,139,140,141,959,346,319,454,686,69,99,113,101,283,284,285,286,467,291,297,436,1538,29,808,809,809,811,812,899,814,1945,333,410,418,1946,291,297,468,1947,1304,1305,1306,69,375,376,1627,1331,1331,1331,1332,1628,468,29,1667,243,244,166,167,638,169,460,179,147,518,534,535,611,537,537,1948,310,727,434,454,455,455,1149,549,1338,808,840,809,809,809,809,809,809,809,809,809,809,1949,1950,959,1015,172,382,510,712,278,430,280,281,280,281,280,281,281,280,281,280,281,280,1211,113,101,156,157,101,624,625,928,206,488,216,449,439,1951,1952,156,157,101,114,119,120,121,109,110,99,111,112,99,826,1282,829,830,831,832,1953,180,606,607,545,671,467,1506,1281,1954,1955,666,667,885,886,1693,1693,1693,1693,1693,1693,1012,1013,1013,1956,148,429,445,445,149,751,752,988,1957,823,492,172,382,1286,602,603,1178,180,181,921,1560,744,188,189,190,1828,192,193,194,1958,351,229,1015,172,382,148,429,854,574,1959,1104,80,1105,367,368,369,370,371,1505,616,1960,622,110,99,111,112,99,100,158,123,124,125,126,492,172,382,401,383,519,520,1332,1909,69,178,179,147,401,356,502,634,538,1961,572,489,665,666,667,1962,333,1232,335,336,337,44,45,524,1718,460,179,147,597,502,634,536,538,538,537,1759,664,297,1963,197,145,146,147,510,278,1522,280,281,280,281,280,281,281,280,1353,147,148,445,854,629,190,245,1964,1074,1965,352,600,172,180,181,921,1966,549,800,1323,243,244,175,176,177,316,317,703,146,390,391,494,495,690,1817,442,1074,366,367,368,399,400,179,231,232,233,190,1967,483,484,485,486,669,179,346,319,454,456,455,528,571,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1968,1969,110,99,111,112,99,100,227,123,124,125,126,145,146,147,510,573,1970,1218,1667,662,169,1268,1971,744,188,189,240,1174,1972,1973,292,1974,1975,355,383,1976,1804,1363,114,119,120,121,109,110,99,111,112,99,100,227,123,134,216,1042,439,266,267,268,1977,1553,152,249,250,565,1978,23,102,103,104,135,136,137,138,139,140,141,959,954,955,1507,1222,178,179,382,401,383,519,1192,1025,1665,333,1232,335,336,337,44,45,524,1275,1114,23,1007,1031,333,1232,335,336,337,44,45,46,47,1059,1060,1979,80,1980,401,383,556,654,679,237,238,184,185,186,239,185,186,240,188,189,240,1174,744,188,189,241,1981,145,146,147,510,696,712,278,150,446,1982,489,665,666,667,1983,23,416,244,1123,1124,1125,379,1084,439,266,267,883,1276,1984,100,101,624,625,626,627,1985,938,939,1986,504,1374,586,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,1615,1366,254,255,258,761,260,261,836,837,262,263,264,265,266,267,554,269,271,270,270,270,726,549,1674,346,319,1094,23,228,178,179,382,355,383,1987,1400,439,450,889,1832,1988,1989,1990,1031,333,1232,335,336,1991,1304,1305,1992,1993,1099,916,1100,1994,104,135,136,137,138,139,140,141,959,231,967,1995,1107,299,1564,1996,859,295,296,492,172,382,510,712,696,696,696,278,759,446,447,636,835,467,467,467,467,291,292,324,253,254,1032,1424,352,791,172,1317,188,1997,549,1338,366,161,328,329,216,1042,439,266,267,1387,193,194,1998,382,510,712,712,696,278,672,280,674,1999,330,332,333,410,335,411,412,713,1107,1691,755,609,169,1099,916,1101,2000,330,252,253,68,435,369,400,179,382,148,1220,1222,369,2001,899,814,815,841,2002,2003,603,602,603,602,2004,1585,439,266,267,268,272,1241,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,140,141,1303,350,351,229,909,146,147,401,383,502,2005,23,577,578,123,124,125,1150,145,777,778,2006,386,113,489,490,216,1042,439,266,267,554,271,2007,1896,23,148,429,429,429,149,150,446,447,447,447,512,1368,436,2008,1562,1289,1855,522,523,2009,1073,782,115,1046,1047,2010,1049,2011,258,259,260,261,262,263,264,763,764,765,1596,1909,403,1074,1323,237,743,744,188,189,239,185,186,190,745,2012,1107,2013,2014,208,2015,388,936,2016,398,2017,148,429,429,429,149,672,280,281,280,281,2018,2019,808,811,812,899,814,815,816,1226,1182,454,455,1149,549,708,146,390,391,494,495,496,1817,295,506,237,238,184,185,186,2020,2021,1148,347,455,1149,549,1571,277,712,278,430,280,281,280,281,280,281,898,2022,333,410,335,336,337,44,45,1545,148,149,759,446,592,447,447,636,69,103,104,135,136,137,138,139,140,141,959,100,158,123,124,125,126,920,492,509,172,382,355,356,384,558,2023,109,110,99,111,112,99,100,122,123,124,125,126,500,146,147,510,712,2024,746,187,188,189,2025,909,146,346,319,320,193,194,1170,104,135,136,137,138,139,140,141,680,1003,1004,2026,355,356,357,302,303,548,549,1093,743,744,188,189,239,185,186,190,986,1940,355,383,534,535,536,538,537,663,435,347,1501,455,528,1658,2027,777,846,495,505,690,496,496,496,1111,238,184,185,186,241,185,186,240,188,189,190,1828,1861,127,128,129,683,379,169,2028,1777,2029,492,172,382,510,712,696,278,150,446,447,1731,400,179,180,181,233,190,1554,1196,1197,2030,105,2031,665,735,489,665,666,667,725,439,266,1041,1071,461,429,429,2032,104,135,136,137,1000,522,523,44,45,2033,819,2034,2035,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,2036,117,794,795,707,99,111,112,99,161,328,329,101,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,147,355,383,2037,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,665,735,489,665,666,667,1564,859,1565,1566,861,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,382,355,383,526,545,671,117,201,202,326,327,99,111,112,99,161,328,329,101,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1694,117,201,202,427,428,99,111,112,99,258,761,260,261,762,262,263,264,2038,463,549,2039,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,400,179,346,319,454,455,528,570,1658,54,55,2040,2041,117,201,202,427,428,99,111,112,99,161,328,393,572,206,488,489,665,666,667,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,382,148,445,670,769,2042,113,101,225,226,120,2043,2044,69,243,244,166,167,609,169,178,179,382,148,445,429,429,149,672,280,281,2045,326,327,99,111,112,99,161,328,329,122,123,124,125,491,492,172,382,355,383,534,535,538,538,2046,549,610,262,263,264,553,439,2047,613,685,434,454,455,528,570,1658,54,2048,203,2049,1915,1915,2050,1915,2051,1915,2052,180,181,921,967,1890,545,2053,1116,572,489,490,489,665,666,667,797,169,178,179,147,401,383,502,634,538,538,537,537,1395,413,102,103,467,291,292,2054,193,194,1577,2055,101,162,163,164,165,313,314,315,169,178,179,180,181,233,239,2056,243,244,166,167,662,169,460,179,147,597,502,634,538,2057,2058,367,368,399,641,642,434,347,2059,203,204,584,585,586,221,222,223,224,206,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2060,113,414,415,487,206,488,489,490,227,123,124,125,508,317,703,146,390,391,494,495,689,690,496,691,1222,472,157,473,474,475,179,382,532,533,874,204,458,459,169,460,179,147,518,384,654,557,558,557,558,557,558,557,558,557,557,557,558,557,558,557,386,545,1188,1846,121,367,368,399,641,2061,2062,477,478,785,786,452,460,179,147,461,445,429,429,445,445,445,149,150,446,2063,145,146,147,148,149,279,281,281,280,281,281,280,1353,2064,2065,2066,1189,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,2067,500,146,147,401,383,402,302,303,304,303,304,303,304,303,304,303,305,2068,2069,644,222,223,224,216,449,439,266,267,268,1294,270,272,549,1338,2070,2071,2072,146,390,391,494,2073,2074,243,244,166,167,638,169,229,1015,172,390,391,494,495,690,1817,282,109,110,99,111,112,99,100,227,123,124,125,126,228,460,179,147,1406,442,113,101,472,157,473,474,475,179,382,589,653,570,571,109,110,99,111,112,99,100,101,624,625,626,627,1985,938,939,130,122,123,124,125,491,127,128,129,130,109,110,99,111,112,99,113,122,123,124,125,126,1573,731,268,1214,403,100,101,624,625,626,627,628,146,346,319,347,728,69,127,128,129,819,2075,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,510,998,463,758,127,128,129,131,132,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,172,390,391,494,495,690,496,689,690,690,1111,393,572,489,665,666,667,668,439,669,179,382,597,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,788,549,1338,1518,950,951,515,1658,54,55,633,367,368,399,1435,2076,2077,352,791,172,147,148,149,279,280,281,281,281,280,281,280,281,1281,182,606,607,769,770,2078,2079,2080,99,113,101,102,154,135,136,137,138,139,136,137,138,2081,180,181,182,606,607,698,490,227,123,124,125,508,317,345,509,172,180,181,1163,232,233,239,185,2082,2083,346,319,454,455,528,570,1658,54,55,2084,162,163,2085,157,216,449,439,669,179,346,319,1094,23,453,476,477,478,785,2086,147,148,149,150,2087,2088,485,2089,54,55,2040,2090,148,445,149,279,280,281,1774,703,146,147,1286,603,602,603,602,603,295,1616,374,178,179,147,355,443,2091,491,228,178,179,382,601,605,2092,1734,2093,491,228,178,179,382,401,383,502,634,537,611,538,663,664,374,352,353,146,147,148,429,429,429,149,511,446,592,592,447,2094,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,924,179,1586,193,194,195,2095,495,2096,711,99,113,101,472,157,473,474,475,179,382,589,653,570,2097,328,329,101,225,226,120,121,367,368,399,400,179,231,232,921,967,1890,545,1188,1846,225,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,237,743,744,188,189,190,1654,848,2098,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,172,382,148,149,759,446,592,447,592,592,636,549,2099,374,178,179,382,148,429,429,149,759,446,592,592,447,790,161,101,162,163,164,165,1589,1590,1591,169,229,230,146,147,510,696,278,591,2100,547,172,382,148,445,445,429,149,1522,442,1887,916,860,1100,1100,1101,1101,1101,1101,1101,1543,564,565,2101,179,1824,23,102,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,2102,134,216,449,439,669,179,346,319,347,581,455,1109,394,395,396,265,266,267,268,1294,271,271,271,726,435,567,568,1425,2103,1427,148,429,149,672,280,281,839,727,434,347,581,455,455,455,455,455,348,1839,815,816,817,333,410,335,336,337,44,45,1006,69,2104,687,688,495,496,1744,782,231,967,1890,769,2105,233,190,2106,483,484,485,2107,100,227,123,124,125,126,228,229,230,146,147,355,383,384,557,654,1635,167,609,169,352,2108,860,1101,1101,1101,1100,1994,492,172,382,601,603,603,603,1350,400,179,382,355,383,514,632,435,662,169,178,179,382,148,445,445,445,429,149,2109,725,439,266,267,554,270,1672,835,472,157,473,474,475,179,147,1663,697,769,770,2110,355,383,526,545,714,508,317,703,146,346,319,347,348,728,69,162,163,164,165,361,619,620,169,352,621,146,147,355,383,383,384,558,282,147,401,383,526,545,2053,2111,2112,1915,2113,699,172,382,513,533,502,634,611,538,538,537,537,663,549,1313,352,798,172,180,181,182,181,311,2114,467,467,467,467,104,135,136,137,138,139,140,141,959,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,628,727,434,347,728,758,472,157,489,490,216,449,439,1951,2115,2116,523,44,45,2117,2118,2119,2120,1106,172,382,148,445,149,430,280,1281,798,172,382,148,429,445,445,429,149,430,280,281,373,147,148,429,429,429,445,445,429,149,511,446,447,447,2121,2122,382,1663,1706,2123,943,319,347,581,455,455,348,348,455,455,588,131,820,243,244,313,314,315,169,460,179,147,1835,558,1482,369,400,179,147,510,573,629,190,191,802,80,2124,2125,665,735,489,665,666,667,668,439,669,179,346,319,454,2126,528,571,390,391,495,1744,497,498,2127,100,216,1042,439,266,267,268,1134,270,271,270,726,664,145,727,434,347,581,455,455,455,455,1215,1368,178,179,147,148,149,759,446,592,592,447,447,592,592,447,512,1216,1887,859,2128,563,587,434,320,2129,203,204,458,459,169,352,2130,184,185,186,241,1165,184,185,186,190,2131,472,157,473,474,475,179,382,532,514,570,571,367,368,399,2132,2133,2134,2135,508,317,345,509,172,382,148,429,445,149,279,280,281,280,1222,197,145,146,147,148,429,429,429,429,445,445,149,150,446,447,636,1241,460,179,147,277,696,696,2136,520,2137,352,600,172,382,148,429,149,150,446,592,592,636,69,445,429,429,429,429,445,149,759,446,592,593,2138,1031,333,410,335,411,412,54,2139,2140,400,179,382,510,278,672,1411,347,1840,1822,403,526,769,770,2141,145,146,147,510,696,712,278,1243,2142,401,383,556,558,692,445,445,429,149,759,446,447,447,512,758,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1007,1008,2143,193,2144,2145,454,2146,549,2147,237,238,184,185,186,239,185,186,239,185,186,190,1828,802,1526,296,589,670,2148,400,179,180,181,921,967,1890,2149,228,756,554,1214,549,2147,401,356,502,634,538,611,537,537,537,537,663,549,1093,180,181,233,241,948,949,1138,549,800,2150,2151,375,376,377,2152,2073,495,497,498,617,1237,589,653,570,2153,665,666,667,1514,1693,1693,1693,543,2154,384,557,654,557,557,558,295,506,694,204,594,595,596,316,317,703,146,147,355,356,2155,2156,147,513,526,545,714,490,227,123,124,125,508,317,703,146,147,148,854,1871,530,231,232,921,967,2157,2158,394,395,1594,396,553,439,266,1366,68,69,251,332,333,410,335,411,412,1455,1163,967,2159,2160,1288,1563,386,180,181,921,967,1890,769,770,2161,251,465,442,783,570,571,233,190,2162,483,484,485,486,531,727,434,454,2126,2163,457,577,578,564,565,566,1544,333,2164,401,383,526,769,2165,638,169,2166,774,47,180,181,233,190,2167,2168,416,244,1123,1124,1125,379,169,352,798,687,688,495,1330,258,761,260,261,836,837,1352,179,1586,435,547,172,382,148,429,149,430,280,281,281,281,280,281,280,281,280,746,2169,2170,2171,735,216,449,439,669,179,390,391,494,495,496,2172,497,498,1745,870,142,1638,172,382,510,573,629,190,245,1409,1044,1189,1116,394,395,1594,396,265,266,267,554,1294,270,270,2173,943,319,347,456,2059,645,646,2174,1490,23,148,429,429,445,445,429,149,591,672,280,281,1211,190,2175,2176,498,617,2177,2178,417,333,334,418,1402,589,747,2179,2179,2180,2179,2180,2179,2181,510,998,463,350,231,232,182,181,2182,1424,703,146,147,510,712,696,696,998,999,2083,258,259,260,261,262,2183,687,688,80,2184,103,291,297,2029,1866,2185,537,950,2186,950,2187,2188,472,157,489,490,489,665,735,216,1042,439,450,1200,2189,2190,891,2191,472,157,216,1042,2192,203,204,458,459,169,178,179,180,181,921,2193,102,103,104,135,136,137,138,139,140,141,959,222,223,224,644,222,223,224,216,1042,439,266,267,2194,345,509,172,382,510,712,696,696,998,999,403,346,476,2195,2196,485,2197,178,179,382,401,383,402,383,402,356,502,2198,2199,616,2172,497,2200,460,179,147,597,402,302,303,304,303,304,303,788,549,708,355,383,534,535,536,1611,429,429,429,445,149,562,281,280,295,982,172,382,401,383,383,556,558,2201,2202,180,181,921,232,233,190,745,80,1941,2203,492,172,382,148,429,429,445,149,759,446,2204,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2205,346,319,347,1501,455,2126,528,571,1254,1255,1256,2206,2207,352,1660,2208,2209,237,238,184,185,186,240,188,189,190,2210,2211,472,1018,1019,1020,423,424,1021,1022,2212,488,489,490,227,123,124,125,491,145,146,147,401,356,502,634,538,537,611,538,663,549,1313,148,429,149,759,1698,180,606,2213,231,232,921,1560,744,188,189,239,1165,184,185,186,190,1617,2142,2214,2215,2216,756,554,1294,270,2217,401,383,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,305,2218,102,103,104,135,140,141,1095,522,523,44,45,1006,403,641,2061,2062,477,478,785,2219,491,228,352,600,172,180,181,233,190,575,192,193,194,1577,2220,2221,266,267,268,270,732,1815,1658,54,55,1238,162,163,796,101,225,226,120,121,109,110,99,111,112,99,100,2222,2223,128,129,905,231,232,182,606,2224,2225,491,228,1026,319,347,1284,510,696,697,545,1188,1189,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,145,146,147,401,356,556,918,318,319,347,349,549,1338,2096,497,498,617,561,237,238,184,185,186,239,185,186,239,185,186,241,1165,184,185,186,190,2226,2227,2228,2229,2230,180,606,607,2231,146,147,401,356,502,634,611,538,537,537,537,663,758,149,759,446,592,592,447,447,592,592,447,447,2121,2232,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2235,346,476,477,2236,2237,735,489,2238,1348,557,557,557,557,2239,665,735,216,449,439,266,267,554,2240,2241,2007,866,99,113,565,566,128,2242,211,2243,367,368,399,400,179,147,401,383,2244,2245,109,110,99,111,112,99,113,122,123,124,125,126,374,375,376,1627,1331,521,522,523,2246,147,1663,697,545,714,662,169,460,179,147,461,445,445,149,1310,393,394,395,396,699,172,382,513,533,402,302,303,305,303,305,303,304,303,304,303,304,303,304,303,304,303,788,637,500,146,147,401,356,356,556,1348,442,777,846,495,690,505,496,690,690,496,496,496,2247,146,147,589,590,445,429,429,445,445,445,445,149,2248,355,383,526,545,1188,2249,178,179,382,355,383,519,990,1804,1363,2250,774,23,554,2251,403,211,2252,318,319,347,581,455,455,455,455,686,549,2147,777,846,495,2096,497,659,2253,2253,2253,2253,2254,2253,2253,2254,2255,1178,883,554,1921,403,1288,765,2256,432,824,1596,521,522,523,44,45,524,1718,641,656,642,434,347,528,570,952,2257,168,169,178,179,382,148,445,445,2258,589,590,429,429,149,562,281,280,281,281,281,280,281,2045,369,2259,147,355,383,384,1348,557,2201,2260,237,743,744,188,189,239,185,186,190,745,2261,491,492,172,382,355,356,384,558,1245,1663,697,2262,180,181,233,2263,1254,1255,1256,2264,492,172,390,391,494,616,1960,1222,557,558,557,2265,373,429,429,2266,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,1007,1031,333,410,418,23,347,455,768,528,1658,54,55,1238,1990,1031,333,1232,335,2267,390,391,494,495,496,497,2268,974,207,208,388,2269,23,147,510,696,697,545,2053,508,317,345,509,172,180,181,1163,232,233,190,992,2270,1499,1555,130,2132,2133,2134,2271,445,670,545,1188,1846,345,509,172,382,148,149,759,446,447,447,592,592,512,426,148,854,574,910,2272,1317,188,2273,631,570,516,2257,168,169,352,791,172,231,232,921,1966,350,461,445,445,445,429,429,445,149,150,446,636,69,573,629,190,191,192,193,194,1577,1942,1890,769,770,2141,2274,738,2275,2276,2276,2277,2277,2276,2276,442,139,140,141,680,943,319,347,348,455,455,643,457,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1286,1281,489,665,735,216,736,179,300,1376,2278,472,157,473,474,475,179,147,1663,783,570,571,458,459,169,178,179,147,148,445,445,445,429,149,511,446,2279,777,846,495,690,690,1275,104,135,136,137,138,139,964,352,600,587,434,347,455,581,455,455,455,1215,549,1093,390,391,494,495,2096,497,659,2253,2253,2280,148,445,670,545,1188,1846,2281,211,1778,247,101,624,625,626,627,1638,172,1586,193,194,1577,2220,2282,216,804,544,401,356,556,654,557,557,558,557,558,557,692,206,207,208,2283,2284,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,2285,490,216,449,439,669,179,346,319,454,348,971,665,666,667,730,731,268,270,2286,1815,571,375,376,377,2287,168,169,170,1585,439,838,23,369,1435,2288,1010,2289,1575,1265,303,305,2290,403,2291,2292,523,44,45,2117,2118,2119,2120,1317,188,2273,2293,927,683,808,811,812,899,814,815,2294,1281,683,509,172,382,355,356,1733,147,597,402,302,303,305,303,305,303,305,303,2295,482,483,484,2296,2297,2249,735,489,490,216,1042,439,2298,2299,2108,1100,1690,2300,1218,583,382,401,383,526,769,2301,276,179,346,319,454,1149,1241,370,433,434,347,455,528,2302,149,2303,2304,2305,447,447,447,592,592,447,447,512,549,1338,429,429,445,429,429,149,150,446,2306,2307,355,356,357,302,303,305,303,788,69,641,775,382,401,356,2308,1887,916,1100,917,563,591,150,446,447,447,592,512,331,147,148,462,463,549,1313,140,141,2309,510,696,1343,300,2310,454,581,2311,103,467,104,135,136,137,138,139,140,141,680,545,1188,1189,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,513,526,2262,460,179,147,518,384,654,557,558,557,558,557,557,557,558,557,557,557,558,557,558,557,622,145,727,434,347,581,348,348,2313,532,526,545,2314,597,402,302,303,304,303,304,303,305,303,305,303,304,303,304,303,304,303,788,403,370,824,765,2315,2316,2317,523,44,45,1531,2318,330,252,253,68,69,492,172,382,601,603,603,602,603,602,603,602,603,602,655,382,148,429,429,429,429,429,445,429,429,445,149,759,2319,727,434,347,348,581,455,686,69,2320,254,255,147,355,356,534,535,538,537,1395,637,1954,80,2321,2322,291,292,324,253,254,255,161,101,162,163,164,165,577,578,123,124,125,1150,276,179,2323,18,526,769,770,2324,233,190,2325,2087,2088,2326,703,146,346,319,454,348,1239,413,352,353,146,147,148,429,445,429,429,445,149,279,280,281,280,281,752,277,696,696,712,278,150,446,636,2083,148,149,759,446,592,447,592,592,447,447,2327,460,179,147,461,429,429,429,429,149,759,446,447,592,636,664,251,332,333,410,418,255,233,240,2328,2329,950,951,570,1658,54,2330,730,731,268,1814,1815,952,2331,2331,2332,2332,2332,2332,2333,959,921,967,1890,545,1188,1846,401,383,402,383,502,634,537,611,537,2334,1595,642,434,320,2335,455,2336,528,571,291,292,324,2337,251,465,1872,161,101,162,163,164,165,1589,1590,1591,169,229,2338,1213,267,554,1214,549,1338,2274,738,2134,2339,2340,2341,180,181,921,1560,744,188,189,190,986,1044,1199,149,759,446,447,592,592,447,447,2342,231,232,233,190,2106,483,484,2343,486,1314,1544,333,334,335,336,337,44,45,822,2344,148,429,429,429,429,445,445,445,445,429,1704,2287,228,178,179,300,2345,302,303,305,303,305,303,548,435,148,445,149,759,446,512,549,2147,190,2346,454,945,455,455,455,348,1215,403,665,735,489,665,666,667,2347,179,147,513,2348,549,1338,1518,2349,148,429,429,445,429,149,759,2350,429,429,149,1522,280,281,280,281,280,1774,810,840,840,809,809,809,809,809,840,809,809,809,1378,1379,2351,523,44,45,1006,549,1093,690,976,605,2249,243,244,313,314,315,169,375,1462,1463,2352,549,760,178,179,382,148,149,150,446,592,592,447,447,512,69,231,232,311,181,233,190,910,192,193,194,1170,355,356,356,384,558,977,123,124,125,1150,492,172,382,401,383,502,634,537,1422,178,179,2353,239,948,2354,549,610,783,570,571,665,735,216,449,439,1951,1952,445,445,445,445,149,759,1054,146,147,401,356,502,634,538,538,2355,426,545,671,557,557,558,557,558,557,558,557,558,557,558,746,453,476,2195,2196,2296,2356,2357,797,169,1026,2358,102,1059,1060,1061,1526,296,504,644,586,565,566,128,2242,211,2359,231,232,233,190,1598,2360,498,2127,178,179,382,401,383,502,634,1759,664,572,489,490,216,1042,439,440,2361,918,370,433,434,347,455,528,515,516,2362,352,798,172,382,148,149,759,446,447,447,592,592,636,549,1093,2363,1499,1555,211,1410,2364,565,566,1544,2365,549,610,513,514,515,516,529,666,667,725,439,266,267,268,1294,270,270,270,270,2366,231,967,1890,769,770,2367,460,179,147,461,149,2368,251,1073,977,148,445,445,445,149,150,446,447,447,512,69,371,372,2369,659,2370,885,2371,1121,68,713,104,135,136,137,1287,139,1304,1305,1306,435,473,474,475,179,382,513,526,545,671,1530,1031,333,1232,335,336,337,44,45,46,23,206,488,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,352,791,172,147,601,602,603,602,603,602,603,602,603,603,603,602,603,602,603,1350,1288,765,1290,1291,523,44,45,1346,2372,783,515,516,2373,461,149,150,446,447,447,447,512,69,190,1967,483,484,2374,54,55,2040,2375,2224,2056,666,667,668,439,266,267,554,1815,516,529,430,280,281,280,281,280,281,2045,300,2376,472,157,216,2377,149,150,446,447,447,512,713,231,232,233,190,1549,193,194,2378,2379,774,23,251,1073,295,466,709,60,61,73,2380,66,93,94,2381,1421,403,367,368,399,400,179,382,355,2382,382,401,383,526,769,770,2383,508,317,345,509,172,382,148,149,430,280,281,1774,149,759,446,592,592,592,512,549,1028,1854,1132,69,1663,2384,2180,2179,2179,2179,2179,2179,2180,2385,2386,370,433,434,347,455,728,549,800,237,238,184,185,186,240,188,189,190,1931,2270,1499,1555,211,1667,216,449,439,669,179,390,391,494,495,2096,497,659,2253,2253,2253,2253,2254,2253,2253,2255,561,656,764,765,2387,2388,2389,608,429,445,445,445,429,1704,990,2390,510,696,573,2391,2392,439,266,267,554,271,271,1895,460,179,390,391,23,756,2393,23,102,1254,2394,161,101,162,163,164,165,577,578,123,124,125,702,580,345,509,172,382,148,854,629,190,745,80,2124,2125,500,146,147,148,445,149,562,281,280,281,281,281,280,281,2395,769,770,2396,54,55,2040,2397,401,356,556,1348,605,390,391,494,495,690,1342,561,564,565,1978,23,1218,2398,346,319,347,455,582,304,1469,570,516,2257,2175,2176,659,2399,438,439,440,80,81,401,383,526,698,1579,340,340,340,1079,1669,2400,157,101,624,625,928,2401,2402,2403,607,545,671,352,600,172,180,181,1163,232,233,190,1931,2270,1499,1555,1218,2404,2405,950,951,570,952,2406,461,445,445,445,445,429,149,591,150,446,447,2407,1665,2365,435,1663,697,769,770,2408,460,179,147,597,402,302,303,788,549,1922,445,429,149,511,446,447,447,447,447,636,2409,613,685,434,320,193,194,2410,482,483,484,485,486,1575,1265,303,903,303,304,303,598,2411,181,233,190,2412,1196,1197,1555,1218,1736,485,486,2413,1915,2050,1915,2051,1915,2414,1915,2414,1915,1718,429,429,429,149,591,150,446,447,592,2415,2416,332,333,2417,367,368,399,400,179,231,232,182,183,1367,231,232,233,190,2325,1811,2175,2176,2418,2419,228,352,600,172,382,510,696,712,278,150,2420,531,146,147,589,590,429,429,429,149,511,446,447,447,636,549,729,383,556,2265,918,390,391,494,2073,495,690,496,690,690,496,373,346,319,454,528,571,545,2421,154,135,136,137,138,139,136,137,138,139,1304,1885,1830,439,440,916,1690,2128,1371,1179,1180,1181,1182,454,455,455,1149,403,182,606,2422,1084,439,838,23,777,778,1064,781,2423,579,580,345,509,172,180,181,2424,403,172,346,319,454,2425,455,768,528,952,2426,355,383,2244,2427,352,2428,2300,346,476,2195,2196,485,486,148,445,149,591,150,446,447,447,447,512,549,1093,355,383,519,990,1408,2195,2429,2430,538,536,1759,69,149,562,281,281,280,281,280,281,280,281,1371,379,169,352,2431,2056,764,765,2387,2432,2317,523,44,45,1531,80,2433,547,172,382,148,854,574,2434,193,194,195,2435,510,696,1706,2436,613,685,434,347,1839,601,603,603,603,602,603,603,603,602,603,602,442,556,654,557,558,557,558,557,558,557,977,450,1200,1831,2437,268,1294,270,1921,835,147,589,670,545,671,382,510,278,150,2087,2088,2438,2356,2364,216,1042,439,2439,2440,178,179,147,148,149,2368,601,603,602,603,603,603,602,603,602,603,602,603,602,603,977,2338,1213,267,554,1244,403,460,179,147,518,384,1784,640,149,759,446,592,592,592,447,447,592,592,447,447,636,69,489,665,735,216,449,439,838,23,449,439,669,179,346,319,347,728,549,2147,429,445,429,149,430,2441,709,60,61,2442,2443,23,311,181,233,190,1549,193,194,2444,356,2445,2166,774,23,2446,348,1840,2447,626,627,628,146,147,510,573,629,190,1549,193,194,2448,453,319,347,455,1239,549,1571,229,1015,172,382,148,149,759,2449,1663,697,545,2314,429,429,445,429,429,429,1704,520,2450,460,179,147,461,429,429,429,445,445,429,149,1053,1550,532,526,545,742,542,1693,1693,1693,543,2451,149,430,281,2452,382,401,383,502,634,1472,637,2214,2453,480,2454,776,777,846,616,505,496,496,690,690,496,690,690,496,496,691,711,614,615,616,496,497,659,2370,136,137,138,139,140,141,959,1644,2455,2456,2457,2458,510,712,712,278,591,672,2459,117,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,2336,528,952,2460,102,103,291,292,324,253,254,419,2461,147,148,445,670,545,2462,352,600,172,382,601,602,603,603,602,603,602,603,602,603,602,603,602,692,445,149,591,150,446,592,592,592,447,592,592,447,636,435,102,103,104,135,136,137,138,139,140,141,1771,356,556,557,558,557,1348,557,557,558,622,445,445,429,149,2463,266,267,554,1921,1368,330,332,333,334,335,336,337,2464,383,556,654,557,558,557,558,655,180,181,233,241,2465,149,2466,2360,498,617,2467,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2468,1413,277,696,278,150,446,2469,149,150,2087,2088,485,2089,2129,271,2286,1921,403,211,2075,608,2470,650,2471,2472,369,2473,823,228,2379,774,23,532,2244,2474,2475,902,303,903,303,548,435,1076,726,758,1120,1121,68,69,237,743,744,188,189,190,745,1526,982,556,1348,557,558,557,557,557,557,2476,526,545,1188,1189,590,1769,429,149,591,150,446,447,447,636,69,142,1528,455,2126,528,571,2411,181,233,190,1195,1196,1197,2477,2478,632,54,55,2479,382,148,429,149,150,446,447,512,758,300,301,2480,950,951,570,571,237,238,184,185,186,241,185,186,240,188,189,190,1598,1599,345,509,172,180,181,233,190,191,192,193,2481,589,670,545,671,502,634,611,537,537,537,537,538,537,1422,2482,727,434,454,1239,549,1338,147,148,429,149,759,446,447,512,435,512,549,1093,44,45,1006,1368,130,1639,463,637,130,616,690,496,689,496,690,2247,2483,271,2484,549,1674,178,179,382,510,278,672,2485,1116,572,489,665,735,216,449,439,266,267,883,1276,2486,783,570,2153,1150,492,172,180,181,233,190,2487,2488,197,492,587,434,1094,23,586,216,449,439,669,179,147,597,556,558,1351,346,319,454,348,581,455,348,1318,519,520,521,522,523,44,2489,172,382,401,383,556,654,1836,269,270,271,272,69,1967,483,484,2438,2356,934,2490,2491,1573,731,1387,193,194,2492,702,580,703,146,147,510,1639,999,549,2147,2035,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1078,1079,1080,1081,713,1002,1286,602,442,416,244,1123,1124,1125,379,169,756,554,2493,758,231,967,1890,545,1188,2249,510,278,994,605,547,172,382,148,429,149,430,280,793,2494,383,402,302,303,305,303,305,303,304,303,305,303,788,426,2228,570,2495,589,670,545,2314,1074,1950,1268,1971,744,188,189,190,745,80,1381,2496,2497,2498,2499,2500,149,562,281,280,281,281,281,295,2501,401,356,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,1453,808,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,811,812,899,814,924,179,2502,23,1840,528,2503,1037,1031,2504,148,149,150,2087,2088,2343,2505,2506,229,1015,172,382,510,712,696,2136,520,2507,547,687,688,495,690,505,496,690,690,746,511,446,592,592,447,512,331,178,179,147,355,383,357,384,558,559,560,2201,2508,587,434,347,348,581,455,348,348,455,455,348,2509,383,556,1348,557,557,557,558,1482,756,554,270,270,2510,549,708,959,730,731,554,1814,1815,952,2331,2331,2511,403,820,145,146,147,401,383,556,746,777,846,495,1817,1222,237,743,744,188,189,241,185,186,240,2512,2513,780,692,909,146,231,232,311,181,233,239,2514,161,101,102,154,135,136,137,138,139,136,137,138,139,140,141,1771,1167,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,401,383,2515,547,172,382,510,573,574,469,2270,1499,1555,211,2516,1564,859,1565,2517,692,2518,495,689,690,496,691,711,322,1428,1526,296,2519,147,510,2520,197,145,777,846,495,689,690,691,782,203,204,175,176,177,169,352,776,146,147,518,519,990,1363,1696,938,939,1986,148,149,279,280,281,1222,2254,2254,2254,2254,2253,2521,2522,537,950,2186,950,951,1658,54,55,2040,2523,252,2524,808,811,812,899,814,815,816,1226,1182,454,455,348,455,1239,549,610,1106,172,147,518,384,558,559,385,746,844,938,939,211,2525,597,402,302,303,304,303,304,303,304,303,304,303,2526,665,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,601,602,2527,2134,2339,1955,180,181,233,240,2528,510,696,696,278,591,1243,782,514,570,2153,347,455,528,2529,2530,564,565,566,1544,2531,311,2532,549,800,1696,938,939,130,461,429,429,445,429,429,445,149,751,782,149,591,150,446,592,592,447,592,592,447,1444,810,809,810,809,1007,1031,333,410,418,23,390,391,494,2533,496,2172,373,300,301,302,303,304,303,788,549,1338,330,332,333,1907,532,514,570,2503,145,146,231,232,233,190,2534,1184,1185,2535,1268,1971,744,188,189,240,1174,744,188,189,240,1174,2536,2537,2538,376,2539,295,2540,608,147,148,149,2541,281,280,692,1598,839,513,514,515,2542,730,731,554,1815,1658,426,445,429,429,445,429,149,430,280,281,280,281,673,769,770,2543,1766,1767,1385,1925,401,383,526,545,1188,1189,1084,439,266,267,554,2544,467,467,467,467,467,467,467,291,1675,2545,1663,783,570,571,178,179,231,232,182,183,184,185,186,2546,510,696,697,545,1188,1189,237,238,184,185,186,239,185,186,240,188,189,2547,603,602,603,602,603,602,1350,355,356,357,384,558,559,560,1935,300,2345,302,303,305,303,304,303,305,303,305,2548,2549,657,1908,2369,498,617,561,1814,1815,952,2550,549,1338,556,654,557,557,557,558,557,558,557,557,558,684,278,591,150,446,447,636,403,696,697,545,2421,149,511,446,447,592,512,713,356,556,654,557,557,557,558,605,554,2551,271,2552,727,434,454,686,413,995,996,299,231,232,182,606,607,769,2105,127,128,129,130,103,104,135,136,137,138,139,140,141,680,149,430,280,281,280,281,281,281,280,281,280,281,280,793,145,146,346,319,347,581,348,348,348,348,455,348,348,455,455,348,2553,2224,2554,149,591,672,281,752,149,511,446,592,592,447,592,592,447,512,549,1338,666,667,725,439,266,267,554,1214,549,1338,545,1188,1189,445,445,149,150,446,447,790,461,445,429,429,445,445,445,462,999,435,1059,1361,1178,589,653,570,571,495,689,496,690,496,1619,231,232,233,190,986,1460,889,1988,1832,890,2555,452,579,580,345,172,346,319,320,193,194,2556,1331,2557,148,149,430,280,674,460,179,147,461,429,429,445,429,149,591,2558,1618,429,429,429,149,759,446,592,447,447,447,447,512,758,777,846,616,2559,442,924,179,390,391,494,616,496,690,976,655,429,149,591,150,446,592,447,447,592,512,549,1313,824,765,2315,2316,2317,523,44,45,1531,2560,1693,1693,1012,1013,1013,1013,1515,518,534,535,611,537,537,537,538,1759,69,402,302,303,2561,657,1908,779,561,148,149,511,446,447,512,549,2562,149,511,446,592,636,835,2563,496,497,2564,104,135,136,137,1287,139,140,141,680,180,181,233,190,1598,2360,498,1745,2177,2178,147,401,383,2244,2565,401,356,502,634,537,2566,1611,145,146,147,401,383,502,634,611,663,69,445,149,279,280,281,280,281,280,281,280,281,280,507,2567,839,429,429,429,149,150,446,447,447,447,636,69,447,447,592,592,636,549,610,237,743,744,188,189,190,2568,193,2569,1518,950,951,570,516,2570,329,216,449,439,669,179,346,319,454,456,455,455,348,455,686,331,2231,291,292,324,2571,356,534,535,611,538,1759,69,511,446,592,592,447,447,636,69,100,565,1978,23,1920,270,2240,1815,1658,2572,367,368,399,400,179,147,510,573,629,190,745,442,147,1663,697,527,355,356,2573,2574,538,2575,549,800,683,1487,777,846,616,2559,673,429,149,591,150,446,447,447,447,2576,756,883,554,555,921,967,1890,2577,745,80,1941,1770,146,147,148,149,591,150,446,592,592,592,447,592,592,512,549,1338,519,2578,769,770,2579,23,445,445,445,149,279,280,281,280,282,300,2345,302,303,304,303,304,303,304,303,304,303,304,303,2580,2101,179,300,301,2581,295,982,104,135,136,137,138,139,140,141,959,1317,2328,2329,950,951,570,516,2230,383,2037,258,761,260,261,836,837,262,263,264,265,266,267,268,270,271,1244,69,510,712,278,591,994,918,401,383,502,2198,2582,231,232,311,181,233,190,1863,1196,1197,1500,511,446,592,593,454,455,456,1215,69,1644,2455,2583,2584,1820,170,171,687,688,495,505,690,496,496,690,690,690,1619,429,149,591,672,280,281,746,680,545,742,1828,2585,653,570,1658,54,55,2586,2587,2588,1101,1565,2134,2339,2589,666,667,797,169,2590,2591,1101,1565,2592,1222,147,510,573,629,190,191,2585,844,938,939,130,370,433,434,454,528,632,54,55,2593,147,148,149,672,280,281,280,281,280,281,280,1211,1424,632,413,477,478,2594,2595,1323,2596,1645,2597,2598,193,194,1577,2599,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,1283,460,179,147,518,534,535,537,2057,1611,2206,2207,1074,1323,2600,333,1232,418,984,1243,280,281,280,281,281,1245,566,1544,333,410,1329,980,780,2601,563,148,445,653,570,2503,2602,2603,2604,23,149,1243,281,280,281,280,281,280,281,280,281,1350,777,846,495,689,690,1245,2605,182,183,184,185,186,241,1165,184,185,186,190,2606,2211,301,2480,950,951,570,1658,54,55,2084,1106,172,382,510,696,696,278,2607,445,149,591,150,2608,1562,1289,2256,2609,782,653,2610,461,445,149,672,280,281,280,281,2611,553,439,266,267,1387,193,2612,581,1215,403,2369,2613,442,641,764,765,2387,2614,445,670,545,2053,102,103,104,135,136,137,138,139,140,141,959,346,319,347,348,581,455,455,455,348,1318,756,268,1294,271,270,2615,229,909,146,147,510,712,696,278,2466,1599,1436,2616,549,1338,149,150,446,447,447,447,512,426,1254,1255,1256,1912,253,68,350,346,319,347,348,581,455,348,1215,69,759,446,592,592,447,447,447,512,69,1026,319,454,456,1215,549,2617,352,600,172,382,401,383,502,634,537,2046,435,383,534,1636,2618,2619,2073,495,752,154,135,136,137,138,139,136,137,138,139,1304,1305,2620,426,394,395,1594,396,432,2621,1188,2249,102,103,104,135,136,137,138,139,140,141,959,401,383,502,634,1242,637,2622,2297,2623,777,846,2073,495,690,496,691,692,2101,179,390,391,616,1083,714,591,150,446,447,636,549,1571,149,562,281,281,281,280,281,280,281,280,281,280,281,1718,353,146,231,232,233,190,910,2624,2478,570,1658,54,55,2625,2626,783,570,516,2627,2189,1832,2628,735,216,449,439,2629,382,355,383,534,535,2630,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,2631,390,391,495,2096,497,498,617,2589,401,383,402,302,303,305,303,304,303,305,303,305,303,304,303,304,303,788,426,149,279,280,281,280,281,281,752,510,712,278,150,2632,149,759,446,447,447,636,435,445,429,149,591,672,281,1222,429,149,759,446,447,447,2342,382,510,573,629,190,630,145,146,147,401,383,556,558,557,654,557,557,557,558,557,558,557,1350,632,54,55,2633,2041,1761,860,1222,816,1226,2634,724,492,172,382,148,149,591,1243,280,281,280,281,280,281,280,281,2018,2635,390,391,494,495,690,689,1758,455,768,528,952,2636,662,169,2379,774,23,162,163,164,165,594,595,596,169,229,909,146,346,319,454,1839,959,526,769,770,2637,735,489,665,735,216,1042,439,266,267,883,268,2638,2274,738,2639,2162,483,484,2640,207,208,388,936,2641,68,1368,2642,669,179,346,319,454,2336,528,571,597,556,654,557,557,557,557,557,557,558,557,558,557,1353,2643,2644,1792,149,759,446,592,447,1787,808,809,809,810,1458,1459,398,237,238,184,185,186,241,185,186,190,2645,2646,1599,147,510,573,629,190,191,192,193,194,2556,168,169,352,791,687,688,616,752,1015,172,180,181,233,190,992,1932,1045,1304,1305,1306,835,231,232,182,606,607,698,438,439,266,267,268,2241,1135,712,2647,697,545,1188,1199,2533,2648,1111,1171,148,445,2649,943,319,347,1215,713,346,319,454,768,528,516,2332,2332,2332,2550,403,253,68,664,608,445,445,149,279,280,281,280,281,280,281,605,2343,2505,2650,2533,496,2651,1350,104,135,136,137,138,139,140,141,959,352,2652,2653,184,185,186,190,1828,2654,352,353,146,147,148,854,574,910,2272,178,179,382,601,603,602,711,382,148,854,629,190,191,576,573,574,2655,2470,650,651,603,602,603,602,603,602,603,602,603,602,2656,532,533,384,1348,557,558,557,558,557,558,563,347,2311,2657,54,55,633,725,439,266,267,268,1214,403,770,2658,382,510,712,278,591,994,1222,1026,319,454,348,728,549,1338,266,267,268,270,1807,549,1338,150,446,512,835,810,809,809,809,809,811,812,899,814,2659,253,254,255,616,2660,496,2096,497,498,2661,390,391,495,2662,497,498,2419,443,2663,2069,644,222,223,645,646,647,648,649,650,2664,2665,492,172,382,148,429,149,591,1243,281,280,281,281,1036,145,146,346,319,347,728,69,1638,172,2666,429,429,149,279,280,281,1774,727,434,347,1239,549,1093,700,874,1086,333,410,2667,445,445,429,149,591,150,446,447,636,549,610,1304,2668,747,2669,429,149,1522,280,281,281,281,280,281,280,281,1245,737,738,2134,2215,390,391,494,2670,709,60,61,2671,2672,66,2673,66,67,254,984,460,179,1586,193,194,195,965,609,169,178,179,180,181,233,190,1643,987,2674,148,445,590,2675,170,1928,146,2676,960,180,2677,182,606,607,769,2678,54,55,633,518,534,535,611,537,537,1759,435,2679,2680,2681,2682,237,238,184,185,186,190,1931,2270,1499,2683,1159,1160,1436,2684,403,429,149,279,1178,149,672,280,281,280,281,280,673,356,502,634,538,611,1759,69,149,150,446,447,447,593,346,319,320,193,194,2556,2622,2297,860,1100,1565,739,740,1085,103,104,135,136,137,138,139,140,141,959,2685,2686,2687,1286,602,2527,2134,2453,2688,134,216,449,439,266,267,554,270,1294,271,1626,346,319,347,768,528,516,2332,2332,2332,2511,758,905,300,2689,1984,590,429,429,149,562,281,280,281,280,281,280,281,673,1159,1901,2690,355,383,2691,735,489,490,216,1042,439,266,267,268,270,726,549,2147,498,2692,480,2693,154,135,136,137,138,139,140,141,680,510,712,712,278,2694,149,279,280,281,281,655,1579,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1078,340,340,341,342,343,1081,426,726,69,148,445,462,999,69,300,301,358,2695,2696,1216,233,190,1967,483,484,485,2505,2697,1120,1121,254,419,231,967,1890,769,2678,54,2698,571,401,383,402,383,402,383,402,302,303,304,303,304,303,304,303,304,303,304,303,788,637,2157,2699,371,1505,616,497,498,617,618,545,2700,511,446,447,512,549,708,180,181,233,2701,642,434,454,528,570,952,2570,401,383,502,634,611,537,537,538,538,537,538,2702,592,447,447,447,447,512,69,1814,2703,959,613,614,615,616,496,497,659,660,355,383,526,769,2678,54,55,56,2693,769,770,2408,147,148,854,574,2704,576,730,731,268,732,1921,549,1313,2325,2087,2088,485,2622,2705,510,278,2466,2360,2268,2370,490,216,1042,439,440,859,860,1101,1101,1101,1101,1543,2268,974,390,391,495,1744,497,498,617,618,1822,403,402,302,303,304,303,304,303,304,303,304,303,304,303,304,303,788,549,1338,518,357,302,303,304,2706,680,178,179,382,401,2707,429,149,759,446,512,69,663,549,708,369,400,179,180,181,921,232,233,190,1554,2708,696,1706,2709,1317,188,2273,631,570,1658,54,55,2479,390,391,494,495,690,505,496,2710,510,712,278,511,446,2711,2232,1830,439,440,916,1690,507,670,545,671,429,149,759,446,447,592,2712,2713,2714,401,356,502,634,536,538,2715,502,634,611,538,538,537,537,1759,1455,352,600,172,382,401,383,502,634,538,538,2716,453,319,454,945,695,401,356,502,634,611,538,537,537,1759,1368,252,2717,2425,455,1840,528,2718,885,2719,439,266,267,1387,193,194,1072,370,371,1505,2720,369,400,179,382,510,696,2721,1549,193,194,2722,147,148,979,1663,1706,696,278,562,281,280,1178,1424,1084,439,2723,2724,1706,278,562,280,674,571,526,769,770,2396,54,55,633,2379,774,23,590,2725,554,271,2493,331,2108,860,1101,1100,1100,1101,605,355,383,519,2726,2727,1915,1915,2050,1915,2051,1915,1915,2728,1718,2729,496,2096,497,498,2730,237,238,184,185,186,239,185,186,240,188,189,190,2731,401,383,526,698,547,172,382,148,149,562,280,373,400,179,147,401,383,502,634,538,799,549,1922,402,383,556,1348,557,558,557,1351,445,149,150,446,447,1787,510,573,574,2732,1550,587,434,347,581,348,348,348,455,455,455,455,686,403,534,535,611,537,538,538,537,538,538,537,537,537,2733,607,545,2700,2734,346,319,347,348,581,348,348,455,455,1898,1254,1255,1256,1257,2735,401,356,502,634,538,611,537,538,538,537,538,2736,557,557,558,557,557,557,1222,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,811,812,899,814,1945,333,1232,418,2737,2551,270,2240,1815,516,2738,2739,369,400,179,180,181,921,232,233,187,2160,489,490,216,449,439,838,23,532,2740,300,301,302,303,548,549,610,134,216,1042,439,440,859,860,1101,1101,1101,1101,711,510,573,629,2741,653,2742,101,162,163,2085,157,216,449,439,266,267,554,1294,270,726,403,239,948,949,950,951,570,2743,526,769,770,2744,148,445,149,672,280,281,280,281,295,506,445,445,429,429,445,445,149,150,2745,401,356,1275,251,252,253,254,984,687,688,495,691,1281,1744,497,659,2254,2253,2254,2253,2399,1133,537,2046,549,2746,2747,1031,333,1232,335,336,337,44,45,46,23,1411,2538,2748,2689,1277,346,476,2195,2196,2438,2749,148,445,653,570,2750,725,439,450,1200,1831,1832,2751,346,319,347,455,528,570,516,2373,182,606,607,2752,429,429,149,150,446,447,447,636,69,2753,191,192,331,460,179,390,391,494,495,1083,518,534,535,611,537,537,537,537,537,537,537,2733,671,477,2236,2754,2755,1260,44,45,1531,2756,240,188,189,241,1165,1520,2440,2388,2757,456,348,2758,995,2759,180,606,2478,570,952,529,1644,1645,2760,2761,2762,429,445,445,149,150,446,447,1731,445,149,150,446,447,447,447,790,2763,2360,498,617,2764,2765,2766,2767,2768,2270,1499,1555,2769,346,319,347,455,686,2770,510,696,696,2136,1793,1794,2771,245,2772,2325,2087,2088,485,2773,586,216,449,439,669,179,390,391,494,782,149,562,281,280,563,2590,1100,1565,2774,2775,995,2776,361,619,620,169,352,621,146,231,232,182,181,182,183,1561,1164,102,103,104,135,136,137,138,139,140,141,959,511,446,447,447,592,2777,149,591,751,692,1967,483,484,485,2505,2297,445,445,429,149,591,150,446,447,447,512,403,445,445,149,150,2778,536,537,1759,549,610,2236,2779,23,222,223,224,644,222,223,645,646,647,1065,1265,303,1519,303,305,303,305,303,304,303,305,303,305,303,788,403,514,570,952,529,346,319,347,2313,1112,2780,445,445,445,445,429,2781,2782,1501,455,2783,664,2132,2133,2784,2785,460,179,147,597,502,634,538,1394,330,1073,563,703,146,147,1286,603,602,752,591,150,446,447,447,636,549,800,495,496,497,498,1745,480,2786,207,208,388,2269,23,636,758,237,743,744,188,189,187,188,189,239,185,186,190,1549,193,2787,237,238,184,185,186,190,575,192,193,194,1072,502,634,538,611,537,538,663,549,708,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2788,714,2348,403,429,149,1522,280,281,281,280,1510,611,537,538,538,537,537,537,2733,1163,232,233,190,2434,193,194,2789,455,1318,300,2345,2480,950,951,570,571,355,383,526,2790,1026,319,347,456,348,455,686,2791,727,434,454,581,455,455,455,348,348,455,455,1215,549,708,2792,422,2793,172,390,391,494,2073,495,690,496,690,690,496,746,756,554,1294,271,271,270,270,272,549,2147,2794,2795,1431,1431,2796,1872,959,756,554,270,1294,270,272,403,252,253,68,69,545,671,527,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2797,2798,1501,2799,291,297,436,1538,1568,147,401,356,556,692,460,179,300,2800,2801,2384,2669,170,171,587,434,454,1109,147,148,429,429,429,149,430,280,281,281,281,280,281,563,2802,536,538,1759,426,686,549,800,601,602,2004,2803,147,2804,429,429,149,591,150,446,447,447,447,636,435,1713,2805,2806,23,390,391,494,495,505,496,496,496,691,782,545,2421,382,401,383,2807,1424,300,301,2480,950,951,570,571,178,179,147,355,383,519,990,2808,231,232,233,190,1549,193,194,195,2809,355,356,384,654,557,557,2201,2260,2810,2143,193,194,1577,2811,1299,401,356,502,634,2812,1611,182,181,233,190,910,192,193,2144,2145,591,672,280,1245,546,519,520,1597,1762,563,1546,1546,340,340,340,340,340,2813,1413,1526,296,180,181,182,183,184,185,186,190,1828,192,2335,1084,439,440,916,2814,694,204,594,595,596,316,317,703,146,147,401,383,874,613,685,434,347,455,528,570,2718,355,383,534,535,537,2815,727,434,347,1779,2799,231,232,233,241,1165,2816,2817,1109,401,383,502,634,536,538,538,2733,178,179,382,510,696,2136,2818,2819,2820,496,505,496,496,496,977,1159,1160,2821,2822,2823,616,497,498,1745,2824,2825,497,2826,743,744,188,189,241,185,186,240,188,189,190,2827,193,2828,698,692,178,179,382,355,356,357,1396,664,330,332,333,334,335,336,337,2829,589,670,545,1188,1846,460,179,147,461,445,429,149,591,150,446,447,592,636,549,2830,401,356,556,654,557,557,558,557,558,557,557,557,558,557,558,557,559,1593,1188,2249,556,654,557,557,557,558,557,1351,1288,1289,1290,1291,523,44,45,524,918,237,238,184,185,186,240,188,189,190,2831,2832,687,688,616,691,692,276,179,346,319,347,455,1149,549,2833,2325,2087,2088,485,2834,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2060,270,1814,2835,2836,383,556,1348,373,352,776,146,346,319,347,945,582,1169,439,266,267,268,2251,549,1338,1573,731,268,269,726,435,429,149,591,150,446,447,592,592,447,447,636,403,401,383,402,502,634,537,799,69,355,383,534,535,536,2837,149,511,446,447,447,447,447,1731,1169,439,266,267,2393,23,300,2345,302,303,305,303,304,303,2838,277,712,278,511,446,512,835,1744,497,498,499,515,1658,54,2839,2145,445,445,445,149,150,446,447,592,592,447,447,2063,545,671,666,667,668,439,838,23,440,916,860,2128,295,506,472,157,206,488,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1968,154,105,1603,507,687,688,495,496,2559,282,149,591,150,446,592,447,447,592,592,512,549,708,712,278,591,994,655,654,557,557,558,557,557,557,558,557,558,1351,2840,611,537,537,1759,403,581,455,686,549,760,2503,2552,445,149,150,446,447,447,447,447,636,1241,276,179,390,391,494,616,505,690,2247,527,672,281,281,752,149,150,446,447,636,435,258,761,260,261,836,837,262,263,264,265,266,267,268,270,271,1672,549,1922,2446,455,528,571,2841,1245,1169,439,266,267,554,726,835,222,223,645,646,647,648,649,2012,2842,1112,2843,2844,2845,69,2331,2331,2332,2332,2332,2333,696,1664,375,2846,2847,2848,2849,1522,281,281,280,281,281,281,280,281,280,281,561,1294,272,69,613,614,615,495,496,505,496,496,496,496,1111,238,184,185,186,187,188,189,190,2850,1642,542,1693,1693,1693,543,1354,1334,355,383,534,2851,1651,172,382,401,356,519,1128,2852,304,303,304,303,304,303,788,549,1338,149,591,150,446,447,592,636,549,760,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2853,1413,348,1822,2156,104,135,136,137,138,139,140,141,142,102,154,135,136,137,138,139,136,137,138,139,1304,1305,1306,2854,500,727,434,320,193,194,2556,2855,2856,2411,181,233,190,745,1526,982,445,445,149,562,281,280,1510,2497,2857,2858,1585,439,266,267,554,271,1294,271,271,270,270,270,270,272,69,355,383,384,557,654,557,557,557,557,557,557,558,557,558,557,558,557,558,557,559,2859,666,667,730,731,268,2860,549,1338,2861,2862,445,445,445,462,463,69,355,356,534,535,538,537,2355,331,1885,514,570,571,278,150,446,447,592,512,549,2863,369,400,179,180,181,233,190,745,2012,417,333,410,418,23,1706,2864,951,1658,54,55,2040,2865,504,2866,586,216,449,439,669,179,180,181,233,190,986,1044,1846,2867,2868,254,1032,776,777,778,779,780,780,2869,1846,149,150,446,447,447,592,512,2854,149,591,1243,281,280,386,1632,333,410,335,2870,1612,658,80,2433,429,445,445,445,149,994,295,2871,429,149,430,281,281,280,281,281,386,187,188,189,2872,401,383,502,634,611,538,1759,758,592,592,1728,375,376,377,990,1804,1363,2336,528,571,1721,68,69,532,526,545,1188,1199,145,146,147,401,356,556,558,557,558,559,560,1935,2028,2873,382,148,445,149,150,446,2874,1585,439,266,267,554,271,1294,271,271,270,270,271,2875,445,445,149,150,446,447,447,2712,1015,172,382,148,149,150,1811,1304,2876,172,346,319,1821,347,348,1215,69,2763,2360,659,974,268,269,271,270,271,2638,147,401,356,2877,357,302,303,305,303,304,2706,366,590,1769,2700,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,669,179,390,391,494,495,690,496,1817,1237,777,846,616,2660,496,2662,2878,1179,2879,179,2880,180,181,921,232,233,190,245,1409,987,2881,921,967,2882,2883,1171,429,445,429,429,445,2884,687,980,779,781,781,780,780,780,780,780,2885,231,232,311,181,233,190,234,848,1045,148,854,629,190,986,2886,2887,2888,984,231,232,921,1966,69,305,303,305,303,304,303,304,303,304,303,304,303,548,758,2326,1835,558,557,558,557,557,655,2343,2089,54,2839,2145,769,1612,148,429,429,445,445,445,445,149,2889,429,429,445,149,759,446,1444,2890,2824,2891,496,2662,497,2564,2892,300,2345,302,303,304,631,515,1658,54,2893,2466,2360,659,2370,545,2894,1876,422,1023,1877,1514,1693,1693,2895,254,419,561,429,429,445,149,150,446,592,2896,514,515,516,2570,2897,1274,2898,232,182,181,1163,1641,149,591,150,446,592,592,447,592,512,549,1313,921,232,233,190,745,80,1381,1382,2387,2388,2899,2900,1133,611,538,538,537,538,538,1759,403,511,446,447,592,592,1772,664,2446,455,1840,528,952,529,178,179,180,181,233,190,2606,2211,233,190,2325,2087,2088,485,486,147,401,383,402,383,502,634,663,69,510,696,783,570,1658,54,55,56,2693,638,169,178,179,147,401,356,556,1593,429,445,445,2901,669,179,346,319,347,456,455,455,348,455,1109,2180,2179,2385,1026,319,347,1132,403,2902,1169,439,838,23,390,391,494,616,690,505,690,690,690,690,1461,1990,2903,333,1232,2904,400,179,382,510,573,2905,530,1575,1265,303,903,303,788,350,266,267,554,1294,270,270,271,271,272,426,485,2622,2749,538,537,1759,69,680,1304,1305,1306,2906,237,238,184,185,186,190,575,2907,513,2515,172,382,148,429,429,445,149,759,446,512,549,610,346,319,347,456,348,686,435,259,260,2792,2908,1598,2360,659,660,687,688,495,496,505,690,690,496,496,691,622,591,150,446,512,403,2909,918,1973,2662,497,2268,2370,1099,859,1101,1690,1101,1100,2128,605,1549,193,194,195,1853,2910,150,2778,147,148,149,150,446,512,549,1338,2911,147,513,2912,1314,1544,333,334,335,336,337,1233,2913,346,2914,237,238,184,185,186,2546,1522,281,280,281,280,281,280,281,280,281,373,2915,1074,1323,180,606,607,2475,2700,2916,2128,605,251,332,333,334,335,2870,2563,497,498,617,2824,2917,698,510,696,278,150,446,592,447,1204,401,443,463,1216,653,516,2331,2333,2483,271,2286,2918,2919,190,2920,670,2149,239,1165,2921,549,1338,460,179,147,597,556,654,557,558,557,558,557,558,557,558,2201,2202,657,658,1526,2922,460,179,147,461,445,149,672,280,281,280,561,205,101,624,625,928,565,2923,23,2924,376,377,1128,1129,776,146,147,518,519,990,1408,1759,1241,2196,485,2197,511,446,512,758,445,429,149,1522,280,281,281,281,280,281,280,281,280,1281,348,1779,2553,2925,355,356,519,990,2926,281,2441,2927,1281,778,2928,780,2369,2613,2929,1423,2930,2931,2162,483,484,485,486,769,770,2657,1241,233,190,2932,645,646,647,1065,1265,303,1519,303,305,303,305,303,304,303,304,303,788,549,800,237,238,184,185,186,241,185,186,239,185,186,190,191,2933,300,2345,302,303,304,631,570,2743,454,581,1215,758,445,149,759,446,592,447,592,592,447,1787,727,434,347,456,348,686,713,149,150,2087,2088,2343,2505,2697,355,356,384,654,557,557,2201,2260,820,2934,23,402,302,303,305,303,304,303,305,303,305,1164,401,356,556,654,557,557,558,557,558,557,557,557,558,557,918,2935,1822,1241,2533,496,1744,497,498,1745,2936,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2937,1413,147,1663,697,545,671,666,667,1564,916,1565,2774,1565,739,2565,291,292,324,253,254,419,382,532,526,545,2700,147,148,429,149,759,446,447,447,447,636,637,747,2180,2179,2179,2179,2180,2179,2180,2179,2180,2179,2180,2179,2180,2205,536,537,538,2938,1294,270,270,270,270,270,2007,2268,2253,2253,2254,2253,2253,2254,2254,2255,295,982,698,2939,47,149,562,280,281,281,281,280,281,280,281,280,782,149,759,446,592,447,592,636,549,760,382,597,556,558,557,2940,513,526,769,2605,727,434,1094,47,180,181,1163,232,233,190,2768,470,471,714,2941,2942,254,724,178,934,2490,1691,532,533,874,553,439,266,1366,254,984,251,1073,640,518,534,535,611,537,537,537,537,663,549,1338,2943,346,319,454,455,2944,2945,54,55,2633,2946,417,2947,592,592,447,447,447,593,998,999,835,2948,515,952,2406,518,384,654,557,558,557,558,557,561,538,538,538,538,538,537,537,537,2349,769,770,2396,54,55,2040,2949,178,179,180,181,233,239,1165,2921,549,2863,2228,515,2495,1026,319,454,1027,549,708,429,445,429,149,1522,280,281,280,1211,608,2393,23,581,455,528,1658,2950,2951,2952,401,383,2953,587,434,1821,347,582,278,2466,2360,498,617,2954,689,496,690,690,1330,2955,355,383,384,654,557,558,1718,764,765,2387,2432,2317,523,44,45,822,23,548,713,607,545,1188,1199,134,216,1042,439,838,2956,2957,1220,602,2958,570,516,2257,345,172,346,319,347,348,1502,2470,2002,602,673,291,292,293,1719,233,190,2959,140,141,959,330,332,333,334,335,2267,178,179,147,148,445,149,591,2960,429,429,445,149,759,446,592,447,447,790,429,429,149,562,281,280,281,281,281,280,281,280,673,148,429,445,445,1704,990,1705,700,502,634,611,538,538,537,2961,2962,1406,558,557,673,149,591,150,446,447,447,636,549,1571,490,216,449,439,669,179,390,391,494,495,690,1083,1356,2963,2964,2965,2966,1490,23,1995,2967,1121,68,403,528,784,370,433,434,454,528,570,952,2627,641,656,642,434,347,528,570,516,2257,545,1188,2249,382,148,149,591,150,446,447,636,403,2505,2968,671,345,509,172,382,510,573,629,190,191,1285,1924,2133,2784,2969,148,552,233,190,1863,1196,1197,2970,2971,502,634,611,538,538,538,537,538,538,537,663,549,2972,2879,934,2490,2207,697,608,383,534,1636,2582,402,302,303,305,303,305,303,305,303,305,303,304,303,304,303,548,426,454,455,581,455,1215,2973,2544,680,1188,2249,171,687,980,781,780,2423,191,802,80,1829,743,744,188,189,241,185,186,240,188,189,190,2974,445,445,149,994,918,658,495,497,498,617,480,2693,777,778,779,282,445,429,149,591,150,446,447,512,403,2700,537,663,350,557,1348,557,558,557,558,1281,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1694,1924,1384,1386,561,355,383,534,535,2185,1492,2812,537,950,2186,1138,758,467,467,104,135,136,137,138,139,140,141,680,148,149,150,2087,2088,485,2505,2749,2763,386,906,808,1007,2975,819,2976,820,2977,333,410,335,336,337,44,45,1006,549,1028,2387,2388,2978,2979,2980,495,689,690,496,691,692,429,429,445,445,445,445,445,149,150,2632,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2981,770,2657,54,2839,2145,510,696,1343,305,303,305,303,305,303,305,303,305,303,304,303,304,1164,2982,686,713,375,376,1627,1331,1332,1331,521,522,523,44,45,1545,1317,188,2273,1670,145,146,147,148,445,149,150,446,447,512,549,1338,513,526,608,1269,184,185,186,240,1174,744,188,189,2983,211,1736,278,430,280,281,1513,2984,2985,495,2559,507,819,820,587,434,347,455,944,758,777,846,495,505,496,496,496,1222,556,654,557,557,558,557,558,557,1482,1931,2270,1499,2986,149,759,446,592,447,592,592,447,2987,370,433,434,347,455,2146,413,2988,2989,1152,1551,398,390,391,494,616,496,497,498,2419,148,445,670,769,770,2990,1863,1196,1197,1555,1002,2359,2525,150,446,2991,671,526,769,770,2992,237,238,184,185,186,190,2768,1932,1199,562,281,281,281,281,280,281,280,281,280,605,2993,2994,1379,1380,1081,1241,443,2995,231,1560,2536,2996,149,759,446,592,447,447,447,447,512,426,810,809,809,809,1489,774,23,2997,1525,2049,1915,1915,2998,1915,507,2999,3000,146,231,232,233,190,910,3001,178,179,147,355,356,357,302,303,548,69,390,391,494,616,690,496,3002,346,319,454,348,581,455,455,455,686,331,3003,3004,1348,1353,149,759,446,592,592,447,592,592,790,3005,3006,600,1288,765,1596,1909,426,270,271,2615,2185,3007,3008,468,2207,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1701,1691,687,688,495,976,442,216,449,439,266,267,1387,193,194,3009,492,172,382,148,854,574,2534,1184,1185,3010,909,146,231,232,233,3011,382,1286,2004,687,688,616,3012,402,302,303,305,303,788,758,355,383,384,654,557,558,559,1593,1903,1904,1905,23,356,402,1718,240,2328,2329,1138,549,800,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1956,703,146,147,510,573,629,190,1617,3013,281,280,281,280,281,280,281,1510,3014,469,2270,1499,1555,211,1736,382,148,854,629,190,191,192,193,2787,510,278,759,446,592,512,549,1922,511,446,592,592,447,592,592,2306,511,446,447,512,69,231,232,233,190,191,1415,47,187,188,189,240,188,189,190,3015,382,510,278,562,280,281,280,281,793,586,3016,1632,333,410,418,1032,510,696,696,2136,990,3017,1262,556,654,1351,136,137,138,139,1304,1305,3018,3019,1182,320,193,194,1577,3020,445,445,429,149,511,446,447,512,549,800,190,2487,3021,745,80,1941,2599,1638,1288,3022,1582,999,426,743,744,188,189,187,188,189,239,185,186,190,3023,1409,987,3024,3025,429,3026,2244,2339,1178,3027,383,502,634,537,611,538,1759,435,149,759,446,592,592,447,447,592,592,636,69,626,627,628,146,147,510,573,629,190,191,2654,980,781,779,780,780,780,780,780,1751,782,2331,2331,2332,2331,2331,2332,2331,2902,454,455,348,1132,549,1338,401,383,519,3028,295,2540,300,2345,302,303,304,631,570,516,2362,149,1522,280,281,280,281,280,1774,571,3029,767,1100,1994,300,301,2480,950,951,570,571,1084,439,266,267,268,269,270,1488,375,376,377,990,3030,769,770,3031,445,445,445,149,150,3032,279,281,281,280,281,281,281,280,281,280,673,375,3033,902,1164,237,238,184,185,186,190,1931,470,471,375,376,377,990,1363,2254,2253,2253,655,140,307,308,3034,587,434,347,2146,637,685,434,320,193,194,195,1897,455,2126,528,571,1107,299,103,104,135,136,137,138,139,140,141,959,147,355,356,356,519,520,3035,3036,1692,216,542,1012,1039,1764,1077,340,2813,1413,3037,3038,769,770,2657,835,492,172,180,181,233,240,1174,3039,426,147,510,573,629,190,1598,1642,1169,439,266,267,554,270,270,2510,549,1571,3040,1241,271,271,270,271,271,270,270,1322,653,570,952,529,992,2270,1499,1555,1487,429,3041,322,1428,1429,3042,295,2540,346,319,1528,1822,331,240,188,189,240,1174,744,188,189,2983,103,104,135,136,137,138,139,140,141,959,401,383,502,634,538,537,537,1395,713,492,172,382,3043,3044,266,267,554,3045,510,712,278,591,150,446,1812,148,149,150,1811,783,570,952,529,2343,486,382,401,383,519,1793,1794,608,777,846,616,505,690,496,2710,573,574,745,2764,2075,1338,3046,2369,498,1745,480,2786,131,3047,346,476,2195,2196,485,2622,3048,638,169,3049,999,435,764,765,3050,605,401,383,556,654,557,558,557,558,557,557,557,558,557,558,557,558,673,237,743,744,188,189,239,185,186,241,2056,545,1188,1846,601,602,603,602,603,3051,1692,216,804,3052,545,1188,1189,3038,1099,859,1101,2591,3053,355,356,384,1348,557,1351,147,355,443,463,69,263,264,1595,642,434,320,193,194,2722,266,267,554,270,269,1626,1663,1706,696,712,712,278,591,751,673,3054,231,967,1890,608,769,770,3055,921,967,2882,3056,382,510,696,278,150,446,447,3057,1644,1645,2597,3058,172,390,391,3059,149,1243,281,282,790,266,1041,68,2854,180,181,921,232,233,190,1643,2886,3060,149,1243,281,280,442,429,149,430,280,281,280,746,3061,3062,558,557,558,1482,3063,355,356,534,535,538,536,3064,1026,319,454,581,348,348,348,348,455,348,348,455,455,686,403,3065,1821,454,3066,291,292,324,253,68,69,2462,584,585,586,644,222,223,645,646,647,1065,902,303,3067,240,2328,2329,950,951,515,571,148,445,445,445,445,149,150,446,447,636,549,708,149,591,150,446,592,592,592,447,447,447,2991,1562,1289,1289,1855,1080,1081,403,347,768,528,952,2331,2331,2332,529,608,149,150,446,447,592,592,447,636,1368,149,430,280,746,867,3068,3069,3070,3071,3072,445,149,2558,2142,429,429,149,759,446,447,447,447,636,637,2591,1101,1565,3073,295,982,3074,69,233,190,745,80,1381,3075,510,696,697,769,770,3076,1687,288,203,204,175,176,177,169,375,1462,1463,1683,3077,1188,1846,3078,537,538,1395,435,737,738,2784,2277,2785,105,2031,2424,549,1093,356,534,535,611,538,1759,713,149,591,150,446,447,592,512,549,1338,1514,1693,1693,1693,1693,1693,1693,543,2451,820,402,302,303,305,303,305,303,304,303,304,303,304,303,3079,277,712,712,278,759,446,512,549,760,686,549,1571,2274,738,2784,2785,271,271,270,3080,502,634,611,538,537,537,538,1759,69,949,950,951,570,1658,54,55,2040,2397,2126,528,571,104,135,1493,3081,725,439,266,267,1276,1984,1099,859,3082,178,179,382,401,383,556,654,557,558,557,558,557,558,295,1911,1074,366,1026,319,347,348,455,348,1149,403,390,391,494,495,505,496,496,496,496,690,1330,515,952,2362,461,445,149,150,446,592,512,69,538,538,1759,549,1338,1519,303,788,713,1304,1305,3083,401,383,402,383,502,634,537,2575,403,445,445,429,429,445,445,3084,3085,510,573,574,3086,149,1243,281,280,281,281,281,280,281,746,2452,808,840,810,840,840,809,809,809,809,809,840,809,1007,1031,333,410,418,23,3087,1721,254,255,3088,3089,390,391,494,495,496,497,3090,3091,3092,937,938,939,130,460,179,147,518,519,520,1559,752,1713,3093,254,1032,1288,1289,765,1289,1290,1291,523,44,45,822,1402,3094,725,439,266,267,883,554,2007,346,319,320,193,194,195,2095,511,446,636,549,610,429,445,445,149,279,280,281,918,3095,545,1188,1189,148,149,1522,280,3096,224,216,1042,439,266,267,554,1294,270,270,270,726,549,1338,445,445,149,562,280,640,3097,605,865,549,3098,567,568,3099,765,3100,211,3101,361,619,620,169,352,621,146,147,355,383,383,519,990,1408,356,356,556,654,557,557,557,557,558,557,557,557,558,557,558,557,558,782,347,528,570,516,2257,608,445,445,149,279,280,281,280,373,355,383,384,385,563,278,150,2087,2088,2343,2505,3102,1317,2328,2329,950,951,570,516,2460,401,356,556,1482,454,2163,3103,3104,383,556,654,557,558,557,558,752,3105,3106,463,664,1528,3107,697,545,2053,231,232,233,190,2763,1642,3029,149,591,150,446,447,592,592,447,636,426,150,446,592,592,447,447,636,69,2657,54,55,2040,2090,429,149,1243,281,280,281,280,507,2622,2297,3029,149,562,281,280,281,281,281,280,746,447,447,447,636,549,1093,1744,497,498,617,3108,402,1396,435,2195,2196,485,2505,3048,240,188,189,240,188,189,239,1165,184,185,186,239,1165,1561,1164,320,193,194,195,196,285,286,104,135,136,137,138,3109,147,401,383,556,1348,557,558,557,558,442,148,429,149,591,672,281,281,373,3110,3111,148,429,445,445,445,445,429,3112,1193,1744,497,659,2254,2253,3113,455,528,515,2495,2518,240,188,189,240,188,189,190,3114,347,455,528,570,3115,502,634,1472,426,768,528,571,1675,1740,3116,1752,148,854,629,190,191,2624,135,136,137,138,139,140,141,680,1099,859,1101,1101,860,1100,1100,2128,782,445,429,1704,1793,1808,534,535,1242,403,149,150,446,447,512,69,502,634,538,1242,549,1093,1073,295,1250,390,391,494,495,690,505,496,690,691,782,454,348,3117,549,3118,1199,2345,2480,950,951,570,1658,54,3119,558,557,558,557,558,692,570,516,2570,1101,1565,2517,1565,2134,2339,3120,367,368,399,400,179,382,3121,355,383,384,558,557,557,654,373,1059,1361,1752,382,401,356,556,1348,557,557,558,557,558,1281,149,591,672,281,281,280,281,280,281,977,390,391,494,495,505,1403,689,690,690,496,1330,3122,3123,453,319,347,1109,445,149,150,3032,870,178,179,147,355,356,384,558,373,545,714,490,216,449,439,669,179,390,391,494,616,689,1083,149,759,446,592,1728,194,195,1897,455,1529,178,179,382,355,356,357,3124,545,1188,3125,1887,859,2441,401,356,502,634,536,3064,777,846,495,690,2559,282,150,446,447,447,447,512,1368,240,2328,2329,950,951,632,54,55,1238,581,348,686,549,1922,347,581,348,348,348,455,348,348,455,455,1109,2169,3126,938,3127,538,611,537,3128,150,446,447,447,592,592,447,447,636,69,417,333,334,335,336,337,44,45,3129,356,357,386,231,232,921,1560,744,188,189,190,3130,2254,2254,2254,2253,2253,2254,2254,2254,660,538,950,2187,3131,616,2172,497,498,617,480,3132,764,765,2387,2432,2317,523,44,45,1531,80,1941,3133,670,545,742,332,333,410,418,1032,2692,3134,2421,510,696,696,696,278,759,1054,1658,54,2139,3135,3136,3137,1094,23,696,697,2577,241,1165,184,185,186,190,3138,1912,253,1122,697,545,3139,515,952,2257,429,149,430,280,281,280,281,280,281,280,281,280,673,1846,1322,988,3140,1476,382,401,383,2037,783,570,2503,485,3141,148,445,653,570,3142,1268,1269,184,185,186,241,1165,3143,653,516,2331,2550,331,455,1149,1455,443,463,69,190,469,2270,1499,3144,3145,539,149,279,280,281,280,281,280,281,280,281,280,782,482,483,484,485,2197,571,548,549,2147,616,497,659,660,382,355,383,383,534,2851,960,2405,1492,433,434,347,2313,1169,439,266,267,268,271,1214,713,429,429,445,445,149,2248,279,280,281,898,3146,1740,3147,270,270,270,1626,3148,3149,148,429,429,445,445,149,150,446,447,636,69,149,672,898,3150,3151,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,3152,46,23,687,688,495,689,496,690,496,1330,150,446,447,447,447,3153,1283,1026,319,454,728,549,610,1294,272,549,760,609,1084,439,266,267,554,1214,549,2863,526,545,3154,587,434,347,348,455,455,944,403,651,603,602,603,602,603,602,603,602,603,602,2656,429,429,429,429,149,511,446,447,592,592,3155,2478,570,3142,980,780,780,3156,149,1522,280,281,281,281,280,281,280,281,1222,2503,2623,1288,3157,571,742,3091,3158,1120,1121,68,350,3159,748,1920,270,2286,1921,69,178,179,180,181,311,834,69,401,356,356,556,558,557,558,559,385,918,382,510,573,574,2534,1184,1185,3160,536,538,1759,549,2147,590,3161,442,150,446,447,447,636,350,1675,3162,193,194,195,3163,671,952,3164,445,445,445,445,429,149,511,446,512,549,1571,1188,1199,1178,455,1215,549,1338,149,150,446,447,447,447,3165,840,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,924,1120,1121,68,758,2336,528,571,2111,2112,1915,3166,1752,482,483,484,2326,316,317,703,146,147,1286,602,1275,1730,426,429,429,445,429,149,759,446,447,447,636,713,1112,2843,3167,1845,549,1922,355,356,384,558,2201,2202,690,505,690,690,496,690,1222,445,429,149,759,446,447,592,3168,700,874,2803,390,391,494,616,497,3169,570,952,2257,2064,2065,2066,1846,430,655,382,355,443,999,549,2099,2096,497,498,1745,2948,3170,333,410,3171,2379,1490,23,727,434,347,728,403,134,216,1042,439,266,267,554,270,2510,549,1313,811,812,899,814,815,841,2002,602,603,603,602,2656,601,603,603,603,602,603,602,442,670,545,2421,3172,355,383,357,383,357,383,534,535,2046,435,2503,777,846,495,689,977,2882,2528,241,185,186,239,185,186,240,1174,744,188,189,241,1165,3173,149,591,150,446,636,549,1338,1835,557,557,558,557,558,557,557,295,506,773,774,23,3174,537,537,538,538,663,426,455,528,571,140,307,3175,1368,1171,178,179,382,401,383,1976,1804,1025,148,445,445,445,501,355,383,526,545,2462,804,544,239,185,186,3176,465,1872,859,1100,1101,860,1101,1101,1543,346,319,347,581,348,455,1318,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3177,3154,669,179,346,319,347,455,581,348,348,455,455,686,549,1338,558,1635,3178,549,610,502,634,2575,713,2262,207,208,388,3179,333,410,335,411,3180,840,1949,1536,1921,549,1313,442,367,368,369,370,433,434,347,455,1284,477,478,785,3181,725,439,838,23,3182,401,383,502,634,611,537,537,537,537,3183,149,430,1774,3184,545,671,2303,2304,2305,447,592,592,447,592,512,549,1571,455,686,549,1338,769,770,2078,149,279,280,281,281,281,280,281,280,1245,305,303,305,303,305,303,304,303,304,303,305,303,305,303,306,180,181,921,232,182,3185,2325,2087,2088,485,486,1564,859,1565,3186,1222,149,1522,281,280,281,280,281,1774,716,717,722,403,348,3074,426,130,247,3187,722,758,909,146,147,355,383,534,535,611,1759,637,375,2846,3188,3189,193,194,3190,700,556,654,557,557,557,558,557,558,557,558,557,558,557,558,711,952,2257,384,1348,557,1351,844,938,939,211,3191,485,2505,2749,2274,738,2134,3192,727,434,454,581,455,455,348,348,455,348,348,455,1215,1241,680,1188,2249,2713,445,149,150,446,447,447,447,2342,3193,190,2434,193,194,3194,545,671,346,476,477,478,785,3195,1014,547,172,180,181,233,241,1165,2816,3196,382,355,383,1976,1363,311,606,957,549,1313,239,185,186,240,188,189,190,3197,1044,1846,536,537,537,538,663,3198,478,785,3199,3200,759,446,592,447,592,3201,608,671,759,446,592,447,592,3202,3203,992,3204,1663,697,698,180,606,607,769,770,3205,3206,2652,3207,510,712,3208,410,335,336,337,44,45,524,295,3209,445,429,3210,147,148,429,149,430,280,281,280,281,280,561,382,277,2136,3211,147,518,357,302,1164,556,654,557,557,557,558,557,558,557,558,1281,1127,216,449,439,669,179,346,319,454,695,756,2483,2615,149,430,281,280,281,280,281,281,280,561,3212,3213,622,169,178,179,147,148,462,463,549,1338,641,764,765,2315,3214,3215,3216,1268,1971,744,3056,3217,1350,318,319,347,455,581,348,348,455,455,686,549,3218,266,267,554,1294,271,271,270,271,1322,3219,3220,240,188,189,190,1643,2886,471,581,455,455,455,455,686,403,538,538,538,3221,239,948,949,950,951,515,1658,54,2839,2145,292,3222,601,602,603,602,603,602,603,602,603,603,603,602,603,602,603,2471,3223,445,149,1243,281,793,1026,319,347,348,581,455,686,403,3224,903,303,305,303,548,435,429,429,445,429,149,591,672,280,752,348,1822,403,2563,496,2096,497,3225,808,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,3228,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,1007,1031,333,410,418,23,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,810,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1489,774,23,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,1007,1031,333,410,418,973,810,840,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3229,3230,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,1007,1031,333,1232,335,336,337,2829,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,810,809,809,809,809,3231,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3226,2724,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,3231,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1249,1222,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,809,809,809,3226,2724,1579,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1078,340,340,340,340,1079,1944,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1546,3232,1078,1078,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,3233,808,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,1007,1008,1009,47,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,809,3234,810,840,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,809,1007,1031,333,410,418,3235,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,809,809,1007,1031,333,1232,335,336,337,44,45,46,23,810,809,809,809,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,1007,1031,333,410,418,23,826,3236,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,3237,1078,1078,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,1274,808,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,809,809,809,3238,3239,3240,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1078,340,340,340,340,340,340,1079,3241,104,135,136,137,1287,139,140,141,3242,114,119,120,121,367,368,369,400,179,231,232,233,241,948,949,950,3243,109,110,99,111,112,99,794,795,707,99,111,112,99,201,202,1899,1900,99,111,112,99,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,1644,3244,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,1037,1031,333,1232,335,336,337,44,45,1398,54,2893,161,328,329,101,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,361,619,620,169,352,621,146,231,232,311,181,233,190,191,802,3245,794,795,707,99,111,112,99,161,101,472,157,489,665,666,667,797,169,1086,333,3246,225,226,120,121,109,110,99,111,112,117,113,101,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,467,104,135,136,137,138,139,140,141,959,118,119,120,121,109,808,809,809,809,809,811,812,899,814,815,816,817,333,410,3247,1364,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,211,132,114,119,120,121,109,110,99,111,112,99,100,133,123,143,144,125,126,492,687,980,779,780,780,780,780,780,780,782,122,123,124,125,126,127,128,129,1002,374,229,909,146,147,401,383,556,654,557,557,558,557,558,557,558,655,152,249,250,101,330,252,3248,3249,3250,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1632,333,334,335,2870,134,101,114,119,120,121,109,1074,1323,808,809,809,811,812,899,814,1945,333,1232,335,336,337,44,45,1545,148,445,429,445,445,149,672,280,281,280,281,280,281,280,295,2871,102,103,104,135,136,137,1287,139,140,141,959,285,286,467,104,135,136,137,138,139,140,141,680,1037,1031,333,410,418,23,102,103,104,135,136,137,138,139,140,141,959,367,368,369,641,657,1908,779,780,780,2423,110,99,111,112,99,100,158,123,124,125,126,492,587,434,347,455,728,69,815,900,901,902,303,903,303,548,2770,197,145,146,390,391,392,251,465,295,982,118,119,120,121,367,368,369,400,179,147,510,573,629,187,2528,117,100,133,123,124,125,126,1194,2379,774,23,367,368,369,400,179,382,510,696,696,696,696,712,696,696,696,278,279,295,1616,310,146,147,401,383,502,634,537,536,537,537,537,2289,115,983,253,254,724,117,201,202,1899,1900,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,102,154,135,136,137,138,139,136,137,138,139,975,117,201,202,427,428,99,111,112,117,113,414,415,487,101,330,332,333,410,335,411,412,637,161,328,329,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,472,157,489,665,666,667,885,2719,439,266,267,554,3251,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,291,1675,1740,3116,442,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,145,727,434,347,581,348,455,455,455,1215,413,152,249,250,101,330,465,295,466,1074,1323,490,216,449,439,669,179,382,510,2024,386,420,801,120,289,109,110,99,111,112,99,100,489,665,735,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2468,1413,374,178,179,382,355,356,384,1784,373,153,103,467,291,297,3252,1568,133,123,143,144,125,126,145,777,846,495,689,496,691,1222,251,332,333,334,335,336,337,44,2489,101,114,119,120,121,109,1074,1323,472,157,275,473,474,475,179,300,2345,2480,950,951,570,571,102,103,104,135,136,137,1287,139,140,141,3182,104,135,1493,1305,1782,3253,367,368,399,641,657,658,3254,99,201,202,203,204,458,459,169,352,2130,184,185,186,239,1165,184,185,186,239,3255,134,101,114,119,120,121,367,368,399,1435,1161,193,194,195,1897,147,510,712,278,511,446,447,447,447,681,114,119,120,121,109,110,99,111,112,99,100,227,123,134,216,1042,439,266,267,268,270,726,403,109,110,99,111,112,99,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,2853,1413,243,244,166,167,609,169,237,238,184,185,186,190,1643,987,3256,736,934,1473,1474,3257,823,197,492,172,382,355,356,357,302,303,304,303,304,303,3258,113,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,229,1212,1213,267,554,2251,549,1922,203,204,458,459,169,178,179,147,355,383,357,356,357,383,357,2155,549,1093,225,226,120,121,109,110,99,111,112,99,100,152,954,955,1324,333,410,418,419,206,488,101,330,332,333,410,335,411,412,331,161,328,393,394,395,396,699,172,382,513,514,516,3259,179,300,301,2480,950,1868,400,179,147,510,696,696,696,712,696,278,3260,1642,104,135,136,137,1287,139,1235,100,158,123,124,125,126,159,128,129,211,3047,168,169,178,179,382,401,383,402,3261,145,777,846,495,976,295,506,154,135,136,137,138,139,140,141,680,45,1006,1455,367,368,399,400,179,382,148,854,3262,382,737,738,2134,2339,480,3263,367,368,399,400,179,231,232,233,190,2325,2087,2088,485,3264,1254,1255,1256,1257,819,755,161,328,393,572,489,665,735,216,449,439,669,179,390,391,494,495,1744,640,961,962,963,135,136,137,1287,139,1304,1305,3265,1074,1323,367,368,369,400,179,180,181,2424,2770,136,137,138,139,140,141,959,460,179,147,277,278,562,281,280,281,280,281,280,281,281,280,281,280,281,2018,1642,140,141,959,330,1073,1281,367,368,369,400,179,147,510,1639,463,426,110,99,111,112,99,100,158,123,124,125,126,920,492,3266,382,510,696,783,515,1658,54,2839,2145,467,467,467,467,467,291,297,978,995,1052,127,128,129,905,467,467,467,467,104,135,136,137,138,139,140,141,959,351,229,909,727,434,454,581,455,455,1215,69,808,811,812,899,814,815,900,901,902,1469,297,3267,148,445,149,150,446,447,636,549,760,460,179,147,597,556,2265,1935,1400,439,440,859,1101,1927,561,461,429,429,429,149,150,446,447,447,636,435,99,113,101,1456,101,251,465,673,367,368,399,1582,999,549,1338,1276,1984,467,467,104,135,136,137,138,139,140,141,680,332,333,410,335,411,412,69,1493,1305,1782,3268,102,103,104,135,136,137,138,139,140,141,959,3269,422,423,424,3270,104,135,136,137,138,139,140,141,959,131,1516,1171,1015,172,382,355,383,384,557,1348,557,558,557,839,472,157,275,473,474,475,179,147,589,670,545,1188,1846,961,962,963,135,136,137,138,139,140,141,959,114,115,983,3248,258,259,260,261,262,263,264,1776,3271,1003,1004,1005,1229,211,2404,467,467,291,1675,1676,80,81,2910,1325,1524,1525,680,370,824,765,1596,1332,521,522,523,44,45,822,823,518,519,520,1332,1332,3272,310,146,147,510,998,463,435,146,147,355,356,534,535,537,1395,3273,1222,119,120,121,109,110,99,111,112,99,100,152,249,250,101,114,119,120,121,367,368,399,400,179,382,355,443,463,331,142,291,292,324,3274,797,169,352,3275,1526,296,149,591,2558,2142,367,368,399,453,319,1094,724,258,3276,1281,101,624,625,626,627,628,1562,765,1290,1291,523,44,45,1006,713,1456,101,251,332,333,1907,601,602,1224,156,157,101,624,625,626,627,1179,2879,179,382,518,534,535,537,538,3277,249,250,101,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,3278,1544,333,410,3247,3279,109,110,99,111,112,99,100,122,123,124,125,126,500,146,231,232,233,239,1165,2921,549,1571,3280,1120,1121,68,549,610,467,291,297,3281,148,149,1522,280,281,280,281,295,982,1059,1361,295,3209,761,260,261,836,837,262,263,264,265,266,267,554,271,3282,3283,735,216,449,439,669,179,390,391,494,495,496,497,659,660,3284,553,439,838,47,253,933,103,467,291,3285,193,3286,1074,1075,162,163,164,165,577,578,123,124,125,1150,145,146,147,355,383,534,535,2046,549,708,995,3287,1304,1305,3288,3019,229,909,146,147,510,712,712,278,591,150,446,447,512,549,1313,3289,1424,148,149,562,280,281,280,281,782,291,292,293,294,622,500,146,147,510,712,278,591,672,280,281,280,281,281,280,281,280,281,622,1000,522,523,44,45,3290,193,194,3291,1562,1289,1289,3292,243,244,175,176,177,379,169,3293,605,283,284,285,286,467,104,135,136,137,138,139,140,141,959,374,229,1015,172,382,355,383,534,535,538,2046,549,3218,326,327,99,201,202,203,204,594,595,596,379,169,1026,319,454,581,348,1934,124,125,126,492,172,346,319,454,455,728,69,492,1288,765,1596,521,522,523,44,45,1006,69,352,791,172,147,355,383,534,535,2046,426,1171,429,445,445,149,751,655,251,332,333,410,2667,3224,113,489,665,735,216,736,179,382,513,3294,3295,2565,3296,243,244,166,504,644,586,565,2101,934,2490,29,1553,152,961,962,963,135,136,137,1287,139,140,141,680,100,101,624,625,626,627,1179,2879,179,346,319,454,728,549,1922,1141,1142,1143,80,3297,666,667,1564,1996,859,282,3298,1524,3299,954,955,1507,752,920,492,172,346,319,347,455,695,1663,1706,696,2136,3300,808,811,812,3301,549,1571,146,147,510,278,511,446,447,447,447,592,447,512,435,167,662,169,237,743,744,188,189,240,188,189,190,2210,3302,1074,1323,702,580,2602,3303,2292,523,44,45,1531,3304,3305,3306,3307,3308,1116,572,206,207,208,388,3309,3310,3311,509,172,180,181,233,190,1246,1409,1044,1045,504,1374,222,223,224,216,449,439,669,179,382,510,998,463,549,760,1007,3312,333,410,335,336,337,1001,2031,1675,1676,3313,1015,172,180,181,921,1966,549,2147,228,352,3314,2536,3315,2867,2868,68,69,291,297,298,29,416,244,1123,1124,1125,379,169,756,268,1807,549,1338,147,1663,783,570,571,322,1428,1430,1431,605,115,1046,1047,1298,333,334,335,336,337,44,45,3316,683,346,319,1528,455,768,528,571,3317,295,1250,1424,231,232,182,183,184,185,186,187,1174,3318,252,253,68,69,1774,115,1046,1047,1790,1791,320,193,194,1202,3319,467,467,467,467,467,291,292,293,3320,808,1007,3227,3321,2106,483,484,485,2197,243,244,1123,3322,216,449,439,669,179,346,319,347,349,549,1338,1730,835,367,368,369,1159,1160,1436,3323,3324,130,297,468,1568,251,1073,640,454,456,455,528,3325,3326,510,712,696,278,1847,600,587,434,3327,104,135,136,137,138,139,1304,3328,3329,1171,1638,172,173,185,3330,3331,401,356,519,1793,3332,1413,510,278,150,446,592,447,447,2469,104,135,136,137,138,139,140,141,959,148,429,149,150,446,447,447,512,69,3289,145,777,846,616,496,1817,1245,2035,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1548,1078,1546,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1548,117,794,795,707,99,111,112,99,161,328,329,101,102,103,1506,386,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,3242,201,202,203,204,458,459,169,178,179,382,401,383,402,383,556,558,507,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,2175,2176,2200,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,203,204,205,101,624,625,626,627,628,146,346,319,320,193,194,3333,427,428,99,111,112,117,113,101,225,226,120,121,109,709,60,61,73,65,1421,549,1338,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,167,609,169,460,179,147,518,534,535,611,537,537,537,663,331,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,178,179,147,148,429,429,429,445,445,429,149,511,446,3334,117,201,202,427,428,99,111,112,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,251,252,253,254,419,117,201,202,326,327,99,111,112,99,161,328,393,394,395,396,531,146,147,513,700,402,302,303,305,303,305,303,304,303,304,303,788,549,708,367,368,399,400,179,180,181,921,967,1890,698,1171,102,103,104,135,136,137,138,139,140,141,959,427,428,99,111,112,99,161,328,393,394,395,396,265,266,267,268,269,726,426,1595,642,434,347,945,348,348,455,455,348,686,549,1338,102,103,104,135,136,137,138,139,140,141,959,472,157,216,449,439,669,179,346,319,347,455,1149,403,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,756,1387,193,194,2556,589,590,429,149,1522,281,281,280,281,281,280,295,1616,1116,572,489,490,489,490,216,449,439,266,1366,254,419,2070,2071,2104,172,390,391,494,2533,496,497,2418,3027,99,113,101,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,100,227,123,124,125,126,228,229,230,146,147,355,383,384,557,558,557,2265,1635,99,113,414,415,487,206,488,489,665,735,489,490,216,542,1693,543,1354,2491,99,113,101,102,103,104,135,136,137,138,139,140,141,959,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,547,687,688,495,505,690,1461,243,244,313,314,315,169,178,179,382,355,383,519,990,1804,3335,113,122,123,124,125,126,127,128,129,1218,1087,243,244,166,167,609,169,178,179,382,148,445,429,429,445,149,759,446,592,512,713,329,122,123,124,125,491,492,172,382,401,356,502,634,538,611,538,538,537,538,538,663,549,1338,99,113,489,665,666,667,725,439,440,916,2588,861,662,169,857,3336,184,185,186,240,1174,3337,145,777,846,495,505,690,690,496,496,691,1245,414,415,487,206,488,489,490,227,123,124,125,491,228,352,600,172,382,148,429,445,445,429,1704,3338,3339,374,3006,600,172,382,355,383,384,557,559,560,295,1616,147,148,445,445,445,429,149,759,446,447,512,549,3218,3340,333,1232,418,255,322,1428,803,2072,727,434,454,686,69,243,244,2069,644,222,223,645,646,647,3341,472,157,473,474,475,179,147,1663,3342,243,244,166,167,638,169,352,1133,537,1103,403,472,157,473,474,475,179,231,967,1890,545,714,504,221,222,223,224,206,488,489,490,227,123,124,125,491,547,172,382,401,383,519,990,1804,1804,1804,1804,3343,352,353,146,147,355,383,384,654,557,557,557,558,557,558,557,557,557,558,557,558,1178,1424,231,232,233,190,482,483,484,485,486,572,206,488,489,490,227,123,124,125,491,547,172,382,510,573,574,575,3344,472,157,473,474,475,179,147,513,3148,819,820,162,163,164,165,1589,1590,1591,169,460,179,147,518,357,302,303,305,303,305,303,304,303,788,549,1093,572,489,665,666,667,725,439,440,859,860,1101,1101,1100,1100,1101,1101,295,506,1074,1075,438,439,440,859,782,182,606,3345,665,735,216,449,439,669,179,346,319,454,2425,455,528,1658,3346,472,157,489,665,666,667,797,169,1866,537,950,2186,950,951,571,225,226,120,121,109,110,99,111,112,99,161,101,102,1356,2963,2964,3347,193,194,3348,328,329,101,225,226,120,121,367,368,399,400,179,231,232,182,606,607,769,770,3349,367,368,399,400,179,382,510,696,3350,3217,746,225,226,120,121,367,368,399,400,179,147,355,383,526,769,770,771,458,459,169,352,776,146,390,391,494,80,1941,1942,547,172,382,148,149,150,446,447,447,512,713,100,216,1042,439,450,3351,3352,508,317,345,172,346,319,347,348,455,3353,699,172,382,589,747,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2180,1752,665,735,489,665,666,667,725,439,838,47,367,368,399,400,179,231,232,921,3354,352,600,172,382,148,445,429,445,429,149,511,446,447,512,549,1028,668,439,669,179,147,461,429,149,1522,280,281,280,561,3355,3356,403,509,172,382,401,356,302,303,304,303,304,303,304,303,304,303,548,713,590,445,429,149,591,150,446,447,592,592,447,636,69,266,267,554,270,732,2638,346,319,454,2425,455,2336,528,1658,54,55,2633,2825,166,167,168,169,460,934,1473,1474,3357,193,194,1072,613,685,434,347,455,528,570,952,2570,203,204,584,585,586,644,222,223,645,646,647,648,649,650,602,2004,180,181,182,606,607,3358,665,666,667,730,731,268,732,1921,3359,355,383,534,535,2349,401,383,556,654,557,557,557,558,1222,808,809,809,840,1949,1323,490,216,449,439,266,267,3360,233,190,2412,1196,1197,1555,211,897,276,179,390,391,494,495,496,505,690,1461,374,460,179,1317,1174,3361,3362,3363,154,135,136,137,138,139,136,137,138,139,140,3364,100,101,624,625,626,627,3365,3366,434,454,455,455,1109,508,317,703,146,390,391,494,2073,495,3367,3368,3369,3370,1323,666,667,797,169,2587,1101,1565,1566,1565,2134,2339,480,3371,291,297,468,1568,285,286,291,1675,1676,3372,161,101,162,163,164,165,594,595,596,169,229,909,146,231,232,233,190,910,192,3373,490,227,123,124,125,491,228,178,179,382,148,445,445,149,3374,367,368,399,1159,3375,23,508,317,703,146,346,319,347,348,455,456,1215,549,2147,393,394,395,396,531,146,346,319,347,768,528,516,2331,2511,3376,367,368,399,400,179,231,232,921,967,3089,504,221,222,223,224,206,488,489,490,227,123,124,125,491,145,727,434,347,581,455,455,348,3377,178,179,382,148,149,562,281,281,280,281,280,281,280,281,280,442,1530,1031,333,410,3378,211,2243,348,348,455,348,348,455,457,510,278,759,446,592,1731,508,317,345,509,172,180,181,1163,232,3379,472,157,473,474,475,179,147,513,700,3380,228,352,600,587,434,347,581,455,455,1215,549,800,500,146,231,232,233,190,3381,1409,1044,2249,233,190,1598,2360,498,617,3382,1840,528,571,467,467,104,135,136,137,138,139,140,141,680,104,135,136,137,138,139,140,141,959,102,103,104,135,136,137,138,139,140,141,959,416,244,1123,1124,1125,379,169,352,798,172,382,355,383,383,534,535,536,663,758,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,662,169,170,171,587,434,347,581,348,455,455,348,1215,549,1922,147,510,278,430,280,622,808,809,809,840,1378,1379,3383,1074,1323,352,798,172,382,148,149,1522,281,281,280,281,281,281,280,281,1245,611,538,538,538,537,663,549,760,276,179,390,391,494,616,3384,442,808,811,812,899,814,924,179,390,391,494,746,510,278,591,672,280,1245,1406,977,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1040,3385,3386,1121,68,549,1338,638,1084,439,3387,147,461,429,429,149,591,1243,281,280,281,280,281,280,281,280,281,280,442,808,810,1007,3388,2143,193,194,3389,587,434,2446,455,2126,528,571,490,489,665,666,667,797,169,178,179,147,510,278,2909,1599,367,368,399,400,179,382,148,445,670,545,1188,2249,472,157,473,474,475,179,300,2345,2480,950,951,570,571,346,476,477,2064,2065,3390,472,157,473,474,475,179,231,967,1890,608,145,146,147,401,356,556,654,557,557,558,557,558,563,1007,1031,333,1232,335,336,337,44,45,46,47,453,476,477,478,3391,3392,178,179,382,148,445,445,445,462,463,69,197,276,179,3393,1317,188,2273,631,2529,2362,382,1286,3394,3395,547,172,382,401,356,556,1348,557,557,558,557,557,558,752,1026,319,454,581,348,348,455,455,455,1215,403,401,383,526,769,2165,147,355,383,526,3038,382,510,696,696,278,591,150,446,512,69,1314,1544,333,410,3247,3396,458,459,169,178,179,147,401,383,402,383,402,383,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,2147,101,162,163,2085,157,216,449,439,669,179,346,319,454,456,455,455,686,549,708,146,147,148,429,429,445,149,672,280,281,280,839,526,608,2470,650,651,603,782,665,735,216,449,439,669,179,346,319,454,2783,69,104,135,136,137,1287,139,140,141,3242,99,113,101,102,103,3289,638,169,756,268,757,549,2863,367,368,369,400,179,180,181,233,190,191,1415,47,382,401,383,526,545,742,258,761,260,261,262,263,264,432,371,1505,80,3397,100,227,123,124,125,126,2233,2234,832,832,832,832,832,832,832,966,168,169,375,2846,3398,3399,193,2144,2145,145,146,147,355,383,384,654,557,557,558,557,557,557,558,557,558,557,558,557,558,557,782,641,656,657,658,495,497,498,617,1955,1887,859,1690,1100,1101,1100,3400,943,319,347,455,1149,426,628,146,390,391,494,495,496,1718,233,190,1967,483,484,485,486,492,172,382,401,383,556,1348,557,558,557,557,558,692,445,429,429,445,149,279,280,507,318,319,347,728,403,589,670,545,1188,1846,602,603,603,603,602,603,602,603,602,605,145,146,147,355,356,534,535,611,538,652,162,163,164,165,577,578,123,124,125,1150,753,2942,254,255,2483,271,3401,3402,1121,68,435,103,104,135,136,137,138,139,140,141,959,148,445,590,3403,401,383,3148,231,232,182,606,607,769,770,2990,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,508,317,703,146,231,1641,145,146,390,391,494,1526,296,687,688,495,505,496,496,690,1461,147,148,445,429,429,445,429,149,1522,280,281,280,1774,1575,3404,545,1188,2249,180,181,233,190,3405,3406,148,429,149,511,446,592,592,447,447,636,835,361,619,620,169,1887,859,373,1638,172,382,148,854,629,190,3407,703,727,434,1821,347,348,455,348,348,455,686,549,2863,1887,916,1690,782,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,2392,439,266,267,268,271,2240,1921,69,162,163,3408,3409,101,251,332,333,410,335,411,412,426,109,110,99,111,112,99,161,101,102,1059,1060,1979,80,2433,228,229,230,146,1317,188,3410,109,110,99,111,112,99,100,101,624,625,626,627,2898,232,233,190,1863,1196,1197,1555,1218,755,127,128,129,131,2359,659,660,237,238,184,185,186,240,188,189,240,188,189,239,1165,184,185,186,190,3411,532,526,545,1188,2249,229,1015,172,173,185,2082,1455,1967,483,484,485,486,2727,1915,1915,2050,1915,2051,1915,2414,1915,442,369,1159,1160,1483,3412,820,641,2061,2062,2195,2196,485,2089,54,55,2040,3413,352,791,172,147,148,445,445,149,279,280,281,281,281,280,281,280,281,280,1718,102,103,104,135,136,137,138,139,140,141,959,460,179,1586,193,194,3414,959,367,368,369,400,179,390,391,494,616,691,746,508,317,345,172,346,319,347,348,581,455,348,3103,162,163,164,165,594,595,596,1084,439,440,859,2128,782,1215,403,401,383,556,654,557,558,557,558,557,558,557,558,557,558,557,558,282,231,967,1890,545,1188,1199,134,216,1042,439,266,267,554,269,272,435,147,148,429,149,759,446,592,592,1204,709,60,61,73,93,94,3415,66,3416,1421,403,229,1106,1288,765,1596,3272,1692,216,542,1012,1013,1013,1013,2312,134,216,1042,439,440,859,860,1101,1101,1101,1101,1101,1100,3417,591,1243,281,280,281,281,281,280,281,1411,178,179,180,181,233,190,3418,3419,237,238,184,185,186,241,1165,1520,3420,146,147,355,383,384,558,559,3421,559,1593,401,356,556,557,654,557,558,557,558,557,558,557,558,557,3422,355,383,514,570,516,2530,542,1693,543,2154,1239,435,609,169,375,2846,3423,3424,180,606,2478,570,571,103,104,135,136,137,138,139,140,141,959,169,178,179,382,510,712,3425,401,383,700,874,581,455,348,455,1318,572,489,665,666,667,730,731,554,2241,2007,2175,2665,266,267,2393,23,400,179,382,510,573,629,190,745,80,3426,3427,1219,545,742,460,179,147,461,445,445,149,759,446,592,447,512,758,382,1663,1706,3428,180,181,233,239,948,949,950,951,515,516,2570,680,460,179,147,518,534,535,1103,435,445,149,150,446,447,592,3429,1579,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,3430,616,496,3431,295,982,467,467,467,467,467,104,135,136,137,138,139,140,141,959,162,163,164,165,361,619,620,169,178,179,390,391,23,300,301,302,303,304,631,3432,355,383,526,545,1188,2249,180,181,233,190,2325,2087,2088,3433,178,179,147,148,445,445,445,445,445,429,149,759,446,447,447,512,664,1026,319,347,456,348,455,1215,403,460,179,147,461,149,150,446,636,758,597,402,302,303,305,303,305,303,305,303,305,303,548,549,1093,3150,3151,832,832,832,832,832,1584,764,765,2387,2388,2899,3434,514,570,3435,665,666,667,725,439,266,267,268,269,271,271,270,3436,190,2175,2176,659,2370,206,488,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1614,2937,1413,145,146,147,401,383,502,634,537,611,537,537,537,537,1611,180,181,233,190,1549,193,194,2378,347,1501,455,3054,237,743,744,188,189,190,910,3437,1099,859,1101,1101,2128,673,330,332,333,334,335,336,337,44,45,1006,713,276,179,346,319,347,3438,147,589,590,445,429,149,511,446,447,592,592,636,403,2162,483,484,485,3439,148,429,149,591,672,280,281,280,839,352,353,146,147,148,429,429,149,511,446,592,592,592,636,435,586,216,449,439,669,179,147,518,534,535,3440,3441,429,445,429,429,445,149,3442,767,860,1101,1100,1100,1101,1101,1101,282,586,216,449,439,3443,1663,783,515,516,2257,172,390,391,494,495,690,1817,711,492,172,382,355,356,357,302,303,304,1164,450,1200,2189,1832,2190,891,3444,3445,1564,916,1565,3186,1565,3446,2300,3447,442,102,1356,2963,2964,3448,3449,346,476,2195,2196,485,2505,2297,228,460,179,147,518,384,654,557,558,557,558,557,558,557,558,557,558,557,558,386,429,149,430,280,281,280,281,281,281,280,281,280,281,1510,182,606,607,545,1188,1199,401,383,502,634,538,1395,549,1338,168,169,352,776,777,846,616,505,673,429,429,445,445,445,445,445,445,3450,492,1288,3451,724,1007,1031,333,410,418,23,346,319,347,348,455,581,686,758,445,445,445,462,3452,694,204,594,595,596,379,169,178,179,147,355,383,519,821,169,1632,333,410,335,411,412,403,445,445,149,1243,281,280,281,280,281,280,605,117,826,1282,829,2890,3453,777,778,780,2369,2613,2369,498,1745,2340,2375,229,909,146,390,391,494,495,496,1178,390,391,495,497,498,617,2340,3454,798,172,382,148,854,574,2768,2270,1499,1555,211,2398,382,513,526,608,228,178,179,147,148,149,562,281,280,281,281,1774,148,445,429,429,429,149,591,672,1774,492,172,382,355,383,384,654,557,558,1635,147,401,383,526,769,770,3205,1042,439,266,267,1387,331,545,3455,2916,1100,3456,1281,921,967,2228,570,516,2362,2855,2856,1663,697,545,1188,1189,510,696,697,545,1188,1199,180,606,2478,570,571,547,172,180,181,233,190,1931,2270,1499,1555,1002,390,391,494,495,1744,497,498,3457,840,810,840,840,809,809,809,809,809,840,809,1007,3458,352,1133,537,1759,549,1338,467,467,467,467,104,135,136,137,138,139,140,141,959,231,232,233,190,2106,483,484,2343,486,147,148,445,670,545,671,1663,697,545,1188,1846,147,510,278,150,2087,2088,485,2089,54,55,2040,3413,508,317,703,146,390,391,494,2073,495,3367,3368,3369,3370,352,600,172,382,148,445,429,445,445,445,149,150,446,636,1241,237,743,744,188,189,240,188,3459,526,608,1100,2128,918,3460,1121,68,350,330,465,977,318,319,347,581,455,455,455,455,1109,382,461,445,429,149,430,280,281,563,687,688,495,690,689,496,496,2441,401,356,519,990,1804,1804,3461,943,319,347,581,455,455,348,348,455,1215,403,429,429,429,429,149,1522,280,281,280,281,280,281,1211,2157,740,666,667,668,439,669,179,2880,584,585,586,2866,222,223,224,216,449,439,669,179,3462,482,483,484,485,2505,3463,243,244,313,314,315,169,237,238,184,185,186,239,185,186,190,3464,2211,148,149,150,2087,2088,485,2089,54,1659,352,798,172,382,510,712,712,278,759,446,512,350,149,3465,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,1156,579,580,703,146,147,510,573,629,190,1549,193,194,1072,345,172,390,391,494,495,505,690,690,690,496,690,690,496,691,752,1598,2360,2268,660,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1032,735,489,490,216,1042,439,266,3466,398,182,606,607,545,1188,1846,756,554,270,2493,549,1338,769,2678,54,55,2040,3467,382,148,445,445,445,445,445,429,429,445,149,150,446,512,435,1120,1121,254,419,725,439,266,267,554,270,2510,549,1922,1435,3468,2616,435,460,179,147,518,519,520,521,1786,233,190,2325,2087,2088,485,486,725,439,266,267,554,1294,270,270,270,270,271,3469,149,430,281,281,280,281,280,281,280,655,172,180,181,233,190,575,1415,47,345,509,172,382,148,854,629,190,1643,1044,1846,727,434,347,581,348,686,713,180,606,607,545,2803,808,811,812,899,814,924,179,346,319,454,455,686,758,127,128,129,1424,934,2490,1108,680,616,690,496,3470,2162,483,484,485,486,390,391,494,495,2729,496,1744,977,216,449,439,669,179,147,510,1639,463,549,760,147,401,383,514,570,952,2257,180,181,233,190,2106,483,484,2374,54,55,633,390,391,495,497,498,3471,369,400,179,382,510,573,3472,791,172,147,355,383,357,356,534,1636,3473,416,244,1123,3322,216,449,439,838,23,145,3474,3475,591,150,3032,149,591,150,446,447,592,636,549,708,669,179,147,518,519,3476,240,2328,2329,950,951,570,571,460,179,147,597,556,654,557,558,557,558,557,558,1935,429,429,149,759,446,447,447,447,447,512,331,850,1409,1044,1045,148,445,670,545,1188,2249,665,735,489,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,277,278,759,3477,3478,3479,2483,270,3480,549,2099,959,399,400,179,382,148,854,629,190,2412,1196,1197,2477,113,122,123,124,125,126,197,145,146,231,232,233,2020,1171,1074,1323,725,439,266,267,554,270,3481,382,1663,783,570,784,597,402,302,303,305,303,305,303,304,303,305,3482,147,148,149,2248,785,786,3483,231,967,1890,545,714,735,489,665,666,667,668,439,669,179,346,319,347,528,571,2405,950,951,570,952,2570,2132,2133,2134,3217,2340,3454,207,208,388,936,3484,68,549,1571,149,279,280,281,280,281,1774,258,761,260,261,836,837,262,263,264,3485,798,172,180,181,182,181,233,3486,3487,472,157,473,474,475,179,382,1663,697,769,1612,355,383,3488,162,163,164,165,1589,1590,1591,169,229,230,777,846,495,1817,655,601,605,318,319,320,193,194,1577,2055,390,391,494,495,505,496,496,691,1245,1846,131,1736,401,383,556,558,557,1348,752,401,356,356,502,634,538,611,538,538,537,537,537,1759,549,1252,607,545,742,545,1188,2249,3489,355,383,384,2201,2260,145,146,346,319,454,1215,549,1093,149,1522,281,280,281,280,281,1774,510,696,697,545,714,2106,483,484,2343,486,1268,1269,184,185,186,240,1174,744,188,189,239,1165,3490,429,429,149,511,446,447,447,447,636,403,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,3491,846,2563,605,988,3492,526,545,2053,489,490,216,449,439,669,179,390,391,494,616,496,496,1817,752,1288,765,765,1596,1909,69,638,169,943,319,1821,3493,460,179,147,461,429,429,149,591,150,446,592,512,69,382,355,383,357,302,303,305,303,304,303,548,549,1313,1846,429,445,429,429,149,150,446,447,512,758,148,149,150,446,592,592,447,447,447,447,636,549,1674,146,346,319,454,348,455,455,1149,835,3029,178,179,147,510,278,2694,495,690,505,690,690,496,496,496,496,691,692,700,3380,382,355,383,526,769,770,2744,146,147,401,383,502,634,1242,1455,402,302,3494,1830,439,440,859,1100,3456,673,330,332,333,3246,382,355,383,383,534,535,536,2188,554,271,271,270,272,435,3495,3496,1719,162,163,164,165,313,314,315,169,178,179,346,3497,1169,439,266,267,268,271,1672,1241,231,232,233,190,2162,483,484,485,486,1026,319,347,348,455,581,455,1318,492,172,382,148,429,429,429,429,149,150,446,592,592,447,3155,510,696,278,511,446,1787,532,2244,3498,170,1585,439,266,267,554,1294,271,271,271,270,271,270,2007,149,150,446,592,592,447,592,592,512,2770,352,621,146,147,355,383,383,534,535,1103,549,708,1610,216,449,439,669,179,346,319,347,1132,2156,500,146,147,510,712,278,2248,666,667,3499,295,1250,429,149,3500,203,204,205,101,624,625,626,627,628,146,147,148,854,629,190,245,1409,1044,1189,3501,54,55,2479,2166,3502,429,429,445,445,429,429,445,462,3503,703,146,231,232,311,181,233,190,191,192,413,401,383,383,556,558,559,385,561,735,216,1042,439,266,1366,68,435,671,370,433,434,347,455,528,515,516,517,769,2605,182,606,607,545,2314,777,778,779,780,780,1751,782,532,526,545,3154,390,391,494,2073,495,3367,3368,3369,3370,401,356,502,634,611,538,537,537,537,537,537,2349,1973,589,670,545,742,1887,859,1100,1888,507,277,278,279,280,281,746,279,280,281,280,281,280,295,982,178,179,147,401,383,502,634,1472,69,231,232,1163,1560,3504,3505,429,429,429,149,150,446,447,447,2063,2069,644,222,223,224,216,449,439,669,179,346,319,347,581,348,582,1099,859,1101,1100,1101,295,1616,1059,1361,295,1250,1924,2133,2784,2969,382,513,526,608,103,104,135,136,137,138,139,140,141,959,291,292,324,253,254,985,690,496,689,691,386,265,266,267,554,269,271,271,726,426,2282,216,1042,439,266,267,268,271,269,726,549,1093,410,335,411,412,69,554,271,3506,3469,2691,453,476,2195,2196,2343,2107,149,150,446,447,447,447,447,512,664,653,570,571,486,783,570,571,222,223,224,644,222,223,645,646,3507,3508,154,135,136,137,138,139,1304,1305,1782,1416,2522,611,537,950,951,952,2257,292,324,253,68,403,1106,172,180,181,233,187,1174,1228,373,145,146,147,401,356,502,634,611,538,537,1611,844,938,939,1002,345,509,172,390,391,494,495,690,505,496,690,691,692,777,846,495,2096,497,659,2254,2253,2253,2254,2253,2253,2255,746,2325,2087,2088,485,2622,3048,1824,823,1522,281,281,281,280,281,280,281,692,3509,2046,1796,2195,2196,485,2505,2749,3510,148,429,429,429,149,591,672,281,280,373,702,580,703,727,434,347,2311,815,900,901,3404,154,135,136,137,138,139,136,137,138,139,1304,3511,346,319,347,348,456,348,3512,607,545,1188,1189,725,439,3513,1325,1524,3299,182,606,607,545,2314,390,391,616,1744,497,498,617,2340,3514,180,606,2224,3515,276,179,346,319,347,686,549,1313,206,207,208,2283,2284,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,345,172,390,391,494,3516,460,179,147,461,445,445,429,149,430,280,281,280,281,280,281,2045,1124,1125,379,169,178,179,147,355,356,534,535,538,1395,758,239,948,949,950,951,570,1658,54,55,1238,2325,2087,2088,485,2505,2697,1996,859,3367,3368,3369,3370,1562,1289,1855,1080,1081,350,952,529,3517,148,149,150,446,447,592,592,512,69,690,3367,3368,3369,3370,508,317,703,146,346,319,347,581,348,588,178,179,382,355,356,384,3518,2529,3519,207,208,388,389,1120,1121,254,541,659,2253,2254,974,100,3520,3521,179,2676,960,687,688,495,2729,690,2172,497,3522,3523,23,181,233,190,245,3524,216,449,439,838,23,587,434,347,581,455,348,455,348,348,686,69,1949,1965,300,301,302,303,304,631,570,952,3525,148,445,445,445,445,445,501,149,591,150,446,592,592,447,592,592,447,636,69,180,181,1163,232,233,190,3526,2325,2087,2088,2296,3527,239,1165,1938,386,149,1522,280,281,280,281,1774,454,581,455,455,686,435,216,3528,1575,1265,303,1576,435,429,429,429,149,511,446,447,592,592,512,549,2833,545,2700,346,319,347,348,348,455,686,549,1338,2676,724,709,60,61,73,74,66,3529,66,67,254,255,374,229,909,146,390,391,494,616,690,505,691,711,1074,1323,382,355,383,526,545,2421,231,232,182,183,184,185,186,239,1165,184,185,186,190,3530,180,181,1163,232,233,239,185,2082,549,800,460,179,147,461,445,445,429,149,591,150,446,447,447,2121,1442,149,759,446,592,447,447,447,447,636,664,460,179,147,518,357,3531,148,854,3532,3533,3534,429,149,3535,316,317,345,172,346,319,347,2313,178,179,382,148,429,3536,355,383,384,654,557,557,558,557,558,557,558,557,558,557,558,557,558,557,558,1275,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,1817,1350,291,292,324,253,254,255,382,355,383,534,535,611,3537,178,179,180,181,233,190,1643,987,3538,547,587,434,347,728,549,1338,161,101,162,163,164,165,361,619,620,169,237,743,744,188,189,241,185,186,190,3539,3540,508,317,703,1562,1289,2900,2236,2754,2755,1260,44,45,1531,480,2786,369,400,179,231,232,182,181,233,190,1549,193,194,195,1853,3541,2455,3542,3543,510,278,279,280,281,281,281,280,782,352,798,172,180,181,182,181,921,1560,3544,943,319,347,1239,549,610,666,667,1564,916,1565,2517,1565,2134,2339,2948,445,445,429,501,390,391,494,495,505,690,691,563,697,545,1188,1846,346,319,454,455,1132,549,1922,346,319,320,193,194,195,196,383,556,654,557,557,557,558,557,558,557,558,557,558,557,684,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1007,1031,333,410,418,541,146,147,513,2348,426,237,743,744,188,189,239,185,186,3545,102,103,104,135,136,137,138,139,140,141,959,735,489,665,666,667,1962,333,2164,2700,291,292,293,294,295,296,237,238,184,185,186,190,745,80,3546,1159,1160,3468,3547,3548,1317,2328,2329,950,951,570,1658,54,55,2633,3549,251,1073,282,382,401,383,402,302,303,304,303,304,303,304,303,304,1469,1159,3550,23,1059,1361,839,3182,1086,333,1232,335,336,337,44,45,1006,1227,591,150,446,592,447,447,636,69,2128,442,291,292,324,253,254,398,1254,1255,3551,3552,777,778,780,780,2869,175,176,177,169,3553,1718,698,577,578,123,124,125,579,580,345,509,172,382,148,854,629,190,191,192,193,194,1577,3554,237,743,744,188,189,241,185,186,239,185,186,190,745,3555,1638,172,382,510,573,629,190,2325,1811,567,568,3556,3557,1427,687,688,495,496,505,690,2710,445,149,759,446,1728,1179,3558,901,1265,303,3559,3560,390,391,2073,616,497,498,2692,2340,2375,1990,1031,333,410,418,23,178,179,382,401,356,502,634,538,536,1759,69,276,179,390,391,494,495,505,496,496,496,496,1461,510,696,696,278,430,280,918,509,172,382,148,429,429,429,149,672,898,616,2660,690,2172,782,104,135,136,137,138,139,140,141,959,276,179,390,391,494,3561,538,1472,664,369,613,685,434,320,835,231,232,233,190,245,1409,987,1248,513,533,556,1348,557,558,557,558,557,558,692,240,2528,147,355,356,534,535,2046,69,429,429,445,429,149,591,672,373,382,461,2781,601,602,2527,2134,3562,518,384,654,557,558,839,445,445,445,429,429,149,759,2420,3563,717,718,3564,722,403,1171,1554,1196,1197,1555,211,2243,447,447,447,593,838,23,1887,916,2128,746,148,445,670,545,3154,371,1505,495,496,497,498,617,480,3132,147,1663,783,570,571,147,1663,697,545,671,148,445,445,429,149,1522,280,281,281,281,692,149,759,446,592,592,592,592,447,512,549,1674,357,561,352,600,172,147,518,534,535,1242,1241,300,301,302,303,305,303,305,303,304,2218,777,778,1765,782,346,319,347,768,528,516,2332,2331,2331,2332,2331,2331,3565,669,179,346,319,347,3566,1037,3567,2724,686,549,800,454,945,348,348,348,348,455,455,455,455,1215,403,1059,1361,295,466,1314,1544,333,410,3568,149,430,280,281,622,808,809,809,809,809,810,811,812,899,814,815,816,1226,1182,347,581,582,496,497,498,1745,480,3263,178,179,147,355,356,519,3569,532,514,515,2495,662,169,178,179,382,401,383,519,520,1332,1597,2195,2196,2343,2622,2749,1887,859,1100,1101,860,1100,1100,1101,2128,1222,756,268,1294,270,271,271,270,272,3570,905,589,3571,190,1828,802,2560,2478,570,2495,148,854,629,190,745,80,3572,401,383,402,383,556,654,557,558,557,558,557,557,557,558,557,558,557,2441,346,476,477,2236,3573,2157,3574,148,445,445,429,149,759,446,447,512,413,2240,1921,1227,307,308,3575,549,2147,154,135,136,137,138,139,136,137,138,906,3576,3577,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,460,179,147,597,402,302,303,548,549,610,149,1522,280,281,280,563,3578,1031,333,1232,335,336,337,44,45,46,47,2533,497,2268,974,356,502,634,538,611,537,538,538,537,537,1759,69,709,60,61,72,71,73,74,66,2381,66,2381,66,67,254,985,182,606,607,545,1188,1189,2421,1294,271,271,270,271,272,664,1304,1305,3579,1402,2157,740,355,383,384,3421,557,558,1351,3580,266,267,554,269,270,272,435,429,445,429,149,759,446,447,447,636,549,800,1084,439,669,179,346,319,347,455,455,944,549,1028,1744,497,498,1745,3581,390,391,494,2073,3582,370,433,434,347,455,528,570,516,2570,168,169,170,171,172,390,391,494,1526,296,2563,497,498,3583,356,502,634,536,538,537,663,1216,429,429,429,149,511,446,592,592,447,512,403,909,777,846,616,496,1342,295,1616,148,445,670,545,3584,173,1165,3490,514,515,3115,3585,356,556,557,654,557,558,557,557,557,558,557,561,1130,1383,1386,1624,1887,916,2128,655,237,238,184,185,186,241,185,186,239,185,186,190,1933,429,149,591,150,446,592,592,447,592,592,3334,810,809,1949,1323,2747,1031,333,1232,335,336,337,44,45,46,23,102,1254,1255,1256,1912,253,254,419,680,694,204,594,595,596,379,169,460,179,147,518,534,535,538,799,549,1571,699,172,382,513,700,556,654,557,558,557,558,295,506,532,526,2231,384,654,557,557,557,558,386,921,232,182,3185,2421,513,526,545,1188,1199,147,355,383,534,535,1103,435,2132,1386,3586,231,232,311,181,1163,1966,1241,149,279,2441,276,179,390,391,494,495,496,690,1236,373,429,429,445,445,149,279,280,673,345,509,172,382,510,573,629,190,191,192,193,194,2448,178,179,382,1730,835,454,686,69,237,743,744,188,189,241,185,186,240,188,189,187,3587,2478,3588,172,382,148,429,149,511,446,447,592,636,637,382,148,429,429,429,429,149,759,446,636,331,278,562,281,280,281,280,3589,3590,239,185,186,239,185,186,239,1165,184,185,186,239,1668,1286,602,2527,2134,2339,2340,3591,1658,54,55,3592,240,188,189,190,191,802,442,657,658,495,1802,690,690,690,690,496,496,496,496,691,442,3593,3594,3595,3235,896,807,445,149,150,446,592,512,1227,149,591,150,446,447,512,69,231,232,311,181,2424,549,1313,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,883,554,3596,367,368,369,613,685,434,320,3597,680,149,150,2087,2088,3598,237,238,184,185,186,239,185,186,190,3599,680,495,505,690,496,690,690,746,197,492,172,382,148,429,429,445,445,429,149,759,446,447,447,512,664,276,179,346,319,347,2146,69,764,765,2315,3600,149,2303,2304,2305,447,447,447,592,592,447,636,549,800,526,769,770,2543,564,216,1042,439,838,23,477,478,3601,1527,2195,2196,2343,2505,3048,401,383,526,2231,485,486,429,149,1522,280,281,281,281,280,281,280,281,3589,3602,382,510,573,629,190,3603,496,3604,1275,347,686,549,3218,460,179,300,301,358,359,3605,382,355,383,526,545,1188,1846,458,459,169,352,776,777,846,616,505,496,1222,369,3606,541,148,445,445,445,149,2909,3607,1522,280,281,281,1222,3608,2575,664,2834,180,181,233,190,575,3609,769,770,2992,401,383,526,545,1188,1846,2169,3126,3610,492,172,382,148,149,562,281,280,281,281,281,280,281,280,839,147,148,854,629,190,245,3611,816,1226,1182,454,3117,549,1571,742,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,2249,268,1214,435,3612,390,391,80,3613,1116,572,489,490,216,449,439,266,267,554,270,1322,666,667,1514,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,237,238,184,185,186,239,185,186,190,2731,148,429,429,149,759,446,592,512,549,1338,3614,346,319,347,581,686,69,510,712,712,712,1343,697,545,2314,258,761,260,2792,422,3615,148,445,445,429,429,149,279,280,281,280,563,216,542,1693,1693,1012,1039,3616,148,854,574,3381,3524,1171,271,1294,271,271,270,270,270,272,549,610,355,383,384,557,654,557,558,557,558,557,558,557,558,557,558,557,558,563,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,3238,616,689,496,497,498,1745,3617,104,135,136,137,1287,139,140,141,959,670,545,1188,3125,400,179,346,319,876,147,510,573,629,190,745,80,3618,429,445,429,149,511,446,2342,2347,179,2502,3235,537,2349,429,429,445,429,149,591,751,1222,401,356,502,634,611,538,538,538,538,537,537,537,537,663,758,902,303,1576,549,708,241,948,949,1138,549,800,429,429,445,429,429,445,462,463,637,445,149,150,446,447,636,549,1571,665,666,667,730,731,2483,1815,1658,426,1956,632,54,55,1238,601,603,603,602,603,603,603,602,603,918,810,1949,366,889,1832,890,891,892,3619,2172,605,777,846,561,2216,2338,1213,267,268,269,272,403,943,319,454,2425,457,3620,383,534,535,2046,758,3621,565,2101,934,1473,3622,495,497,498,2692,870,356,556,557,654,557,558,557,557,557,558,557,558,557,711,556,692,1294,270,272,403,653,570,1658,54,2839,2145,1632,333,334,335,336,337,44,45,1006,350,291,292,3623,149,562,281,280,281,3330,149,591,150,446,447,592,592,447,447,512,549,550,3624,3625,3626,291,1675,3627,2572,251,252,253,254,255,698,1893,774,23,516,2570,318,319,347,581,455,455,455,1215,2770,500,146,147,148,149,759,446,592,592,447,447,447,447,447,512,435,1553,565,2101,179,3462,1254,3628,3252,3352,690,690,496,690,690,691,295,1616,401,356,302,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,1338,591,150,446,592,592,592,447,592,592,3629,390,391,495,1744,497,498,3027,2061,2062,477,478,723,398,3630,401,383,556,1348,442,402,302,303,305,303,3258,1171,510,696,697,545,2462,148,445,149,279,280,281,280,1178,136,137,138,139,1304,1305,1306,1455,394,395,1594,396,763,642,434,1094,23,454,2425,455,3074,549,2147,1171,808,811,812,899,814,924,179,390,391,494,495,496,496,1960,295,506,147,510,278,150,2087,2088,2296,2697,1665,333,410,3631,178,179,147,148,445,445,149,1243,281,280,563,149,430,281,281,281,280,281,280,281,280,281,280,281,1211,2343,486,1075,346,319,347,581,3632,390,391,494,2073,616,3633,2977,333,1232,418,985,573,574,3634,1498,1499,3635,145,146,231,232,233,1404,665,735,216,1042,439,838,47,727,434,347,3636,300,301,2480,950,951,570,571,445,445,445,445,445,149,150,446,447,512,549,800,1007,3637,3638,2590,2591,1101,1565,2134,2339,480,3132,154,135,136,137,138,139,136,137,138,139,140,141,680,231,967,1890,769,770,3639,251,3640,665,666,667,730,731,268,2286,1921,713,300,2345,302,303,305,303,305,303,304,303,305,303,305,303,304,303,548,69,564,565,3641,429,445,429,149,591,150,446,636,403,1034,3642,2228,570,2216,1225,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,3643,613,614,615,495,496,497,498,2661,3482,601,603,603,603,603,602,603,603,603,746,247,101,624,625,626,627,2411,181,233,190,1643,1044,849,2462,251,465,282,769,770,2543,2126,1822,403,455,2336,528,2503,796,101,225,226,120,121,109,110,99,111,112,99,100,2222,3644,3645,3646,523,44,2489,510,278,2466,2360,659,2370,237,743,744,188,189,240,188,189,239,185,186,190,986,3647,613,614,615,495,1461,237,238,184,185,186,190,2768,2270,1499,1923,401,383,502,634,611,538,538,538,538,537,537,537,1759,549,550,3648,2976,770,3055,672,280,281,281,281,280,281,281,281,280,281,280,281,280,2018,2142,3649,355,383,1540,3650,557,557,558,557,558,557,793,175,176,177,169,352,3651,3652,2249,382,510,696,2136,3653,513,700,556,654,557,557,557,558,557,557,557,558,557,558,557,3654,616,2172,507,348,1840,1822,69,231,232,182,183,184,185,186,190,2827,193,194,1170,369,400,179,382,510,1639,463,1241,609,169,237,743,744,188,189,240,188,189,240,188,189,190,191,802,782,460,179,147,518,534,535,536,537,1759,549,1571,172,346,319,454,456,946,1150,3655,1872,777,846,495,505,690,690,496,496,496,752,510,696,697,608,3656,355,383,384,558,1482,3657,570,3142,1026,319,1528,1839,1330,401,356,561,482,483,484,2343,486,616,689,496,1330,454,348,1132,549,800,465,640,2126,528,3658,2522,537,950,3659,950,951,1658,54,55,3592,453,476,477,478,3660,18,665,666,667,668,439,266,3466,23,207,208,388,389,179,390,391,23,147,401,356,402,1396,549,1338,178,179,147,401,383,402,383,502,634,537,537,799,549,1338,401,356,502,634,611,538,538,538,1759,1368,230,146,147,355,383,534,535,538,2046,549,1338,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,2478,570,571,2195,2196,2374,54,55,56,57,769,770,2543,401,356,502,634,538,611,537,537,537,537,1759,435,182,3661,2600,333,2687,3662,1967,483,484,2296,2297,356,534,535,538,537,799,435,429,429,429,149,759,446,447,592,592,447,447,636,549,2863,511,446,447,636,549,2863,322,1428,2794,2824,3663,1920,270,3596,2551,270,1815,952,3664,467,467,104,135,136,137,138,139,140,141,680,352,621,146,231,232,233,241,185,2082,637,510,696,783,570,516,2257,1744,497,2268,974,382,1663,783,570,516,3164,2977,333,410,335,336,337,44,45,1006,403,1179,2879,179,2502,47,401,443,463,69,587,434,454,455,944,69,355,356,357,655,518,534,535,537,538,538,1611,769,770,2396,54,55,56,2693,1112,3665,3666,3667,581,455,455,455,455,455,455,1109,149,150,2087,2088,3668,3669,3670,382,3671,2784,3672,782,645,646,3673,2680,3674,3675,237,238,184,185,186,190,1931,2270,1499,1555,130,783,570,571,352,600,172,382,148,445,429,445,429,429,445,462,999,664,145,146,147,148,429,429,445,445,429,149,591,994,622,233,190,1654,1498,1499,1555,1218,755,545,1188,2249,3676,23,515,1658,54,55,56,3132,401,356,556,1348,557,557,558,557,558,559,2859,672,280,281,1774,345,509,172,346,319,347,348,348,944,549,1571,148,462,463,549,1338,3455,304,303,1519,303,305,303,305,303,304,303,788,331,3677,146,147,148,854,629,190,1195,3678,455,3679,3487,375,2846,3680,3681,709,60,61,73,93,94,3682,182,606,2478,570,1658,331,485,486,238,184,185,186,240,188,189,240,188,189,190,1828,802,2688,3179,333,1232,335,336,337,44,45,524,3683,332,333,334,335,336,337,1233,3684,237,743,744,188,189,190,2831,3685,653,516,2332,2331,2331,2332,2332,2332,2511,435,3686,744,3687,910,802,80,3688,502,634,537,611,538,538,537,1759,758,712,278,591,1243,673,382,510,712,696,3689,1025,346,476,2195,2196,485,486,233,190,910,192,193,194,3690,3691,3692,3693,2478,570,952,2570,148,445,854,574,1643,3694,1304,1305,3695,532,514,570,3142,178,179,147,355,383,519,990,1408,703,146,346,319,347,348,2313,382,148,445,445,445,445,445,149,2558,1642,601,602,603,603,603,602,603,603,603,2441,366,390,391,494,80,3696,2339,618,1598,2360,498,2419,465,295,466,1026,319,347,348,455,456,348,1215,403,447,447,447,512,69,777,846,495,691,1281,147,355,383,519,990,3461,3091,3697,3698,3699,1866,3700,1721,68,3701,147,589,670,545,2700,534,535,538,538,3702,1286,602,295,506,3703,492,172,382,401,356,556,1348,557,557,558,557,1351,2108,1690,1101,1101,3704,383,502,634,537,1395,435,493,1644,2455,2583,2584,3705,3706,549,1338,3707,587,434,347,581,348,455,348,348,455,455,3708,429,445,445,429,149,430,1245,279,281,281,280,281,281,281,280,281,280,281,280,711,134,216,449,439,669,179,346,319,454,581,3377,712,278,430,280,281,280,507,442,791,687,688,495,673,916,1245,240,2328,2329,950,951,570,1658,54,55,2040,3709,1249,507,885,2371,1121,933,662,169,1268,1269,184,185,186,190,630,607,545,3710,401,383,526,608,591,672,1599,178,179,231,232,233,3711,671,172,382,510,712,278,150,446,592,2874,429,149,591,150,446,447,447,512,549,800,277,696,278,994,977,445,590,2725,2228,515,952,2570,383,502,634,611,537,1759,435,265,266,267,554,1294,270,3712,389,934,1886,1300,401,383,556,654,557,558,557,558,557,1353,281,281,839,348,455,944,403,148,854,3713,1206,142,952,2257,330,332,333,410,335,411,3714,510,712,278,2558,1599,402,302,303,304,303,304,303,304,303,304,303,304,303,788,549,610,369,400,179,390,391,494,495,692,148,149,591,150,446,447,592,592,447,512,403,211,1516,727,434,454,348,348,686,664,3402,1121,68,758,3715,2175,2176,659,2370,355,383,357,302,303,2580,511,446,592,592,447,447,447,447,636,549,610,826,1282,829,3716,254,47,410,335,411,412,54,55,56,3371,103,104,135,136,137,138,139,140,141,959,276,179,1586,193,194,3333,2325,2087,2088,485,2197,714,382,148,445,429,445,2258,401,383,502,634,536,537,1759,1368,278,150,2087,2088,485,2505,2297,252,253,254,985,2657,54,2839,2145,742,228,756,1387,193,3717,771,148,445,670,769,770,2396,54,55,2586,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1040,390,391,494,2073,616,3718,429,149,1522,280,281,280,281,280,281,1281,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,811,812,899,814,924,934,1473,3622,2425,1215,549,610,147,401,383,402,1396,403,382,532,526,769,770,3719,367,368,369,400,179,231,232,233,190,191,802,782,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1412,1413,172,346,319,1094,23,345,509,172,382,148,429,429,429,445,149,759,446,592,447,447,2991,589,670,545,1188,2249,2442,2443,23,148,429,445,429,429,445,445,462,999,331,429,445,149,562,280,282,231,232,233,187,1174,3039,637,429,429,149,1243,281,280,281,280,281,1371,712,712,712,3720,320,193,194,3721,3691,251,252,253,254,419,510,696,573,574,3405,3722,1499,2477,278,430,2018,2019,486,1703,769,770,3723,564,216,1042,439,266,267,268,270,1214,549,610,178,179,147,601,603,603,602,603,603,1350,237,238,184,185,186,239,185,186,240,188,189,190,2412,1196,1197,2477,390,391,494,616,496,497,498,617,782,461,429,149,511,446,2712,402,1275,777,846,495,496,1330,714,429,445,149,150,446,447,447,1731,178,179,180,181,182,183,1520,2440,134,216,1042,439,3724,277,696,696,278,759,446,447,512,713,485,3441,1076,272,758,447,447,447,447,512,549,1338,495,689,690,496,1330,838,23,3725,1767,3726,401,383,526,545,2053,597,519,520,1332,1332,1628,453,319,320,1241,355,383,534,535,536,663,331,149,1522,281,281,281,280,281,281,281,280,281,280,281,655,2037,698,402,302,303,305,303,304,303,304,303,304,303,788,435,3727,769,770,2543,510,696,696,278,591,3728,1265,303,304,303,1519,303,305,303,305,303,788,435,449,439,669,179,346,319,2446,528,571,348,581,455,455,455,1318,485,486,2108,860,1101,1100,2128,282,149,430,281,281,281,280,281,280,281,280,281,280,281,1222,558,557,557,558,692,1579,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,1079,1080,1856,320,193,194,195,1897,154,135,136,137,138,139,136,137,138,139,140,3729,665,735,489,665,735,216,1042,439,266,267,268,3730,258,761,260,261,762,262,263,264,763,642,434,3731,3732,3733,171,687,980,781,779,780,780,780,780,1751,1222,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,1641,347,348,581,455,455,348,348,348,1839,518,534,535,611,537,537,537,537,1759,549,1313,147,401,356,302,303,548,69,2700,3734,1498,1499,2030,846,495,689,690,690,282,3735,3736,735,216,449,439,266,267,554,2551,271,2286,3737,180,181,182,606,607,545,1188,1846,1663,783,570,571,1074,1323,943,319,454,455,349,403,589,590,445,429,429,445,149,759,446,592,447,512,549,1338,514,570,571,1644,2819,3738,3739,383,556,654,557,558,557,558,557,558,557,558,557,558,557,1935,375,1462,1463,1464,1464,2352,713,698,548,549,3740,1887,80,1592,3741,916,1100,1690,2128,1178,591,1243,281,281,280,281,280,281,280,281,1281,1562,1289,3742,270,1814,1815,1658,426,883,268,1921,713,233,240,2328,2329,950,951,3743,756,554,270,270,2510,435,247,101,624,625,626,627,1179,2879,934,1473,1474,3744,478,785,3745,3746,172,346,319,347,581,348,455,455,455,455,455,686,435,769,2678,3747,80,3748,538,611,538,538,537,538,538,537,537,663,2770,545,714,1074,366,587,434,347,455,581,348,348,1215,549,1028,445,149,150,446,592,592,636,549,800,382,401,356,402,302,303,305,303,304,303,2580,1099,859,1101,1690,1101,1100,2128,692,759,446,447,447,447,447,447,1731,1661,1662,616,1960,692,268,270,3480,69,466,231,967,1890,545,1188,1189,564,216,1042,439,266,267,268,271,3749,352,600,172,382,401,383,502,634,536,538,537,663,403,3275,3750,1835,558,557,558,557,558,557,558,557,558,557,558,557,558,1635,2343,486,240,188,189,241,1165,184,185,186,190,986,1044,1189,3751,515,3752,1967,483,484,485,486,182,181,921,1966,549,2863,902,303,305,303,3753,549,800,445,149,1243,281,280,655,613,685,434,347,348,2163,457,1037,1031,333,1232,335,336,337,44,45,3754,3755,2523,3756,445,445,445,429,149,511,446,447,512,549,1338,346,319,347,348,944,69,2286,1815,1658,637,104,135,136,137,138,139,140,307,3757,641,3758,485,3759,400,179,147,355,383,384,1348,557,557,1635,1928,146,346,540,541,149,511,446,447,447,636,549,610,769,770,2543,1537,442,266,267,554,1294,726,69,1706,3760,346,319,320,758,581,455,1215,403,477,2236,3761,54,2330,3212,3762,714,148,429,149,591,150,446,447,592,592,1728,271,271,270,270,271,271,270,272,69,2660,496,2172,497,498,1745,1955,2364,216,1042,439,266,267,268,1294,272,549,1338,366,490,216,1042,439,266,267,1276,3763,1796,147,401,383,402,302,303,304,303,548,549,2039,1665,333,1232,418,419,355,383,357,383,534,535,1103,758,2249,231,232,233,3764,2092,147,148,149,150,446,512,1241,2347,179,3675,3716,254,23,1528,455,1840,528,1658,54,2330,352,791,172,382,518,384,2202,1706,3765,173,185,926,1670,3766,401,383,502,634,611,537,537,538,3221,2106,483,484,485,2505,2650,608,1971,744,188,189,190,3023,1409,987,1248,498,2127,1059,1361,782,687,688,616,1960,295,1616,44,45,1006,1455,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,601,602,603,603,603,602,603,602,603,602,752,1317,2528,2446,455,3074,758,2223,128,129,1002,233,190,482,483,484,2326,777,778,781,2423,390,391,495,2662,497,498,2419,355,356,302,303,304,303,305,303,788,413,149,150,446,592,512,549,1922,429,149,591,150,446,447,592,592,447,447,636,403,149,759,446,447,447,447,447,636,758,3441,556,654,557,558,557,558,692,148,149,3768,331,1965,1286,603,602,603,603,1224,597,402,302,303,304,303,305,303,305,303,304,303,305,303,305,303,304,3482,429,149,591,994,1245,514,570,516,2257,601,603,602,603,602,603,1371,347,581,348,348,348,348,455,686,69,1084,439,440,859,1690,3053,3769,885,3770,1101,1565,2774,977,495,1744,497,659,3771,1761,3772,663,69,1708,376,1627,1331,1332,1332,1909,69,445,445,429,429,445,149,150,446,636,69,2053,460,179,147,597,502,634,1242,758,429,445,429,429,429,1704,990,3773,735,489,665,666,667,668,439,266,267,268,1814,1815,952,2331,2550,435,670,698,709,60,61,73,93,94,3774,66,67,1071,149,279,280,281,280,281,507,3775,810,809,809,809,1378,1379,1380,1081,69,270,271,1322,1015,1288,1289,825,1435,3468,1438,2684,549,1338,601,602,2527,2134,2453,480,2786,178,179,382,355,383,534,535,1759,2854,589,653,570,952,529,690,496,690,691,1178,601,603,603,603,603,602,603,603,602,1353,2662,497,498,617,480,2786,429,445,149,279,280,281,1350,3776,712,3350,2565,3777,454,2126,528,571,571,266,267,554,270,1322,688,495,496,690,1083,587,434,454,2163,971,3778,2286,1921,69,420,801,120,289,109,110,99,111,112,99,100,489,665,666,667,1514,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1040,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1694,237,743,744,188,189,190,745,80,1381,3779,440,859,860,1101,1101,1100,1100,1101,1101,861,330,332,333,410,3780,3781,3763,350,587,434,347,348,581,455,455,348,348,455,686,549,610,266,1041,1071,382,355,356,534,535,1242,1241,258,259,867,3782,668,439,669,179,346,319,1094,973,355,356,384,654,557,557,557,558,557,558,557,558,557,558,557,558,557,711,237,743,744,188,189,190,910,3783,777,846,616,690,690,691,782,2325,2087,2088,2343,2622,2356,597,402,302,303,304,303,548,549,708,725,439,266,267,554,1214,549,1922,854,629,190,1598,3784,1239,758,270,2240,1815,952,3259,237,238,184,185,186,240,188,189,239,185,186,239,1165,184,185,186,239,1165,1520,3785,3786,3787,375,376,377,3788,607,769,2605,687,980,779,780,781,781,780,781,1223,445,445,445,149,150,446,1728,778,781,1349,692,370,824,765,2387,2388,3789,3790,502,634,611,538,538,537,537,537,538,3221,769,770,3791,823,1965,545,2421,943,319,347,3792,616,691,793,150,446,447,447,2711,3793,3794,23,759,446,447,447,447,636,1216,737,738,2275,2785,352,798,172,382,1286,602,603,602,605,3795,3796,700,3531,510,278,150,446,592,447,512,549,1571,346,319,454,582,429,429,445,429,149,1522,280,281,280,281,563,632,54,55,2633,3797,3798,445,149,150,446,447,447,1812,714,1890,2577,735,216,1042,439,266,267,554,1814,2241,3469,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,548,549,1338,2345,2480,950,951,570,3435,641,657,1908,781,3799,3800,591,150,446,1787,3801,1840,528,2216,222,223,645,646,3802,1281,573,629,190,1554,1196,3803,990,1534,608,509,172,382,148,429,445,445,149,1847,401,356,502,634,538,536,537,538,1422,3224,659,974,645,3804,3805,1890,2714,2214,740,510,3806,3807,908,429,149,1522,280,281,280,679,712,712,3808,239,1165,2816,3196,455,528,3809,382,148,429,979,127,128,129,211,248,1967,483,484,485,486,1188,1189,447,447,447,447,447,512,637,382,510,278,759,3810,980,1765,918,502,634,611,538,538,3811,2111,1915,2050,1915,2051,1915,977,680,355,443,2995,390,391,494,616,2096,497,659,2253,2253,2255,1752,147,148,445,149,150,446,447,1787,3734,1498,3812,429,149,430,280,281,281,281,280,281,280,281,793,538,3813,810,809,1007,1031,333,1232,335,336,337,44,45,46,47,450,1200,3814,826,1282,829,830,831,832,832,832,832,832,832,1584,356,384,673,472,157,489,665,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,808,811,812,899,814,815,841,650,2664,1281,355,356,357,302,303,305,303,2295,1516,371,1505,616,497,2826,149,150,446,1444,527,1188,1846,280,281,280,281,280,281,280,655,513,526,545,1188,2249,231,232,1163,3815,401,383,402,383,402,302,303,548,549,708,1286,602,603,603,839,810,809,1007,1031,333,1232,335,336,337,44,45,46,23,779,3816,3817,149,2303,2304,2305,512,549,760,231,232,233,190,3818,556,507,454,581,348,686,549,1571,355,383,384,1784,711,653,570,2750,1544,333,410,335,3819,149,150,446,592,592,447,447,3202,401,383,556,654,557,557,557,557,557,558,557,558,557,3820,1821,347,582,671,2064,3821,54,3822,429,445,3823,3824,587,434,347,455,1027,403,732,1815,1658,54,55,56,3825,1663,697,769,770,2543,513,514,570,516,2530,2017,2826,665,735,489,490,216,449,439,838,23,2898,232,233,190,191,802,3750,1598,2360,498,2419,346,319,347,348,581,455,455,455,455,686,637,429,445,429,429,149,279,280,295,1616,1084,439,450,889,3826,460,179,180,2114,1199,2657,54,55,2040,2825,759,446,3827,616,1836,445,429,429,149,3828,840,809,809,1007,1031,333,410,418,47,1288,3829,3830,3831,1425,3557,3832,100,101,624,625,626,627,3833,3834,240,2328,2329,950,951,570,571,513,526,545,3154,180,606,607,545,1188,1199,348,728,549,1922,240,188,189,190,745,782,460,179,147,597,556,2940,105,1603,640,429,429,445,445,149,279,280,281,280,2775,346,319,347,456,455,455,348,348,455,695,490,216,1042,439,266,3835,3836,150,446,447,447,447,447,3837,384,654,557,557,557,558,557,558,557,557,557,558,557,558,557,3820,3838,2096,295,506,2850,977,1169,439,3839,442,237,238,184,185,186,187,188,189,3840,697,545,714,687,980,781,780,2423,149,591,1243,280,281,280,282,683,3249,3841,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,1924,3842,977,262,263,264,1595,642,3843,826,1282,829,3844,266,267,1387,193,3845,510,696,998,3452,928,565,2101,179,300,301,3846,477,2236,3847,492,172,180,181,233,190,3848,1254,3628,1538,3352,2079,3849,3850,23,1026,319,454,456,686,549,1093,179,147,597,402,302,303,305,303,788,549,1338,1171,608,170,171,172,231,232,233,190,1643,2886,2887,2888,985,3851,3852,601,602,603,603,602,603,602,603,602,603,602,603,793,402,302,303,305,303,305,303,304,303,304,303,788,549,1338,355,383,534,535,538,1472,549,760,601,602,2527,2134,3217,2340,2946,743,744,188,189,239,185,186,241,1981,952,3853,727,434,320,193,194,2378,2462,768,528,952,2332,2332,3854,2894,3855,1099,859,1101,860,1101,1101,1101,1101,1101,3417,592,3856,840,809,840,3857,2928,780,2369,2613,2369,498,1745,3858,142,147,532,526,545,742,492,172,382,401,356,502,634,538,611,537,663,664,1967,483,484,2374,54,55,633,2600,333,410,335,336,337,44,45,822,1402,601,603,603,603,602,603,602,603,602,603,602,603,602,603,3859,461,429,429,462,999,758,237,238,184,185,186,190,992,2270,1499,1555,211,3860,819,1516,742,1084,439,266,267,554,1806,350,382,401,383,3861,495,690,689,496,690,1281,187,188,189,240,188,189,190,3023,1409,1044,849,735,216,3862,3863,254,255,278,150,446,592,636,435,554,1672,549,1338,2746,1522,281,280,281,386,3864,768,3865,1320,577,578,123,124,125,1150,492,172,390,391,494,495,752,697,769,770,2657,54,1509,697,769,770,2543,1013,1013,1013,1013,1013,1014,510,278,150,3032,355,443,463,549,1922,1716,355,356,534,535,538,537,1395,3273,149,562,281,281,281,280,281,280,281,280,281,280,281,280,1774,180,181,233,3866,616,497,3867,3312,333,410,335,336,337,44,3868,130,384,1348,557,557,655,769,770,2110,502,634,538,536,663,69,453,319,454,457,2551,270,2240,3737,147,355,383,534,3869,3870,1424,3871,23,401,383,526,769,770,771,641,656,657,1908,2369,498,3872,154,135,136,137,138,139,136,137,138,139,1304,1885,382,401,383,556,654,977,429,445,429,429,445,149,3873,697,769,770,3874,518,384,559,560,561,147,510,278,591,150,446,2711,3875,482,483,484,485,2622,2356,180,181,1163,232,233,190,3876,656,642,434,347,528,2529,2627,266,267,554,1814,1815,952,2332,2332,2332,2332,2331,2426,305,303,305,303,304,303,548,549,1338,573,629,190,3877,2935,401,356,302,303,305,303,305,303,304,303,304,303,304,303,3878,149,511,446,592,592,447,592,592,512,435,455,2357,148,429,3879,921,967,3089,224,216,449,439,669,179,346,319,1094,2956,786,787,2411,181,233,190,1549,2335,819,3224,3880,586,565,2101,934,1473,1474,3881,785,3882,1573,731,1387,2335,429,429,429,445,429,429,445,445,3883,838,23,687,980,781,779,780,781,780,3884,355,383,534,535,611,538,538,538,538,3811,362,216,1042,439,266,267,1387,193,194,2789,1921,664,1287,3885,453,476,2195,2196,2296,3527,347,455,581,348,348,1318,490,216,1042,439,450,1200,1832,3886,261,836,837,262,263,264,265,266,267,554,1244,69,450,889,891,3887,1188,2249,460,179,147,518,534,535,537,1395,549,1338,266,267,1920,2007,3888,727,434,347,581,455,455,686,69,510,696,696,3889,727,434,454,455,970,1318,840,840,809,809,809,809,809,840,809,810,809,1949,1950,1562,3890,1424,300,301,2480,950,951,515,571,2323,23,654,557,557,557,558,557,558,557,558,557,558,557,558,557,1275,370,433,434,347,455,528,515,2718,485,486,1632,333,334,335,336,337,44,45,1006,3891,2840,611,538,538,538,537,537,537,537,537,663,403,172,390,391,494,2533,1083,280,1281,149,2303,2304,2305,447,592,592,447,592,592,447,512,403,149,759,446,592,447,447,447,512,69,2224,2056,149,759,3178,549,1313,382,148,854,574,2768,2270,1499,1555,130,779,780,780,780,780,1751,1836,777,846,616,505,690,690,690,690,690,295,506,401,383,556,557,557,558,557,558,559,560,918,1171,1890,769,770,2744,352,776,146,147,597,519,1192,3892,145,146,147,148,854,574,2534,3893,1248,180,181,1163,232,233,190,469,2270,1499,1555,211,3894,737,738,2134,2453,480,2454,3895,554,270,2510,549,1338,537,799,403,149,759,446,447,592,592,447,1204,149,279,281,281,280,281,280,281,280,281,280,281,2452,657,658,1131,240,1174,1228,563,727,434,347,945,1318,696,712,712,278,591,150,2350,401,383,556,558,557,558,561,1573,731,554,1626,445,445,429,149,1522,280,281,280,281,295,1616,401,383,502,634,611,537,1759,331,266,267,268,1294,270,726,1455,390,3794,23,808,811,812,899,814,924,179,2323,724,3896,3897,3898,2252,2106,483,484,485,2505,2297,1518,950,951,3899,727,434,454,455,944,350,318,319,454,3117,713,197,145,146,147,148,445,1760,346,319,347,581,348,348,455,348,686,331,150,446,447,1787,537,2057,2702,533,2581,172,390,391,494,3094,346,319,347,348,581,455,455,348,348,1215,69,1549,193,3900,383,556,654,557,558,557,558,557,558,557,558,1351,533,502,634,611,538,538,537,537,538,538,537,2837,1077,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,2927,977,1815,1658,54,55,2586,698,532,514,570,952,529,149,150,446,592,592,636,549,2830,429,429,429,445,445,429,429,445,149,3901,1086,333,3902,233,239,1165,2816,3903,3904,3905,3906,149,279,280,281,280,281,1211,608,460,1120,1121,68,350,527,519,520,2557,587,434,347,581,348,455,3907,1281,147,510,1639,1056,502,634,611,538,538,537,2349,698,450,1200,1831,3908,680,1029,696,697,545,2803,921,967,3669,2669,180,181,1163,232,233,190,245,1409,987,2881,591,3909,148,445,149,3910,150,446,447,447,447,447,592,592,447,447,512,549,1338,445,429,3112,991,2089,54,55,633,1562,765,1596,1628,433,434,454,1822,549,1028,450,3911,1568,534,535,537,3813,2017,2315,2316,3912,224,216,1042,439,2439,2440,440,859,1927,711,266,267,554,1214,549,2863,2073,616,1353,641,2061,2062,2195,2196,2343,2622,2697,375,2846,3913,386,687,688,495,690,1342,605,148,445,670,769,770,3205,207,208,388,3904,3905,3914,445,429,149,1522,280,281,281,281,280,281,280,563,382,355,383,357,357,302,303,304,303,305,303,548,403,355,383,526,545,2894,147,401,383,519,990,1804,1363,2053,300,301,2480,950,951,515,571,390,391,494,495,2096,497,2268,2253,2253,2254,2255,640,510,573,574,850,1409,1044,2098,429,445,429,979,562,281,281,280,281,280,281,280,281,280,281,280,281,280,507,390,391,494,495,690,1083,689,1222,178,179,147,1286,602,295,2871,2073,495,497,659,3915,356,1976,1408,1887,916,917,746,1706,2721,460,179,147,461,445,445,149,562,281,2045,149,1243,281,280,281,280,281,280,1211,346,319,347,1215,435,785,786,3908,936,3916,3917,523,44,45,524,640,357,3918,3154,347,348,581,455,455,455,455,686,549,1571,429,429,445,445,429,149,591,150,446,447,447,636,637,180,181,1163,232,233,190,1931,2270,1499,1555,1218,2925,545,1188,2249,645,646,647,648,649,650,2664,3919,401,383,402,383,402,302,303,304,303,304,303,304,303,304,303,548,549,1922,268,269,1433,1007,1031,333,1232,335,336,337,44,45,46,47,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,1007,1031,333,1232,335,336,337,44,45,46,23,519,3338,3920,460,179,147,518,384,654,557,1351,489,490,216,1042,439,266,267,1276,1984,154,135,136,137,138,139,136,137,138,139,1304,2876,251,1073,386,233,190,1598,2360,2200,329,216,449,439,266,267,554,2251,637,666,667,725,439,266,267,1387,193,194,195,3921,297,803,518,534,535,611,538,1422,429,445,149,150,446,592,592,447,636,713,3922,1644,2455,3923,430,281,280,281,563,3689,3924,510,696,696,712,696,696,3689,3925,239,948,949,950,951,570,1658,331,240,1174,744,188,189,241,2056,182,183,3490,3926,1031,333,410,2667,375,2846,3927,3928,295,2540,589,670,545,2314,238,184,185,186,187,188,3929,355,383,534,535,1242,549,1093,1821,347,348,348,1109,671,346,319,347,455,581,348,1215,69,916,860,3417,357,302,303,304,303,305,303,305,303,598,2233,2234,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,3789,3930,1169,439,266,267,268,270,2493,549,1338,564,565,2101,179,390,391,392,149,511,446,447,447,592,592,447,512,549,1313,485,2505,2749,533,2581,148,429,149,430,280,281,280,295,1616,581,455,528,571,440,916,1101,3456,295,506,300,2345,358,3362,3931,1544,333,410,3247,3932,147,510,278,279,563,460,179,147,461,149,591,1310,101,162,163,3091,3933,396,265,266,267,554,1294,726,1241,3139,3934,179,300,2689,1984,149,562,281,281,281,281,280,281,281,281,280,281,280,1245,3935,1543,700,3936,672,281,281,280,918,443,2091,769,770,2543,346,319,454,348,581,1215,325,347,348,455,581,686,403,429,149,150,446,2306,485,486,810,1007,3388,1009,973,690,3604,561,3937,2536,303,304,3938,631,571,251,465,1178,241,185,186,239,185,186,241,1165,184,185,186,239,2056,743,744,188,189,187,188,189,240,188,189,190,1190,556,558,1635,2893,445,445,429,149,511,446,447,512,549,1028,3939,347,456,686,549,1093,1706,3428,445,445,149,562,281,977,509,172,3462,777,846,616,496,691,1245,401,383,502,634,611,538,537,538,538,663,637,686,549,2863,2017,147,148,501,3940,3941,541,756,268,3942,147,401,356,556,1348,557,557,295,1616,1692,216,3943,3944,934,3945,1436,1438,3946,304,303,304,303,304,303,304,303,304,1884,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2312,1026,319,1094,3235,3947,3025,860,2128,746,510,696,278,1522,1411,2405,950,951,570,516,2460,1112,2843,3167,3948,69,1690,1101,1565,2134,2339,618,418,973,519,520,1331,521,522,523,44,45,1545,589,653,570,571,736,934,3949,134,216,1042,439,266,3950,23,1967,483,484,485,486,445,445,429,149,759,446,447,447,447,447,1787,1638,172,382,510,2024,602,3951,3533,670,3817,2108,1690,1100,1100,1101,1994,231,232,233,241,1165,1938,752,3952,422,3953,3954,986,1044,2098,148,149,279,280,281,280,281,280,281,280,673,558,559,385,563,601,602,673,485,3441,332,333,334,335,336,337,44,45,524,561,191,192,193,194,2789,147,518,534,535,537,1395,758,401,383,526,608,1268,1269,184,185,186,241,2056,3732,1296,422,1023,1877,2069,644,222,223,645,646,647,648,3955,3956,1555,1388,896,807,2053,515,1658,54,3957,502,634,536,537,538,663,835,1973,449,439,669,179,390,391,3059,597,519,520,1332,521,522,523,44,45,1346,1572,149,279,280,281,280,281,280,281,280,1281,502,634,611,537,663,637,3958,402,302,303,304,303,304,303,304,303,304,303,304,303,548,758,3154,2336,457,105,294,295,296,3148,180,181,182,183,184,185,186,241,3959,777,846,616,2660,1403,319,320,3960,2274,738,2784,2277,2277,2276,2276,2277,3961,3962,2073,495,690,496,496,690,690,496,1461,2474,187,188,189,239,185,186,190,745,80,1780,742,2622,3048,2343,486,2347,179,390,391,494,616,3963,636,637,3214,3964,271,2286,1921,435,1692,216,542,1012,1013,1013,1013,1013,1763,3616,526,545,3584,178,179,231,232,921,1560,744,188,189,241,1165,184,185,186,239,1165,1561,2537,180,181,233,190,992,2270,1499,1555,211,755,613,685,434,347,455,528,515,2495,669,179,390,391,494,3965,747,2180,2179,2180,2179,2180,2179,2179,2179,2180,2179,2180,2179,2180,1222,2356,3966,429,149,591,672,752,1632,333,410,418,985,545,742,430,280,281,1774,537,1759,549,1313,526,608,366,375,3967,401,383,402,302,303,548,69,810,809,1007,1031,333,410,418,47,1472,549,1922,142,735,216,736,179,147,3706,1455,1059,1060,1979,80,1941,3020,239,948,949,950,951,570,516,2257,149,279,280,281,280,281,280,281,281,281,280,281,1036,1406,558,1371,401,383,556,654,557,558,557,558,557,557,558,282,712,712,712,2520,573,629,190,2412,1196,1197,3968,1573,731,554,270,1294,271,271,272,69,756,268,1294,270,270,270,271,726,549,1338,3969,533,3380,429,429,445,429,149,430,280,1178,768,1822,664,1493,1494,1687,1719,180,181,182,606,607,2713,460,179,147,461,462,999,435,628,146,346,319,454,455,2146,413,149,759,446,447,636,549,708,660,2470,80,1829,149,759,446,592,512,549,1313,259,260,261,262,263,264,553,439,266,267,883,3970,132,148,429,445,429,429,445,149,150,446,2712,591,150,446,447,3971,591,672,280,3096,2992,511,446,447,592,592,636,549,3972,131,2359,3973,1281,140,141,680,346,476,477,2236,3761,2027,743,744,188,189,190,2768,470,3974,2061,2062,2195,2196,2343,3975,2941,3976,1413,149,591,150,446,447,447,592,592,447,636,426,583,2134,3977,320,193,194,3978,1323,1744,497,498,1745,442,3979,3980,211,3047,266,1366,254,985,1169,439,266,267,554,1244,69,1314,128,3981,713,777,846,2073,495,690,690,690,496,496,496,496,679,2175,2176,498,1745,1178,3982,988,3983,287,288,387,216,449,439,3984,482,483,484,485,2089,2129,382,148,149,279,280,281,281,281,280,281,1211,346,319,347,581,348,348,455,455,455,455,686,69,2105,429,429,445,429,149,430,280,281,280,746,1579,340,340,340,3985,2470,2002,3986,1224,300,301,3987,759,446,592,592,447,512,69,776,727,434,454,581,455,455,348,348,455,348,348,455,455,1215,549,1313,636,549,1922,432,371,372,3988,780,781,781,1751,563,1575,1265,303,548,403,2343,2505,2506,1654,1498,1499,2970,3989,430,280,281,281,281,3096,300,301,302,303,304,631,570,952,3990,1314,3991,1836,251,332,333,334,335,336,1715,489,665,735,216,542,1693,1693,1012,1956,3063,2966,774,23,401,383,502,634,611,538,538,537,538,538,537,537,537,539,252,253,68,69,1339,463,350,571,68,350,366,3507,1375,333,410,418,255,3992,1764,389,934,1473,1474,3993,193,3717,280,281,281,281,280,281,280,839,1658,54,55,3994,3995,542,1693,1693,543,805,445,429,149,591,150,446,447,512,2770,1706,3996,1528,1839,382,532,3997,815,3998,47,355,383,3148,532,3656,172,346,319,1821,347,348,455,1318,601,602,603,603,603,602,603,603,603,602,603,602,603,711,347,455,1149,403,508,317,703,146,147,510,1639,3999,601,603,602,603,602,603,295,982,4000,1018,1019,1020,507,492,172,390,391,494,495,691,692,445,445,445,149,2909,4001,590,2675,792,1178,2279,4002,23,2126,1822,331,104,135,136,137,138,139,140,4003,4004,2162,483,484,485,2773,346,476,477,2064,4005,316,317,345,509,172,346,319,347,1215,549,610,4006,401,383,502,634,536,4007,149,1522,281,281,281,280,281,281,281,280,281,280,1510,1188,1846,1835,558,557,558,557,558,557,558,557,557,977,608,486,346,319,347,348,455,581,455,455,455,686,2083,149,150,446,447,447,447,447,4008,316,317,345,509,172,4009,498,4010,382,355,383,534,535,663,549,1338,727,434,347,348,581,1215,69,545,1188,1846,2185,4011,2214,2453,2936,241,185,186,239,185,186,190,745,4012,492,1288,765,1290,1291,523,44,45,4013,491,145,146,231,232,233,190,4014,3722,1499,4015,4016,149,279,281,280,1245,454,581,686,549,1338,783,570,1658,54,2839,2145,355,383,384,557,2265,295,1911,149,150,446,447,592,592,447,447,636,549,800,659,660,4017,149,672,281,1836,616,496,3384,673,742,346,319,347,455,528,515,2503,357,1396,549,800,537,538,538,537,537,537,663,758,429,429,445,445,445,149,150,446,512,435,1949,1950,1223,352,798,172,382,148,854,1871,979,2677,1026,319,454,348,1027,637,147,401,356,502,634,536,538,537,537,663,69,4018,148,429,429,445,149,279,280,1222,510,696,696,4019,1562,3451,255,1675,1676,618,782,445,445,429,429,429,4020,597,502,634,611,537,1759,69,347,768,528,952,2550,2854,429,429,445,149,150,446,512,69,1086,333,1232,418,255,401,356,502,634,663,413,671,149,279,280,281,280,281,605,1007,1031,333,1232,335,336,337,44,45,46,47,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,811,812,899,814,815,816,817,333,410,335,336,337,44,45,1006,549,1338,980,2006,1222,628,727,434,320,193,194,1577,2055,2343,2505,3102,756,554,271,1672,549,1338,2863,240,2328,2329,950,951,515,2503,355,383,534,535,611,538,537,537,537,537,537,537,537,1422,538,538,538,537,537,538,538,537,537,1759,549,1313,844,938,4021,3025,602,2527,2134,2453,2954,1461,591,672,280,281,280,281,280,281,280,281,280,2018,1642,4022,545,671,533,599,977,534,535,611,537,538,538,537,537,537,2349,1065,4023,193,194,195,2435,356,357,302,303,788,403,2478,570,516,2460,149,759,446,592,447,447,447,447,3837,3280,1120,4024,4025,340,340,340,340,340,1546,340,340,340,340,3430,2286,1815,1658,54,1659,330,3111,369,1518,1422,1171,472,157,216,449,439,669,179,346,319,347,455,643,457,460,179,147,597,556,1348,557,558,622,538,611,538,538,537,663,549,1338,545,1188,2249,518,534,535,611,537,537,538,538,537,537,537,3183,142,1188,2249,278,150,446,592,636,1455,2483,1135,1099,859,860,1101,1101,1100,1100,282,657,658,495,497,498,499,465,295,2540,943,319,347,455,4026,2243,527,1007,3388,2143,193,194,3389,537,950,3659,950,951,952,3259,352,798,172,180,181,233,187,188,561,247,3187,718,4027,589,670,545,661,665,666,667,2347,179,147,737,738,4028,4029,237,743,744,188,189,241,185,186,239,185,186,190,745,80,1381,4030,1499,1555,130,782,591,1243,281,281,280,281,281,281,280,281,640,1059,1361,442,4031,1564,916,1565,2517,1565,2275,2277,2277,2276,2277,2277,2276,2276,4032,373,497,498,617,618,485,486,1519,303,304,303,305,303,788,835,687,688,2073,616,1350,810,809,840,840,809,809,809,809,809,840,809,809,1949,366,737,673,472,157,216,449,439,669,179,346,319,1094,1010,2325,2087,2088,485,486,2345,2480,950,951,570,516,2373,1179,3558,901,902,303,305,303,3753,69,4033,23,510,696,2136,990,3773,587,1491,724,150,446,592,592,447,592,592,447,1787,410,335,336,337,44,45,3316,2529,2570,180,181,233,190,745,80,4034,180,181,1163,232,233,190,992,2270,1499,1555,211,820,570,571,685,434,347,455,528,570,2503,1073,282,401,443,463,549,1338,149,759,446,3202,100,565,4035,4036,1294,270,1815,516,529,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,833,382,355,383,357,295,1911,2325,2087,2088,2326,4037,2470,2002,651,603,373,737,738,2784,2277,4032,1222,3975,1954,1017,430,281,281,280,281,280,1211,2314,632,637,239,1165,184,185,186,241,1165,1520,2440,642,434,454,528,570,952,3525,4038,1121,68,69,429,429,445,429,429,462,4039,237,743,744,188,189,239,185,186,190,910,802,80,4040,456,686,549,1338,2446,455,2163,971,251,465,977,589,670,769,770,2543,1835,558,1718,278,591,672,295,982,4041,541,355,383,357,383,384,558,559,385,1245,519,990,1804,1804,1804,3773,146,147,148,149,511,446,447,512,403,2600,333,410,3247,4042,231,232,311,181,233,239,1165,2921,549,1922,1294,726,549,800,3324,735,216,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,148,445,149,4043,2380,66,93,94,4044,1314,1544,333,1232,418,1402,562,281,281,281,280,281,280,281,280,295,1616,838,23,2563,496,1744,2441,995,996,299,2750,2069,4045,222,223,645,646,4046,373,382,355,383,534,535,536,663,758,228,2166,774,23,148,429,429,149,150,3032,645,646,4047,537,538,538,537,538,538,2715,1696,938,939,211,212,952,4048,2309,456,348,348,348,455,1457,2127,2244,2158,149,591,150,446,512,549,1028,3148,4049,4050,4051,231,4052,713,816,1226,1182,347,2146,350,783,570,1658,54,55,4053,700,4054,180,181,233,190,191,4055,601,602,603,603,603,602,603,602,603,602,603,1178,712,278,759,446,592,2711,1442,248,429,149,591,150,446,636,549,1313,592,592,447,447,447,447,512,549,2147,696,712,998,999,69,240,188,189,240,188,189,190,1643,2886,471,1871,2725,1100,1101,1100,4056,295,506,348,348,348,2313,1356,2963,2964,1155,3019,3154,356,519,2287,756,554,4057,4058,597,556,558,1371,101,624,625,626,627,628,727,434,347,455,1502,614,615,616,496,497,4059,1268,1971,744,188,189,241,1165,184,1981,267,268,1294,4060,346,319,320,193,194,3348,1288,765,1596,1909,758,383,502,2198,1637,23,324,4061,240,2328,2329,950,951,570,571,149,751,442,680,179,147,518,384,654,1353,429,149,672,280,281,280,281,1211,356,1281,1026,319,347,686,637,773,774,23,589,670,545,3584,240,188,189,190,1643,1044,4062,589,653,570,571,346,319,347,348,581,1215,637,149,511,446,592,447,447,592,636,69,534,535,538,611,538,538,538,537,537,537,663,549,1338,149,150,446,592,592,447,447,447,447,636,549,1093,2657,54,2839,2145,356,384,1348,977,390,3794,23,429,429,149,150,446,592,592,636,664,1514,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1763,4063,556,557,654,557,558,557,558,1351,778,779,780,781,781,780,781,282,1908,2369,498,617,4064,4065,496,2096,782,728,549,4066,170,1585,439,266,1041,68,435,4067,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1956,482,483,484,2326,587,434,347,455,581,455,455,686,403,510,998,463,435,382,148,445,445,429,1704,3338,4068,1893,774,23,1906,333,410,335,336,337,4069,456,686,549,1338,370,433,434,454,3907,2559,605,514,570,3115,347,455,528,570,516,2627,149,150,446,512,69,838,23,1188,1846,4070,23,608,278,591,150,446,447,592,2121,3875,537,2349,3145,1138,713,451,1832,2190,2555,4071,1920,271,2484,713,1304,1305,1312,1783,495,2096,497,498,2127,1026,319,454,348,349,549,1922,266,267,554,1214,350,382,148,445,149,150,446,447,592,512,69,4072,769,2678,4073,2314,653,1658,4074,1114,23,1667,3874,461,445,445,429,149,4075,1518,4076,1241,2075,356,384,654,557,295,982,455,944,549,1571,1586,193,194,2789,401,383,502,634,2188,419,238,184,185,186,187,188,189,240,188,189,3545,698,224,216,449,439,266,1366,254,985,820,671,601,602,603,603,602,603,602,603,602,603,602,603,602,711,445,445,149,279,280,281,280,281,442,2079,4077,1872,502,634,537,536,663,4078,592,592,447,592,592,2874,4079,324,3248,510,696,1343,402,302,303,304,303,305,303,305,303,304,303,305,303,305,303,304,303,548,549,4080,590,1769,180,181,233,187,1174,1228,295,506,1114,23,382,510,573,2905,4081,172,382,355,356,384,557,654,655,239,185,186,240,188,189,190,3023,1247,987,3060,355,356,534,535,2349,2185,1611,2404,860,1100,1100,1100,1100,1101,1101,4082,401,383,383,502,2005,23,1846,1325,1524,3299,149,1522,280,295,506,2453,4083,4084,71,73,74,66,1420,1421,549,2833,269,270,270,1322,429,429,445,429,429,149,150,1811,1949,1323,348,2126,1822,549,2617,808,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,809,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3229,2724,810,840,810,809,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,809,1007,1031,333,410,418,3235,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1031,333,410,418,973,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,810,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,973,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,4085,810,809,809,1007,3388,1009,973,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,973,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,1031,333,410,418,23,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,809,1007,3227,2597,4085,810,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1031,333,410,418,23,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,809,809,809,1007,1008,1009,47,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,809,809,809,809,1007,3227,2597,3228,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,3231,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,3231,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,1007,1031,333,410,418,973,1579,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,4086,4087,1078,1546,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1517,1078,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1078,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,340,1079,4088,810,810,809,809,809,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,4089,1078,1546,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1546,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,2036,101,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,113,152,249,250,101,283,284,285,286,467,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,567,568,3556,4090,161,328,329,101,472,157,275,473,474,475,179,180,606,2478,570,571,326,327,99,201,202,203,204,594,595,596,379,169,178,179,147,148,149,562,281,295,506,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,117,113,152,249,250,101,114,119,120,121,109,110,99,111,112,99,100,227,123,124,125,126,145,146,147,355,356,384,1784,1350,101,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,109,1074,1323,102,103,104,135,136,137,138,139,140,141,959,114,119,120,121,109,110,99,111,112,99,100,133,123,134,101,102,103,104,135,136,137,138,139,140,141,959,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,310,146,147,510,696,696,696,696,696,696,278,430,280,673,122,123,124,125,126,145,146,147,510,712,278,672,280,281,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,280,281,280,442,99,113,489,665,735,216,736,179,382,589,4091,637,156,157,101,283,284,420,801,120,289,109,110,99,111,112,99,100,101,102,103,467,104,135,136,137,138,139,140,141,959,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,492,172,382,401,383,502,634,611,663,1368,351,178,179,382,510,696,696,696,696,278,150,446,447,1731,143,144,125,126,145,146,147,355,383,357,1396,549,1338,197,492,172,382,401,356,402,302,303,304,303,548,549,2863,330,1073,1275,201,202,203,204,584,585,586,1374,222,223,224,216,449,439,669,179,382,355,443,999,1368,225,226,120,289,109,110,99,111,112,99,201,202,203,204,313,314,315,379,169,1076,726,1368,285,286,467,104,135,136,137,138,139,140,141,959,367,368,369,400,179,346,319,454,455,2425,4092,500,146,147,510,712,712,696,278,672,281,280,281,280,281,280,281,280,281,280,281,280,281,281,280,281,280,281,280,1178,808,811,812,899,814,815,900,901,1265,303,903,303,4093,808,1007,1031,333,1232,335,336,337,44,45,46,47,110,99,111,112,99,100,158,123,124,125,126,159,128,129,4094,276,179,346,319,347,455,2146,758,355,356,356,356,534,1636,2618,1099,916,1101,917,977,367,368,399,400,179,382,510,696,696,696,712,696,696,696,696,696,278,1243,280,281,280,281,280,281,295,506,101,225,226,120,289,109,110,99,111,112,99,113,101,947,226,120,121,367,368,399,400,179,231,232,233,190,1967,483,484,485,3441,117,201,202,427,428,99,111,112,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,330,332,333,410,335,2870,161,328,329,101,472,157,206,488,101,114,119,120,121,109,110,99,111,112,99,100,152,153,103,104,135,136,137,138,139,140,141,959,117,794,795,707,99,111,112,99,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,609,169,237,743,744,188,189,239,185,186,241,1165,3173,117,113,101,283,284,420,801,120,289,367,368,369,453,319,347,1132,637,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,683,152,153,103,291,292,324,253,254,419,133,123,134,101,102,103,291,292,324,253,254,255,251,465,752,249,250,101,114,119,120,121,367,368,369,400,179,382,510,573,4095,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,145,146,147,510,696,278,759,446,447,636,549,708,866,99,258,259,260,261,4096,3955,4097,109,110,99,111,112,99,100,227,123,124,125,126,228,943,319,347,581,455,1109,351,229,1015,172,382,355,383,534,535,538,536,537,537,1759,1455,472,157,275,473,474,475,179,147,532,526,698,153,103,104,135,136,137,138,139,140,141,959,947,226,120,121,109,110,99,111,112,99,161,101,162,163,164,165,577,578,123,124,125,579,580,345,509,172,382,510,1639,463,69,330,332,333,334,335,336,337,44,45,822,255,109,110,99,111,112,99,100,489,665,735,216,736,179,382,589,4098,367,368,399,400,179,231,232,233,190,245,1409,1044,1655,203,204,458,459,169,352,776,727,434,1821,454,686,549,1571,251,465,1281,374,229,1015,172,382,148,429,149,511,446,447,447,447,447,636,69,399,1130,1383,1623,4099,159,128,129,131,212,382,355,383,534,535,536,537,537,538,537,663,549,1338,808,811,812,899,814,924,179,346,319,347,581,348,455,455,455,455,1109,1775,1158,1594,396,553,439,669,179,346,319,4100,808,811,812,899,814,924,179,390,391,494,616,976,295,506,182,606,2150,3670,361,619,620,169,417,2365,637,113,489,665,735,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,285,286,467,104,135,136,137,138,139,4101,330,1073,782,467,467,104,135,1493,2876,154,135,136,137,138,139,4102,1074,1323,140,141,959,156,157,489,665,735,216,736,179,147,4103,68,4104,104,135,136,137,138,139,140,141,959,102,103,467,467,467,467,467,104,135,136,137,138,139,140,141,959,101,114,119,120,121,109,808,1007,1916,977,367,368,399,400,179,147,510,278,150,2087,2088,485,2505,2697,102,103,291,297,298,4105,995,1052,1074,366,4106,310,146,231,232,233,190,1643,1044,1045,178,179,147,355,356,384,654,557,557,558,557,558,557,558,1351,460,179,147,277,278,2248,815,816,1226,1182,454,581,1318,168,169,1314,3991,507,197,145,146,147,355,356,534,535,536,537,537,1759,331,243,244,166,167,662,169,237,743,744,188,189,241,185,186,239,185,186,190,4107,156,157,152,954,955,1673,673,275,473,474,475,179,147,513,526,545,742,954,955,1324,333,410,1329,909,146,231,232,233,190,1654,1498,4108,1077,1546,340,340,340,340,340,340,340,2927,640,258,761,867,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4109,492,687,688,495,496,1960,1350,638,169,178,179,382,355,383,384,654,373,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1448,1413,211,2404,1107,29,1456,101,162,163,796,216,449,439,669,179,346,319,454,455,455,349,549,800,260,261,836,837,262,263,264,265,266,267,268,2251,835,147,355,383,526,769,770,2408,156,157,101,114,119,120,121,367,368,369,641,4110,823,352,600,172,382,1286,603,602,1350,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,131,1716,154,135,136,137,138,139,136,137,138,139,1304,1305,1782,3019,134,216,1042,439,266,267,268,270,269,726,403,161,328,393,394,395,396,531,146,390,391,494,495,1744,497,659,2255,295,982,1003,1004,1264,253,254,984,819,4111,961,962,963,135,136,137,1287,139,140,141,1742,567,568,1425,4112,514,515,516,2570,587,434,454,457,472,157,101,624,625,626,627,628,777,846,495,496,3470,432,371,1505,3555,429,149,672,442,115,1046,4113,4114,2563,1403,467,1506,1178,4115,809,809,811,812,899,814,924,179,390,391,494,616,679,237,238,184,185,186,240,188,189,239,185,186,190,3023,1409,4116,297,436,1538,2207,909,146,147,355,356,302,303,305,303,305,303,304,303,304,303,548,1368,239,185,186,240,188,189,241,3959,1553,152,961,962,963,135,136,137,1287,139,140,141,959,2014,208,2015,388,1167,1693,1693,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,467,467,467,291,1675,4117,130,161,328,393,572,489,665,735,216,449,439,669,179,346,319,1094,23,229,1106,172,390,391,494,616,496,925,357,302,303,304,303,304,303,305,303,304,303,4118,147,355,383,384,1348,557,558,373,291,292,324,253,68,549,2147,510,278,562,281,280,281,280,281,280,281,281,280,281,280,281,561,995,996,1568,815,816,1226,1182,347,581,348,455,455,455,455,686,549,800,2106,483,484,485,2197,113,101,114,119,120,121,1037,1031,333,1232,335,336,337,44,45,1398,54,4119,961,962,963,135,136,137,138,139,140,141,959,100,101,624,625,626,627,1179,1180,1181,1182,347,1239,403,467,467,467,467,3289,815,841,650,2003,673,743,744,188,189,239,185,186,240,188,189,190,1828,4120,115,1046,1047,1048,1049,1337,1281,375,1462,1463,1683,4121,4122,4123,442,1212,1213,267,554,1322,1317,4124,401,356,502,2198,1637,23,564,216,542,1012,1013,1013,1013,1013,1614,4125,712,712,696,696,696,278,430,280,281,1752,203,204,458,459,169,460,179,147,597,556,1348,557,558,557,558,692,102,103,104,135,136,137,138,139,140,141,959,104,135,136,137,138,139,140,141,959,367,368,369,2132,4126,692,988,4127,269,271,270,270,270,271,270,270,272,549,1338,293,4128,489,665,666,667,730,731,268,865,758,251,465,1281,180,181,233,190,986,1940,156,157,101,624,625,928,206,207,208,388,936,937,938,939,4129,118,119,120,121,109,110,99,111,112,99,100,133,123,134,216,1042,439,838,23,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,564,216,1042,439,4130,240,188,189,239,1165,184,185,186,190,4131,756,268,269,271,271,270,270,270,271,726,331,251,332,333,410,335,411,412,637,147,510,712,712,573,574,575,192,193,194,1577,1942,572,489,665,735,489,665,735,216,1042,439,266,267,554,732,1921,549,1313,145,727,434,347,581,348,455,455,455,455,1215,1241,641,642,434,454,686,403,2079,4077,4132,175,387,216,3940,178,179,147,510,278,4133,2304,2305,636,549,3972,367,368,399,400,179,180,181,2424,549,1922,109,110,99,111,112,99,100,158,123,124,125,126,492,172,382,401,383,556,558,1351,961,962,963,135,136,137,138,139,140,141,959,178,179,382,148,149,150,446,447,512,4078,1005,333,334,1329,382,4134,140,141,1095,522,523,44,45,524,640,4135,4136,4137,400,179,382,148,854,629,190,4138,883,4139,956,4061,3557,4140,454,686,331,109,808,811,812,899,814,924,179,390,391,494,495,690,1236,752,159,128,129,131,820,1116,394,395,1594,396,4141,1451,1107,29,104,135,136,137,138,139,140,141,680,900,901,1265,303,903,303,304,303,305,303,304,303,1527,104,135,136,137,1287,139,140,141,680,1074,1323,143,144,125,126,492,687,688,616,689,496,690,496,496,691,752,2070,2071,2747,3227,4142,4143,230,146,147,401,383,502,634,537,4144,4145,4146,4147,4148,610,148,429,854,574,3411,99,113,101,283,284,285,286,467,467,104,135,136,137,138,139,140,141,1449,680,382,737,738,2134,2453,618,584,585,586,1374,222,223,224,216,449,439,669,179,147,148,445,1704,3338,4149,460,179,300,301,358,2695,2695,359,359,359,360,549,800,1673,295,466,147,510,278,430,280,281,280,281,280,3096,113,565,1978,23,1493,1305,4150,386,222,223,224,221,222,223,224,216,542,1693,4151,2243,352,791,172,147,148,979,1600,1601,1602,135,136,137,138,139,140,141,680,4152,295,1250,326,327,99,201,202,203,204,594,595,596,316,317,703,146,346,319,1821,347,348,1215,549,708,662,169,352,776,777,778,779,1751,692,680,841,2002,3051,1455,1013,1013,1013,1013,1039,1968,216,1042,439,838,23,467,104,135,136,137,138,139,140,141,680,1304,1305,1306,549,610,1320,330,332,333,410,335,411,412,69,1721,254,255,276,934,2490,4153,4154,148,445,854,1970,104,135,136,137,138,139,140,141,959,1171,1120,1121,68,713,173,3515,510,696,278,591,672,280,281,280,281,281,280,281,280,281,280,692,1169,439,4155,23,104,135,1493,1494,797,169,352,798,172,382,401,383,383,402,1396,758,332,333,410,335,411,412,69,150,2632,465,561,980,918,467,467,291,292,324,253,68,1241,3047,2035,1546,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,1548,2070,2071,2747,1031,333,410,418,47,161,328,329,101,225,226,120,121,109,110,99,111,112,117,113,101,283,284,285,286,104,135,136,137,138,139,140,141,959,201,202,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,99,113,101,102,103,104,135,136,137,138,139,140,141,959,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,182,606,2224,4156,117,161,101,225,226,120,121,109,110,99,111,112,99,201,202,243,244,166,167,662,169,1665,333,3246,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,102,103,104,135,136,137,138,139,140,141,959,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,508,317,345,509,172,382,148,429,149,150,446,592,592,636,549,800,203,204,458,459,169,460,179,147,461,445,445,429,462,999,835,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,665,735,489,665,666,667,3170,333,1232,335,4157,117,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,1171,161,101,225,226,120,121,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,145,146,147,355,383,384,654,557,1281,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,460,179,147,461,445,445,445,429,149,1522,280,281,280,281,752,99,113,101,225,226,120,121,109,110,99,111,112,99,100,3187,718,4158,4159,472,157,473,474,475,179,382,513,526,545,2421,161,101,102,103,104,135,136,137,138,139,140,141,959,508,317,703,727,434,347,348,581,348,348,455,455,455,1215,549,2617,367,368,399,400,179,382,510,278,150,2087,2088,2343,3264,113,122,123,124,125,126,500,146,147,510,278,4160,102,103,104,135,136,137,138,139,140,141,959,167,662,169,170,1585,439,266,267,554,269,270,2615,1573,731,268,269,270,1488,276,179,346,319,347,1109,101,624,625,626,627,1179,1180,1181,1182,454,728,403,1116,572,489,490,489,665,666,667,797,1084,439,669,179,346,319,347,348,455,455,944,403,99,258,761,260,261,262,263,264,553,439,838,23,472,157,206,488,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,2797,328,329,101,225,226,120,121,367,368,399,2132,2133,2784,2969,203,204,175,176,177,169,352,791,172,382,597,502,634,1103,435,225,226,120,121,109,110,99,111,112,99,100,227,123,124,125,126,228,1099,916,3367,3368,3369,3370,367,368,399,4161,703,146,390,391,494,2073,495,4162,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,382,401,356,502,634,611,1422,490,227,123,124,125,491,492,172,382,401,383,556,558,557,558,559,385,2814,367,368,399,400,179,180,181,233,190,2325,2087,2088,485,486,162,163,164,165,361,619,620,1084,439,266,267,2393,823,345,509,172,346,319,347,348,581,348,348,455,946,369,1159,1901,68,435,127,567,568,1425,1426,4163,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,352,600,172,382,510,712,696,1343,393,572,489,665,666,667,668,439,669,179,147,461,429,429,429,429,445,149,562,281,280,281,280,281,1718,508,317,4164,641,2061,2062,477,478,4165,169,352,621,146,147,510,573,574,910,4166,564,565,2101,179,390,391,80,2124,4167,472,157,473,474,475,179,390,391,495,1744,497,2268,660,169,352,1133,537,537,1395,549,4168,102,103,1107,29,203,204,458,459,169,178,179,147,148,149,4133,2304,2305,512,549,1338,225,226,120,121,367,368,369,453,319,454,728,549,1338,101,102,103,104,135,136,137,138,139,140,141,959,109,110,99,111,112,99,113,122,123,124,125,126,145,146,147,355,356,384,558,1351,400,179,147,148,445,4169,2699,472,157,473,474,475,179,382,1663,697,545,3139,326,327,99,111,112,99,161,328,329,122,123,124,125,508,317,345,509,172,346,319,347,348,1239,403,346,476,477,2236,4170,680,609,169,352,798,172,382,148,149,591,1243,281,280,281,280,281,280,281,280,281,280,605,492,172,180,181,233,190,2167,4171,3980,211,820,134,216,449,439,669,179,346,319,454,456,1215,69,231,232,233,239,948,949,950,951,570,1658,758,2069,644,222,223,224,216,449,439,669,1120,1121,4172,197,492,172,382,148,149,591,150,446,592,447,447,592,592,447,447,1731,147,401,383,526,545,2421,128,129,1424,508,317,703,146,346,319,347,348,581,455,348,1215,69,394,395,396,699,172,382,513,533,502,634,611,538,538,537,537,537,2349,808,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,1949,1323,467,467,467,467,467,104,135,136,137,138,139,140,141,959,285,286,104,135,136,137,138,139,140,141,959,641,2061,2062,477,478,4173,1116,572,489,490,216,449,439,669,179,390,391,23,161,101,102,103,104,135,136,137,138,139,140,141,959,231,967,1890,545,1188,1189,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,460,179,147,461,445,445,149,150,446,447,3155,808,809,809,840,1949,1323,453,476,2195,2196,2374,426,577,578,123,124,125,1150,145,146,147,148,149,2694,146,346,319,347,1132,1796,355,383,514,570,1658,2027,374,229,909,777,846,616,690,496,2247,382,532,700,4174,1887,859,1100,1762,1281,1406,558,557,558,557,557,557,558,559,4175,416,244,1123,1124,1125,379,169,352,2108,4176,295,506,102,103,104,135,136,137,138,139,140,141,959,148,445,653,570,952,2257,458,459,169,178,179,382,401,383,402,356,402,356,502,634,4177,1026,319,347,456,348,686,403,510,696,697,545,671,2070,2071,2392,439,266,267,554,1921,69,1171,367,368,399,400,179,390,391,494,616,1281,127,128,129,1424,382,355,383,526,545,3154,102,1254,1255,1256,1912,253,68,1241,178,179,147,148,445,445,149,562,281,280,281,280,281,280,674,810,1949,1323,190,2162,483,484,485,2505,3048,179,390,391,494,495,496,976,692,145,146,231,232,233,190,4014,4178,4179,1171,162,163,164,165,1589,1590,1591,169,229,230,146,147,148,445,149,1847,1074,1323,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,147,148,854,574,2763,1599,147,532,526,545,1188,1199,3280,934,2490,1691,959,687,688,495,505,690,690,496,496,496,1111,277,712,278,1522,280,295,982,237,743,744,188,189,239,185,186,190,245,1409,987,471,2072,727,434,454,728,549,2147,243,244,166,167,168,169,352,2652,4180,2886,4181,162,163,164,165,313,314,315,169,352,1660,3366,434,454,1027,435,161,101,102,103,104,135,136,137,138,139,140,141,959,3269,422,423,4182,665,735,489,665,666,667,4183,1071,243,244,313,314,315,169,237,238,184,185,186,239,185,186,240,188,189,241,4184,147,510,696,697,608,4183,254,255,1663,697,769,770,4185,148,149,2466,2360,498,1745,2824,4186,345,509,172,382,510,712,696,278,562,752,145,146,147,148,429,429,429,3966,943,319,320,4074,4187,3025,228,352,600,172,382,355,383,384,557,654,557,1718,352,353,146,147,148,445,429,149,591,150,446,447,447,447,790,1579,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1078,1546,1546,340,340,340,340,340,1546,340,1548,109,110,99,111,112,99,161,101,162,163,164,165,594,595,596,169,178,179,382,355,383,534,535,663,435,826,1282,829,3716,68,54,55,4188,167,609,169,1418,23,382,355,383,534,535,1242,549,1338,237,238,184,185,186,241,185,186,239,185,186,4189,694,204,594,595,596,316,317,703,146,346,319,320,193,194,1577,1587,382,401,383,526,545,2700,564,565,2101,179,173,2056,665,666,667,3593,4190,563,472,157,216,449,439,669,179,147,148,854,629,190,191,2272,228,178,179,382,355,383,357,711,258,259,260,261,262,263,264,1838,685,434,320,193,194,4191,460,179,147,518,357,1396,403,401,383,502,634,536,538,538,1759,713,1663,697,545,1188,1189,547,687,980,781,780,779,780,780,1751,295,506,808,809,809,840,1949,1323,100,216,1042,439,440,859,2128,295,1911,1171,1713,930,4192,367,368,369,400,179,382,510,573,629,2546,229,1106,687,980,781,780,2601,1275,367,368,399,400,179,147,401,383,526,545,3584,178,179,390,391,494,616,496,3002,345,509,172,382,355,356,302,303,304,303,304,303,788,69,683,401,383,502,634,538,537,611,537,537,1759,549,1338,429,429,429,429,445,429,149,511,1811,231,232,233,190,482,483,484,2326,589,670,545,2421,147,510,278,511,446,512,549,1338,4193,23,1171,147,148,429,149,511,446,447,636,1241,2175,2176,498,2127,579,580,703,146,346,319,454,1215,549,760,581,348,348,1318,453,476,477,478,479,2824,4194,460,179,147,597,502,634,537,799,1216,113,101,102,103,467,467,467,467,467,467,467,104,135,1493,1305,1782,1783,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,472,157,473,474,475,179,382,513,526,2714,665,735,489,665,666,667,730,731,268,1921,403,491,374,178,179,147,401,356,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,788,549,760,145,146,147,355,383,534,535,538,538,538,4195,370,371,1505,495,691,782,145,146,1824,18,147,737,738,2134,3498,838,47,178,179,147,148,445,445,445,149,279,280,281,2018,1642,382,355,383,384,654,557,558,557,557,557,557,557,558,557,558,557,918,564,565,2101,179,173,2056,808,811,812,899,814,815,816,1226,1182,347,455,944,403,696,697,545,1188,2249,352,791,172,147,148,445,445,149,759,446,592,447,512,435,1074,1323,798,172,382,355,383,383,357,302,1670,472,157,489,490,216,449,439,669,1120,1121,68,69,472,157,473,474,475,179,382,513,526,545,671,102,103,104,135,136,137,138,139,140,141,959,203,204,458,459,169,237,743,744,188,189,240,188,189,240,188,189,190,986,1044,1189,251,252,3248,162,163,164,165,577,578,123,124,125,702,580,345,509,172,180,181,233,190,191,192,193,194,195,1897,393,394,395,396,531,146,346,319,1094,4196,379,1084,439,838,23,492,1288,765,1290,4197,429,429,149,430,280,281,280,281,507,178,179,382,355,356,357,302,303,305,2706,1074,4198,148,445,429,2955,346,319,454,348,581,348,348,348,455,455,348,348,455,455,3708,769,770,2396,54,55,2625,460,179,147,461,429,429,445,445,445,149,150,446,2121,1442,2676,23,322,1428,1429,1430,746,104,135,136,137,138,139,140,141,142,178,179,382,401,383,402,356,402,383,519,3338,4068,4199,1061,4200,382,148,149,591,150,446,636,403,300,301,2480,950,951,515,571,367,368,369,400,179,382,401,383,977,460,179,147,597,402,1275,401,383,556,654,557,557,557,558,557,1718,508,317,345,172,390,391,494,2073,495,691,711,4201,68,713,1692,216,542,1012,1013,1013,4202,382,401,356,302,303,304,303,304,303,304,303,304,303,304,303,304,1884,641,656,764,765,2315,3214,4203,510,696,697,769,770,2141,460,179,147,518,384,654,1935,207,208,388,3309,3310,4204,4205,4206,1081,4207,178,179,147,401,356,519,520,1331,2557,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,2104,587,434,347,4208,549,1338,1990,2810,1009,47,131,2252,641,764,765,2387,3172,369,1339,463,403,491,228,352,600,587,434,347,581,455,686,403,500,146,147,401,383,402,302,303,305,303,305,303,548,69,147,589,590,445,445,445,429,149,591,150,446,636,69,783,570,952,2460,240,2328,2329,950,951,570,571,1026,319,1821,347,348,455,348,348,686,549,1338,178,179,382,148,429,429,445,429,149,1522,280,281,711,399,1130,1383,4209,782,291,297,4210,299,3355,3356,403,943,319,347,581,455,455,455,2059,355,383,384,654,557,558,557,557,557,557,557,558,557,558,557,558,557,558,557,558,2201,2202,601,3394,561,628,1187,500,146,147,148,429,429,429,429,149,759,446,447,512,69,401,383,526,545,671,1169,439,266,267,268,270,2493,435,489,665,666,667,797,1169,439,266,267,554,270,2493,2770,300,2345,2480,950,951,632,54,1509,1171,243,244,313,314,315,169,460,179,147,518,534,535,611,1759,1241,472,157,473,474,475,179,382,589,670,545,1188,1189,100,101,624,625,626,627,1179,3558,901,902,303,548,325,1906,333,410,335,336,337,44,45,524,561,921,967,1890,545,1188,1189,400,179,382,148,149,672,280,1774,638,169,460,179,147,461,445,1704,4211,727,434,347,581,455,348,348,455,348,348,455,686,69,586,216,449,439,669,179,382,518,534,535,3440,369,400,179,180,181,182,181,233,190,245,1409,1044,2098,251,252,253,68,69,300,2345,302,303,305,303,305,303,305,303,304,303,304,303,304,303,304,303,548,2083,2169,2170,4212,4213,4214,355,383,514,570,516,4215,330,252,253,68,835,461,445,429,149,430,280,281,281,281,280,281,4216,510,696,712,712,278,511,446,636,435,808,811,812,899,814,815,816,817,333,410,335,336,337,44,45,822,419,348,1027,549,1338,662,169,170,171,587,434,454,348,1027,549,1028,291,297,468,2207,374,460,179,147,597,556,558,559,385,295,506,510,278,150,2087,2088,485,2505,4217,103,291,292,1974,253,4218,756,554,270,270,2493,549,1313,513,700,402,302,303,304,303,304,303,304,303,548,549,1338,356,356,502,634,536,538,538,538,537,4177,526,2262,1169,439,266,267,268,270,3506,1322,429,429,429,445,445,149,279,280,281,295,506,1286,602,603,2004,318,319,454,581,455,686,403,482,483,484,2374,54,55,4219,362,216,1042,439,266,4220,23,429,445,149,562,281,280,281,782,2405,950,951,570,952,529,182,606,2478,515,1658,54,55,2040,2523,172,382,401,356,556,557,654,557,442,148,445,445,445,429,429,445,462,999,69,687,980,2369,4221,711,460,179,390,391,494,616,1330,1097,4222,173,948,949,950,951,570,516,4223,547,172,382,401,383,402,302,303,304,303,305,303,305,303,304,303,548,713,322,1428,1429,561,485,4224,178,179,147,1486,835,445,445,445,429,429,429,3112,1193,1286,3394,1245,146,147,1286,603,602,603,602,2471,4225,589,2725,401,383,556,558,557,1348,557,557,558,373,429,462,4226,1575,1265,303,305,2290,549,789,390,391,495,1744,497,659,660,4227,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,1764,180,606,607,769,1612,394,395,1594,396,4228,433,434,1094,23,169,237,238,184,185,186,190,575,802,80,1829,399,641,2061,2062,2195,2196,2343,2505,4229,251,252,253,254,255,99,113,414,415,416,244,1123,1124,1125,316,317,703,727,434,347,728,549,1338,487,206,488,489,490,227,123,124,125,491,2600,333,410,1891,180,181,921,967,1890,608,756,554,269,270,726,403,197,145,146,147,148,149,511,446,592,592,592,447,447,2121,3875,1388,346,476,2195,2196,485,2505,2297,172,346,319,454,581,686,69,180,181,233,190,4230,169,352,353,146,147,355,383,357,874,390,391,494,495,505,691,977,382,148,429,429,149,511,446,592,592,447,592,592,447,636,69,231,232,233,190,745,80,4231,1254,1255,4232,4233,523,2246,3614,147,401,383,502,634,611,537,537,537,537,2733,355,383,302,4234,808,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,810,809,809,809,1007,1008,1009,47,4146,4235,1171,382,148,149,150,2087,2088,485,2622,3048,638,169,178,179,147,401,383,556,558,557,1784,561,2538,376,1627,4236,547,687,688,495,690,505,496,295,506,1903,1904,1905,23,3212,3213,443,463,549,1338,2106,483,484,485,3439,460,179,147,461,149,150,446,447,447,447,592,636,331,1458,4237,4207,145,146,147,401,356,502,634,536,538,537,537,1759,549,1313,4238,2813,1413,4239,355,383,357,383,384,1784,295,506,531,146,346,319,347,2336,528,516,2511,549,610,1763,1764,266,267,268,269,270,270,272,403,2522,950,4240,950,2187,3064,467,104,135,136,137,138,139,140,141,959,1585,439,266,267,554,270,726,549,1093,1074,1323,147,532,526,769,770,2992,367,368,399,400,179,147,148,445,149,751,782,662,169,178,179,147,355,356,519,990,2926,699,172,382,1663,1706,696,712,712,712,998,999,69,178,934,2490,3352,709,60,61,73,93,4241,352,600,172,180,181,233,190,469,2270,1499,1555,1218,820,477,2236,2779,47,2622,2356,168,169,237,238,184,185,186,239,185,186,241,1981,382,597,556,654,557,558,557,558,557,558,557,558,557,559,4175,3578,1031,333,1232,335,336,337,44,45,46,23,4242,645,646,2174,4243,4244,401,383,383,502,2198,4245,1413,709,60,61,2671,2672,66,2673,1421,69,400,179,180,181,233,241,2056,229,909,146,390,391,494,495,496,496,1236,1178,345,1288,4246,4247,3061,80,1496,2470,2002,602,2471,4248,673,532,526,545,671,1007,1031,333,410,418,23,445,445,149,759,446,636,713,375,376,377,1230,4249,146,390,391,494,495,976,373,2064,2467,390,391,494,616,496,497,659,660,147,510,278,2541,280,281,280,281,280,3096,318,319,320,193,194,4250,1549,193,194,195,2809,3381,1409,1044,1199,429,429,445,445,445,445,4251,148,149,150,446,592,592,447,1787,4252,838,23,510,696,712,712,696,2136,520,4253,472,157,473,474,475,179,382,532,526,545,1188,1846,162,163,164,165,1589,1590,1591,169,229,230,146,346,319,347,1239,549,1093,180,181,182,606,607,545,2314,666,667,730,731,554,1814,1921,435,203,204,175,176,177,169,237,238,184,185,186,241,185,186,187,1174,2536,2537,477,2064,4254,702,580,703,146,147,510,573,629,190,1617,4255,401,383,402,302,303,304,303,304,303,305,303,305,303,548,69,921,967,1890,769,2605,2195,2196,2343,2505,3102,735,489,490,216,449,439,266,267,883,268,2835,366,4256,442,4257,23,554,1294,270,270,270,270,272,403,127,128,129,819,2925,4258,265,838,23,162,163,164,165,361,619,620,169,178,179,382,401,383,519,990,1804,1408,641,657,658,4012,228,460,179,147,1835,558,557,558,557,558,557,2023,231,232,233,190,2175,2176,498,4259,172,382,401,383,556,557,1348,557,558,557,558,1222,352,353,146,147,355,383,384,1348,557,557,557,558,1482,1026,319,1528,582,737,738,2134,2565,147,401,356,556,654,557,557,558,557,558,557,692,147,589,590,429,429,445,445,149,759,446,592,447,447,512,549,610,3322,216,449,439,4260,131,132,149,511,446,447,512,69,147,401,356,402,302,303,305,303,304,303,788,549,3098,461,429,429,445,149,150,446,447,4261,352,4262,1561,4263,485,2622,2297,1962,333,1232,335,336,337,44,45,1006,549,1338,147,510,696,696,1343,1573,731,554,1294,270,2875,104,135,136,137,1287,139,140,141,959,489,490,216,449,439,266,267,554,270,270,726,403,489,665,666,667,3170,333,1232,335,336,337,44,45,1006,835,180,606,2478,3588,375,2846,3423,4264,1368,735,216,449,439,669,934,4265,547,4266,541,429,429,149,591,1243,281,281,280,281,280,281,280,281,280,746,769,770,2658,513,526,545,671,492,687,688,495,505,496,690,690,496,496,691,782,3447,563,542,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,2214,2245,231,232,233,190,1549,193,194,1072,513,700,402,302,303,305,303,305,303,304,303,304,303,548,403,2563,497,498,2692,2340,2946,347,1781,1254,1255,1256,1912,253,254,255,532,526,545,1188,1199,694,204,594,595,596,379,169,237,743,744,188,189,190,1654,1498,1499,1555,1218,755,1084,439,4260,401,383,502,634,537,538,4267,172,180,181,233,190,745,1526,296,486,653,570,952,2460,375,2846,4268,4269,4270,80,4271,149,511,446,592,447,447,447,512,331,2162,483,484,2343,486,1317,2328,2329,950,951,570,1658,637,211,820,1435,1436,1438,4272,549,1338,382,401,383,556,558,2441,149,150,446,447,592,4273,311,181,233,190,245,1409,2886,471,231,967,1890,769,770,2543,510,278,562,281,977,808,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,811,812,899,814,924,179,2502,23,4101,352,2652,2653,184,185,186,190,2827,193,194,2722,375,1462,1463,4274,549,729,670,527,180,606,607,2518,356,357,302,303,304,1884,265,266,267,554,269,270,271,271,271,726,713,589,4091,69,1821,347,348,455,455,348,348,455,455,1215,69,180,181,182,606,2478,570,952,2636,601,602,752,460,179,147,597,502,634,663,758,429,429,149,279,280,281,1774,1044,1846,1106,172,382,510,696,696,998,999,69,1317,2328,2329,950,951,570,1658,54,2839,2145,148,429,149,591,672,280,281,692,180,181,233,239,185,2082,835,810,809,809,809,1007,1031,333,410,418,23,390,391,616,1744,497,498,617,480,2454,808,811,812,899,814,924,179,346,319,347,1132,1241,1304,1305,1306,637,641,2061,2062,4275,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,4063,589,590,429,149,591,672,280,281,281,281,280,281,280,281,280,673,764,765,2387,2432,2317,523,44,45,3290,193,194,1577,1587,680,231,232,182,834,664,101,162,163,3091,3933,396,432,824,1290,1291,523,44,45,1346,4276,2064,2065,4277,617,2340,3454,171,687,688,495,690,505,690,690,496,690,690,690,1330,735,216,449,439,266,267,554,732,1815,516,2332,4278,247,101,624,625,626,627,2411,181,233,190,1643,4279,1518,950,951,632,54,55,56,2454,4280,390,391,392,445,670,545,1188,1846,1314,567,4281,300,301,302,303,304,631,4282,1906,333,410,335,336,337,44,45,1006,69,727,434,320,193,194,4283,1632,333,334,335,336,337,44,45,3129,149,759,446,592,447,447,512,549,1338,485,486,776,146,147,597,4284,4285,258,761,260,261,762,262,263,264,4286,355,383,526,545,2700,147,510,573,629,190,191,802,1526,296,149,430,280,281,280,281,280,1774,698,180,181,921,232,233,190,986,4287,162,163,796,101,225,226,120,121,109,808,811,812,899,814,1945,333,410,335,411,412,435,147,589,670,545,1188,2249,547,172,382,355,356,384,558,1350,148,445,429,149,591,150,446,447,447,512,549,1313,1026,319,347,348,455,455,944,549,1338,450,889,4288,1832,4071,2343,486,4289,1323,680,180,181,233,190,469,2270,1499,1555,1218,820,2538,376,2539,295,506,346,319,347,455,528,570,3142,4290,429,429,445,445,149,279,280,281,3589,3602,661,735,216,449,439,669,179,346,319,4291,577,578,123,124,125,4292,370,433,434,454,455,1149,350,735,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,3767,382,148,445,429,429,445,429,149,430,280,281,782,1015,172,382,355,443,463,835,4293,3078,611,537,538,538,537,663,403,653,516,2332,2331,2550,4207,489,665,666,667,3170,333,410,418,985,346,319,347,348,455,581,348,348,4294,4295,445,670,545,1188,1199,510,696,278,150,446,592,512,549,1338,591,150,446,447,636,403,429,429,149,591,672,561,808,840,840,840,3229,2724,490,216,4296,504,2866,586,216,449,439,669,179,382,401,383,519,4297,231,232,233,190,2162,483,484,485,486,178,179,300,301,302,303,548,69,142,104,135,136,137,138,139,140,141,4298,943,319,454,581,1215,549,1338,429,149,591,672,280,281,280,605,2924,376,1627,1331,521,522,523,44,45,524,507,231,232,233,190,3381,1409,1044,1045,375,376,377,990,1705,587,434,347,455,728,435,149,279,280,281,280,281,281,281,280,281,280,1510,1675,3627,193,194,195,2435,320,193,3286,2855,2856,665,735,489,665,666,667,668,439,266,267,554,1814,1815,952,2332,2332,2331,2331,2332,2332,2550,69,545,714,1663,1706,2721,148,149,279,280,281,280,281,280,281,280,1510,429,445,429,149,759,446,512,758,727,434,347,686,3376,172,147,1286,602,1222,1007,3388,2143,193,194,3389,589,670,608,178,179,147,401,356,502,634,4299,1311,149,562,281,281,281,280,281,280,281,281,281,280,281,280,281,3589,3602,492,1288,1289,1596,1909,69,173,948,949,950,951,3743,601,603,603,602,1350,352,600,172,382,148,149,150,446,4300,178,179,300,2345,302,303,304,303,304,303,305,303,548,637,756,554,1294,270,270,271,270,2007,197,492,172,382,148,445,979,178,179,147,401,383,402,383,556,654,557,558,557,558,557,558,557,558,557,684,445,445,445,445,149,150,446,447,4301,382,148,445,1704,990,3461,455,455,944,549,1338,2303,2304,2305,636,549,708,1150,492,172,382,355,356,534,535,663,549,1338,145,146,231,232,233,190,2704,4302,238,184,185,186,241,185,186,240,188,189,239,1165,184,185,186,240,1174,2536,4303,429,429,429,445,445,445,149,994,839,785,3195,190,191,192,193,194,1577,2599,178,179,231,232,1163,1560,2536,1164,429,445,149,562,281,280,281,280,281,1411,447,636,403,769,2105,190,3634,4304,149,279,711,608,696,278,4305,280,281,280,281,280,1350,149,150,446,592,682,266,1041,254,398,1821,454,1822,403,638,169,943,319,4306,500,146,390,391,494,616,1461,231,967,1890,545,1188,1199,1074,1323,170,1585,439,266,267,554,271,269,272,549,4307,145,146,147,148,445,445,445,445,149,150,446,447,512,426,179,231,232,233,190,4308,4309,4179,233,190,1967,483,484,485,2089,54,55,4219,1514,1693,1693,1693,1693,1693,1012,1614,4125,1435,1436,1437,4310,591,759,2745,237,238,184,185,186,190,1931,4311,1248,429,445,149,279,280,281,280,281,442,510,278,591,1243,280,442,2325,2087,2088,485,2197,352,600,172,147,597,502,4312,180,181,233,190,850,1409,3694,490,216,1042,439,266,267,554,1244,549,708,810,1949,1323,840,840,809,809,809,809,809,840,809,809,809,1007,1031,333,410,418,47,401,383,526,545,3584,237,743,744,188,189,239,185,186,190,4313,680,101,162,163,2085,157,216,1042,439,266,267,554,1807,435,532,2953,2282,216,1042,439,838,23,2108,860,1100,1100,1101,1101,1101,1101,1101,3053,3340,333,4314,258,761,260,261,836,837,262,263,264,265,838,23,4315,69,2085,157,216,449,439,669,179,390,391,494,616,505,496,496,496,4316,1706,3996,4317,724,665,735,489,665,666,667,1564,916,1565,4318,507,510,712,278,511,446,592,512,4319,492,172,180,181,233,239,1165,2921,69,460,179,147,597,502,634,536,4320,2398,656,764,765,2315,4321,1171,390,391,494,616,3367,3368,3369,3370,429,445,445,429,429,445,149,693,769,4322,2252,4323,1517,149,279,280,281,280,281,280,281,605,1112,2843,4324,4325,4326,549,1571,147,510,573,4327,490,216,1042,439,266,3950,23,291,292,324,253,68,350,318,319,347,455,455,944,549,1252,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,346,319,347,581,348,348,455,455,455,455,3377,714,554,4328,4329,4330,370,4331,2111,1915,4332,346,476,2195,2196,2640,581,455,455,348,348,455,455,686,403,2096,497,659,2370,542,1693,543,1354,4333,300,4334,149,759,446,592,447,447,593,134,216,1042,439,838,47,231,232,233,239,185,4335,489,665,666,667,725,439,440,859,3772,661,1254,1255,1256,1912,253,68,331,147,148,445,445,429,429,445,445,429,4336,3954,777,846,495,505,690,690,496,496,496,496,1111,688,616,2172,711,420,801,120,289,109,110,99,111,112,99,100,489,665,735,216,736,179,147,532,2348,549,550,4337,147,148,429,854,872,873,589,670,608,366,171,687,688,495,505,690,496,1178,429,429,429,429,445,429,149,591,2558,2142,231,232,233,190,234,1498,1499,1555,211,1716,783,570,1658,54,1659,445,149,150,446,592,592,447,592,592,447,447,790,497,659,3915,2806,23,429,149,591,150,446,447,512,549,1338,727,434,1821,347,348,686,549,1571,401,383,402,383,519,990,2808,207,208,388,1167,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1851,241,948,949,1138,403,3943,4338,4339,4340,510,712,278,430,280,1718,266,267,554,271,270,270,4341,154,135,136,137,138,139,136,137,138,906,400,179,231,232,233,190,245,1409,1044,849,154,135,136,137,138,139,1140,352,798,587,434,347,456,1215,1240,460,179,147,518,534,535,611,3064,515,516,2373,430,280,281,281,281,280,507,2405,537,799,69,178,179,147,510,278,562,2045,943,319,347,581,455,455,348,348,455,686,403,597,502,634,611,537,538,538,537,538,538,663,549,610,2879,179,390,391,494,616,1960,977,154,135,136,137,138,139,4342,1719,545,1188,2249,382,148,429,149,591,150,446,447,592,592,447,447,512,549,800,810,840,840,809,809,809,809,809,810,809,809,809,1007,1031,333,410,418,47,656,642,434,454,528,632,637,472,157,489,490,216,449,439,669,179,346,319,347,686,549,1338,162,163,164,165,594,595,596,169,229,909,146,147,355,383,519,990,991,2478,570,1658,758,145,146,147,148,429,149,430,280,281,1774,2898,232,233,190,2850,1599,482,483,484,2326,401,356,4343,777,846,495,690,505,496,496,496,496,496,1461,2096,497,498,2661,346,319,454,455,581,1215,549,1093,347,581,348,1109,145,146,147,355,383,534,2851,398,3078,537,1472,549,1338,356,302,303,304,303,304,303,304,1469,1026,319,347,581,686,403,265,266,267,554,1294,270,270,270,272,69,810,809,809,811,812,899,814,1945,333,1232,335,336,337,44,45,4344,291,292,324,253,68,1241,495,4345,382,601,602,603,1222,1015,172,180,181,233,190,2768,2270,1499,1555,1002,147,1663,697,527,757,549,1674,492,172,382,148,429,429,149,562,281,280,281,280,281,280,281,280,281,280,605,178,179,382,1286,602,603,507,231,232,233,190,3634,1498,1499,4346,807,526,3358,545,3154,743,744,188,189,240,188,189,239,185,186,190,1881,2886,1248,1920,1815,516,2426,390,391,494,80,1062,526,769,770,2657,54,2839,2145,777,846,616,689,691,752,140,141,1095,522,523,44,45,1006,664,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,809,810,809,809,809,809,811,812,899,814,815,3998,23,680,2563,497,498,617,4347,815,816,1226,1182,454,349,403,346,319,454,455,528,570,1658,54,55,2040,4348,445,149,150,446,447,512,435,1112,1843,1844,4325,4349,664,3620,292,324,4350,231,232,233,187,1174,1228,561,149,759,446,592,592,447,447,447,447,2991,355,383,357,302,303,305,303,788,413,355,383,526,545,1188,1846,508,317,703,146,346,319,3781,1834,770,4351,513,526,545,1188,2249,148,149,562,281,280,281,280,281,280,281,280,373,429,149,430,281,1774,460,179,300,301,358,4352,4353,584,585,586,2866,222,223,224,216,449,439,838,23,680,229,909,146,346,319,454,348,3792,1518,950,951,570,952,2570,959,172,346,319,1821,3781,2486,572,489,665,666,667,1564,4012,147,597,519,520,521,522,523,44,45,524,4354,148,445,670,769,770,3723,445,445,429,429,149,279,442,216,449,439,669,179,346,540,960,666,667,725,439,266,267,554,1294,270,270,270,271,1488,759,446,592,592,592,592,447,447,4261,478,3660,4355,495,2729,1111,445,445,429,149,759,446,636,549,1338,180,181,233,241,185,2082,403,390,391,494,1813,2413,2112,1915,3166,1915,373,276,179,346,319,454,1027,403,173,948,949,950,951,570,2503,472,157,216,449,439,669,179,346,4356,178,179,147,148,445,445,149,150,446,592,592,3334,725,439,440,859,860,1101,1101,1100,3400,178,179,147,148,149,150,4357,514,570,571,502,634,611,538,538,537,537,1759,69,400,179,382,510,573,629,190,245,1409,2886,3060,698,461,149,150,446,447,592,592,2121,3793,445,429,149,759,446,447,447,512,413,3580,266,267,554,269,270,271,271,2875,533,402,302,303,305,303,305,303,304,303,304,303,304,303,788,69,322,1428,4358,2795,4358,2795,1429,295,466,4359,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,1074,1323,251,332,333,410,4360,352,600,172,382,401,383,502,634,538,611,537,538,663,549,800,533,556,559,4361,589,670,769,770,2396,54,55,1238,366,375,2846,4268,4362,4363,679,607,769,770,4364,641,642,434,347,1132,549,2147,390,391,494,616,496,1836,149,150,2350,1239,403,514,570,952,2570,148,445,149,511,446,512,426,532,533,534,535,611,538,538,537,537,537,537,537,663,549,708,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,809,1949,1323,4266,724,1268,1269,184,185,186,187,1174,744,188,189,190,4365,4366,247,101,624,625,626,627,1638,172,382,510,573,629,190,1554,1196,1197,4367,820,379,169,352,798,172,382,355,383,383,357,1396,549,708,756,554,1294,726,549,1313,1692,3122,4368,1037,1031,333,1232,335,336,337,44,45,46,23,401,356,556,654,557,557,558,557,558,557,558,557,558,557,558,655,429,429,149,279,280,281,281,281,280,281,280,281,1510,401,383,519,990,4369,149,279,280,281,281,281,605,429,149,591,672,281,386,509,172,180,181,1163,232,233,190,245,1409,1044,849,147,510,712,712,696,696,2136,3338,3339,670,2518,348,455,456,455,695,375,4370,921,967,2228,570,952,2362,554,271,4371,926,4234,840,809,840,840,809,809,809,809,809,810,809,809,809,811,812,899,814,815,900,1604,254,419,104,135,964,1171,1663,697,545,3154,1317,2328,2329,950,951,515,952,2570,148,429,149,591,150,446,447,592,592,447,512,549,1338,366,4372,1383,4373,305,303,305,303,304,303,305,4374,206,488,216,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,783,570,571,382,401,356,556,557,654,557,558,557,557,557,442,943,319,454,581,455,348,348,455,348,348,4375,2175,2176,498,3583,934,1473,4376,2491,510,696,696,2136,4211,759,446,592,447,447,592,4273,345,509,172,180,181,2424,549,2147,703,146,147,148,149,511,446,447,447,636,549,1093,2723,1621,330,252,253,254,419,382,148,445,653,570,952,529,2166,774,23,429,429,445,149,759,446,592,4261,777,778,780,4377,782,251,465,1237,590,4378,401,356,519,1230,4379,1586,193,194,3333,1356,1357,1108,980,2006,977,687,980,981,752,3472,440,916,1690,442,783,570,952,2636,172,382,148,149,759,446,592,447,592,592,512,435,322,1428,4380,100,3520,4381,23,142,2149,508,317,345,509,172,180,181,233,190,2175,4382,438,439,266,267,554,2240,1921,350,653,570,571,445,445,445,462,999,713,149,150,446,447,636,413,316,317,703,146,390,391,494,1526,982,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,1842,148,149,1522,280,281,280,281,280,281,280,281,280,281,280,442,1012,1039,3616,150,2087,2088,485,3759,1549,637,429,429,445,429,429,1302,591,150,446,592,447,447,592,592,447,636,435,2747,3227,2597,3058,291,292,324,253,254,419,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,401,383,2244,2245,736,179,390,391,494,616,782,148,445,429,429,445,429,149,591,672,280,281,507,737,738,2275,2785,149,4383,2138,1031,333,410,335,411,412,54,55,2625,1554,1196,1197,1555,211,2243,727,434,347,581,348,348,455,455,686,549,1338,2763,2360,498,3583,671,4384,725,439,266,267,554,1294,271,271,270,270,270,270,270,2007,390,391,494,1526,982,3289,382,401,383,556,558,1836,769,770,2408,665,735,216,4385,4386,300,301,2480,950,951,570,3752,756,554,269,271,726,403,429,149,591,150,446,592,592,447,512,549,610,921,967,3669,2669,356,384,654,692,148,429,429,445,429,429,149,150,446,636,435,445,429,149,591,150,446,447,592,592,636,403,1887,916,860,2128,1752,581,348,455,348,348,455,455,1215,69,149,759,446,592,447,512,69,149,759,446,592,636,549,1338,429,149,511,446,592,592,447,592,512,549,1338,2073,495,497,498,617,480,4387,2195,2196,2374,54,2839,2145,534,535,536,663,758,148,149,1522,281,280,281,280,281,280,281,442,320,193,194,2378,4388,100,227,123,124,125,126,145,146,147,401,356,502,634,1103,69,352,600,172,382,401,383,556,1348,557,1351,545,671,628,146,346,319,1821,454,4389,148,149,562,281,281,281,281,280,281,692,190,2850,2142,556,654,557,557,557,557,558,1718,4390,23,656,657,658,495,497,498,3027,1960,622,4391,769,770,3205,305,303,788,69,2840,611,538,538,538,538,538,537,538,538,1759,403,687,688,495,1817,2958,1171,2714,352,353,146,390,391,494,3094,1317,188,2273,631,515,1658,637,148,445,429,445,429,149,591,672,2485,492,172,382,510,712,278,591,994,782,401,383,526,545,3584,998,999,4392,1133,611,538,537,1422,231,232,233,239,1165,2921,435,2387,2432,2317,523,44,45,1531,80,3546,346,319,454,1027,549,1338,726,549,1313,1042,439,266,267,268,1807,4392,586,216,449,439,669,179,147,518,384,654,1178,445,149,562,1774,490,216,449,439,669,179,390,391,494,616,496,1960,1353,429,445,429,149,511,446,447,447,4393,146,346,319,454,457,258,761,260,261,836,837,262,263,264,432,433,434,1094,23,180,181,233,190,2325,2087,2088,485,2505,3527,178,179,382,148,429,149,759,446,447,592,592,447,447,512,1216,756,268,1294,271,271,271,271,271,270,271,726,664,1830,439,266,267,554,269,726,4394,347,455,455,1110,589,590,429,429,445,445,429,429,429,1704,3338,4395,743,744,188,189,239,185,186,240,188,189,190,4396,2197,382,510,573,629,190,2412,1196,1197,4397,180,181,1163,232,233,190,745,80,1829,2231,653,570,1658,54,2839,2145,597,556,654,557,557,557,558,557,558,557,558,557,558,557,684,511,446,447,447,447,447,636,549,1313,4398,687,688,616,2651,563,702,1903,1904,1905,23,1663,697,2713,316,317,345,172,346,319,347,686,435,4198,147,401,443,999,1227,270,2493,435,278,2466,4399,453,319,1821,454,1839,2345,302,303,304,303,304,303,304,303,788,435,591,150,446,592,592,447,592,592,447,447,636,549,1338,356,356,502,634,538,611,537,537,537,663,549,1093,1169,439,266,267,268,757,664,355,383,534,535,663,4319,445,445,429,149,511,446,447,447,636,758,348,348,455,455,686,69,149,511,446,592,512,403,840,809,809,1949,366,104,135,136,137,138,139,140,141,959,147,589,653,3743,608,589,653,515,516,2257,564,565,2101,179,300,301,4400,2274,738,2784,2277,2277,2277,4401,2662,497,4402,3750,2575,4207,445,445,429,149,591,759,4403,587,434,347,456,455,455,1215,713,276,179,346,319,454,455,4092,429,149,279,280,281,918,573,629,190,191,802,782,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4404,2478,632,54,55,4405,1644,1645,2597,3228,142,297,4406,370,824,4407,3065,532,526,545,1188,2249,429,149,591,672,281,1752,532,533,534,535,611,537,538,538,537,537,537,2349,4408,611,1759,549,1571,366,390,391,494,495,2559,622,456,455,686,549,2972,1890,527,581,455,348,1110,597,502,634,536,537,538,538,538,538,537,4409,178,179,147,355,356,384,4410,1171,2262,237,743,744,188,189,241,185,186,239,185,186,190,1828,576,665,666,667,668,439,669,1120,1121,68,664,4411,1383,295,296,1042,439,266,4412,1356,2963,2964,4413,4414,4415,4416,4417,759,446,592,592,447,636,4418,180,606,607,545,1188,1199,300,2345,302,303,304,631,570,1658,54,55,3592,383,402,443,463,549,1313,2754,2755,1260,44,45,46,47,429,429,445,429,429,445,445,3084,429,445,149,150,446,592,4419,510,696,278,591,150,446,3155,300,301,302,303,788,758,562,281,281,281,280,281,282,346,319,454,455,1132,3376,1317,2328,2329,1138,69,375,4420,401,356,356,556,558,557,655,532,526,769,770,2992,134,216,1042,439,440,916,1101,1101,3456,373,266,267,554,1294,270,270,271,271,270,726,549,1338,587,434,347,348,455,456,686,69,1610,216,542,1693,1693,1693,1693,1012,2312,300,2345,1733,545,671,601,602,603,602,603,602,603,2004,642,434,347,528,570,516,3519,2169,3126,1697,759,446,592,592,512,69,429,429,149,511,446,592,592,512,549,1571,1026,319,347,455,695,570,516,529,429,445,149,562,281,280,1774,1663,1706,696,712,696,998,999,69,810,840,840,809,809,809,809,809,840,809,1007,1031,333,410,418,47,680,346,476,477,478,785,4421,390,391,494,616,690,497,2418,2419,382,510,712,278,150,446,592,636,403,513,533,502,634,611,538,538,538,538,537,537,537,538,1422,278,759,446,592,4261,1967,483,484,485,2505,2697,601,602,603,602,603,603,603,602,603,603,603,602,603,602,603,602,507,934,4422,383,556,559,4423,4424,4415,1269,1561,4425,445,445,429,149,1522,280,281,280,281,3096,2343,2089,54,55,2625,2834,136,137,138,139,1657,383,502,634,611,537,537,537,537,663,637,281,281,280,281,280,563,178,179,382,148,1220,3051,110,99,111,112,99,100,2222,2223,128,129,819,3224,347,1132,549,2863,777,846,495,505,1461,180,181,311,4426,769,770,2657,2572,586,216,449,439,669,179,382,518,384,558,557,558,557,1784,640,148,429,429,429,429,445,429,429,445,445,462,463,331,4427,445,445,445,445,4251,778,779,781,781,605,727,434,347,686,435,149,759,446,2121,3875,534,535,611,538,538,538,538,538,538,537,537,537,2349,1486,549,1338,819,132,278,759,446,636,549,1338,222,223,645,646,4428,1121,254,419,2821,3763,350,4429,680,100,101,624,625,626,627,3833,4430,2061,2062,477,478,785,4431,23,510,696,697,769,770,2579,23,4432,445,149,150,3032,613,685,434,454,455,528,515,516,2627,1042,439,266,3950,23,150,446,592,592,447,447,447,4433,429,429,149,759,446,592,636,549,610,2262,976,673,149,511,446,447,592,592,3334,266,267,268,270,270,4434,2213,663,549,610,510,278,511,446,447,636,549,1571,149,279,280,281,280,281,1774,1575,902,303,304,303,903,303,304,303,1798,4296,628,146,147,510,573,629,190,986,2886,1248,258,259,260,261,1352,179,2676,398,401,383,526,769,770,4435,460,179,147,597,502,4436,23,429,149,759,446,592,447,447,447,447,512,435,258,761,260,261,836,837,262,263,264,265,266,267,554,269,271,271,270,1626,608,1730,435,4411,1383,2133,739,2245,429,149,430,280,281,295,1616,587,434,454,581,348,1318,562,281,281,281,281,442,1906,4437,154,135,136,137,138,139,136,137,4438,172,390,391,494,495,690,505,691,1718,149,759,3477,4439,1431,4440,1431,1432,1431,1431,4441,237,238,184,185,186,240,188,189,239,185,186,240,1174,744,188,189,190,3015,3033,1265,1164,696,697,545,2700,1169,439,838,23,510,696,278,150,446,592,512,758,587,434,347,456,348,348,686,549,4442,534,535,538,611,538,538,538,538,538,537,538,538,537,537,663,549,1338,4443,770,2992,383,402,383,402,302,303,304,303,304,303,305,303,305,303,304,303,4093,4444,3000,401,356,402,1396,549,800,383,357,302,303,305,303,304,303,788,549,1313,4445,382,510,712,278,150,1811,759,2350,301,302,303,304,631,632,54,2839,2145,943,319,347,348,686,549,2147,1059,1060,1061,80,1105,1846,767,860,1100,4446,727,434,347,581,348,686,549,1093,1928,146,390,4447,696,278,511,446,636,713,4415,4416,23,2763,2360,498,617,1178,666,667,725,439,266,267,554,271,2510,403,251,332,333,334,1329,486,1586,193,194,2789,429,149,591,150,446,447,593,769,770,3874,1838,614,615,2073,495,1403,104,135,136,137,138,139,140,141,959,301,2480,950,951,570,1658,54,55,4219,352,2130,184,185,186,240,1174,744,188,189,187,1174,2536,4448,510,696,1706,3996,382,148,445,445,445,429,149,430,280,281,280,281,280,281,280,442,1007,1031,333,1232,335,336,337,44,45,46,47,1663,783,570,571,1996,859,3367,3368,3369,3370,742,928,216,4449,4450,401,383,402,519,520,1332,4451,401,383,402,302,303,305,303,304,303,305,303,305,303,304,303,788,549,2863,502,634,611,538,538,537,538,538,537,537,663,549,1338,429,149,511,446,447,592,592,447,447,636,549,800,590,2725,1218,2359,1573,731,554,270,1294,270,270,4434,567,568,3556,1426,1427,769,770,2657,2335,180,181,233,240,1174,3039,835,3487,2478,570,952,2257,666,667,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1679,1413,300,301,2480,950,951,570,3142,777,846,495,1461,241,185,186,241,1165,4452,617,480,4387,700,556,1348,1935,4453,182,606,607,3358,429,429,149,279,1281,429,149,2694,3381,1409,2886,3060,4454,271,271,270,270,726,549,1571,1288,4455,190,191,802,80,81,1031,333,1232,335,336,337,44,45,46,47,773,774,23,352,353,146,231,232,233,190,234,1498,1499,1555,211,919,492,172,382,401,356,402,302,303,305,303,304,303,305,303,305,303,305,4456,455,455,348,348,348,2509,390,391,494,616,496,497,498,1745,3108,429,149,591,150,446,447,447,512,549,708,518,534,535,611,537,538,538,537,537,537,537,1611,239,185,186,187,1174,2536,1164,1890,545,2700,251,332,333,334,1364,1514,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1788,429,445,445,429,149,591,150,446,512,426,1562,1289,1290,1291,523,44,45,822,398,4457,54,55,2040,4458,346,319,347,348,456,455,348,455,1839,1663,1706,278,150,446,447,592,592,636,549,1571,1323,489,665,735,216,736,179,300,2345,2480,1138,403,698,402,302,303,305,303,304,303,548,549,610,445,445,445,445,445,445,3450,697,545,742,547,687,688,2318,252,1622,1413,370,433,4459,1413,838,23,725,439,266,267,268,270,2251,69,401,383,556,654,557,557,557,558,557,1351,1120,1121,254,960,524,4460,233,190,1617,3013,512,549,1338,148,1220,602,839,1094,541,211,1087,147,355,383,2953,1639,463,69,680,2314,148,445,149,759,446,447,447,447,4261,445,429,462,2663,597,556,654,557,558,557,558,640,2773,447,512,549,2863,2046,2770,590,4461,2953,1644,1645,2597,2598,193,194,1072,277,696,278,150,446,512,69,205,101,624,625,626,627,1638,172,382,510,573,629,190,245,1409,2886,471,182,606,607,545,1188,1846,696,696,278,759,1550,1163,232,233,190,850,851,346,319,454,455,528,515,2495,399,400,179,147,510,573,629,190,191,192,193,194,1577,4462,211,212,1518,950,951,570,516,2570,445,429,149,759,446,4393,1965,150,2087,2088,485,2089,54,55,633,445,445,429,429,445,149,150,446,512,549,708,1160,1483,3468,4463,4464,180,2114,268,1814,1815,516,2332,2332,2550,1241,1179,4465,23,4466,382,518,519,1793,4467,938,939,211,1219,117,826,1282,829,830,831,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,4468,2195,2196,485,2089,54,55,2479,727,434,454,348,456,1215,69,172,180,181,233,190,469,2270,1499,1555,211,3894,168,169,1893,774,23,429,429,429,429,149,591,150,446,512,549,1922,149,591,150,446,447,447,592,592,636,549,1922,346,319,454,348,581,455,348,3792,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,653,570,571,54,2330,518,384,1348,557,2201,2260,429,429,149,1243,373,716,717,718,719,718,720,718,721,718,4469,718,4470,318,319,454,455,456,686,69,2505,2749,3154,300,2345,302,303,304,303,304,303,305,303,305,303,304,3494,384,2476,498,617,605,233,240,1174,3039,4471,538,799,637,666,667,725,439,266,267,2393,23,355,383,526,545,4472,980,781,1064,781,622,1514,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,4473,2338,1213,267,268,271,269,2366,3193,402,302,303,305,303,304,303,304,303,788,426,149,511,446,447,447,592,592,447,447,512,549,1338,352,791,172,382,597,502,634,2575,435,300,2345,302,303,304,631,570,784,1573,731,554,270,2007,1120,1121,254,724,769,2301,2249,2966,774,23,934,1473,1474,4474,562,281,281,280,281,280,281,280,281,280,281,280,281,280,295,982,2132,2133,2134,2565,556,558,559,560,977,1074,1323,147,532,526,608,168,169,170,1585,439,450,1200,2189,4475,346,319,454,3117,549,1338,1254,1255,1256,1257,687,688,616,689,691,442,445,445,429,429,149,759,1441,4476,401,383,556,654,1351,346,319,347,456,348,455,348,1109,445,429,429,445,429,149,591,672,280,1211,798,172,180,181,233,190,2434,193,3900,3365,3366,434,347,455,728,549,708,280,1245,545,1188,2249,148,445,670,545,1188,1199,172,382,401,383,502,634,611,1759,435,390,391,494,616,690,689,690,690,690,496,2247,510,573,629,190,1195,1196,1197,4346,4477,139,1304,1305,1306,1241,532,526,769,1612,665,666,667,725,439,838,23,2301,3563,717,4478,127,128,129,211,1516,2343,486,147,4479,4480,4481,237,238,184,185,2082,1241,1701,299,382,401,383,402,402,302,303,2295,608,357,302,303,788,664,2347,179,382,4482,69,382,510,573,629,190,245,1409,1044,1846,147,148,854,629,190,1643,2886,4483,641,642,434,454,1027,549,1313,346,319,454,348,455,348,349,549,1338,840,809,809,809,1007,1031,333,1232,335,336,337,44,45,1531,480,3371,1112,4484,4485,4486,549,2863,1169,439,266,267,554,1672,403,147,148,445,670,545,2421,477,2064,3821,4074,149,562,280,281,280,281,280,281,280,281,280,282,1424,278,2960,759,1054,149,591,1243,281,281,280,281,281,2441,231,232,233,239,1668,3821,54,55,2040,2375,772,148,149,150,446,447,447,592,592,447,592,592,636,413,1188,1846,382,148,854,574,4487,1184,1185,4488,390,391,494,495,690,496,1236,746,4489,295,1616,1692,216,542,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,3616,382,355,383,2037,205,101,624,625,928,565,1978,23,3931,1544,333,334,335,336,337,44,45,524,918,665,666,667,730,731,554,1814,1921,664,148,149,150,2608,1934,445,149,2909,3602,4490,2109,587,434,347,456,348,348,3566,687,688,495,1817,1237,1665,333,410,418,984,1239,549,1338,536,538,538,1759,403,513,526,545,1188,1846,300,4491,4492,401,383,556,557,558,1351,668,439,3724,2249,526,698,231,232,233,240,2328,2329,950,951,515,2743,352,776,146,231,1560,4493,669,179,147,4494,758,485,486,532,700,519,990,1804,4495,2231,1522,280,281,1281,469,4311,1248,384,654,557,557,557,557,1752,254,984,172,390,391,724,445,429,149,511,446,447,592,592,447,447,512,549,2147,390,391,494,616,839,268,2286,1921,69,580,703,146,147,148,854,629,190,745,80,1941,4496,4497,460,179,147,1406,558,563,148,445,670,769,770,2110,2069,644,222,223,224,216,449,439,266,267,554,270,757,758,819,2976,478,4498,541,486,4499,356,556,557,2265,2201,2202,267,4500,276,179,390,391,494,495,689,691,282,806,807,2872,1053,2745,669,179,346,319,454,768,528,516,2331,2331,2331,2331,2332,2331,2511,549,708,4501,3732,4502,4503,2351,523,44,45,1006,403,402,302,303,305,303,304,303,2580,780,781,781,1751,442,756,554,270,757,403,1506,1718,641,642,434,347,1501,1318,231,232,921,1560,744,188,189,239,1165,184,185,186,4504,148,149,2466,2360,498,2692,4505,597,402,302,303,304,303,304,303,305,303,305,303,304,303,305,303,305,303,2580,148,429,429,445,445,149,150,2745,1487,4506,1416,683,3403,3047,237,743,744,188,189,239,185,186,190,1881,1044,849,149,562,281,280,281,280,281,280,281,280,281,622,645,646,647,648,649,2002,602,603,2471,3986,295,982,1947,548,549,708,759,446,592,592,592,447,447,512,69,3150,3151,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,966,178,179,231,232,311,4507,401,383,526,545,671,1026,319,347,348,581,455,455,455,686,435,1522,281,281,280,281,280,281,280,281,280,281,692,2106,483,484,485,2773,346,319,1094,23,562,281,280,281,752,149,562,281,281,281,281,280,1752,823,4508,999,549,1571,277,278,279,280,1350,2602,4509,1555,211,2925,545,1188,1199,3759,445,149,279,280,281,280,281,280,281,280,281,280,281,280,977,172,390,391,494,616,2172,692,251,252,253,254,255,180,181,233,190,1967,483,484,4510,382,510,1639,463,549,610,1356,1357,29,453,476,2195,2196,2343,3975,510,998,999,435,747,2179,2179,2179,2179,2180,2179,2180,2179,2180,2179,782,2478,515,571,304,303,304,303,4511,355,356,384,557,558,282,2505,4217,2424,350,346,319,347,348,455,581,348,348,455,686,1241,145,146,147,355,356,534,535,663,403,1954,1526,4512,387,216,449,439,266,267,1920,4060,148,445,149,994,295,982,597,502,2005,23,696,1343,2268,660,237,238,184,185,186,240,188,189,190,575,1285,251,252,253,254,419,182,606,4513,641,642,434,347,1132,403,4514,1544,333,334,335,336,337,1299,429,149,1522,281,281,281,1510,356,519,990,1804,1804,1804,1804,1804,1804,1025,2575,664,268,1294,270,271,271,270,270,726,549,1922,510,573,629,190,1549,637,4444,4515,545,742,3732,1296,422,1023,1877,4516,231,232,233,190,1266,3685,3558,901,902,303,305,303,4517,1164,429,149,1522,280,281,280,281,280,674,545,1188,1199,4518,4519,148,445,670,545,1188,1199,1084,439,440,916,1101,1543,1084,439,838,23,515,571,687,980,2369,4221,4520,2262,587,434,347,455,455,4521,4479,486,346,319,347,455,643,1318,1169,439,838,47,1562,765,1596,1909,835,3746,1288,1289,765,765,1290,1291,523,44,45,1006,69,687,688,80,3696,581,455,455,1215,403,320,193,194,195,3921,609,169,178,934,1473,1474,3257,1783,3242,1692,216,542,1012,1013,1013,1014,2262,347,348,456,455,1215,69,4522,735,489,665,666,667,668,439,266,267,554,865,69,172,346,319,347,348,581,455,455,686,549,1338,270,726,549,4523,900,901,902,4524,303,304,303,788,549,1338,401,383,556,654,557,558,557,558,557,557,557,558,557,295,1616,278,562,281,281,280,605,1288,1563,442,355,356,519,990,3773,2228,570,952,2362,355,383,357,383,357,383,519,990,4525,434,347,455,528,570,516,3203,268,270,4526,952,2570,147,401,383,502,634,538,538,538,1422,3242,228,229,1106,587,434,347,455,1149,69,509,172,180,181,233,187,1174,3361,4527,1663,697,545,1188,1199,1692,216,542,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1515,2603,4528,23,591,751,605,383,357,4529,3154,130,1084,439,266,1366,254,419,519,3653,140,141,1095,522,1154,687,980,1064,295,982,727,434,454,581,455,348,348,455,455,455,1109,2325,2087,2088,2326,2819,4530,4531,4532,154,135,136,137,138,139,136,137,138,139,1390,346,319,347,455,528,632,54,55,56,4387,355,383,357,356,357,383,384,558,557,558,559,560,442,190,482,483,484,485,486,1294,270,270,726,549,4523,1288,2387,4533,2899,4534,2244,2215,4535,1288,765,1596,1909,758,2106,483,484,485,486,172,382,355,383,384,1348,557,558,782,543,1354,4536,2073,495,3367,3368,3369,3370,2570,735,216,736,179,147,589,4091,549,4537,591,150,446,592,636,549,1674,149,150,2087,2088,485,2505,2297,346,319,347,2336,1822,1368,460,179,147,1835,558,1482,709,60,61,73,2380,66,93,94,3529,66,67,254,419,824,765,2256,178,179,180,181,1163,1560,4538,492,172,390,391,494,616,505,691,507,390,391,616,2096,497,498,1745,4539,581,455,348,348,1215,426,641,642,434,1094,23,4540,4541,570,571,445,445,429,149,591,672,746,581,348,348,455,455,455,686,403,570,952,3990,268,270,4542,382,401,356,556,558,1482,148,445,445,429,149,759,446,512,435,1562,1289,765,1290,1291,523,44,45,524,977,4543,725,439,266,3466,3235,1721,68,69,3154,1074,1323,1026,319,347,1132,403,460,179,147,597,519,520,1332,1331,521,522,523,44,45,1346,4544,355,383,526,545,1188,1199,147,148,149,2303,2304,2305,447,592,636,403,148,429,429,445,149,150,446,790,3006,600,172,382,355,383,534,535,537,799,403,616,496,690,605,940,1188,1199,140,4003,4545,270,1294,270,270,270,1626,149,1243,280,605,231,232,233,190,1643,987,1248,435,455,4546,727,434,347,2336,528,516,2332,2331,2331,2332,2426,390,391,80,1941,3554,4547,666,667,1962,333,410,335,411,412,1241,1638,172,382,148,854,629,190,245,1409,1044,1846,369,400,179,180,181,233,190,191,4302,245,4548,357,442,445,429,149,511,446,447,447,593,616,497,2268,2399,149,150,446,1444,445,445,445,445,445,149,150,2745,4003,4549,608,581,348,1109,149,591,672,386,347,581,686,549,610,1314,1544,2365,69,429,149,591,150,446,592,592,447,447,512,549,708,149,279,280,281,280,281,280,281,280,1371,4550,653,570,571,145,146,147,401,356,556,557,559,622,2157,2339,4551,1150,145,146,147,148,854,574,3086,445,445,429,149,511,446,447,4261,640,510,4552,445,445,429,429,445,429,979,430,280,431,700,874,460,179,147,518,384,1935,542,1693,1693,1693,543,805,23,1486,69,759,446,447,447,592,512,69,809,809,809,809,809,840,809,840,840,809,809,809,809,809,810,809,1949,1323,222,223,224,644,586,565,1978,23,1188,1199,4553,774,23,150,446,592,592,447,447,447,636,549,1313,355,383,534,535,4554,352,791,687,688,495,1836,150,446,447,447,447,447,636,549,4555,1661,1662,616,496,496,373,224,644,222,223,645,646,647,648,649,2002,602,2471,4556,1094,398,445,445,149,4557,266,267,268,271,271,272,549,4558,402,302,303,304,303,548,549,4559,1199,356,556,557,1348,557,558,557,558,692,366,347,581,1215,758,4560,23,1039,3616,783,570,1658,54,55,2586,352,776,777,846,495,1802,2247,666,667,1564,1996,916,386,149,1522,281,280,1350,502,634,536,538,538,537,1759,3701,417,333,334,335,336,337,44,45,822,1032,300,2345,302,303,305,303,305,303,305,303,304,303,304,303,548,549,1338,401,356,302,303,304,303,548,69,276,179,390,391,494,616,496,691,507,154,135,136,137,138,139,140,4561,1018,1019,1020,423,424,4562,1022,2793,3092,4563,2244,4564,1244,69,680,589,653,2229,2460,545,671,237,743,744,188,189,240,188,189,187,1174,4565,355,356,534,535,1103,835,2061,2062,2195,2196,485,2505,4566,1348,557,622,180,181,1163,232,233,190,1931,2270,1499,1555,211,583,590,2675,1740,4567,1103,549,708,759,446,447,592,592,447,512,549,1338,430,280,281,280,281,281,281,295,2501,370,824,765,2315,3214,3215,3930,507,1472,758,429,149,430,280,281,280,1245,4568,547,172,180,181,233,190,575,4569,508,317,345,509,172,346,319,347,348,455,348,1502,1658,426,207,208,388,1167,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,4202,347,456,1215,69,191,802,782,130,632,54,55,2479,998,463,1241,148,445,445,445,445,445,445,2955,592,636,549,2147,1967,483,484,485,2505,2697,429,149,1522,280,281,280,281,280,281,280,281,692,347,581,455,455,455,686,758,769,770,771,1887,4012,233,190,482,483,484,485,486,609,4570,4571,216,542,1012,1014,769,770,3791,23,429,445,429,149,759,446,447,447,636,69,1522,281,281,280,281,1774,1268,1269,184,1165,3490,371,372,2369,659,2370,511,446,447,592,512,549,610,268,271,2493,549,1338,1514,1693,1693,1693,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,3616,756,554,269,272,549,1093,1696,938,939,1218,2243,401,356,556,654,557,557,558,557,557,557,655,556,654,557,557,557,558,557,558,557,557,557,558,557,558,673,417,333,410,335,336,337,44,45,1545,370,371,1505,495,496,689,690,2710,2347,179,147,532,4572,447,447,447,636,549,760,735,216,4296,172,382,355,356,534,535,1242,1241,1288,1289,1289,1290,1291,523,44,45,4573,216,4574,462,999,549,760,703,146,390,391,494,495,690,505,496,496,691,692,549,1338,2364,565,566,4575,4576,1413,4577,23,239,1165,2921,549,610,2803,570,1658,54,55,4053,1288,1289,765,1289,1290,1291,523,2829,149,430,280,442,607,545,2462,4578,826,1282,829,3716,254,47,2411,181,233,190,1554,1196,1197,1555,4579,492,172,382,510,998,3452,241,1165,4580,258,761,260,261,836,837,262,263,264,265,266,267,554,271,3282,4581,382,510,696,3350,2453,2954,390,391,494,616,505,2710,429,429,149,759,446,592,447,592,592,447,447,4582,538,537,537,537,537,663,549,1338,429,445,149,150,446,636,549,1922,511,446,592,592,447,447,447,447,636,549,1338,1931,2270,1499,4015,1749,276,179,390,391,494,616,4583,498,617,480,4387,1575,4023,193,194,195,2435,253,254,255,390,4584,149,150,446,447,447,512,1241,613,685,434,347,455,528,2302,4585,467,104,135,136,137,138,139,140,141,959,513,526,545,2314,1171,178,179,180,181,921,1560,744,188,189,187,4586,537,537,537,538,2961,287,1719,346,319,454,455,528,570,2495,601,602,603,602,603,602,603,602,603,602,603,4587,148,854,629,190,2412,1196,1197,2970,2971,180,181,233,190,469,2270,4588,755,921,232,233,190,4014,4178,807,318,319,347,581,455,455,455,455,455,686,403,570,516,2530,154,135,136,137,138,139,136,137,138,139,1304,1305,3083,2359,355,383,534,535,663,549,610,429,445,445,445,462,999,69,608,690,2559,692,532,526,2262,638,169,460,1120,1121,254,960,149,511,446,447,447,447,447,512,549,708,401,356,402,302,303,548,549,1338,512,549,1338,300,2345,2480,950,951,570,516,2257,1522,280,281,280,281,280,281,280,281,280,1237,229,4589,80,1496,445,445,445,429,149,591,994,282,4590,696,573,629,190,4591,1286,602,2527,2134,2453,4592,1065,1265,303,305,1841,403,2405,537,3221,810,809,809,809,809,809,4593,4594,2292,523,44,45,2117,2118,2119,2120,1531,3304,3305,3306,3307,3308,291,292,324,2571,1074,1323,346,476,477,478,785,4595,547,172,382,401,383,402,302,303,304,303,304,303,788,664,2224,1981,361,619,620,169,375,3033,4596,1854,3159,3670,382,401,356,519,990,3773,533,534,535,611,537,538,538,537,538,538,537,537,663,69,4597,608,611,538,538,538,537,538,538,537,1759,713,1612,697,769,1612,905,445,445,149,150,446,447,447,447,447,512,331,278,3535,810,1007,1031,333,1232,335,336,337,44,45,46,47,1876,422,1023,4598,1039,3616,237,238,184,185,186,190,1931,1932,2249,287,1719,346,319,454,455,1239,435,178,179,382,510,278,759,446,448,680,401,356,556,557,558,557,1348,557,557,386,231,967,1890,769,770,3973,148,429,445,429,149,759,446,512,637,149,150,446,592,592,3629,735,216,449,439,266,267,2393,3235,429,429,149,672,280,281,280,281,280,507,496,1817,561,680,2678,4073,207,208,4599,1041,254,984,1077,340,340,340,340,340,340,340,340,1546,1078,1546,1078,340,340,340,340,4600,4601,1782,1156,1116,572,489,665,735,216,449,439,669,179,390,391,494,2563,497,2418,2419,1026,319,454,348,695,590,3741,511,446,592,592,447,512,350,737,738,2134,3217,870,276,179,346,319,347,1502,1159,1160,3468,3547,4602,1638,172,2676,18,355,383,357,357,302,303,304,303,548,758,771,4603,1887,916,3367,3368,3369,3370,347,1822,549,708,240,2328,4604,918,355,383,534,535,538,611,663,549,760,429,149,591,150,446,447,592,592,447,512,549,610,548,549,610,1163,4605,538,1242,549,4606,4607,254,1032,401,383,2244,2453,618,791,172,147,401,383,519,520,1332,1909,435,698,445,445,445,149,150,446,447,592,592,447,636,713,460,179,147,597,556,654,557,557,557,558,557,3820,240,2328,2329,950,951,515,1658,54,55,2040,2375,278,150,2087,2088,485,2505,2749,231,232,233,190,745,80,1941,2599,3468,1792,300,301,302,303,1527,934,1473,4608,193,194,1577,3020,687,688,495,505,496,690,1461,759,446,447,447,593,1304,1305,1306,549,1028,616,690,2710,311,181,233,190,234,1498,1499,1555,683,495,690,496,691,295,1911,445,462,463,1241,2136,1793,3332,1413,1093,3830,3831,1425,2103,1427,382,401,383,402,356,556,558,559,4609,173,1981,1663,697,545,2700,626,627,1638,172,382,148,854,629,190,191,2654,375,376,1627,1331,1331,1909,350,670,545,2421,883,4610,687,688,616,2559,507,149,150,2087,2088,485,3759,545,1188,1846,445,445,1302,608,2224,4611,355,383,357,383,357,356,534,535,652,382,355,383,534,3869,650,4612,1846,140,141,680,714,271,271,271,272,549,1313,149,562,281,280,281,280,442,545,3154,187,188,189,4613,291,297,3252,29,367,368,369,400,179,382,510,573,4327,513,526,545,714,1169,439,440,916,1100,917,386,3403,182,606,2214,2339,3581,3367,3368,3369,3370,429,429,429,429,445,445,445,149,759,4614,1418,3235,147,355,383,384,558,557,373,300,301,358,359,359,4615,401,383,502,634,611,537,537,538,538,4616,1286,4617,777,778,779,1751,782,3261,777,846,495,505,690,690,690,690,496,690,690,496,691,782,4618,4619,2857,4620,302,303,304,303,304,303,304,303,304,303,304,303,304,303,788,2854,1099,916,1101,860,1101,1100,1100,1101,1101,2128,295,1616,4061,921,967,4621,69,355,383,526,545,714,178,179,390,4622,4623,1037,1031,333,410,418,255,579,580,703,146,147,355,443,999,549,2099,300,301,358,359,3903,2411,181,233,190,245,1409,987,2674,518,384,654,557,558,557,557,558,507,149,759,446,592,512,549,550,4624,2323,23,534,535,538,2057,2733,187,1174,1228,295,506,149,511,446,592,592,447,592,592,447,512,549,1338,687,688,495,690,3384,782,769,770,3791,724,4625,4626,333,1232,418,985,2153,875,146,346,319,347,4627,665,735,216,3940,399,400,179,147,401,3124,216,1042,439,4568,401,383,526,769,770,2744,231,232,182,183,184,185,186,190,4065,445,445,149,150,446,447,4261,4628,23,3471,518,384,654,557,558,1351,570,571,554,1244,1241,556,654,557,3654,1522,281,281,280,281,281,782,390,391,494,495,689,496,690,496,496,1619,4198,591,150,446,447,592,592,636,549,760,356,502,634,538,1472,435,348,1839,330,332,333,4629,178,179,147,401,383,556,654,557,558,557,295,982,370,371,1505,495,782,291,292,2054,54,55,2479,172,390,391,494,495,496,1083,498,1745,4083,429,445,445,445,462,999,331,447,592,512,549,610,429,445,429,429,429,1704,4630,1693,543,1354,4631,924,179,390,391,494,495,689,655,149,591,150,446,447,592,592,447,447,512,549,1338,756,554,270,269,271,272,549,1338,1396,713,1169,439,838,23,490,216,449,439,669,179,346,319,454,1027,69,1658,2335,291,292,324,253,68,3891,3148,278,150,446,1523,429,149,279,280,281,280,1718,148,854,574,575,4632,253,254,960,367,368,369,641,642,434,454,2146,403,1890,545,2314,764,765,2315,2316,2317,523,44,45,4633,769,770,2990,134,565,2923,23,134,216,1042,439,266,267,554,1294,271,271,270,270,3080,654,557,558,557,558,557,558,782,430,281,281,280,281,281,281,280,281,280,442,383,502,634,611,537,537,537,2349,514,570,2750,934,1473,4608,193,2828,696,573,629,190,745,80,847,3089,149,759,446,592,447,447,3165,1595,657,1908,1750,781,781,780,780,781,1752,1163,232,233,240,1174,3039,637,271,1294,726,549,1338,4362,4363,1245,1348,557,558,557,557,557,557,558,1635,566,128,2685,4634,1744,507,905,613,685,434,454,455,528,570,1658,4073,352,776,146,1824,23,382,1286,602,603,602,603,507,527,390,391,494,495,690,839,1663,1706,278,150,446,592,1204,278,511,3810,2662,497,498,2419,355,356,384,1348,557,605,511,446,592,592,447,592,592,447,447,636,549,1338,447,447,592,592,447,447,512,69,1304,1305,1306,435,1189,597,556,654,557,557,557,558,1351,191,192,193,194,4635,727,434,347,348,4636,1598,2360,498,2419,1348,557,557,558,557,558,1482,1077,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,4637,237,238,184,185,186,241,185,186,3486,4638,513,526,545,661,69,1288,1289,1596,4639,1522,280,281,280,1510,180,181,1163,232,233,239,1165,2921,835,700,4640,266,267,554,270,269,272,69,1784,1275,689,605,330,252,253,254,419,545,1188,1846,300,2800,4641,271,271,270,270,270,2007,653,570,952,2570,356,534,535,538,538,538,799,549,2147,921,232,233,239,1165,2921,69,231,232,311,181,233,190,234,1498,1499,1555,1218,248,747,2179,2179,2180,2179,2180,2179,2179,2179,295,4642,2162,483,484,485,2505,4566,347,2336,1822,549,729,297,436,1538,1702,1013,1014,515,952,2406,182,606,2478,570,1658,54,55,2625,172,382,148,429,429,149,511,446,447,592,592,447,447,512,549,1028,2108,860,1100,1100,1101,1100,1101,3053,402,302,303,304,303,788,549,2863,727,434,347,348,944,549,708,616,2172,497,659,974,148,149,150,446,447,447,447,447,447,512,549,1674,728,835,583,149,759,446,790,1690,1100,1100,3417,1348,557,561,591,1243,281,1281,401,383,519,1128,1129,666,667,2347,1120,1121,254,985,670,769,2105,233,190,482,483,484,485,2622,2697,1339,463,549,760,149,591,994,561,401,356,502,634,611,538,538,538,537,537,537,2349,608,518,534,535,536,538,538,2702,537,2289,2053,445,445,429,149,511,446,447,636,549,610,417,333,410,418,960,755,518,534,535,537,2566,1611,402,302,303,305,2548,445,445,445,429,429,445,445,429,1704,3338,4068,587,434,454,2336,1318,1304,1305,3288,1783,154,135,136,137,138,139,140,141,680,1189,545,1188,1846,445,149,759,446,636,549,610,4643,774,23,270,1244,549,1338,149,759,446,592,447,592,592,512,664,346,319,454,686,69,587,434,2446,4644,3154,4645,2308,759,3178,4646,271,271,270,270,3080,2228,570,952,2570,510,696,2024,3951,4647,449,439,669,179,346,319,454,2336,4644,943,319,347,456,348,1318,680,148,429,429,149,759,1811,383,519,520,1597,300,2345,302,303,788,758,545,1188,1199,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1968,239,948,949,950,951,570,1658,54,4648,1562,1289,1289,4649,355,356,519,520,521,522,523,44,45,524,1275,769,770,3874,611,663,713,173,185,926,4650,601,602,603,2441,4651,1268,1971,744,188,189,241,1165,184,185,186,240,1174,2536,3560,591,150,446,592,592,447,592,592,447,447,636,426,777,846,495,2662,2648,1083,332,333,334,335,336,337,2829,231,967,1890,545,1188,1846,680,2338,1213,267,268,271,270,2251,549,1922,4652,169,178,179,346,4653,1171,154,135,140,141,1095,522,523,4654,703,146,390,391,494,2073,495,690,496,496,496,496,496,1111,149,591,1243,281,280,281,752,383,357,534,535,536,537,538,537,537,3131,2157,3217,3581,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1014,382,401,356,402,874,601,602,1275,3061,3062,558,557,1635,239,948,949,950,951,515,516,4655,783,570,516,2373,455,970,1318,462,999,549,1338,445,445,429,149,591,150,446,447,447,512,549,1338,854,574,2534,1184,1185,4656,382,2274,738,739,2245,251,332,333,334,335,336,337,44,3868,570,3142,147,355,383,514,570,952,2627,330,4657,180,181,233,190,1554,1196,4658,145,777,846,495,505,496,496,690,691,711,1887,859,860,1100,1100,1100,1100,1275,3556,1426,1427,445,445,445,149,3260,1642,759,446,592,4659,1658,54,3957,401,383,556,654,557,558,557,557,557,684,542,1693,1693,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1763,1764,2462,654,557,558,557,557,557,558,557,558,557,605,271,271,271,270,270,271,272,549,1674,826,1282,829,830,831,832,832,832,832,832,832,832,832,966,2244,3217,2467,482,483,484,485,486,1042,439,4660,1243,281,280,281,281,282,278,759,446,592,636,549,4555,1744,497,498,4010,777,846,495,505,496,496,690,655,401,443,999,435,3360,820,147,510,573,629,190,1549,193,194,1202,3691,1830,439,266,267,2393,23,498,2419,670,2262,401,383,556,558,557,752,838,23,462,999,1368,601,602,2527,2275,4661,390,391,494,495,673,1013,1013,1039,3616,180,606,607,545,2421,510,696,697,545,1188,2249,504,644,222,223,224,216,449,439,669,179,346,319,4662,251,252,253,254,1032,532,700,2581,346,319,347,348,455,581,455,3708,3593,4663,332,333,2417,614,615,495,496,497,2268,2399,2538,376,377,990,1363,1007,1031,333,1232,335,336,337,44,45,46,23,756,554,2251,549,1093,2329,950,951,515,571,231,232,182,183,184,185,186,190,1785,2558,4664,1736,270,726,549,1571,134,216,1042,439,266,267,554,270,757,549,2830,516,2257,148,429,429,445,445,445,445,429,1704,520,4253,810,809,4665,4666,1152,1551,255,1456,216,449,439,669,179,147,518,519,990,1534,819,2243,513,526,545,2314,460,179,147,461,445,445,445,445,2884,149,430,281,280,281,280,281,1774,4667,148,445,445,445,445,445,149,150,1811,356,556,654,557,557,557,557,558,557,557,557,558,557,558,918,382,148,854,629,1404,526,769,770,2992,2652,2653,184,185,186,190,1643,1940,149,430,280,1510,485,486,4668,1552,128,3981,1241,709,60,61,2671,2672,1421,69,4669,4670,190,2325,2087,2088,485,486,178,179,382,355,383,519,990,1025,366,237,743,744,188,189,187,188,189,190,986,987,4671,1037,1031,333,410,335,411,412,4074,245,1409,987,2887,4672,3566,348,686,403,297,4673,398,581,1215,69,769,770,2744,461,445,445,429,149,591,150,446,447,512,549,1338,268,1814,1815,952,2332,2332,2331,2331,2332,2550,549,1338,1294,272,549,1571,449,439,4674,23,355,356,384,557,557,2265,1635,597,2308,430,280,281,280,281,280,281,280,281,280,674,1215,549,760,4675,132,240,2328,2329,950,951,515,571,171,587,434,347,348,455,455,1149,2770,547,587,434,347,348,695,613,685,434,454,455,528,570,1658,54,55,633,429,445,149,562,281,622,1962,333,1232,335,336,337,44,45,4344,4676,346,319,347,581,1109,2066,1199,2503,384,1350,429,149,511,446,447,447,447,790,149,1243,281,280,281,373,1613,4677,601,603,603,602,603,603,602,918,767,860,1101,1101,1101,1100,1543,375,376,1627,1331,521,522,523,44,45,524,3683,1424,764,765,2315,2316,2317,523,4678,148,445,670,545,671,229,4679,3366,434,347,2146,3198,586,216,449,439,669,179,147,4680,758,4681,348,4682,543,1354,1568,355,356,534,535,2575,758,460,179,147,597,402,1396,549,1571,305,303,305,303,304,303,305,303,305,303,304,303,304,303,304,1884,279,280,281,280,281,280,281,280,281,280,281,280,2018,2142,1887,916,2128,563,445,445,462,463,435,502,634,538,536,663,69,4683,333,334,335,336,337,44,45,3316,777,778,780,4684,570,571,1286,602,2527,2134,4685,300,301,302,303,304,631,570,2503,4686,687,688,495,505,690,690,496,496,793,149,591,150,446,447,512,435,356,502,634,538,538,799,69,348,455,695,553,439,4687,147,597,4688,173,948,2354,1796,281,918,345,509,172,382,510,712,2136,3338,4689,4690,949,950,951,570,952,529,1189,148,149,2303,2304,2305,447,447,447,592,512,69,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,4691,791,172,231,232,3379,355,383,526,698,4692,4693,149,511,446,592,1728,545,742,943,319,454,686,435,456,1215,549,1338,490,216,1042,439,266,267,883,268,4694,514,570,952,3853,348,944,413,510,278,759,446,447,636,758,2314,534,4695,23,1294,270,270,270,270,4696,454,2146,549,550,4697,1254,1255,1256,1912,253,254,255,601,602,2004,4698,1245,251,252,253,254,255,4699,147,401,356,556,654,557,558,684,791,172,147,148,445,445,429,149,511,446,447,447,512,758,490,216,1042,439,4260,769,770,2141,382,148,854,574,469,2270,1499,1555,4700,147,401,383,874,401,356,402,1733,4701,541,538,1395,549,2147,514,570,952,2362,4702,238,184,185,186,190,745,80,4034,332,333,410,335,411,412,69,1967,483,484,485,2197,584,585,586,644,222,223,224,216,449,439,669,179,390,391,494,495,4703,460,179,147,277,278,562,280,281,280,295,1616,742,2602,2603,4528,23,401,356,302,303,305,303,305,303,305,303,304,303,304,303,305,303,305,303,304,303,548,549,1338,429,149,759,446,447,447,447,512,549,1571,510,712,278,1522,280,2018,2142,557,558,557,557,1482,430,280,281,280,281,280,281,280,281,280,281,280,1275,148,429,445,445,149,150,446,447,2121,4704,445,429,149,759,446,447,592,512,1368,728,403,3855,496,1342,782,2274,738,2784,2276,2276,2276,2276,4032,295,1616,728,69,142,251,465,386,703,146,390,391,494,495,691,295,1616,1171,4705,4706,1291,523,44,45,46,541,587,434,347,581,455,455,1318,4707,134,216,1042,439,440,859,860,1100,1100,2128,1245,515,571,4708,149,511,446,447,447,636,69,348,348,348,348,348,455,348,455,3103,608,632,54,55,1238,383,402,383,556,654,557,557,557,558,557,558,557,282,1232,335,336,337,44,45,46,47,241,185,186,240,188,189,190,1828,4709,921,967,1890,769,770,2657,4710,534,535,663,549,1093,2028,4711,149,279,280,281,281,295,982,462,2663,510,696,696,278,591,1243,280,442,356,519,4211,1348,557,557,622,698,510,712,278,430,280,622,1436,4712,628,777,846,2073,495,1403,3462,980,781,779,781,1751,295,506,591,150,446,592,1728,553,439,838,23,616,2172,497,2418,4713,356,1629,4714,921,967,2228,570,3104,492,172,382,148,429,429,445,149,562,281,280,281,280,281,280,2018,2142,1692,216,542,1693,1012,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1039,4473,1846,756,268,270,1806,403,149,279,281,281,280,281,280,281,280,281,280,281,280,640,485,2197,3193,270,270,270,726,350,278,150,446,447,4300,2898,232,233,190,2412,1196,1197,1555,130,149,279,280,281,280,295,1616,180,181,233,2546,486,3106,999,549,610,272,549,1922,885,4715,687,980,2369,4221,711,4716,154,135,136,137,138,139,136,137,138,139,4717,2470,650,651,603,3951,1206,502,634,538,611,537,537,538,538,537,2289,608,430,280,281,281,373,696,278,759,2778,1536,2224,1981,390,391,494,2073,495,3367,3368,3369,3370,642,434,347,945,455,348,686,403,571,545,3455,355,383,519,1128,1129,239,185,186,239,185,186,190,1828,192,193,194,195,4718,268,270,270,2007,3084,1528,2447,797,169,4398,587,434,347,1840,2163,4719,229,909,146,231,232,311,181,233,190,245,3611,1304,2876,564,216,1042,439,266,267,268,271,270,1214,549,708,375,1462,1463,4720,2073,495,497,498,2692,618,712,712,998,999,1216,1562,2315,4721,4203,2594,777,846,616,496,1342,1353,4722,355,356,534,535,663,69,559,560,1178,570,3142,502,634,538,536,1759,69,149,279,280,281,1245,454,455,348,686,413,591,672,280,281,280,507,686,549,2830,429,149,279,280,442,686,403,1506,1872,332,333,3246,197,492,172,382,510,573,4723,1995,401,383,502,634,611,537,537,537,537,4724,1101,3456,1718,454,728,549,1674,447,447,592,592,447,512,549,1571,558,557,558,557,558,557,558,557,558,557,558,557,1935,3193,1658,54,2839,2145,402,4725,231,232,233,190,4014,3722,1499,4015,1749,278,4726,1642,2394,401,383,502,634,537,1103,4727,390,391,494,495,690,505,690,690,496,496,496,1803,564,565,566,1544,2365,69,369,400,179,147,148,854,629,190,2175,4382,230,146,147,355,443,999,4392,1086,333,410,335,336,337,1233,4728,373,401,383,502,634,4729,445,149,279,280,1774,777,846,616,689,691,673,429,429,445,149,759,446,592,636,758,2244,2453,4064,608,820,180,181,182,183,184,185,186,240,1174,744,188,189,190,986,1044,1199,454,945,455,686,549,1313,477,2064,2065,2066,1189,455,686,549,2746,1214,549,800,687,980,4730,455,581,455,455,686,403,149,511,446,512,403,1199,190,4731,3926,1031,333,410,418,3235,776,727,434,1821,454,348,348,1215,69,1086,333,410,335,336,337,44,45,822,2344,1077,1517,490,216,542,543,1354,1702,2069,4045,586,216,449,439,838,23,698,147,510,573,574,234,1498,1499,1555,905,382,148,445,445,445,429,462,463,758,1690,1100,1543,3063,239,185,186,240,188,189,240,1174,744,188,189,239,1165,1561,3560,390,391,23,700,3936,4732,964,4733,422,423,424,425,4734,4735,149,562,281,280,281,280,782,3588,672,1618,4736,4737,4738,23,240,188,189,240,188,189,4739,211,4740,400,179,147,148,854,629,190,191,4741,1074,1973,2652,2653,184,185,186,241,1165,184,185,186,190,1643,2886,471,1242,549,1338,429,429,445,149,759,446,592,447,447,636,637,401,356,556,654,557,557,557,557,558,557,4742,266,267,883,554,4743,3242,237,238,184,185,186,190,575,802,80,4744,2470,650,602,603,2471,4745,373,510,712,278,511,446,636,549,2147,147,401,356,519,1192,3924,462,463,426,698,2262,329,216,449,439,266,267,554,2551,3469,810,809,840,840,809,809,809,809,809,810,809,1949,1323,370,371,1505,616,497,498,3649,278,150,2087,2088,485,2622,2697,736,179,147,4746,709,60,61,72,4747,54,55,2479,462,2995,511,446,447,447,592,592,447,512,403,777,778,1064,1751,711,62,93,94,4748,4749,68,549,1093,401,356,302,303,304,303,304,303,305,303,305,303,788,435,1835,557,557,557,557,557,558,557,558,782,671,756,554,270,271,2510,435,445,149,759,446,592,447,1772,4750,4751,1286,2004,839,440,859,1762,1222,496,1960,655,883,4752,1015,172,180,181,233,190,2768,1932,1045,943,319,1094,23,2478,515,952,2257,511,446,512,549,708,366,545,1188,1846,2089,54,2839,2145,1112,2843,4324,4753,511,446,592,447,1787,402,302,303,305,303,305,303,305,303,305,303,304,303,304,303,788,403,2505,2650,2570,231,232,311,181,233,3486,172,390,391,494,495,690,3367,3368,3369,3370,2301,783,570,1658,54,2839,2145,240,188,189,240,188,189,190,4754,1044,4755,429,429,445,429,149,759,446,2121,4756,2570,449,439,266,267,268,1814,1921,325,4757,477,2064,3821,54,55,633,382,510,2024,3951,4647,237,743,744,188,189,190,234,1498,1499,1555,130,1188,2249,687,688,495,689,496,1350,536,537,537,538,2349,295,466,608,346,319,3781,2486,447,592,592,2121,4758,231,232,233,190,191,192,193,2144,4759,4453,2762,1519,303,305,303,305,303,304,303,304,303,548,435,390,391,494,495,689,690,691,673,497,2268,3771,429,429,149,279,1513,810,1949,1323,170,4760,4761,4762,2881,2195,2196,2438,4763,460,179,147,597,502,634,536,538,663,549,1338,2162,483,484,485,2505,2356,587,434,347,581,455,348,1215,69,527,1518,611,538,663,549,2746,742,2130,184,185,186,190,1828,802,782,4764,4765,401,383,519,990,1408,492,172,382,355,356,384,1784,673,614,615,1511,486,745,80,1381,4766,840,809,809,809,811,812,899,814,815,816,817,333,410,335,336,337,44,45,524,839,645,646,4767,333,2164,1171,355,383,526,545,714,2387,2432,4768,401,383,402,383,502,634,611,537,537,537,612,382,1286,602,711,2854,1658,54,1509,402,302,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,548,69,355,443,999,549,800,1288,1289,765,765,4769,713,587,434,347,582,429,149,430,280,281,280,281,280,281,280,281,280,918,759,446,447,592,592,447,512,758,514,570,1658,54,55,4053,502,634,663,435,104,135,136,137,1287,139,140,141,1095,522,523,44,45,1006,664,514,570,952,2362,2262,687,688,495,496,505,690,4770,1294,270,726,549,2830,1787,429,149,591,672,280,281,280,2018,1642,512,331,3224,663,758,429,149,591,994,561,4771,272,69,769,770,4772,346,319,347,348,3566,330,3111,433,434,4100,1106,172,147,277,696,2136,990,4773,460,179,147,518,534,535,611,537,537,537,538,538,1759,758,429,429,149,1243,281,280,281,280,281,563,330,252,253,254,255,3580,4674,541,429,429,429,149,150,446,447,447,447,512,637,516,2373,454,686,637,2567,782,4774,4775,668,439,669,179,346,319,454,768,528,952,2331,2331,2332,2332,2511,664,447,512,637,291,292,324,253,254,985,347,581,1318,537,539,505,690,496,496,496,839,366,944,549,1093,513,2244,2699,921,967,1890,769,2301,1159,1160,3468,2616,549,1674,683,492,172,382,148,445,445,149,1310,769,770,4776,743,744,188,189,241,185,186,239,185,186,187,1174,744,188,189,240,1174,2536,1164,4777,4778,4779,422,1023,4780,556,654,557,558,557,558,557,557,557,977,429,429,445,4781,686,403,2478,570,952,3525,2533,497,659,660,777,846,2073,616,1245,495,691,793,291,292,2054,193,194,1162,601,602,2527,2134,2453,2824,2375,1657,808,1007,3388,2143,835,355,356,356,357,1396,403,771,4782,4783,2807,2228,570,571,2981,2880,3148,921,232,233,239,1165,1938,295,506,617,4539,224,3122,4784,1242,549,2863,462,999,637,2400,157,101,624,625,626,627,628,146,147,148,854,629,190,1195,3678,291,297,436,1538,1691,180,606,2224,4785,518,534,535,536,538,663,403,1323,4786,4787,356,502,634,538,538,799,435,709,60,61,4788,251,332,333,410,335,411,412,713,542,1693,1693,1693,1693,543,1354,2491,502,4789,454,686,549,610,4084,725,439,266,267,268,1294,270,270,271,726,549,760,4260,810,809,840,840,809,809,809,809,809,840,809,809,1007,1031,333,410,418,23,4790,575,192,193,194,195,965,352,621,777,778,2006,692,769,770,3639,943,319,320,193,194,2556,1965,231,232,921,1560,744,188,189,190,986,2886,3060,2596,2819,4791,4792,4793,1526,982,602,1362,3955,4794,4795,4796,4797,4798,601,602,603,602,603,602,295,982,2953,2073,495,3367,3368,3369,3370,976,3367,3368,3369,3370,355,383,383,384,558,559,560,2775,100,216,1042,439,266,267,554,269,271,726,549,800,943,319,454,348,348,1149,549,1922,355,383,534,535,538,1472,549,1338,346,319,1821,347,4799,4800,777,846,495,505,690,691,692,1501,971,995,4801,3365,1661,1662,80,1381,1382,1410,3148,3637,4802,4803,770,2141,4118,348,348,455,455,686,549,1338,727,434,454,455,1149,403,1169,439,4568,430,281,281,280,281,281,281,280,281,280,281,782,557,1348,557,558,561,519,1230,4804,587,434,347,348,581,455,348,348,2313,149,759,446,592,447,447,593,514,570,4805,4806,4807,4808,422,1023,4809,514,570,3142,2162,483,484,485,2089,54,3957,665,666,667,1514,1012,1851,207,208,388,3309,4810,4811,149,430,280,281,280,281,280,281,280,281,752,290,383,502,634,536,537,537,538,537,1759,403,445,149,150,446,447,447,636,549,3098,4812,2249,2404,2510,403,686,549,1922,2331,2331,2331,2331,2332,3853,271,271,270,270,1626,537,537,537,1759,403,443,4226,465,1872,532,700,4640,55,2625,147,355,356,357,384,1348,557,2201,4813,355,356,302,303,305,303,788,713,461,429,429,149,591,759,2745,2108,2128,977,149,1522,1411,390,391,494,616,496,691,673,510,278,759,446,447,636,758,2236,2779,23,611,538,538,537,663,4814,239,4184,502,634,4177,454,4815,440,859,1927,295,982,80,2433,686,69,1026,319,347,2146,331,1406,558,1482,4816,792,561,4817,2257,1099,859,1101,860,1100,1100,1101,1101,282,759,446,636,549,1338,1073,782,999,549,1338,148,149,511,446,447,636,549,1922,534,535,538,611,537,1759,549,1252,571,149,562,280,1371,402,302,303,305,303,305,303,305,303,305,303,304,303,305,303,305,303,304,303,304,303,2580,401,356,502,634,538,4818,1188,1189,2150,2151,355,383,384,558,1482,390,391,494,616,1960,563,840,809,809,1949,1323,1763,3616,1663,1706,4819,231,967,1890,769,770,4820,1665,333,334,4821,149,150,446,592,592,447,592,4822,1188,1846,266,267,883,554,1322,690,690,496,2247,2417,3451,1402,4823,746,2503,478,3660,4355,402,302,303,305,303,304,303,304,303,304,303,304,303,548,835,3145,3537,1579,340,1546,1546,1546,340,340,340,340,340,1078,340,1078,341,4824,645,646,647,1065,902,303,304,303,304,4825,664,230,146,231,232,233,190,910,4826,589,653,570,516,2627,536,538,537,612,429,429,149,150,446,2306,519,520,521,522,523,44,45,524,977,670,545,1188,2249,238,184,185,186,190,2434,193,194,1577,2811,149,591,150,446,447,592,592,447,447,512,549,1338,1804,1804,1804,1804,4525,735,216,1042,439,266,267,554,865,758,105,4827,601,602,603,603,603,602,603,603,603,602,373,150,446,592,592,447,592,592,512,69,2574,538,2575,549,4307,4828,507,2106,483,484,485,486,1268,1269,184,185,186,190,3023,1409,2886,3256,382,510,696,696,2136,990,1025,513,4829,4830,1026,319,347,581,348,686,403,149,759,446,447,592,4419,1002,278,2466,2360,2418,2661,1665,333,410,335,336,337,44,45,1006,549,1338,1667,4831,4832,1643,3694,587,434,347,581,686,403,4833,347,455,581,455,1215,2770,454,456,455,455,686,549,610,100,565,2923,23,840,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3229,2724,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,3231,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,810,3226,2724,810,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,3231,810,809,809,809,809,809,3226,2724,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,3226,2724,809,840,840,840,809,809,809,809,809,840,809,840,810,809,809,809,809,3226,2724,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,3226,2724,810,840,840,809,809,809,809,809,810,809,809,809,809,809,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,810,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,840,809,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,3229,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,810,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3229,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,3226,2724,810,810,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,809,809,809,3226,2724,810,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,3229,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,3226,2724,809,809,809,809,840,809,809,3226,2724,810,840,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,3226,2724,810,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,3226,1621,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,840,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,3226,2724,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,809,809,809,809,840,809,3226,2724,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,810,809,810,809,809,809,809,3231,810,809,809,809,840,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,810,809,809,809,809,809,3238,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,810,840,809,809,809,810,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,810,3226,2724,810,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,810,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,810,840,840,809,809,809,809,809,810,809,809,3231,810,840,809,809,809,809,809,809,809,840,809,809,809,809,810,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,840,809,809,809,809,809,809,809,809,809,840,840,840,809,809,809,809,809,840,809,840,840,809,3226,2724,1546,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,3430,1078,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1546,340,1078,340,340,340,340,1274,1078,1546,340,340,340,1546,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1078,1546,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,1546,1546,1546,340,340,340,340,340,1078,340,1546,1546,340,340,340,340,340,1546,340,340,340,340,4834,1078,340,340,340,1078,340,340,340,340,1546,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1546,340,340,340,340,340,340,340,1546,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,1078,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,1078,1079,3241,4388,285,286,104,135,136,137,138,139,140,141,959,283,284,420,801,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,369,370,433,434,454,2146,435,117,161,101,225,226,120,121,109,110,99,111,112,99,161,328,329,101,225,226,120,121,367,368,399,400,179,231,232,233,190,482,483,484,485,486,117,161,328,329,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,1687,1688,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,117,113,101,225,226,120,121,367,368,399,400,179,147,355,383,526,608,161,101,225,226,120,121,367,368,399,400,179,382,148,445,429,149,591,994,1245,109,110,99,111,112,117,201,202,243,244,166,504,221,222,223,224,206,488,489,490,227,123,124,125,491,492,687,688,495,505,496,496,691,1281,326,327,99,111,112,99,161,328,329,122,123,124,125,491,374,352,353,146,147,148,445,429,429,445,149,150,446,592,592,636,549,1338,149,591,150,446,592,592,447,592,636,549,1313,117,201,202,427,428,99,111,112,117,113,101,472,157,473,474,475,179,382,513,533,599,231,967,2228,570,571,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,367,368,399,613,685,434,347,455,528,570,3104,117,201,202,203,204,584,585,586,221,222,223,224,206,488,489,490,227,123,124,125,491,228,375,376,377,3476,472,157,216,449,439,669,179,180,181,233,190,191,192,413,203,204,175,176,177,169,178,934,1473,1474,3257,1156,225,226,120,121,367,368,399,400,179,231,232,182,606,2478,570,516,529,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,508,317,4835,4836,102,103,104,135,136,137,138,139,140,141,959,102,103,104,135,136,137,138,139,140,141,959,641,764,765,2315,4321,400,179,147,148,445,670,545,742,458,459,169,460,179,147,597,502,634,536,538,1759,835,4837,4838,4839,243,244,166,167,638,169,943,319,347,348,1027,549,610,427,428,99,111,112,99,161,101,283,284,420,801,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,100,101,624,625,626,627,1179,4840,23,117,161,101,225,226,120,121,109,110,99,111,112,117,161,328,329,101,472,157,473,474,475,179,147,1663,697,769,770,2543,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,145,146,390,391,494,495,505,496,496,496,691,782,117,113,101,472,157,473,474,475,179,147,1663,783,570,516,2902,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,99,161,328,393,572,206,488,489,490,227,123,124,125,491,228,178,179,382,355,356,534,535,2046,69,117,201,202,427,428,99,111,112,99,113,414,415,487,206,488,489,490,227,123,124,125,491,145,146,147,401,356,502,634,538,537,1472,4841,117,113,101,225,226,120,121,109,110,99,111,112,99,113,122,123,124,125,126,127,128,2307,161,101,225,226,120,121,109,110,99,111,112,99,113,101,225,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,326,327,99,111,112,99,161,328,329,101,1692,216,542,1693,543,2451,102,103,104,135,136,137,138,139,140,141,959,472,157,473,474,475,179,382,589,670,698,161,101,102,103,104,135,136,137,138,139,140,141,959,243,244,166,504,221,586,216,449,439,669,179,390,391,494,2073,616,1111,122,123,124,125,491,127,128,129,683,367,368,399,370,433,434,454,528,2529,2627,180,606,607,545,1188,1199,367,368,399,400,179,147,1286,602,2527,2134,2565,203,204,458,459,169,375,2846,3423,4842,549,610,2939,23,206,4843,4844,888,439,266,267,268,1921,549,1338,101,225,226,120,121,109,110,99,111,112,99,201,202,427,428,99,111,112,99,161,101,225,226,120,289,109,110,99,111,112,99,113,101,947,226,120,121,367,368,399,400,179,231,232,233,190,2162,483,484,2343,486,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,140,141,959,117,201,202,427,428,99,111,112,117,113,101,114,119,120,121,109,110,99,111,112,99,100,158,123,124,125,126,159,128,129,131,583,161,328,329,101,472,157,275,473,474,475,179,382,589,670,545,2314,326,327,99,201,202,203,204,594,595,596,316,317,703,146,147,148,149,511,446,512,549,1338,117,201,202,427,428,99,111,112,117,161,101,225,226,120,121,109,110,99,111,112,99,113,101,947,226,120,121,109,110,99,111,112,99,161,101,102,103,104,135,136,137,138,139,1304,1494,117,201,202,427,428,99,111,112,99,113,101,156,157,101,1456,101,162,163,4845,4846,118,119,120,121,109,110,99,111,112,99,100,101,156,157,101,114,119,120,121,367,368,399,400,179,147,148,4847,999,549,1571,117,113,414,415,487,101,225,226,120,121,109,110,99,111,112,99,100,152,249,250,101,330,465,442,161,328,1116,572,4848,243,244,313,314,315,169,1644,2455,4849,4850,4851,243,244,166,167,609,169,178,179,382,510,696,1343,156,157,101,114,119,120,121,367,368,399,4317,23,329,101,472,157,206,488,101,156,157,152,249,1157,1158,396,553,439,838,23,4329,4852,203,204,458,459,169,2079,3386,1121,4853,109,110,99,111,112,99,100,158,123,124,125,126,920,145,146,231,232,233,190,1959,1415,2956,114,119,120,121,109,110,99,111,112,99,100,152,153,1254,1255,1256,2264,99,113,152,249,250,101,283,284,285,286,467,467,104,135,136,137,138,139,140,141,959,283,284,285,286,467,104,135,1493,2876,118,119,120,121,109,110,99,111,112,99,100,133,123,124,125,126,1194,178,179,147,355,383,534,535,537,1472,435,249,250,101,114,119,120,121,109,110,99,111,112,99,100,122,123,124,125,126,127,128,129,819,1667,104,135,136,137,138,139,140,141,959,136,137,138,139,140,141,959,1553,152,954,4854,808,811,812,899,814,924,934,1473,4608,835,4855,101,225,226,120,121,109,808,811,812,899,814,924,179,147,1286,602,603,602,655,313,314,315,316,317,345,509,172,382,401,443,999,435,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,563,80,4877,4878,4879,80,1381,4880,4881,3426,4880,4882,782,4883,4884,4885,4886,4887,752,4888,80,3426,4880,4889,4890,4876,4884,4885,4869,4891,4892,4893,4869,4891,4892,4894,4884,4885,4869,4870,4895,4894,4884,4885,4869,4891,4892,4867,4896,4897,4885,4869,4891,4898,2340,4899,4897,4900,4869,4891,4892,4884,4885,4897,4901,2340,4899,4902,4867,4903,4904,4897,4891,4892,4897,4884,4884,4885,4884,4885,4884,4885,295,4512,4905,4906,4907,4908,295,466,4870,4895,4909,4866,4884,4885,4884,4885,4884,4885,4910,4885,4884,4894,3367,3368,3369,3370,4911,4884,4885,4869,4891,4898,1746,2178,4912,782,4897,4913,4869,4870,4895,4884,4885,4884,4884,4884,507,4914,4884,4885,4884,4885,4884,4885,4884,4885,295,1911,2261,4915,4916,4906,4917,4906,3367,3368,3369,3370,4918,4919,2012,4897,4920,4897,4921,4906,507,442,918,442,295,4512,4884,4894,295,4512,295,4512,4922,4884,4885,4884,4885,4884,4885,295,4512,4923,2340,3663,4884,4885,4884,4885,4884,4885,4884,4884,4885,3367,3368,3369,3370,1941,4924,640,4925,561,563,4926,295,466,563,4884,4900,3367,3368,3369,3370,4927,605,752,605,4928,4929,295,466,4869,4868,4869,4891,4901,4930,746,507,4931,2688,4884,4885,4884,4885,4884,4885,4884,4885,4884,4932,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4933,4876,3367,3368,3369,3370,4886,4920,4216,605,4934,563,4935,4899,4897,782,442,4884,4885,4884,4885,3367,3368,3369,3370,3453,3367,3368,3369,3370,4936,295,4512,3367,3368,3369,3370,3367,3368,3369,3370,4886,4920,295,506,4887,4925,4891,4898,2340,4899,4885,4884,4884,4885,4884,4885,4884,4910,296,782,4937,4938,4939,80,3426,4880,4884,4885,4884,4885,4884,3410,4940,1526,296,746,480,481,4897,4885,4886,4887,1353,4917,4913,4936,3367,3368,3369,3370,3367,4941,4942,4943,4936,1718,3613,4893,752,3367,3368,3369,3370,4875,4884,4885,1371,752,673,4870,4871,3367,3368,3369,3370,295,4512,4906,3367,3368,3369,3370,4885,4884,4885,3367,3368,3369,3370,4892,4892,4886,4944,746,4943,4869,4903,673,2124,4945,1245,1381,4880,4884,4885,4884,4885,4884,1350,4886,4920,640,4946,1780,4884,4885,4884,4885,4884,4885,4884,4884,4885,4884,4885,4884,4885,4925,4947,4948,4949,373,295,4512,2395,4914,4897,4885,4884,4885,4884,4885,4897,386,4512,4950,2756,4870,4871,977,3367,3368,3369,3370,4951,3410,4896,4869,4891,4898,2340,2891,782,2433,2891,4887,1275,295,4512,4952,4925,4925,4897,4950,4870,4871,4884,4885,4869,4868,4869,4891,4898,2340,2891,282,4925,4885,442,4884,3410,4943,4869,4870,4871,4910,4953,4897,3367,3368,3369,3370,2340,2891,4914,782,4954,2688,752,4936,782,1872,4868,4869,4870,4871,3367,3368,3369,3370,563,4886,4887,373,4955,1526,296,4884,3367,3368,3369,3370,4956,4885,4869,4896,4869,4870,4871,4901,480,481,3367,3368,3369,3370,4957,4885,4869,4868,4869,4870,4871,4870,4871,4885,4869,4891,4892,4891,4892,4958,4884,4885,4884,4885,4884,4885,4884,4885,4884,711,4959,4913,4869,4870,4871,4869,4903,4960,4960,4961,4961,4961,4962,4963,4964,3367,3368,3369,3370,4867,4870,4954,480,481,4913,4869,4891,4901,480,481,673,4936,4965,2124,4945,4896,4869,4870,4871,4966,4967,4884,4885,4869,4868,4869,4870,4871,4936,295,4512,4901,2756,4884,4885,4897,4950,3367,3368,3369,3370,282,4870,4871,1371,4869,4868,4869,4911,295,4512,4913,4936,3395,4968,673,4896,4869,4870,4871,3368,3369,3370,4884,4884,4884,4885,4897,1526,982,4897,480,481,4870,4895,4969,295,4512,4897,4970,81,4871,4913,4869,4870,4871,3367,3368,3369,3370,4884,4910,4897,982,2954,4884,4885,4897,4966,4971,4884,4885,295,1616,4972,4950,4973,4966,4969,2441,4891,4898,2340,2041,4950,4884,4884,4885,4884,4885,4884,1245,4901,480,481,4885,4884,4885,4933,3371,918,2397,4891,4901,480,481,282,4913,4869,4870,4871,4966,4961,4961,3367,3368,3369,3370,4974,4975,4870,4871,4895,977,4887,3367,3368,3369,3370,4976,4868,4869,4870,4871,4977,4978,4917,4966,4967,1281,4936,3367,3368,3369,3370,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,295,1616,4969,4979,1245,4950,1105,4911,4892,442,4901,480,481,4898,2340,2891,4880,4891,4898,4930,4884,4885,4884,4885,4884,4885,4950,4885,4884,3367,3368,3369,3370,295,1616,4936,3367,3368,3369,3370,1353,80,4980,4981,3369,3370,4982,4869,4913,622,4964,4983,80,3426,4880,4884,1350,442,4984,4901,2824,2891,4966,4985,4884,4894,4884,4885,4884,4885,4884,782,4903,4969,4891,4898,442,4986,295,1616,4870,4871,4914,1281,480,481,4966,4967,4869,4891,4892,1237,4917,1350,4950,4867,4966,4985,4987,4936,3367,3368,3369,3370,4988,4989,4064,4936,507,4967,4990,4886,4887,782,1353,4884,4885,4884,4885,4884,746,1526,296,4991,4992,4901,2340,4899,4910,4884,4885,4884,4885,4884,4885,4884,3367,3368,3369,3370,752,4885,4886,4887,4897,4870,4871,4936,3367,3368,3369,3370,918,4966,4967,4897,4901,480,481,507,4894,3367,3368,3369,3370,4985,4869,4903,4961,1353,4993,4870,4895,4884,4885,295,4512,4884,4885,4884,3367,3368,3369,3370,4891,4898,4994,2340,2891,2560,4897,4870,4871,4885,4884,4885,4884,4885,4884,4885,1350,480,481,4995,1382,4996,4899,386,4867,4911,4034,4885,4884,4885,4884,4884,655,4997,1746,2178,4896,4869,4870,4871,4897,4997,2340,3413,4884,4885,4884,4884,1350,2340,4899,4903,4967,4869,4868,4936,442,4976,4903,4971,4892,4998,4936,4999,5000,563,4884,4884,4885,4884,839,5001,4933,4870,4871,5002,442,1955,4891,4901,5003,5004,3369,3370,4913,4869,4891,4898,2340,2397,5005,4869,4913,4936,3367,3368,3369,3370,4539,295,4512,1281,4997,5003,5004,3369,3370,4886,4914,673,2891,5006,4869,4913,4936,3367,3368,3369,3370,4966,4967,5003,5004,3369,3370,4903,5007,1930,1178,4898,5003,5004,3369,3370,4897,507,480,481,4884,4884,4885,4884,782,4988,5008,4892,1353,507,4943,4869,4870,4871,4885,4950,4910,480,481,4901,5003,5004,3369,3370,4950,4977,5009,4897,4961,4960,4962,4881,442,4903,4967,507,4884,4876,3367,3368,3369,3370,4891,4898,3306,3307,3308,4940,2824,3514,4895,3367,3368,3369,3370,5010,605,5003,5004,3369,3370,1245,4876,4884,4885,4884,4885,4884,918,4936,3367,3368,3369,3370,4943,4869,4870,4871,3367,3368,3369,3370,4897,2891,4898,2340,4899,4901,1955,4950,295,1616,4950,5011,3306,3307,3308,4903,4971,5012,1237,3306,3307,3308,1178,5003,5004,3369,3370,4954,4911,5013,5014,3369,3370,4884,4885,4884,4885,4910,4980,4981,3369,3370,4966,4971,1131,4898,5015,4966,4967,4871,5016,5003,5004,3369,3370,618,295,4512,4896,4869,4870,4871,5017,4978,4880,5003,5004,3369,3370,5003,5004,3369,3370,5018,563,803,4948,4979,782,5003,5004,3369,3370,4897,1245,5013,5019,4903,4985,3306,3307,3308,4900,622,1496,4950,4885,4886,4887,4925,3367,3368,3369,3370,1178,655,506,5020,1178,4968,5021,5022,5023,793,5024,4950,5014,3369,3370,4966,5025,563,4034,1281,386,4901,480,481,4951,622,1746,2178,4996,4910,5000,5026,4894,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,640,4891,4898,480,481,4898,3306,3307,3308,4936,295,4512,640,507,3779,4884,4884,4885,4884,3367,3368,3369,3370,4932,5027,622,1245,4885,4884,295,4512,3382,5028,5003,5004,3369,3370,4200,4870,4895,295,4512,4997,480,481,4871,2891,655,3696,4901,2177,5029,5030,4884,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,4884,1222,2891,5031,295,1616,480,481,4884,4884,4885,4884,4884,4884,4885,4884,4885,4897,4976,4884,4884,4885,4884,4885,4897,1350,4871,782,4997,480,5032,4885,442,1746,2178,4969,5033,4885,386,4933,4897,1371,1941,5034,4891,4898,480,3132,4897,4966,4967,5035,673,4870,4871,5036,4884,4885,4884,4884,4885,4897,1746,5037,4910,5003,5004,3369,3370,4912,4354,5038,3306,3307,3308,5039,4891,4898,3306,3307,3308,4884,4885,4897,4943,4869,4870,4871,4967,4936,295,4512,4952,4966,4967,5040,442,2775,1281,5041,4903,4967,4971,4997,5003,5004,3369,3370,4966,4961,4961,4960,4960,4960,5042,4885,4897,3613,4884,4884,4884,4884,4885,4884,4885,1222,673,782,4950,5043,4904,507,282,4997,480,481,3367,3368,3369,3370,673,5044,5045,4083,5003,5004,3369,3370,480,481,5046,80,4977,4978,4917,4936,1281,4961,5047,3367,3368,3369,3370,4884,4884,4885,4884,4884,4884,4885,4884,4885,4884,4885,4948,4979,3306,3307,3308,4964,5048,4936,3367,3368,3369,3370,1017,5030,4897,5036,4891,4898,480,481,5049,3367,3368,3369,3370,3306,3307,3308,442,4954,4898,5003,5004,3369,3370,3367,3368,3369,3370,5050,4885,4884,4885,4884,4884,4884,4897,5038,442,563,4903,4969,5051,295,5052,711,4936,3367,3368,3369,3370,4884,4885,4884,4885,4950,4960,4960,4961,4961,4961,4961,442,5003,5004,3369,3370,4950,1250,3410,640,4948,4979,4869,4891,4898,5003,5004,3369,3370,4911,4891,4898,3306,3307,3308,4897,4911,1752,5053,5054,4950,4952,5003,5004,3369,3370,1350,605,4885,4884,1353,4884,3367,3368,3369,3370,4903,4967,4933,4870,4871,4961,5007,282,5055,4898,2764,4987,2340,5056,4885,4884,1371,4968,4968,4968,5036,4876,4884,4885,4884,4885,1371,5057,2184,442,3367,3368,3369,3370,1178,2824,5058,373,4885,4884,4885,4884,4885,4884,4885,4884,3367,3368,3369,3370,4885,4884,4885,746,5059,1526,4512,1350,4925,1718,4886,4920,605,295,466,5003,5004,3369,3370,2891,442,4980,5060,4961,4961,4961,4961,4961,4962,655,1371,4880,4985,2441,3367,3368,3369,3370,5061,5003,5004,3369,3370,561,4884,4885,4884,4885,4897,295,4512,5062,4884,507,5063,4884,4885,4884,4884,4884,4885,4884,4885,4884,4886,5064,282,4948,4979,5036,4898,5065,5003,5004,3369,3370,1371,5013,5014,3369,3370,5020,4930,5003,5004,3369,3370,4968,4903,4985,442,2397,4895,1275,4933,3133,4885,4884,4885,4884,4885,4884,4885,4884,918,3382,5003,5004,3369,3370,3367,3368,3369,3370,1245,5066,3572,4980,4981,3369,3370,4985,507,4868,4936,3367,3368,3369,3370,5067,4950,4910,640,4920,295,982,4967,4885,295,506,4985,5067,1245,1872,1496,295,1616,4884,4884,4885,4950,1752,5036,1350,4933,4910,4884,4885,782,295,982,4898,5003,5004,3369,3370,1829,2433,4954,4884,4885,1281,3367,3368,3369,3370,5068,4960,4960,4961,4961,4961,4967,4972,5069,4885,4884,4884,4884,4885,4884,4885,4925,3367,3368,3369,3370,673,5070,563,480,2454,605,5003,5004,3369,3370,507,1275,5071,4886,4874,4903,4971,752,4911,4985,4969,4870,4871,4884,673,1245,2340,4194,4885,782,4884,4885,4884,4885,4884,4885,4884,4885,4884,4885,295,4512,563,4885,4884,4885,4884,4885,295,4512,563,5020,4910,5067,655,5003,5004,3369,3370,5003,5004,3369,3370,4910,4962,4884,2814,4884,673,5072,5073,5074,3369,3370,4876,3367,3368,3369,3370,1222,295,4512,4954,5075,3306,3307,3308,1836,5007,4964,1281,3367,3368,3369,3370,4894,295,982,1353,640,918,640,1353,1178,605,4885,4884,4885,4884,4885,4950,4933,1752,4903,4971,4933,4895,4884,4884,4885,4884,4885,4884,4885,1371,5051,4884,4885,4884,4885,1350,386,4997,2340,2090,1281,442,2340,5076,2688,2340,4458,2540,1350,4034,4925,5077,5003,5004,3369,3370,295,4512,4885,4950,507,4980,4981,3369,3370,4895,5003,5004,3369,3370,4960,3367,3368,3369,3370,295,2540,4954,295,982,507,4884,4884,442,5073,5074,3369,3370,640,4886,4944,1245,673,4925,5078,673,4884,4885,4950,1350,3367,3368,3369,3370,1941,5079,4933,918,5020,2340,5080,5081,3304,3305,3306,3307,3308,3304,5082],"category":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"subcategory":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"stringArray":["dyld","0x60df","cli","0x7126f","0x4826d7","0x7603f","0x609ef","0x6ac2b","0x483807","0x486697","libsystem_kernel.dylib","0x2474","0x6ae37","0x1e049f","0x464383","0x45cc2f","0x3ec73b","0x40e013","0x3e5c34","0x3eb5bb","0x407ebf","libsystem_platform.dylib","0x3674","0x3eadaf","0x3f2c94","0x3ea40f","0x3fb95f","0x3704","0x45cba3","0x45ba6b","0x45b04f","0x45a64b","0x4654f3","0x129c","0x3ed477","0x3e7f60","0x45cbf0","0x3ec6b7","0x409550","0x459c4c","0x3eab5f","0x40954f","0x3ec283","0x4095dc","0x3eb4a7","0x40473b","0x4bc3ef","0x4575f3","libsystem_malloc.dylib","0x271e3","0x26adf","0x566b","0x36f8","0x3ea3c0","0x1e05d3","0x1e0a3f","0x1e13bf","0x1e4293","0x1f6047","0x22eb","0x24bb","0x2d7f","0x6d84","0x1e4ba3","0x1e7e13","0x1d1187","0x1f71ef","0x1fbad3","0x1fc603","0x1f358f","0x1fc56b","0x1fd3e3","0x1fcfaf","0x4a038b","0x1380","0x1f6bef","0x1fbe27","0x1fb583","0x1fb71f","0x1fcb57","0x1fcfe3","0x1f2ed4","0x1e0dd7","0x1ef1c7","0x1f04ff","0x5eb3","0x63f8","0x1e0643","0x1d9f7b","0x23d6e7","0x1f3b17","0x238f6b","0x23fb93","0x1dcbb3","0x247da7","0x23d3eb","0x241d3b","0x1fb20f","0x1fc583","0x1f3723","0x1da083","0x26e81b","0x1dc553","0x1d8a03","0x142817","0x14984f","0x13f983","0x1a240f","0x2baf6b","0x2a9c63","0x1d44ff","0x281b5c","0x1da3db","0x146fe7","0x1a8def","0x1a99cf","0x14cff3","0x14eb47","0x1498cf","0x1a531b","0x1b0cc3","0x1ad224","0x1427c7","0x1a504b","0x1b0cef","0x1a7d9f","0x1b03df","0x140003","0x18417f","0x184937","0x184c87","0x184ff7","0x17fd73","0x28a557","0x311323","0x3df480","0x3df41f","0x3e0764","0x13fc7b","0x18440f","0x1d4423","0x1d4f5f","0x2afba7","0x216b3f","0x1e9747","0x1d4f1b","0x2b037b","0x219218","0x1848ef","0x1cdd37","0x17ebcb","0x29f81b","0x29ec47","0x295bcf","0x296227","0x2efbf3","0x2f917c","0x13fa97","0x1ab017","0x2baf8b","0x1e96b8","0x1a2b6f","0x1a66bb","0x13fec7","0x18001f","0x3112f8","0x1497c7","0x1a4a7b","0x1b0a2f","0x1b436f","0x13ee8f","0x18edcb","0x190dc3","0x195e6b","0x19696b","0x19cb0b","0x19921f","0x2a02f3","0x29eb4b","0x25b0a0","0x18ed47","0x191cc3","0x196283","0x19ed67","0x2be6c7","0x29eaf7","0x258da3","0x2a355f","0x267f9b","0x29463b","0x25aeaf","0x296c73","0x2a2ef7","0x25a417","0x296a4b","0x2a306f","0x2f495b","0x2e0977","0x22c7","0x353b","0x41fb","0x4318","0x180b6f","0x1804cb","0x2a08e7","0x298518","0x14cdff","0x187d7f","0x188477","0x189013","0x18cc7b","0x13f8cb","0x12a473","0x12a883","0x12935b","0x12dadf","0x3df4b7","0x3e0774","0x1a91cf","0x1accdf","0x1ad0bb","0x13f26b","0x1a095f","0x15b5b3","0x1add57","0x1ae0c7","0x13f763","0x1538d7","0x13e557","0x153b83","0x1a52eb","0x1b115b","0x13ff2f","0x1807fb","0x19d1fb","0x19a6ef","0x29ec2b","0x258bf3","0x2a35db","0x2f2d17","0x3065cc","0x18872b","0x19fc43","0x2972b7","0x2a2ddf","0x2a2e3f","0x2a2e9b","0x296c40","0x18835f","0x139bc3","0x2f497f","0x2cac2c","0x18cd43","0x3e06bc","0x1aba57","0x1ced57","0x1a26c7","0x287ecb","0x23f163","0x4a03b3","0x381c","0x18876b","0x13d72f","0x1498ff","0x13802f","0x14e05f","0x1502af","0x1327bf","0x13728b","0x132d77","0x1529ab","0x150ea7","0x1d7633","0x1d62df","0x1d6c3b","0x1d6c87","0x1d6cd7","0x1d6fdf","0x13fa43","0x1768bf","0x13f017","0x17f747","0x267bc3","0x295f2f","0x2eff5b","0x2ef347","0x2eefeb","0x1f5b8","0x1a4703","0x1beedb","0x1bf8f3","0x12c427","0x1e9697","0x281b28","0x1affdf","0x3e06f4","0x2a9ca3","0x27e457","0x20efcb","0x281b83","0x1f4af","0x340c","0x27e473","0x231a17","0x4c0458","0x29edaf","0x2a292b","0x296517","0x2a4b07","0x2a54ab","0x2a54fb","0x2a5518","0x2b03b3","0x2801b7","0x220b60","0x17ff73","0x2a359b","0x2a36cc","0x18ed9f","0x19371b","0x193d4f","0x1964bb","0x29e893","0x29c6c7","0x28f07b","0x29213b","0x41e4","0x1a99f3","0x1c4d80","0x20effb","0x14e4","0x188837","0x13e043","0x13f9f3","0x130693","0x1a2adb","0x2688c","0x287f27","0x49fcfb","0x4a675f","0x4a0513","0x4bfa93","0x49f7e7","0x45a4","0x137bf3","0x2b642f","0x2b658b","0x2b4787","0x2362ff","0x235df0","0x29c89b","0x29ea5b","0x292093","0x29315b","0x29327b","0x1408","0x1812a3","0x19ceab","0x197edb","0x2920c8","0x295a3b","0x296607","0x2687ef","0x2685bf","0x27478f","0x2747cb","0x18ed73","0x1901cb","0x1aa24f","0x1ca963","0x1aa793","0x200584","0x1a84e3","0x27d6f7","0x20c35f","0x2b25fb","0x2a108b","0x2ec373","0x1d44","0x1811ff","0x19fdaf","0x2ba353","0x29d2cf","0x29d020","0x1968cb","0x19e523","0x2be8e0","0x29eb13","0x296593","0x26885f","0x269adb","0x1f5fc","0x19183b","0x129407","0x12bd1f","0x29ee9f","0x2a25eb","0x2eb454","0x130c07","0x1312f7","0x1315fb","0x14118f","0x152383","0x3650","0x20c42b","0x2b27c3","0x295b5f","0x268833","0x1f250","0x146f2b","0x1a77db","0x210cef","0x22799b","0x2bbf1b","0x1d4ee4","0x4a6713","0x4bfac3","0x49f80b","0x48a0e8","0x13f687","0x185e43","0x186467","0x19f273","0x4a04e7","0x3804","0x1c01cb","0x1c03ef","0x2be023","0x2bdc93","0x25e5a3","0x2094fb","0x26880","0x1887f7","0x1357b7","0x29617b","0x2f0157","0x1d20","0x1520c7","0x2a0f0b","0x289d3f","0x26838","0x231737","0x234e80","0x152483","0x140e17","0x151313","0x1c709f","0x1cd4","0x29667f","0x2a3450","0x29611b","0x2f9157","0x2fa187","0x2fa144","0x1a1a77","0x1516a3","0x2ee447","0x2edf00","0x2b225b","0x2920d7","0x29310b","0x2930bf","0x2936a0","0x18ee77","0x19294f","0x19fbcb","0x267cfb","0x2962ab","0x2a3417","0x1a2ae0","0x287f7f","0x3430","0x2a9d47","0x23197b","0x2f31db","0x30630f","0x30f7f0","0x1a32f3","0x13f2fb","0x1ca43f","0x18ad13","0x28f1ab","0x31e257","0x2e41bb","0x2cfe8b","0x4e5f","0x6e18","0x2f5f43","0x32d6a3","0x3315db","0x2e6fb7","0x2e70f0","0x186f7f","0x129a17","0x13fa27","0x178b53","0x18511f","0x17e9ef","0x29617c","0x2eb4a7","0x2ea3ef","0x2ea807","0x2ea8d7","0x2e7b33","0x2e68e4","0x17fcc7","0x296224","0x2686eb","0x2a2350","0x19093b","0x2ea7cb","0x2f358","0x1f3a4","0x18507b","0x2a02d7","0x295a97","0x2efe03","0x2fa117","0x25883f","0x25ba5f","0x285ad3","0x285cfb","0x283fa4","0x267b67","0x26863b","0x29cf03","0x29a8cb","0x4b4db3","0x235e17","0x4587","0x1f498","0x25bc43","0x28076c","0x2934ff","0x2840d4","0x259c0c","0x152f13","0x258973","0x25bbfb","0x2686cb","0x2a221b","0x265b6b","0x265bb7","0x265c07","0x265960","0x28f1bb","0x371c","0x1a0aeb","0x2be5c3","0x2bc8e0","0x28077f","0x222e68","0x1808d3","0x2a54e7","0x1f20f","0x19e3","0x1c30","0x296168","0x151afb","0x1d629b","0x1d7208","0x26889b","0x26a05b","0x26d4eb","0x26a043","0x269ac7","0x1f2b8","0x2effc3","0x1f3b4","0x183bfb","0x13f89b","0x18a797","0x28a4c3","0x310d17","0x3e0244","0x285b8b","0x285cc4","0x130e6f","0x295f8b","0x2a3cd3","0x2f3b03","0x2e0b14","0x18ccdf","0x13fb4f","0x185607","0x29d6cf","0x29306f","0x292ea0","0x3e06e4","0x18cb63","0x13f733","0x1538a3","0x29fe6b","0x293160","0x25889b","0x259a37","0x2efe27","0x2fa463","0x2fa17c","0x18edf7","0x18fed3","0x19437f","0x267c8b","0x2a54c8","0x25a398","0x197d43","0x295cc3","0x298b2f","0x297f8b","0x298af4","0x1cfc","0x258e03","0x25c7a7","0x28079c","0x195c27","0x183c","0x265b1b","0x265c08","0x2b26af","0x2a1ef7","0x2ec61b","0x2ea40b","0x2e684f","0x4b70","0x190653","0x1954b7","0x1981b7","0x1f4cc","0x2f1098","0x1a46cb","0x1a636f","0x1b4fe7","0x1b8c13","0x267003","0x2a3b4f","0x2f7ec0","0x2a4eeb","0x285af7","0x2ce4","0x2a2367","0x265f24","0x2fa3eb","0x4c0440","0x195ddb","0x19e763","0x1f560","0x2b252f","0x2a162f","0x292fe3","0x13f4bb","0x154017","0x15432f","0x15666f","0x29d4b3","0x29dbc3","0x298533","0x298b17","0x265f38","0x2597ef","0x26d4d3","0x1cf0","0x2a188f","0x2a17af","0x2ebae7","0x2e7b27","0x2e5708","0x2234fc","0x195e2b","0x265bf3","0x1400","0x17917f","0x17988b","0x179c8b","0x17a4b3","0x15151b","0x259a83","0x2230f0","0x2f186f","0x1f3c0","0x2eefd8","0x13f83b","0x13a5b7","0x143c1f","0x142443","0x1f4c4","0x2193c8","0x2fa3b0","0x2fa38c","0x3df4a8","0x26a018","0x2a1d4f","0x293147","0x2a01fb","0x2eb77b","0x2ea7eb","0x2ea823","0x2ea817","0x1f5bc","0x2efc18","0x1869f3","0x292dc0","0x295e23","0x259377","0x280774","0x152d3f","0x25bbb7","0x265a9c","0x18566b","0x29c8db","0x29f140","0x14cd97","0x133877","0x17becb","0x178c","0x1a9407","0x1fb740","0x1f5f0","0x295e83","0x1378","0x222e64","0x2840b0","0x139bab","0x1d2673","0x1d2f9b","0x1d25fb","0x1d20cb","0x1d2057","0x1d2f87","0x2cff97","0x4c0464","0x17a163","0x1d6cc3","0x29f3c7","0x2930ab","0x17c8","0x17a793","0x1d108f","0x1d6f83","0x1d7098","0x29315c","0x179403","0x1a1e2f","0x258ad7","0x25e367","0x28729b","0x281ef4","0x2fa428","0x222e78","0x2972eb","0x294587","0x2f614f","0x1d18","0x25995b","0x25e300","0x1d4ebc","0x2f490c","0x2f187f","0x1f47c","0x17eea3","0x29abd0","0x3e06c0","0x19c6c7","0x1d69a7","0x26860","0x2efbff","0x16fc","0x137faf","0x132387","0x1527d7","0x2a138f","0x296367","0x259d4c","0x1986df","0x2933b7","0x280887","0x26db83","0x21f7a0","0x259378","0x19edef","0x275a4b","0x2a13b4","0x1975fb","0x29f723","0x2ebd8f","0x31d92b","0x31d967","0x31d983","0x4c03ec","0x2590e3","0x285d4c","0x2cfd3b","0x2e9817","0x2ee158","0x2a5593","0x1844","0x2fa6ec","0x197587","0x29fb57","0x4c03e8","0x14ce57","0x17d36b","0x1b29cb","0x17a64b","0x19861f","0x265a1b","0x16ac","0x1c09c7","0x2e0b83","0x1758c","0x1a08b3","0x2bc8a4","0x3114bf","0x3e017c","0x1a99e3","0x1af2cf","0x1aefb7","0x1af72f","0x25e7f3","0x1f3e2b","0x22734b","0x227c3f","0x29e0b7","0x28ba8b","0x271ec","0x3df437","0x3e0780","0x29d1a8","0x4577","0x365c","0x2a0c6b","0x296368","0x14989b","0x13ce13","0x1cbd47","0x14f6a3","0x131a6b","0x2b968b","0x2b938f","0x2b937c","0x268007","0x1350","0x132527","0x200327","0x15148b","0x1f3e4","0x1aef93","0x29e253","0x6220","0x14d9a0","0x2b1ecb","0x28c87b","0x2ebdd3","0x60c0","0x3066c7","0x3e010c","0x2f3b27","0x2cad48","0x188663","0x188913","0x296283","0x2e07f0","0x2a3a38","0x19cd63","0x18c643","0x1c708b","0x1c8e27","0x1c8d1c","0x4a65a0","0x13f6d3","0x154517","0x1d6f6f","0x17cedb","0x14dbcf","0x1404e8","0x19f7e3","0x17518","0x287f50","0x2a3ab3","0x2601b4","0x25a18c","0x19dbcb","0x292078","0x1c0e67","0x13464b","0x1c1b43","0x1b2bcb","0x1369b3","0x1b895f","0x1d6357","0x1d6928","0x17a5c7","0x125fe7","0x1b850f","0x127507","0x2ee457","0x2ee247","0x2ee3cf","0x2e77bf","0x2e91bc","0x17ab0f","0x1d3d30","0x31132f","0x3e06c8","0x2ef324","0x1f3d2f","0x29e09f","0x2a5b0b","0x2a48af","0x2a545b","0x2a4a38","0x3df474","0x1e975c","0x1a1aab","0x2bec04","0x19ac93","0x2f3e5b","0x4310","0x146ae3","0x1e89ff","0x29ee14","0x18c64b","0x1c70a7","0x1c8def","0x1f514","0x3e0734","0x180c5f","0x2a357b","0x258b9c","0x1b03e0","0x227e17","0x2ea740","0x296c03","0x2a5064","0x1b2ca3","0x1a1bf7","0x28a9db","0x28c723","0x2ded4b","0x4a0360","0x2be7ff","0x280f04","0x12bb83","0x28ae03","0x28c7bf","0x31ec6f","0x3e0718","0x2f323b","0x30516c","0x19c483","0x292f6f","0x293237","0x293434","0x1a4e53","0x25aef7","0x25c577","0x265943","0x25ef23","0x285cef","0x25bb98","0x1ab2a3","0x21607f","0x287bdb","0x25c82f","0x2f291c","0x219210","0x3668","0x1ab2c3","0x2bba5b","0x2a9923","0x1d4e54","0x437c","0x2b9390","0x258c53","0x25c194","0x268768","0x292f83","0x292eb4","0x2a179f","0x36e0","0x2e5724","0x1d4e90","0x2ea7fb","0x1f49c","0x234e38","0x259628","0x2eb737","0x31d91b","0x3420","0x1ad3a3","0x3814","0x380c","0x2f21b3","0x30287f","0x2a9fa3","0x21ec20","0x29cee7","0x29a334","0x2f3487","0x306448","0x2f185f","0x2a9f17","0x22266b","0x3e0714","0x295fb3","0x2a344b","0x216ceb","0x271d4","0x3df494","0x1bf92f","0x20575b","0x2af987","0x455b","0x1af573","0x2b5c3b","0x1f746b","0x3724","0x1a80a3","0x2be60f","0x2b6b73","0x2b6b74","0x19adfb","0x295e4c","0x5d80","0x1a71f7","0x16a3ab","0x2bcbd7","0x20949b","0x22767b","0x2bdd13","0x2bcf48","0x29a370","0x19c70f","0x292e2b","0x16f4","0x14279c","0x29fb78","0x2b539b","0x37f4","0x302890","0x2b27ab","0x677c","0x2ef340","0x1a801f","0x1d10","0x2b6ac3","0x2bad10","0x1d7583","0x1a16b7","0x1510fc","0x3028db","0x3e0124","0x1ad2ef","0x2ae22b","0x2ae6a7","0x2a817f","0x2a8ea3","0x2a8ce0","0x222698","0x2efe0f","0x2f92dc","0x180853","0x2a3494","0x287f44","0x49fbd4","0x2bb477","0x286e47","0x281a7f","0x627c","0x129948","0x31d94b","0x29d42f","0x2a4927","0x2a48f4","0x2f651f","0x2ef49f","0x2e3280","0x4a037c","0x3d7c","0x287f6b","0x1a960f","0x2005a8","0x19ec4f","0x14274f","0x2b63db","0x2b6477","0x4b4ddf","0x235e3f","0x17aaef","0x2ea664","0x1968f3","0x150ea0","0x19e447","0x3e0654","0x2f44bf","0x32ea7b","0x3311c3","0x330a9b","0x330b5f","0x17b0","0x29215f","0x2194eb","0x17f748","0x19ccb3","0x28faec","0x19fe33","0x1c8e7f","0x1c8e63","0x2f3d10","0x265b57","0x2e08d7","0x62f8","0x19a677","0x2a9e93","0x12d4","0x292e04","0x2936a8","0x2ea61c","0x19c6f7","0x31c2b3","0x2b2193","0x19e46f","0x130b87","0x1774af","0x177feb","0x17881f","0x2be6e3","0x29b5cf","0x4a03c8","0x18ed1b","0x191543","0x193a37","0x3c5c","0x18fa4b","0x29d137","0x29ceb8","0x2b20b7","0x175b4","0x293007","0x1980db","0x1d6e0b","0x1d6a30","0x2f5173","0x2ef440","0x26592f","0x25a394","0x1d4f60","0x1b0c77","0x20a4f7","0x2253c7","0x2297ff","0x22a537","0x22a374","0x22531b","0x28c9f3","0x292fcf","0x1856db","0x2a3a8b","0x2a9cb3","0x2aa33c","0x235de0","0x21ecb7","0x38ec","0x1cf247","0x1b16ff","0x2b1caf","0x2c03af","0x2bf553","0x3c3c","0x2a35b7","0x2a50a0","0x25ae8f","0x294618","0x12b6c7","0x2b6abc","0x196933","0x4268","0x219224","0x25c704","0x2ea654","0x25a3f7","0x268adf","0x25f8d0","0x182c7f","0x1f2cc","0x266633","0x29bc63","0x2895db","0x293fc7","0x2f2633","0x305b2f","0x3dfcdf","0x3df700","0x29f290","0x223243","0x3e0160","0x2f7e94","0x2b1f14","0x29d003","0x29a2dc","0x180e3f","0x2f481f","0x304303","0x30da83","0x30eb9c","0x3e0130","0x2ee413","0x2edfe8","0x3e3b","0x2df4c","0x2fa6c0","0x2a3b03","0x297d58","0x1ad52f","0x21868b","0x2b126f","0x3103df","0x2eefc0","0x19a60b","0x15072f","0x1d6c6f","0x293463","0x14f0","0x29f0a0","0x3df4eb","0x3e071c","0x29628b","0x297fb8","0x1f2e0","0x31d8bc","0x297f6c","0x23edf0","0x28ba07","0x1444","0x2689af","0x49fc6c","0x29d117","0x29e4dc","0x4a6703","0x2710f","0x45dc","0x1d4e88","0x2ea76b","0x1d3c","0x2c7c","0x2930f3","0x14b0","0x48a0dc","0x265b07","0x2f184f","0x1d6b83","0x1d1c","0x2f6fd3","0x2cad13","0x30f8bc","0x2b532b","0x3434","0x2931f8","0x16e0","0x2945c8","0x2bafc3","0x27e58b","0x213c1f","0x2a6858","0x31041f","0x2e351b","0x2e2f77","0x36a8","0x3e0768","0x2056fb","0x2af92f","0x2a486b","0x2f3ebf","0x2d6c54","0x19caa3","0x28fb03","0x2945a0","0x31d843","0x31d820","0x14b98b","0x2b6314","0x1f3f4","0x1d6323","0x1f9240","0x1a85cf","0x23f7b7","0x2046e0","0x1f494","0x13ce5b","0x2b925c","0x292ff8","0x2e0a5c","0x295b43","0x216c97","0x29faa7","0x296393","0x2684f7","0x2362d3","0x235e68","0x2ea65f","0x1d6beb","0x1a6c2f","0x1a747f","0x2bdcc0","0x2ae517","0x27078","0x3e0678","0x139c","0x296064","0x219393","0x1d4ec7","0x280ae3","0x21a603","0x28efc8","0x2a9e64","0x293180","0x2efc4c","0x2965f4","0x21a9cb","0x16b4","0x19ee13","0x310d6b","0x29305c","0x29ec7f","0x2936b4","0x1af210","0x2a9e74","0x2317f0","0x1d7230","0x20059c","0x287c3b","0x2bb187","0x20a95b","0x27cd34","0x2ae5d3","0x4a04c4","0x2ea644","0x29a887","0x29a847","0x29a774","0x12b4","0x23f150","0x2a819b","0x2a8e87","0x16d8","0x2b23df","0x180287","0x1d43f8","0x2ea6f3","0x258f9c","0x293118","0x1ad333","0x4457","0x1fcc","0x26d4e3","0x31d8f3","0x1cc0","0x26a054","0x13272b","0x1f3e8","0x2bc8c3","0x12e0","0x2bb04f","0x280323","0x2f97fc","0x2ae407","0x3df3f0","0x286e6b","0x297f60","0x29a254","0x4a04fc","0x2a235c","0x1d7577","0x29460c","0x1464","0x2afbdf","0x220bb8","0x1f2d4","0x184c5b","0x31b848","0x13f5cb","0x156f2f","0x2a29cb","0x31714c","0x1af76f","0x2bec17","0x2367c7","0x645b","0x6b90","0x2b3913","0x2b42ef","0x2b430b","0x2b4327","0x1d6343","0x3df4a0","0x193cfc","0x1d4e60","0x2e32bf","0x53bb","0x5bfc","0x265898","0x265a7b","0x296503","0x310317","0x5623","0x2be8","0x17fe03","0x29a8e3","0x37fc","0x2ea638","0x2a2f58","0x2e0a28","0x267c6f","0x2687dc","0x29a280","0x2cac37","0x3e0704","0x2ef2f8","0x2b9343","0x2eb264","0x2a8e67","0x2e0a3f","0x4c0470","0x2a9ed4","0x19c7f7","0x1fb28b","0x1fc50b","0x1fd3cf","0x26594c","0x2319ac","0x3df410","0x3e0283","0x3dee6f","0x4adc8c","0x1c4d97","0x1f01e7","0x1ed807","0x1f0477","0x1ed7fb","0x1d6930","0x3e0684","0x2b1f4f","0x2bf4ab","0x2bf9b7","0x2bfa03","0x2bfd5b","0x29a8ac","0x2f9067","0x2faeac","0x5374","0x2f933c","0x29a204","0x2b21b4","0x3102df","0x2b92b3","0x2191e4","0x2b224b","0x1d3b24","0x2ea6e4","0x2a5564","0x17e90b","0x13f8","0x1a2be7","0x29369c","0x1af66f","0x1f9907","0x3028ac","0x2ea694","0x2ba7ff","0x318747","0x317f6f","0x3180e7","0x2ece93","0x2ee8eb","0x2ee8c3","0x2a4afc","0x2226a4","0x2fa3b8","0x265ab3","0x280fcb","0x26dcc3","0x21d2b7","0x3820","0x280ad4","0x2a8ebf","0x2a8cd4","0x19fe13","0x28f1bc","0x26a03c","0x2bf567","0x2bf5d8","0x2a5524","0x295b1b","0x3df458","0x1d693c","0x1af597","0x275a07","0x289eaf","0x26596c","0x1d4faf","0x280a20","0x2f703b","0x6274","0x1e973c","0x3066eb","0x30d823","0x30e180","0x29301b","0x292ec0","0x2f187c","0x2a54ac","0x2ec3d7","0x2aa09b","0x287c7f","0x280350","0x28b0","0x2eefa8","0x5fb4","0x2f2104","0x2eef98","0x17a43b","0x2b6b60","0x3e0700","0x2b6208","0x2b232b","0x2a540b","0x269543","0x29a48b","0x2efe8b","0x2fa6ac","0x20aa13","0x27cc7c","0x5d4b","0x2a54c4","0x2920b3","0x293530","0x187ebb","0x567b","0x17624","0x2fa6d0","0x29a250","0x1a8117","0x200594","0x17eddf","0x234e97","0x23ee88","0x2687db","0x26d3f8","0x19b99f","0x1c8dc8","0x28a50b","0x445c","0x2b634b","0x2b6334","0x2b6220","0x2f2dab","0x2f92e0","0x2aa353","0x19278f","0x18720f","0x2f2def","0x30f27b","0x1abe93","0x2f2974","0x2a8d00","0x29a8ff","0x267e9f","0x29465b","0x29f077","0x29640b","0x17ac1b","0x1c8e97","0x1c21bb","0x60d4","0x1218","0x142704","0x258f64","0x1794","0x1f74","0x17f63f","0x13e003","0x29e80f","0x2a5447","0x4147","0x69c4","0x1497ff","0x2b62fc","0x29cdf4","0x2b24c3","0x131923","0x2b92c4","0x199083","0x29ee43","0x6ad8","0x1356b7","0x18ee23","0x18f753","0x194067","0x62a8","0x269ab4","0x14155b","0x152077","0x2684c3","0x29a78c","0x2f7ea3","0x2ef268","0x2a9a47","0x202f37","0x1e902b","0x281caf","0x2a5a5b","0x1966c7","0x2a23af","0x297d5c","0x18eb8f","0x1cb21f","0x193293","0x265f3c","0x26dbcc","0x3e0750","0x2b6b13","0x1d3768","0x3320","0x2f7e7f","0x2ef250","0x2ea6f4","0x153eff","0x2b8ed8","0x23edef","0x2b427f","0x2b4168","0x1d6db3","0x1d6980","0x29d27b","0x29a824","0x2687d0","0x49fce4","0x267fd8","0x19f2ff","0x2be7f4","0x258f1c","0x26a048","0x2a215f","0x2911c3","0x266f7b","0x295f77","0x184038","0x258bdc","0x2eee08","0x2f221f","0x19fc57","0x2bab03","0x2bf178","0x28c79f","0x151fa3","0x28f233","0x2abb98","0x4c0460","0x2a3a8c","0x29644c","0x2f326f","0x3e012c","0x2bcfdc","0x1d4f0c","0x285cbb","0x28ec","0x197967","0x2a1bfb","0x2ec063","0x2589e3","0x25927c","0x19e73b","0x4a6704","0x3e06a4","0x25ae80","0x4b4d4c","0x2a4ae4","0x1d6fc0","0x1d6c27","0x287c93","0x16c4","0x27e4c7","0x221c2f","0x25a3f8","0x296540","0x2b6a7b","0x1d7114","0x1a929c","0x1d7124","0x317f7b","0x318077","0x2ed17b","0x2ee96b","0x1e96b7","0x281bc8","0x19b957","0x1c8e47","0x12fc","0x1a26fb","0x2be643","0x2bad98","0x2aa0a8","0x132427","0x28c7a4","0x2f9078","0x265bd8","0x21eb88","0x287f4f","0x1210","0x2ea640","0x268357","0x29a218","0x25932b","0x295e24","0x13ef54","0x25efa4","0x3810","0x2e0820","0x2935a4","0x1a7b87","0x28ab7c","0x49f840","0x3e0754","0x2b3904","0x1f504","0x281cc4","0x4a6ef8","0x2a9eff","0x17a4e7","0x2bea78","0x2ea46c","0x41e8","0x2f18b4","0x259d30","0x2fa108","0x25af44","0x295c9b","0x2fa228","0x2ee054","0x25a218","0x19e4b3","0x29a15c","0x3e076c","0x2686b8","0x1d6ad4","0x4a0510","0x221aaf","0x2a6328","0x219600","0x2fa3d0","0x2ea8b7","0x2e697b","0x4d3b","0x7244","0x28c8e4","0x3e05b0","0x31d88b","0x31d977","0x1f5c4","0x3e0728","0x12c4c3","0x281953","0x5d14","0x49fcb8","0x2ea7fc","0x265d9b","0x259670","0x19b9bb","0x1c8e37","0x2b6a47","0x2bad78","0x31d95b","0x2ba903","0x2b392f","0x2b431b","0x259684","0x6914","0x2193ec","0x2fa68c","0x1e968c","0x2eefe4","0x1cf1c3","0x152447","0x29acd0","0x3e06dc","0x29328f","0x60b0","0x293178","0x21a5bf","0x38f4","0x26d4af","0x2f1dec","0x4b4db4","0x2fa3dc","0x2b6a30","0x2a9e44","0x2ae42b","0x28eb3f","0x2bf6fc","0x29cf57","0x29bb30","0x2f2d90","0x1420","0x2ea79b","0x2a52c8","0x268540","0x30526b","0x3df094","0x2ea77b","0x2ea808","0x29a35f","0x2a3454","0x1d6df7","0x1d6d9f","0x29ba48","0x2b53d0","0x2a9f9c","0x2f9050","0x2f9898","0x5d18","0x1d6f33","0x1d707b","0x283ecc","0x2ea7bb","0x153a2f","0x2bdcf4","0x281990","0x29214f","0x292e5b","0x49f7d8","0x29ee8b","0x2efed0","0x4a6714","0x2fa468","0x2f5a97","0x6100","0x17fbbf","0x2edf9f","0x2edfdf","0x2ee064","0x1f9180","0x267def","0x1d00","0x1240","0x1523b3","0x292db4","0x2932d7","0x2a4ba3","0x2b9330","0x31c123","0x32249f","0x322fab","0x3e0148","0x2efef8","0x29ce80","0x141343","0x1cf58f","0x2b692c","0x2f2c8b","0x42ec","0x3e0720","0x2963d7","0x235e30","0x311344","0x17801b","0x2bd614","0x49fbe4","0x2e0b48","0x19e583","0x2f4787","0x30da8c","0x14989c","0x19d8db","0x25ee67","0x25ef6c","0x2f9174","0x287f8c","0x2a38b7","0x1f4b4","0x1e88cb","0x201c","0x1c0d10","0x1792c3","0x2bcf74","0x18ee4f","0x192433","0x19508f","0x2f8383","0x1d75b0","0x2a4c0f","0x2a4ac4","0x280aac","0x280f50","0x19d63b","0x1c8e57","0x2a2804","0x25c237","0x4a0504","0x220dab","0x19eedb","0x20aa08","0x1d6c10","0x2b2143","0x43b0","0x292e14","0x188697","0x135113","0x2c02ff","0x13a0","0x29d63b","0x28fc87","0x260073","0x17f047","0x4a66ec","0x2eba83","0x29a7a7","0x3e06cc","0x3338","0x2a681f","0x18a980","0x13f98b","0x1c7e93","0x2b53af","0x49fd18","0x1f3e9f","0x281c18","0x1d62bb","0x1d69d7","0x1830","0x30e1b4","0x2b2757","0x2b4198","0x1fcb50","0x1c8e17","0x1992c7","0x1b0347","0x1f48c","0x2f296b","0x3063cf","0x2f21ac","0x293174","0x26a030","0x234e14","0x281974","0x2695e7","0x94870","0x3028a0","0x62bb","0x6970","0x231a08","0x4b4df0","0x227d57","0x3660","0x1300","0x265c58","0x1af9cb","0x200680","0x15159b","0x1d37f4","0x2b940c","0x1a3c3b","0x4d60","0x2b6a74","0x21ec93","0x418c","0x2f6fb3","0x2ea72f","0x265a54","0x17a3eb","0x231a34","0x2cab8c","0x200588","0x267f0b","0x2f620b","0x2bad18","0x29ecf4","0x2a3918","0x28fb73","0x268a0c","0x2005a0","0x20eeaf","0x23ede4","0x26865b","0x1d722c","0x18a877","0x281a47","0x6788","0x25ae74","0x2fa1a4","0x17aa7b","0x1f9238","0x26676b","0x3df490","0x25a198","0x2edf4b","0x2ee3a4","0x187fcf","0x49f7c8","0x21a5df","0x49f8d8","0x1c8d28","0x25c238","0x1c710f","0x296977","0x41a4","0x13f050","0x1c8df0","0x2b24e4","0x29854f","0x298b27","0x297f84","0x2a22ef","0x31d93b","0x1d6a1c","0x234e84","0x2708c","0x2ae667","0x2a8ca4","0x5d50","0x1258","0x12a10f","0x1292ab","0x28aef7","0x1d4e6c","0x2eefdf","0x2eedfc","0x2a2ec4","0x2ae183","0x28baf7","0x26a090","0x295f93","0x2a2fb0","0x2af90c","0x22cc","0x19d3d3","0x231850","0x30eb94","0x281b38","0x296228","0x4448","0x3e0604","0x17bef3","0x2b6430","0x25bc44","0x15283f","0x179c","0x2d5f","0x73a4","0x26dbb8","0x1afe2f","0x1f72bf","0x2ef334","0x2658ff","0x1510ec","0x2428","0x189027","0x1c5cbb","0x1c5b97","0x1c5b54","0x223050","0x20ef23","0x6984","0x25b0b4","0x265a2f","0x265de8","0x29310c","0x1d3784","0x2a14e3","0x28da3f","0x2f942c","0x2e4163","0x2c8beb","0x2cb6eb","0x1e972c","0x2a4a34","0x18cda7","0x17c2d3","0x1c9eff","0x17c763","0x2ea473","0x2ea404","0x3e0784","0x2bf4cb","0x2bf6ac","0x21f694","0x19d2a7","0x29b028","0x1e96dc","0x296bef","0x14cc","0x2c44","0x1b2ea7","0x2e97e0","0x2f90bb","0x2fab4b","0x2e70e7","0x73bc","0x2a3408","0x1a93e4","0x29a1f0","0x2fa6dc","0x43d4","0x2ea897","0x285d3c","0x3e015c","0x1724","0x2efbfc","0x18a89f","0x38fc","0x3dee37","0x17c62b","0x26dc28","0x2f5ff3","0x2e70fc","0x1986c3","0x2efdb8","0x21f798","0x188367","0x1c5cd3","0x1c5c90","0x258d6c","0x1d385b","0x23606f","0x5657","0x49bb","0x13d2f","0x18b4","0x2fa423","0x2facd0","0x2594ec","0x60c7","0x124dc","0x29332f","0x2e6804","0x1c8e73","0x2388","0x196e9b","0x2f3084","0x2b2777","0x2b43db","0x2872cf","0x281df8","0x26813f","0x29a948","0x185f93","0x294b","0xb33c","0x21f3e0","0x2eedf0","0x1f7447","0x344f","0x1a864","0x29305b","0x17bc","0x280734","0x280878","0x25c68b","0x25d90c","0x29cfa8","0x285d18","0x2bc8b0","0x2685ab","0x142c","0x25c127","0x281ea8","0x25c02b","0x25a48c","0x21f550","0x2f5e93","0x2934e3","0x4a6728","0x26db44","0x19ed4b","0x2f57eb","0x31754c","0x2b2287","0x2406e7","0x23b364","0x2ea867","0x1d6948","0x15720f","0x2f49bf","0x2d6ee7","0x4d93","0x7274","0x25dbc3","0x25e3f3","0x25dbbc","0x2a359c","0x136e7c","0x6404","0x265913","0x25ed7f","0x25ef07","0x265f04","0x2edf87","0x2ee223","0x2e7708","0x140db0","0x267ed0","0x1d62bc","0x31e323","0x323047","0x2e7144","0x2a22ab","0x290fa8","0x2e7b28","0x26a04f","0x26c28c","0x69d0","0x2fa470","0x25dbb0","0x2a6877","0x1290","0x2a1a2b","0x2a0658","0x2f550f","0x3172bc","0x2bdd9c","0x25c7a8","0x25c697","0x281d8c","0x285cd0","0x1d6d14","0x2a4a78","0x2e97cc","0x69a0","0x25c18c","0x13f31f","0x18b737","0x25c763","0x25ae44","0x2f836f","0x3029a8","0x25c0af","0x285b6b","0x2837c0","0x28074c","0x2faeec","0x180f83","0x2b89d3","0x2b9360","0x2e4147","0x2de9dc","0x178fec","0x26d4ec","0x1d6e53","0x1d705f","0x3112bb","0x3e077c","0x25bae7","0x281df0","0x271ac","0x2ea944","0x2efbe4","0x3e0110","0x17fd4b","0x1d6bd7","0x3e0738","0x2e590f","0x2e58f3","0x2e5903","0x259dbc","0x2837d4","0x259634","0x2b2234","0x26c298","0x1f42c","0x2808a4","0x2a3024","0x2a68a4","0x26d4c3","0x296204","0x4bfa94","0x2e7b1b","0x12bbef","0x3063f3","0x281e80","0x2e0b34","0x29698b","0x25895b","0x2872b7","0x27fca3","0x27fcbf","0x317160","0x2fa3b4","0x2e58e8","0x2964e4","0x18ce6f","0x129543","0x15914f","0x2b6948","0x1d6eab","0x29d1b4","0x2bf577","0x265be4","0x2a4c8b","0x2b2177","0x236213","0x2a4ecf","0x29e1e3","0x2a5538","0x2e6fa3","0x2e85ec","0x150eec","0x2599ac","0x1c6c30","0x26db04","0x285c90","0x2f0857","0x316c07","0x2ef583","0x2fa1b0","0x311498","0x268788","0x219608","0x2a2b24","0x293124","0x2b6a1c","0x293138","0x2230e0","0x259f8b","0x200223","0x4b4e83","0x5d2c","0x2f9128","0x2b1d73","0x612c","0x19fb78","0x29ead3","0x21f578","0x2f49a7","0x2e6f30","0x2fa690","0x25a45f","0x25bf67","0x2488","0x283b7b","0x283b2b","0x283824","0x265d7c","0x23dc","0x293407","0x23f064","0x19a633","0x281edf","0x4d4f","0x75bc","0x2fa430","0x2e6eff","0x2f378","0x2a276f","0x2f1e0c","0x17ab47","0x25bcdf","0x2658d8","0x2f9168","0x23679b","0x3182ab","0x29eae8","0x25c563","0x265d27","0x2e85b4","0x293420","0x28efac","0x3e0770","0x2ef2bb","0x1c70ff","0x2837bc","0x302c8b","0x18ce0b","0x49fcc7","0x1d6c7c","0x21f730","0x2effb4","0x31d99b","0x2e5a30","0x125f37","0x1fd8","0x283f9c","0x2e6f23","0x7314","0x2a2b00","0x1a1228","0x3c48","0x19fbaf","0x1fcb67","0x1fc497","0x2965d4","0x21fddc","0x25924f","0x25dba4","0x2594e4","0x259e43","0x214fdf","0x2274f4","0x29a2a8","0x2a3c60","0x17c5d7","0x1d6367","0x27e5cc","0x1d30","0x21fc7b","0x73f8","0x3e0758","0x2e5750","0x1bf9b7","0x14004b","0x28a673","0x2aa6c4","0x3e068c","0x2b2433","0x2840d0","0x2fa3a8","0x21fbf0","0x1f1f8","0x3ce4","0x266b0f","0x2f4887","0x139bd7","0x1c5b5b","0x2f9324","0x29fac8","0x4a6760","0x2e7aff","0x2e67f4","0x2f906c","0x2234f8","0x25c714","0x31d8cc","0x2a3707","0x292e3f","0x2838c0","0x281e10","0x1986f3","0x32302b","0x322904","0x19745f","0x21501f","0x614c","0x2f2937","0x43f4","0x2594f8","0x2ee050","0x2e6f97","0x150e43","0x29a570","0x48a148","0x1fb543","0x1fbe3f","0x3ef8","0x296638","0x2920f7","0x2936ac","0x3e24","0x2f912c","0x29a780","0x2bc8f0","0x2ef30c","0x281db3","0x6e80","0x2bab13","0x260f2b","0x27e69b","0x213334","0x2ef274","0x2840c0","0x2b2508","0x222e90","0x2efe80","0x270fc","0x25afa0","0x2eff67","0x4f6c","0x2b692f","0x2fa150","0x29c537","0x297f73","0x297bdc","0x2b22b3","0x281d68","0x2807c0","0x26d4b0","0x30e164","0x25c61f","0x2b94","0x25b947","0x3438","0x1405d4","0x1d62ff","0x1d6e3f","0x2ef294","0x1f9250","0x2f2623","0x305f4c","0x26a9c","0x280f33","0x12b8","0x3d60","0x1d6aeb","0x25bb40","0x285d64","0x6ba8","0x28da17","0x1dd2af","0x2aec7c","0x1a444c","0x33f4","0x29ee57","0x285d58","0x49fbf8","0x2e7127","0x2e85c4","0x29a70c","0x26c2a0","0x2931ac","0x1d6b4b","0x283b67","0x25a3e8","0x2eb70f","0x25b070","0x25bb50","0x3e0730","0x1c2217","0x2807dc","0x3e064c","0x295f2c","0x2e57e0","0x19d5f3","0x7474","0x23f06c","0x3e072c","0x2a54a0","0x297f9b","0x25a3dc","0x285b77","0x283f8c","0x49fbec","0x258e6b","0x2ea41f","0x2f2653","0x3df6b0","0x2945a7","0x2a4a54","0x181b3f","0x29d337","0x343c","0x2f0083","0x285d2c","0x21fc88","0x1d6c3c","0x221aa8","0x2a2e2c","0x2a3030","0x2a4a70","0x190028","0x283e83","0x1d6b97","0x1d69e4","0x292fb0","0x25af84","0x2ee3bf","0x3c74","0x29a704","0x2f1843","0x2ea7db","0x1779c","0x2a54b0","0x1824","0x2ea403","0x2e7abc","0x281d58","0x265a8f","0x2b1d8b","0x2f2ce3","0x352c","0x2838d4","0x23ee78","0x2298","0x25a1c0","0x266b7b","0x265b9f","0x2fa194","0x280788","0x29d0fc","0x21f4db","0x2a5550","0x25a1f4","0x290fa4","0x260eab","0x286ed7","0x2e0c5c","0x2c70","0x19dc1f","0x1c8ddf","0x1766c","0x19dc27","0x1c8e07","0x1c21cb","0x2d68","0x2cfdc4","0x292154","0x1884ff","0x2bf1b7","0x284eb3","0x6964","0x17eda3","0x31d853","0x29c3cb","0x290533","0x1d3e23","0x26db6c","0x2f553f","0x2efe28","0x2f9164","0x17f083","0x285bbc","0x2ef020","0x3854","0x31d1b7","0x214fcc","0x1d71f8","0x2bf9a3","0x15f8","0x290f9c","0x2b1d80","0x21a8ff","0x2a0c7c","0x2e711b","0x2599e4","0x2e0b44","0x2cbc","0x192928","0x28409c","0x2ee21c","0x150c08","0x265b40","0x2bac84","0x2f92ac","0x2be7","0x293fe3","0x2eedf8","0x284094","0x21f544","0x1d721c","0x2872c4","0x2e6fd4","0x28af13","0x2592c8","0x2a27f4","0x2bf967","0x2f584f","0x2ef44b","0x258fcc","0x2ea8cf","0x2599cc","0x2e84b4","0x2ea887","0x197563","0x296fcf","0x2e0924","0x2f1e20","0x297f78","0x21f417","0x21f718","0x227cfb","0x2ea71f","0x2e6990","0x2ea83b","0x2a3458","0x298b07","0x1f364","0x29ec50","0x4a6bfc","0x280a2c","0x25e314","0x5f98","0x1fb517","0x1fcaa7","0x1fc9a3","0x30f890","0x2595e4","0x29ea97","0x258de4","0x26dbc7","0x182557","0x1dd25f","0x288eb3","0x291b24","0x30e19c","0x2bfa3f","0x31198b","0x3e0337","0x4a6780","0x1f440","0x2a2aff","0x4a03bc","0x25bb64","0x2e6943","0x6f1c","0x2efc38","0x2747df","0x2749d7","0x2e7cec","0x241c","0x281ef0","0x223238","0x2a2ff4","0x265854","0x1d69c0","0x2f26f3","0x2e7df0","0x2a4a7c","0x296664","0x3041e4","0x2594fc","0x2ea7bc","0x2fa14f","0x2fa3f8","0x28071c","0x280874","0x265bd0","0x265c8c","0x23f068","0x285d90","0x1264df","0x2ea3e0","0x258ed8","0x41b0","0x150b73","0x2b8ef8","0x259c20","0x29d06c","0x188e37","0x1c5c43","0x2ea74b","0x2e691c","0x2f206c","0x2f3ea7","0x265888","0x2e6f98","0x18ae7c","0x265efc","0x3818","0x283fc3","0x3e0b08","0x25bd48","0x2a2fa4","0x285c8c","0x285cfc","0x21f7d4","0x2f9114","0x17a4","0x17c937","0x2ba6e7","0x2e7dec","0x285cf0","0x2edf14","0x280748","0x213c3c","0x2dec0f","0x4b7d9b","0x4e48","0x2274e8","0x292e70","0x22264c","0x2bf17b","0x1f9c58","0x259a84","0x2f7e97","0x17594","0x295b9c","0x19faff","0x31df94","0x2f3623","0x3df3e4","0x144c","0x1a0c0c","0x2cabd0","0x2e711c","0x1c21e7","0x1f500","0x222650","0x2fa238","0x2f92d8","0x2de9ef","0x31bd28","0x259690","0x1902fc","0x29331b","0x2872c3","0x27fae0","0x6e64","0x3868","0x2b6ad0","0x41d0","0x280778","0x48a0e0","0x15016b","0x2bdc24","0x1ecf7b","0x1ece9f","0x1ed9df","0x2b6b14","0x28089c","0x293678","0x2a2813","0x317128","0x2e9890","0x223234","0x258790","0x28ac04","0x1a81cf","0x2686e8","0x29a274","0x4388","0x2b5baf","0x693c","0x265ac7","0x2b6207","0x1f3f0","0x265db8","0x2695a7","0x274bd4","0x29cf48","0x2babeb","0x2b363c","0x2bf533","0x1f920b","0x1feb00","0x4da7","0x73fc","0x2e7b34","0x2f2c07","0x3884","0x4c0638","0x1838","0x2f3b67","0x2d6c3c","0x1790","0x2e715c","0x1d7228","0x222688","0x2658e8","0x2a54b8","0x242b","0x197ad7","0x2afbc3","0x25baec","0x31bf43","0x3220e3","0x2ef887","0x2ba863","0x2fdf17","0x2d51d7","0x2d6c60","0x2f7e8f","0x2a21a3","0x29ce5c","0x2b925b","0x2686c","0x14b373","0x20dc6c","0x1dd2f7","0x1c61a0","0x269b08","0x1d6f1f","0x137c53","0x2b9af4","0x17d4","0x2594dc","0x7744","0x13f703","0x2b1b03","0x23fe73","0x31d82c","0x4bfa68","0x3330","0x2a3008","0x29acc4","0x2fa418","0x1d6ffc","0x280a3c","0x268814","0x2ea6b8","0x29be9b","0x29ed98","0x30f818","0x25c1f3","0x25a4ec","0x29622c","0x31d590","0x30288f","0x30f89f","0x3e00cb","0x2efbc8","0x131c13","0x74b0","0x1fb138","0x24ac","0x2230f4","0x2be670","0x2fa494","0x1a098f","0x266c4b","0x22746b","0x259d2c","0x296040","0x2840c4","0x2b522f","0x4a04e4","0x2a37f3","0x26868","0x2e0968","0x2bdf3c","0x2effcf","0x1d4e4c","0x1c219c","0x25bad8","0x1e38","0x2a2020","0x25877c","0x19b93b","0x7550","0x1d7080","0x1d6e6c","0x2f2204","0x269593","0x2f38c","0x18a767","0x182637","0x3e07bc","0x29a244","0x2b64ab","0x31d8e3","0x31d804","0x180457","0x3170c0","0x2f5e80","0x2e0938","0x2a02ab","0x1d4ecc","0x4ba4","0x1d3767","0x265bd4","0x1326fb","0x26d4cc","0x19e35f","0x29abdb","0x2fa6a8","0x293490","0x2cfdbb","0x75a4","0x1d08f8","0x4f78","0x7758","0x1490","0x13ef97","0x2b61f0","0x25bc10","0x4b28","0x2596a8","0x372c","0x25c220","0x1f3c8","0x2f2940","0x2f10b4","0x265c20","0x25bc28","0x2803bb","0x26d92b","0x21ed90","0x17f72b","0x17a283","0x2e85f0","0x27f894","0x30e45f","0x30c124","0x1700","0x13bc","0x2f1e18","0x2b5094","0x3e0748","0x181913","0x22750c","0x19e2bb","0x29ac54","0x2b9354","0x131a44","0x2a3048","0x13eae7","0x2b9b90","0x30e194","0x2fa3ac","0x17a1bb","0x2ab848","0x21f3d4","0x2fa69c","0x21f420","0x1a2583","0x140177","0x2a33f8","0x2a4f48","0x17c4c7","0x1c5ca3","0x19e3eb","0x2fcaf8","0x2e0980","0x2ea76c","0x267103","0x26c3ef","0x17edb8","0x19d0ef","0x265870","0x1d4e98","0x3e0c","0x3df580","0x2a3014","0x1f51c","0x2ef244","0x259c18","0x2f2d60","0x13f878","0x29a214","0x21a9e3","0x3914","0x6948","0x305c7c","0x29635c","0x2f5abb","0x30f947","0x3e05a0","0x2961c4","0x2e698c","0x29cf43","0x2592d8","0x29a360","0x21f790","0x2f914c","0x2ba7a7","0x220ba8","0x29a77f","0x2eb434","0x3e0710","0x280780","0x26895b","0x2a4b47","0x296144","0x1f0803","0x295c24","0x14d964","0x1d6bf8","0x31d1e3","0x3e07c0","0x2e85d8","0x19e4df","0x25a0f3","0x298b0c","0x2bc8d8","0x1c8db8","0x2932b4","0x21f5b8","0x25a61c","0x2fa51c","0x284ec0","0x2eb468","0x30f80c","0x26682f","0x26c40b","0x25bb54","0x265f28","0x142818","0x292e44","0x2a5478","0x14014f","0x1d78c3","0x288fa0","0x2b27eb","0x1d3c08","0x1c2227","0x2932c3","0x6be4","0x21f520","0x317f5c","0x19777f","0x2a5574","0x1d6ca4","0x280a24","0x1c8e40","0x21a984","0x29611c","0x186be0","0x2f226c","0x2ea410","0x25bb2c","0x25c1a4","0x2e7b1c","0x1b516f","0x1b6deb","0x28abb3","0x2ea400","0x2a273c","0x2eefcc","0x2b63c7","0x1748","0x3e02b0","0x296384","0x3e0638","0x2e84b8","0x29367c","0x285d40","0x1a0904","0x1985df","0x2936b0","0x17628","0x1e9748","0x30eb88","0x287f38","0x268377","0x2e5780","0x2f5acc","0x285d48","0x2a625f","0x293223","0x1730","0x28d8","0x4d5c","0x295a28","0x13efa3","0x448960","0x2964e0","0x3e0138","0x2405e7","0x31e6e0","0x265f34","0x44e8","0x2f7e9c","0x265f30","0x6d64","0x68cc","0x176c8","0xb477","0x164f","0x174c","0x2f2174","0x2230d4","0x21f0ef","0x2e71ac","0x285ce4","0x269834","0x30f308","0x2b239f","0x27e5fb","0x2a620c","0x25bbb0","0x21f494","0x188577","0x2b67c3","0x2b939c","0x2fa450","0x223228","0x2fa3c4","0x31d86c","0x268538","0x1b6f97","0x25bc5f","0x3df6cc","0x259814","0x221afb","0x43f8","0x2837d0","0x2fa124","0x1c5c97","0x322187","0x2fa47c","0x2e7b0c","0x17a9bf","0x4a6bd4","0x214ff0","0x269818","0x29e75c","0x280173","0x2a2dcc","0x2b6a28","0x2f90a7","0x12b67b","0x49f7fc","0x2e97c8","0x2191cc","0x265bac","0x14936c","0x258dc4","0x1c2237","0x13f95f","0x2fdcdb","0x315f0f","0x4004","0x3e06d0","0x281d78","0x2807a4","0x4104","0x2e97a0","0x274530","0x2f82af","0x1358","0x2e97f0","0x27e5d0","0x2fa45c","0x2fa6b8","0x283fb0","0x3063f8","0x21f528","0x25c168","0x296fdc","0x295f98","0x3450","0x268358","0x29cec0","0x14275b","0x4489fc","0x2001ef","0x256f27","0x27cb38","0x281ea7","0x17b8","0x259e83","0x213ee0","0x265850","0x20efcc","0x297c00","0x3e06e8","0x2e7b44","0x1af157","0x2b582f","0x284ebc","0x1aef27","0x2b8ec8","0x1af19c","0x2b6200","0x2b641c","0x1aef28","0x370c","0x13ca93","0x2b6298","0x1aef74","0x147033","0x135d2b","0x4b4de0","0x219220","0x25ef84","0x2babc8","0x3290ec","0x4a6758","0x4ad153","0x23f07c","0x1b016f","0x31b914","0x1d6b74","0x234e4b","0x3824","0x5eb4","0x25b088","0x30f93c","0x21d293","0x2a54c0","0x2837e0","0x2eff2f","0x2966c4","0x2a38b8","0x6d38","0x2e716c","0x21a66c","0x29fae0","0x2318a4","0x3834","0x1b1007","0x2094a8","0x29ad04","0x29a8d0","0x26890","0x23ee08","0x198477","0x137e9b","0x2658f0","0x180307","0x4a69c4","0x1a7c1b","0x234e5c","0x1d6aff","0x1d6a34","0x2316dc","0x27e493","0x353c","0x2226a8","0x21a693","0x2a9ec0","0x447b","0x3c98","0x2963fc","0x19e74f","0x25bc73","0x287327","0x2a13a4","0x66fc","0x12c4bb","0x27cca0","0x29ced0","0x1f3daf","0x3171a8","0x29033f","0x177c7","0xc22f","0xdcaf","0x3377","0x1728","0x12b923","0x226d43","0x241778","0x2b5317","0x4b58","0x196f6b","0x2a5090","0x4504","0x2af9cb","0x268c90","0x2df54","0x281c58","0x2bf1fc","0x1910bb","0x2bf913","0x2bf678","0x285aa8","0x1a2d20","0x2921b0","0x280a4c","0x185b94","0x1f4c8","0x2b1ab4","0x29ba2f","0x3c10","0x2fa3e8","0x29a2e8","0x18c373","0x2945bc","0x29cfc7","0x29b714","0x18240b","0x29d444","0x259284","0x29a300","0x2e09a8","0x25c68c","0x4c0444","0x21eb67","0x4098","0x21f4cc","0x25925b","0x2eb2cb","0x1320","0x2930e4","0x267e94","0x1b014b","0x1d047b","0x21d167","0x28075c","0x14f8","0x1d62d0","0x26896f","0x274aa0","0x184c4c","0x2b03f0","0x2670a3","0x2a1a53","0xacdb","0x1fbef","0xad9f","0x4538","0x6ef8","0x176a4","0x26888","0x2f05c8","0x2c040f","0x2683c","0x293198","0x2bf13c","0x2a354c","0x25a39c","0x2f3e7f","0x4d80","0x236764","0x2ea78b","0x19dc4b","0x29af5b","0x1510e4","0x2b545f","0x3c40","0x2cb6ec","0x2cff53","0x38c0","0x29ed34","0x297fab","0x1f4b0","0x4a04a8","0x6120","0x2fdd77","0x2e49bf","0x1c8e64","0x1d70c8","0x17a303","0x259c04","0x2a4848","0x2f576f","0x30a8a8","0x2f49b0","0x1b4147","0x1cd5dc","0x1f3a8","0x2f1e24","0x2bf528","0x738c","0x3f94","0x1fc97f","0x1fc743","0x1c8d00","0x2f30bf","0x308780","0x29a484","0x269aeb","0x26d4c8","0x2fdc03","0x301a7c","0x295fc8","0x61eb","0x6b8c","0x25950c","0x2fa484","0x2b6320","0x2ea8a7","0x285adc","0x2e70bc","0x25a0d0","0x285d30","0x1d6940","0x2e0930","0x29301c","0x2e7170","0x265bbc","0x2e7184","0x2efbd0","0x150ac0","0x2e7783","0x2e3748","0x1c224f","0x2b1dc7","0x21f10f","0x4c0474","0x259c1c","0x2963ef","0x2a3428","0x4eb4","0x755c","0x223244","0x1c8d4f","0x2e6974","0x2b5418","0x2969b8","0x19f0eb","0x29a29c","0x29ead4","0x2e85e4","0x2f5657","0x2efe50","0x1d764f","0x7448","0x2bf4ef","0x1d6a3c","0x2ea774","0x2e688c","0x2a3894","0x2911d0","0x29f49f","0x3730","0x29cf64","0x2f9178","0x1b1183","0x1efa5c","0x1d6e97","0x1d7238","0x2a4b20","0x2ee170","0x28ae5f","0x151f84","0x2a2fdc","0x2a9eb0","0x25bbe8","0x1d44fc","0x2694b8","0x2b9240","0x21ec48","0x292110","0x2a5098","0x12c43b","0x1302ab","0x2a2000","0x281e48","0x17a547","0x2efedc","0x2e4183","0x275a08","0x2a3424","0x268a27","0x29a48c","0x1d6b5f","0x1566e3","0x156bb8","0x197e6b","0x19c474","0x280a44","0x293444","0x151454","0x7570","0x25ae5c","0x5d34","0x18fe30","0x26a08c","0x2840cc","0x13f373","0x18938f","0x2e7ae0","0x29ee13","0x2cabf4","0x2840b4","0x2f48c4","0x2e7cd4","0x1a0834","0x1fc4af","0x2f1df8","0x25a174","0x2a3b23","0x297d40","0x19edf0","0x2f00bc","0x259808","0x265e20","0x30f8c0","0x2f57d3","0x2ef3c4","0x1883f7","0x260f37","0x1f9c40","0x268930","0x2a3058","0x604c","0x2bfa53","0x2bfb04","0x7694","0x2c048b","0x213b5f","0x2a6868","0x19f29b","0x6b08","0x5ec4","0x3e02c3","0x3dee53","0x29bc37","0x2a53bb","0x2a4ad8","0x5d10","0x281d80","0x188333","0x1d260b","0x283b38","0x293128","0x2b546f","0x4ad0f8","0x29d048","0x1f16c","0x259a20","0x66f0","0x2dea98","0x281e54","0x220c93","0x19d283","0x29a0f8","0x1860af","0x21a657","0x1807c7","0x176d4","0x2ea448","0x2e6988","0x2234f0","0x2592d0","0x2b4278","0x25a600","0x285b04","0x2eefd3","0x2eec94","0x771c","0x2c3c","0x17a7a7","0x28e5d7","0x28eb53","0x1d6918","0x2264","0x2e6fd0","0x2f834c","0x2001dc","0x2cfd54","0x2eecd4","0x2f2090","0x2ea84b","0x274554","0x2b1ee7","0x2eec70","0x19ad2f","0x2e0940","0x28c870","0x2cab78","0x2aa0f0","0x62d4","0x259250","0x2bdd14","0x2baca4","0x4b30","0x6264","0x2e92b0","0x26db24","0x18cc17","0x26dd24","0x20f010","0x1ca8","0x17a337","0x29cce8","0x221b2f","0x27e5a7","0x2fa3c8","0x3e070c","0x1d0c70","0x29342c","0x2ea8a8","0x2f36a7","0x30f31c","0x2930c4","0x2b5123","0x23edbc","0x21fd24","0x287eb8","0x18a8e4","0x5f94","0x2bac8c","0x18b2f7","0x27c707","0x23691f","0x3028c0","0x1bc4","0x2e6828","0x26d448","0x198713","0x1f2290","0x29cef8","0x26d4d8","0x17edb7","0x25bbcc","0x2b20fc","0x285ab8","0x25edd7","0x2cfd23","0x267f84","0x2cfd14","0x7424","0x283ea0","0x31c083","0x31f503","0x2ef844","0x2e6fb8","0x25c11b","0x25e2fc","0x267bf4","0x27faec","0x15716f","0x288f84","0x29ebb4","0x15690b","0x2962c0","0x304354","0x2933d0","0x2fddf7","0x329744","0x1fca10","0x1f38c","0x1ec8","0x2d4e44","0x266ca3","0x25a4ac","0x6440","0x26815f","0x3d77","0x2df28","0x17fc07","0x30d53c","0x3028b8","0x21a6ac","0x6250","0x1b6bcf","0x22d7d0","0x2e71bc","0x265b1c","0x1f1c4","0x26597c","0x25c778","0x1c8d98","0x281a80","0x258a9b","0x214fb8","0x292ff0","0x7320","0x222e58","0x2a2e7c","0x1d6d10","0x2a3ac7","0x49f7b4","0x259b38","0x1318d7","0x39ac","0x2ea948","0x21f75c","0x295e70","0x411b","0x30aa77","0x21f5e4","0x1510e8","0x2b279b","0x2b412c","0x1a2a64","0x2f1880","0x2b036c","0x1d68f8","0x2921a0","0x1a6c8f","0x1a76ec","0x2f3533","0x19fc37","0x1d3bdc","0x1d70b4","0x2b370b","0x281404","0x1930","0x2595f8","0x259d38","0x285b90","0x21d248","0x2e9744","0x13f8d0","0x227c","0x63fc","0x1d6998","0x5d4c","0x280a08","0x285d28","0x2a53a7","0x5403","0x7137","0x151500","0x2801cc","0x2a16d8","0x2e7174","0x259118","0x2de943","0x448a28","0x1f91bf","0x2a2f80","0x259514","0x19ed10","0x2b6a0c","0x2f00f8","0x1d6990","0x126b03","0x2e5728","0x1c8e18","0x29a268","0x1fca0b","0x29ec2c","0x21a6bc","0x25c16c","0x148f84","0x6b64","0x4a6be0","0x29211b","0x13f0bc","0x2e0b24","0x2ef270","0x29a50c","0x2b204f","0x2904f8","0x29ceec","0x22744b","0x27cbd8","0x21f4cb","0x292f28","0x2faee4","0x2a25df","0x17abc7","0x2bec28","0x7594","0x29c7dc","0x31d838","0x13f0c0","0x29e1ec","0x156f57","0x30da0c","0x15430b","0x31b8b8","0x258fbc","0x1a16eb","0x295ff0","0x285cac","0x2f9158","0x265c24","0x30d810","0x265a30","0x2ee180","0x267efc","0x31d824","0x280770","0x2f485c","0x4bfa38","0x26d49c","0x2c8b33","0x2494","0x2962c8","0x19e614","0x6dd4","0x2ededc","0x2fa50c","0x2efee4","0x259d78","0x311dd3","0x30b937","0x4adce8","0x266797","0x29af04","0x1d7728","0x3e06f0","0x2fa6e4","0x185048","0x151123","0x2a2fac","0x31b924","0x2b42ff","0x289d38","0x1318d8","0x347c","0x25a178","0x2debf4","0x2f579c","0x29b0c0","0x17bddb","0x1b0387","0x2071b0","0x2840c8","0x283b2c","0x20efe0","0x2fa48c","0x1aef7c","0x4b90","0x297fac","0x3e0744","0x26887c","0x1a19eb","0x28ac53","0x1a7ddc","0x2934e4","0x2a3064","0x2e7b18","0x26af4","0x2a2263","0x298524","0x26683f","0x2e6894","0x2f18c4","0x21f3a0","0x2fadb4","0x2f4198","0x2f7e84","0x2a5358","0x259bdc","0x21fc6c","0x21d134","0x2e97e8","0x296054","0x31d578","0x1e9698","0x2ee2bc","0x2e7774","0x259a68","0x2681ac","0x259f98","0x1508","0x29a2f4","0x305a93","0x3e067c","0x19d06b","0x1b111b","0x31b95f","0x326b74","0x285ba8","0x387c","0x2efc68","0x4a6708","0x274bf8","0x12b5af","0x241493","0x448868","0x293100","0x2ee14c","0x2efc6c","0x2f1838","0x2eb2ab","0x4b4e50","0x2fdf3f","0x23c364","0x2e570c","0x28af2b","0x4b4f37","0x268600","0x297fbc","0x29b66c","0x43ec","0x1975e0","0x260900","0x29a314","0x29a328","0x17bd6f","0x2fd897","0x2ecc53","0x296a4c","0x27cc04","0x18ac07","0x4a67c0","0x1b7003","0x19599f","0x180a37","0x25a368","0x1265fb","0x2a4d7f","0x1fb758","0x1a0bf4","0x28fde3","0x1d6cf4","0x1a150b","0x1d7a44","0x280ef0","0x2bfd88","0x311307","0x322c8f","0x280f60","0x1d7693","0x297f7f","0x1a620f","0x2bdcfb","0x317ec0","0x29da47","0x28d293","0x2458","0x1878e8","0x25aed8","0x22bc","0x27fbbc","0x2debe8","0x2ea6b4","0x256f2c","0x2ea438","0x2961ac","0x2ba60c","0x30e464","0x1d4e3c","0x1d6390","0x2fa3a4","0x17e0","0x21f680","0x30f8d4","0x2e7190","0x29ab47","0x281eec","0x417c","0x199237","0x30fc23","0x3115df","0x1d7068","0x21f19c","0x150f24","0x2b6374","0x297c07","0x25a1b4","0x31d8ab","0x30c130","0x2840b8","0x28a51f","0x2b53cf","0x21d603","0x2d1c","0x29eaf8","0x258f78","0x25bcd0","0x29e2b3","0x2a343c","0x184a14","0x2eec80","0x189253","0x2b0397","0x235510","0x2c8be0","0x2191dc","0x265c0c","0x2f9344","0x29ec38","0x2e6814","0x265bf4","0x5f90","0x45a0","0x2f41ab","0x30f287","0x30d0a4","0x2e084c","0x2eff44","0x258f48","0x2683c4","0x31ec13","0x2ea8ec","0x2a4913","0x29b53c","0x1306b7","0x2930c0","0x1d2ab0","0x25d883","0x25d918","0x6c68","0x287ebc","0x27fcb3","0x2a01eb","0x6134","0x18a2a3","0x3dec00","0x2cfd90","0x19e647","0x2a3470","0x607c","0x19ee9f","0x4a6a0c","0x2efc58","0x1fcf90","0x13fac7","0x156d5f","0x157230","0x2838e0","0x1af5d3","0x2b73a7","0x2fd020","0x258cbb","0x2d14","0x25a378","0x2e0b4c","0x1c8d77","0x1d6b6c","0x1a22f4","0x2e7aec","0x1d7130","0x23f19c","0x3e0144","0x2bad80","0x4b2c","0x2f20e0","0x287f18","0x29b798","0x2fe4","0x18abd7","0x2ee198","0x152c73","0x238c","0x148c","0x2f0158","0x265ccf","0x29afab","0x1360","0x29ec54","0x1834","0x259840","0x1c8e38","0x4d04","0x280858","0x284ec8","0x2b65c7","0x2b9ec8","0x4b4dd0","0x1aef10","0x3ded98","0x259b0b","0x292db8","0x2a54fc","0x3df47c","0x2a3a7c","0x1322db","0x28ce14","0x259b48","0x2b4448","0x2920f8","0x1d4e8c","0x1d4f24","0x258810","0x14d4","0x1278","0x20ef68","0x2f1e14","0x30d99c","0x2b6ab0","0x2a16d7","0x3e0688","0x3ded40","0x2ae57b","0x277514","0x2af998","0x30287c","0x221b08","0x2a54d8","0x29dc","0x2e0aac","0x31809f","0x315393","0x3153af","0x25a3c4","0x1d3754","0x2b4233","0x21f168","0x281b48","0x3df48c","0x1514d8","0x2f25b0","0x1f4f0","0x2f0863","0x25892c","0x21922c","0x17a09f","0x1c24a4","0x2f1de0","0x1d63c8","0x4adcb0","0x151f53","0x2bf243","0x1f9444","0x265d40","0x23196c","0x2aa0c7","0x222be3","0x5ce8","0x29b6a4","0x21a97c","0x2be67c","0x129f17","0x1314","0x2a9eb8","0x151063","0x25b07c","0x4bfa80","0x1d2abb","0x1d0d8c","0x2effd0","0x2b2300","0xacdc","0x4adcf8","0x29c670","0x2cfcdc","0x2e0990","0x12480","0x1750","0x259967","0x2deaa0","0x302c0b","0x4a0344","0x2cfd74","0x25a1e0","0x269aec","0x1c8d97","0x265894","0x30a9b7","0x3e0190","0x297033","0x30f8c8","0x25e594","0x17a847","0x25af24","0x21fe28","0x7394","0x311313","0x2d48","0x2a2e68","0x28e54f","0x3d04","0x28c7d0","0x19275b","0x7488","0x265a3c","0x3714","0x2362b0","0x2005a4","0x2bb017","0x1759c","0x28f15b","0x2b6930","0x256f20","0x241837","0x23c3a3","0x4b4f67","0x1310","0x2933f3","0x2b41f7","0x2315b3","0x29cf1c","0x23b2cf","0x23bfab","0x287288","0x2840d8","0x1ce0","0x2e84a4","0x4a03a4","0x2c1c","0x1d770f","0x31d213","0x28fa24","0x2840bc","0x2e7178","0x297c08","0x2a3474","0x1e96d4","0x15285b","0x2e85c8","0x2f4874","0x6484","0x213c57","0x4b532f","0x2a4f80","0x222bbc","0x29a6ec","0x1f98e3","0x1a6d63","0x259a1c","0x25eeb7","0x1f36ac","0x25bb88","0x275a34","0x25bb3c","0x2a23eb","0x29643c","0x26dc30","0x297be3","0x29e4d0","0x41f0","0x296290","0x1b115c","0x29a6e0","0x2c8bf8","0x2ef284","0x19fe27","0x1a9417","0x259990","0x2e681c","0x150f0c","0x2fa1a8","0x1970a7","0x2a505c","0x3019d7","0x280f20","0x29ff57","0x26588c","0x2fdefb","0x2e785f","0x2e60bb","0x634c","0x2bf867","0x2fa480","0x31833b","0x31e370","0x1eec","0x2cb6dc","0x2837b0","0x3028a4","0x29eda0","0x310d44","0x285b1c","0x3d48","0x26881f","0x26d44c","0x152984","0x302894","0x2edfc3","0x2a357c","0x29c3a8","0x2920c4","0x18565c","0x2cb320","0x293164","0x3df45c","0x1a0bec","0x29cf6c","0x2191d4","0x265b90","0x2fa458","0x2fa6d4","0x2e07e0","0x2a5088","0x3066f0","0x2efdc8","0x2921a8","0x1550","0x2f2d53","0x30871b","0x2bfea0","0x306323","0x2a22d4","0x2f1dd0","0x4a659c","0x25b933","0x2ea730","0x2b203b","0x1c2207","0x1f220","0x265c44","0x200208","0x26db28","0x190963","0x322193","0x322c53","0x322973","0x2a3978","0x1d6bec","0x14b3c3","0x1e878c","0x2a0d4c","0x1c5bc0","0x12c0","0x2a2900","0x296c30","0x268343","0x1c10","0x1d79cb","0x289127","0x291c48","0x1d700c","0x1d4f93","0x268588","0x4404","0x2ea830","0x30f293","0x175e8","0x7418","0x322bf3","0x23f17c","0x21fcf8","0x2747bc","0x17c604","0x1f3b8","0x3720","0x2a1fe8","0x2f92d4","0x1ecf5b","0x19e570","0x4a6efc","0x269ad4","0x2e788b","0x2d51e7","0x21f74c","0x2f2b8f","0x3089e4","0x30e1c0","0x4489a4","0x29a340","0x2ba388","0x1d7134","0x2b274b","0x2b41b8","0x2a4b08","0x293120","0x26dd48","0x31d89b","0x259be8","0x29e5f8","0x1ecf98","0x189367","0x2d6c38","0x2efefc","0x1d4f84","0x1a1eb3","0x1d3950","0x6e88","0x1a2d00","0x293680","0x18816b","0x259504","0x26894","0x2fa43c","0x1f238","0x29b720","0x2f4990","0x30e4a8","0x19da43","0x2ef2b0","0x25a360","0x27fb20","0x2e7b10","0x2f9134","0x2b6a18","0x2cb0","0x2314f8","0x2963b8","0x19a977","0x265a5c","0x26d3f4","0x2b212f","0x1d7700","0x21ecef","0x38d8","0x17f46f","0x28fa9b","0x4c0468","0x1f118","0x2fa474","0x2ba370","0x2e97ac","0x280fbc","0x269ae8","0x2a2160","0x2a5094","0x258d88","0x3df2d4","0x156bab","0x1497d4","0x29aea4","0x2e97ff","0x293168","0x2fa188","0x1d6cb4","0x21f724","0x2a233b","0x1d08e4","0x216b18","0x1ecf4f","0x1ed8fb","0x1ed87c","0x1b44","0x153a18","0x19e637","0x1498d0","0x1c6c48","0x2a2524","0x2a5060","0x1a0f3f","0x2b8ee0","0x29a7b8","0x26955c","0x259970","0x1a6a28","0x259e50","0x2a4bdc","0x2cfd87","0x7754","0x2a051f","0x1f3d8","0x259be4","0x690c","0x2bf7ac","0x150a1c","0x29be73","0x25bbe0","0x29ba28","0x2b92a8","0x1d206f","0x1d2b74","0x48a0ec","0x222e7c","0x2bad88","0x21d2a0","0x2ee17c","0x2face0","0x3e0178","0x1d2fbc","0x295a80","0x19d293","0x29a0d4","0x25891f","0x30f7d8","0x31bd13","0x31f96b","0x2ef8bb","0x2f2643","0x3df6bc","0x25c0b0","0x29eb34","0x2a29bb","0x3226b8","0x268c3c","0x267dc7","0x29a2bc","0x6940","0x2592b4","0x2d000f","0x2592fc","0x1d63b0","0x2001f0","0x1a75df","0x2bd58f","0x2a2e78","0x4c14","0x18809f","0x26802c","0x29c83f","0x2904a7","0x2e7028","0x2a5544","0x33ec","0x25c6f0","0x19580f","0x2fcb88","0x25925c","0x2a5303","0x292140","0x311424","0x31d990","0x2931ec","0x25c150","0x1814","0x2a4cef","0x29a260","0x1d6b2c","0x27453c","0x1d3e67","0x25a200","0x2b36a3","0x28717b","0x281630","0x214f0b","0x26850c","0x1b8a68","0x12a8","0x1644","0x268bc8","0x4d78","0x19773b","0x1c6c1c","0x1d7004","0x2e7068","0x1ffc","0x2354f0","0x29368c","0x2934d4","0x2cac00","0x232cc0","0x150f38","0x4e84","0x258eec","0x181b23","0x265868","0x1764","0x297c04","0x2efc90","0x17dc","0x16c0","0x17ca57","0x2b03d0","0x209567","0x28adf8","0x281d9c","0x268b00","0x2e84c8","0x2a6194","0x150ee0","0x2e0a4c","0x19691b","0x29a0bc","0x25b9e0","0x4418","0x1a16ec","0x28a4a7","0x25f8d7","0x19c6db","0x2b936c","0x3df478","0x269554","0x1d7224","0x2fa454","0x2ea714","0x2a25e0","0x19fdb0","0x25a440","0x297fc0","0x30d7c8","0x19b997","0x25995c","0x2f4968","0x4cb8","0x1af264","0x15146f","0x2e9818","0x2a48c0","0x29f8ac","0x2bcf94","0x1291a7","0x2b656b","0x2b9f58","0x2bf6b8","0x1a0bd0","0x25bfaf","0x258bd0","0x17d8","0x178cd0","0x26dd03","0x269ae0","0x1d63cc","0x25b098","0x298a6c","0x2a2f5c","0x2f9068","0x274564","0x265c04","0x297f48","0x29fbcb","0x28d7b7","0x1c61c8","0x25c2bf","0x2a2660","0x200604","0x1ba0","0x1b2bef","0x289f97","0x2932f0","0x15233b","0x4a670c","0x29cfb8","0x12c4","0x2e0a40","0x4578","0x3e0210","0x3eac","0x292d80","0x2b6338","0x182000","0x29a798","0x25a1fc","0x317138","0x3428","0x1a1e13","0x293518","0x2debd0","0x1f12c","0x297d4c","0x2414","0x2963c8","0x2a4d54","0x29ee7c","0x17ec18","0x28f078","0x271e4","0x283fa0","0x3df678","0x287f08","0x30da34","0x2f98ac","0x1514e8","0x27fac4","0x29218c","0x28e28c","0x2eee00","0x1af59b","0x31ba84","0x5fa8","0x25c180","0x14cc8b","0x1cca34","0x30f948","0x3e00e4","0x2319db","0x15143f","0x1d76b4","0x2e7158","0x19c87c","0x27224","0x19a153","0x267c47","0x152080","0x2936a4","0x289767","0x31d89c","0x281d70","0x1a83c8","0x150fb8","0x26880c","0x29b71f","0x2eb42c","0x2b9338","0x15157f","0x1d3924","0x1d7214","0x2a21ef","0x1d6d08","0x1c8c","0x2aa143","0x29ed84","0x3df488","0x2a2b23","0x280854","0x1f544","0x2faed8","0x2ba8fb","0x2b47d3","0x1d4f64","0x28ef9c","0x2e09bc","0x22ec","0x29ad40","0x2bfd78","0x2e6898","0x1d63c0","0x12679f","0x151508","0x1d4e58","0x4314","0x292da4","0x317f00","0x20014b","0x184180","0x2a39c0","0x2658ec","0x2964b8","0x2effa3","0x1f244","0x1e34","0x265b38","0x31d900","0x2f1df0","0x1a169c","0x14da2b","0x1f1f7","0x1b60","0x1a70e3","0x2b8fbc","0x19c6a7","0x2a2e40","0x3e0778","0x2e09f4","0x26d4e4","0x1d7220","0x6058","0x297bf7","0x258818","0x1fb1d7","0x1fcedb","0x1f9327","0x14902b","0x2b9dfc","0x1d63d0","0x322c70","0x2f829b","0x3e0158","0x2faebc","0x234e08","0x2fad78","0x1a858","0x198fdb","0x28fbd7","0x302247","0x2e7cf4","0x2baf2b","0x2bad94","0x6c2c","0x156d23","0x4b4e58","0x2684b0","0x2ea7dc","0x292f88","0x21f5fc","0x29a36c","0x1907fb","0x2bdffc","0x21f76c","0x19edd3","0x1d3c10","0x1842ab","0x2bcfa0","0x2961c8","0x180b70","0x20efe8","0x448954","0x25af88","0x19faab","0x1dd25c","0x1fb270","0x2a22f0","0x219438","0x2b36ab","0x2870f7","0x2811bf","0x28d25b","0x2abb94","0x1fb7a3","0x1fceff","0x1f51f0","0x292d90","0x13ccfc","0x222658","0x23f174","0x3df49c","0x29e508","0x285d80","0x29fe47","0x2a0684","0x1b08ef","0x2bcee4","0x226d2f","0x32a728","0x198468","0x26c2a4","0x26840","0x292e1c","0x25c208","0x21f518","0x265a6c","0x258f04","0x21f530","0x4a04d4","0x2fa40c","0x25e618","0x2b4788","0x2a4bfb","0x2e0a7c","0x281b30","0x151137","0x25bc67","0x25d91c","0x28d2cf","0x1d3e24","0x27d6cc","0x2b628c","0x29c967","0x297e4c","0x1a7797","0x1d5627","0x1f2988","0x29be27","0x1354","0x30192f","0x12a567","0x13053b","0x1b479f","0x1bc9c0","0x29626f","0x13f8a0","0x260f63","0x1f4aef","0x24d5a0","0x1e8ba0","0x4a03b4","0x216084","0x18cf37","0x6b177","0x88b93","0x86537","0x1e5db","0x24648","0x6b79b","0x679eb","0x66c77","0x17d67","0x115f8","0x151e7","0x1849f","0x10a0f","0x111e7","0x37f57","0x321d4","0x17c88","0x1523b","0x10838","0x15203","0x18523","0x6368","0x1805f","0x31787","0x6b94","0x6bd4","0x18053","0x17b1c","0x111d7","0x1852b","0x111bf","0x10827","0x18083","0x10a4b","0x14ca0","0x37f8b","0x32118","0x184ef","0x18513","0x321b4","0x10a33","0x11194","0x32277","0x7614","0x18503","0x3214b","0x151fb","0x37f7f","0x2fb4c","0x17fa7","0x1f478","0x11180","0x17c9b","0x1526f","0x111c4","0x109fc","0x6c74","0x10a23","0x10837","0x180cc","0x17caf","0x6bb8","0x1802b","0x316c4","0x10813","0x17f77","0x6b68","0x17f8b","0x6a0c","0x111ac","0x17fcb","0x316e4","0x32110","0xac58","0x4db0","0x1525f","0x184f0","0x111b8","0x17c54","0x7714","0x111f7","0x1337f","0x3792b","0x31be7","0x7650","0x1fba7","0xf20","0x10a43","0x10814","0x124b8","0x1f2b0","0x17c9c","0x111cb","0x14cac","0x111d0","0x18478","0x184dc","0x37f00","0x3228c","0x17c90","0x6794","0x15217","0x3178c","0x1f604","0x3015f","0x30143","0x2ffc0","0x10a10","0x1f4a4","0x1cec","0x37f73","0x2ff64","0x32100","0x2fb60","0x6268","0x2ff80","0x14ccc","0x6384","0x17faf","0x10ed4","0x321e0","0x654b","0xd11b","0x14cb4","0x63cf","0x2c613","0x5e24","0x151ec","0x316f0","0x2fb78","0x378ec","0x1844c","0x6597","0xd288","0x32188","0x1529c","0x1120c","0x151fc","0x4ec0","0x15234","0x18434","0x3223f","0x638c","0x1ccc","0x18504","0x10800","0x17feb","0x51db","0xe2df","0x6bc8","0x6394","0x30153","0xd238","0xd050","0x3214c","0x66e7","0x4cac","0x668f","0xd593","0x4ed4","0x37f74","0x180f0","0x6434","0xd3fc","0x32288","0x15af4","0x10ef0","0xd0ec","0x1f490","0x2ffac","0x17f94","0x17b8c","0x1f428","0x72e4","0x10834","0x5d28","0x6e48","0x2ffb8","0x6960","0x18524","0x37f68","0x7284","0x4f94","0x18458","0x1f2f4","0x17cc0","0x300b8","0x4f88","0x37907","0x31a60","0x3165b","0x30144","0x60c8","0x6c60","0x17790","0x339c","0x2f350","0x31600","0x37f94","0x18510","0x7324","0x18518","0x7740","0x3174f","0x2c6b8","0x320f0","0xd444","0x37f64","0x10854","0x4ed8","0x37f9c","0x10820","0x773c","0x32124","0x17514","0x1f2c0","0x18440","0x4f5b","0x1a423","0x6924","0x764c","0x63cc","0xd4c0","0x69b8","0x7334","0x66c9b","0xc0f4"],"tid":5970075,"unregisterTime":13416.374542}],"pages":[],"profilerOverhead":[],"counters":[]} \ No newline at end of file From 2f5f4058b6bf5c6b25dc33fba10f422c212dd3d7 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 17:09:56 -0800 Subject: [PATCH 35/71] member access restructure --- crates/solc-expressions/src/array.rs | 2 +- .../src/func_call/intrinsic_call.rs | 2 +- .../src/member_access/builtin_access.rs | 288 +++++ .../src/member_access/contract_access.rs | 130 ++ .../src/member_access/enum_access.rs | 52 + .../src/member_access/library_access.rs | 64 + .../src/member_access/list_access.rs | 315 +++++ .../src/member_access/member_trait.rs | 269 ++++ .../solc-expressions/src/member_access/mod.rs | 1111 +---------------- .../src/member_access/struct_access.rs | 69 + 10 files changed, 1204 insertions(+), 1098 deletions(-) create mode 100644 crates/solc-expressions/src/member_access/builtin_access.rs create mode 100644 crates/solc-expressions/src/member_access/contract_access.rs create mode 100644 crates/solc-expressions/src/member_access/enum_access.rs create mode 100644 crates/solc-expressions/src/member_access/library_access.rs create mode 100644 crates/solc-expressions/src/member_access/list_access.rs create mode 100644 crates/solc-expressions/src/member_access/member_trait.rs create mode 100644 crates/solc-expressions/src/member_access/struct_access.rs diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 3cead0f6..f5b48f95 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,4 +1,4 @@ -use crate::{member_access::MemberAccess, require::Require, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ListAccess, require::Require, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ elem::RangeOp, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index 1d0f3834..012a2fb5 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -1,5 +1,5 @@ use crate::{ - array::Array, member_access::MemberAccess, require::Require, ContextBuilder, ExprErr, + array::Array, ListAccess, require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr, }; diff --git a/crates/solc-expressions/src/member_access/builtin_access.rs b/crates/solc-expressions/src/member_access/builtin_access.rs new file mode 100644 index 00000000..9d96dbaa --- /dev/null +++ b/crates/solc-expressions/src/member_access/builtin_access.rs @@ -0,0 +1,288 @@ +use crate::{LibraryAccess, ExprErr, IntoExprErr}; + +use graph::{ + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; + +use ethers_core::types::{I256, U256}; +use solang_parser::pt::{Expression, Identifier, Loc}; + + +impl BuiltinAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} +pub trait BuiltinAccess: LibraryAccess + AnalyzerBackend + Sized { + fn builtin_member_access( + &mut self, + loc: Loc, + ctx: ContextNode, + node: BuiltInNode, + is_storage: bool, + ident: &Identifier, + ) -> Result { + tracing::trace!("Looking for builtin member function"); + if let Some(ret) = self.library_func_search(ctx, node.0.into(), ident) { + Ok(ret) + } else { + match node.underlying(self).into_expr_err(loc)?.clone() { + Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { + match &*ident.name { + "delegatecall" + | "call" + | "staticcall" + | "delegatecall(address, bytes)" + | "call(address, bytes)" + | "staticcall(address, bytes)" => { + // TODO: check if the address is known to be a certain type and the function signature is known + // and call into the function + let builtin_name = ident.name.split('(').collect::>()[0]; + let func_node = self.builtin_fn_or_maybe_add(builtin_name).unwrap(); + Ok(ExprRet::Single(func_node)) + } + "code" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + "codehash" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Bytes(32)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + "balance" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Uint(256)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + _ if ident.name.starts_with("send") => { + let bn = self.builtin_or_add(Builtin::Bool); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(node)) + } + _ if ident.name.starts_with("transfer") => Ok(ExprRet::Multi(vec![])), + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on address: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + } + } + Builtin::Bool => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on bool: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::String => match ident.name.split('(').collect::>()[0] { + "concat" => { + let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); + Ok(ExprRet::Single(fn_node)) + } + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on string: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + }, + Builtin::Bytes(size) => Err(ExprErr::MemberAccessNotFound( + loc, + format!("Unknown member access on bytes{}: {:?}", size, ident.name), + )), + Builtin::Rational => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on rational: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::DynamicBytes => match ident.name.split('(').collect::>()[0] { + "concat" => { + let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); + Ok(ExprRet::Single(fn_node)) + } + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on bytes: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + }, + Builtin::Array(_) => { + if ident.name.starts_with("push") { + if is_storage { + let fn_node = self.builtin_fn_or_maybe_add("push").unwrap(); + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::NonStoragePush( + loc, + "Trying to push to nonstorage array is not supported".to_string(), + )) + } + } else if ident.name.starts_with("pop") { + if is_storage { + let fn_node = self.builtin_fn_or_maybe_add("pop").unwrap(); + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::NonStoragePush( + loc, + "Trying to pop from nonstorage array is not supported".to_string(), + )) + } + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on array[]: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )) + } + } + Builtin::SizedArray(s, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on array[{s}]: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Mapping(_, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on mapping: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Func(_, _) => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access on func: {:?}, ctx: {}", + ident.name, + ctx.path(self) + ), + )), + Builtin::Int(size) => { + let max = if size == 256 { + I256::MAX + } else { + I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1) + }; + match &*ident.name { + "max" => { + let c = Concrete::Int(size, max); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.max"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + "min" => { + let min = max * I256::from(-1i32) - I256::from(1i32); + let c = Concrete::Int(size, min); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.min"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + e => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown type attribute on int{size}: {e:?}, ctx: {}", + ctx.path(self) + ), + )), + } + } + Builtin::Uint(size) => match &*ident.name { + "max" => { + let max = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(size)) - 1 + }; + let c = Concrete::Uint(size, max); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("uint{size}.max"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + "min" => { + let min = U256::zero(); + let c = Concrete::from(min); + let node = self.add_node(Node::Concrete(c)).into(); + let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) + .into_expr_err(loc)?; + var.name = format!("int{size}.min"); + var.display_name = var.name.clone(); + var.is_tmp = true; + var.is_symbolic = false; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } + e => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown type attribute on uint{size}: {e:?}, ctx: {}", + ctx.path(self) + ), + )), + }, + } + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/contract_access.rs b/crates/solc-expressions/src/member_access/contract_access.rs new file mode 100644 index 00000000..3919df14 --- /dev/null +++ b/crates/solc-expressions/src/member_access/contract_access.rs @@ -0,0 +1,130 @@ +use crate::{ExprErr, IntoExprErr}; + +use graph::{ + nodes::{ + Builtin, Concrete, ContextNode, ContextVar, ContractNode, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl ContractAccess for T where T: AnalyzerBackend + Sized {} +pub trait ContractAccess: AnalyzerBackend + Sized { + fn contract_member_access( + &mut self, + member_idx: NodeIdx, + con_node: ContractNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + maybe_parent: Option, + ) -> Result { + tracing::trace!( + "Contract member access: {}.{}", + con_node + .maybe_name(self) + .into_expr_err(loc)? + .unwrap_or_else(|| "interface".to_string()), + ident.name + ); + + if let Some(func) = con_node + .funcs(self) + .into_iter() + .find(|func_node| func_node.name(self).unwrap() == ident.name) + { + if let Some(func_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { + let fn_node = self.add_node(Node::ContextVar(func_cvar)); + // this prevents attaching a dummy node to the parent which could cause a cycle in the graph + if maybe_parent.is_some() { + self.add_edge(fn_node, member_idx, Edge::Context(ContextEdge::FuncAccess)); + } + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unable to construct the function \"{}\" in contract \"{}\"", + ident.name, + con_node.name(self).into_expr_err(loc)? + ), + )) + } + } else if let Some(func) = con_node + .structs(self) + .into_iter() + .find(|struct_node| struct_node.name(self).unwrap() == ident.name) + { + if let Some(struct_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { + let struct_node = self.add_node(Node::ContextVar(struct_cvar)); + // this prevents attaching a dummy node to the parent which could cause a cycle in the graph + if maybe_parent.is_some() { + self.add_edge( + struct_node, + member_idx, + Edge::Context(ContextEdge::StructAccess), + ); + } + return Ok(ExprRet::Single(struct_node)); + } else { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unable to construct the struct \"{}\" in contract \"{}\"", + ident.name, + con_node.name(self).into_expr_err(loc)? + ), + )); + } + } else { + match &*ident.name { + "name" => { + let c = Concrete::from(con_node.name(self).unwrap()); + let cnode = self.add_node(Node::Concrete(c)); + let cvar = ContextVar::new_from_concrete(loc, ctx, cnode.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + "creationCode" | "runtimeCode" => { + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = + ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + "interfaceId" => { + // TODO: actually calculate this + let bn = self.builtin_or_add(Builtin::Bytes(4)); + let cvar = + ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + return Ok(ExprRet::Single(node)); + } + _ => { + return Err(ExprErr::ContractFunctionNotFound( + loc, + format!( + "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", + ident.name, + con_node.name(self).unwrap(), + con_node + .funcs(self) + .iter() + .map(|func| func.name(self).unwrap()) + .collect::>() + ), + )) + } + } + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/enum_access.rs b/crates/solc-expressions/src/member_access/enum_access.rs new file mode 100644 index 00000000..657b400c --- /dev/null +++ b/crates/solc-expressions/src/member_access/enum_access.rs @@ -0,0 +1,52 @@ +use crate::{ExprErr, IntoExprErr, LibraryAccess}; + +use graph::{ + nodes::{ + ContextNode, ContextVar, + EnumNode, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl EnumAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} +pub trait EnumAccess: LibraryAccess + AnalyzerBackend + Sized { + fn enum_member_access( + &mut self, + _member_idx: NodeIdx, + enum_node: EnumNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + ) -> Result { + tracing::trace!("Enum member access: {}", ident.name); + + if let Some(variant) = enum_node + .variants(self) + .into_expr_err(loc)? + .iter() + .find(|variant| **variant == ident.name) + { + let var = + ContextVar::new_from_enum_variant(self, ctx, loc, enum_node, variant.to_string()) + .into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(cvar)) + } else if let Some(ret) = self.library_func_search(ctx, enum_node.0.into(), ident) { + Ok(ret) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on enum \"{}\"", + ident.name, + enum_node.name(self).into_expr_err(loc)? + ), + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/library_access.rs b/crates/solc-expressions/src/member_access/library_access.rs new file mode 100644 index 00000000..b15d6466 --- /dev/null +++ b/crates/solc-expressions/src/member_access/library_access.rs @@ -0,0 +1,64 @@ +use crate::{ExprErr}; + +use graph::{ + nodes::{ + ContextNode, ExprRet, FunctionNode, + }, + AnalyzerBackend, Edge, +}; +use shared::NodeIdx; + +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::pt::{Expression, Identifier}; + +use std::collections::BTreeSet; + +impl LibraryAccess for T where T: AnalyzerBackend + Sized {} +pub trait LibraryAccess: AnalyzerBackend + Sized { + fn library_func_search( + &mut self, + ctx: ContextNode, + ty: NodeIdx, + ident: &Identifier, + ) -> Option { + self.possible_library_funcs(ctx, ty) + .iter() + .filter_map(|func| { + if let Ok(name) = func.name(self) { + Some((name, func)) + } else { + None + } + }) + .find_map(|(name, func)| { + if name == ident.name { + Some(ExprRet::Single((*func).into())) + } else { + None + } + }) + } + + fn possible_library_funcs(&mut self, ctx: ContextNode, ty: NodeIdx) -> BTreeSet { + let mut funcs: BTreeSet = BTreeSet::new(); + if let Some(associated_contract) = ctx.maybe_associated_contract(self).unwrap() { + // search for contract scoped `using` statements + funcs.extend( + self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { + matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == associated_contract.into()) + }).map(|edge| edge.target().into()).collect::>() + ); + } + + // Search for global `using` funcs + if let Some(source) = ctx.maybe_associated_source(self) { + funcs.extend( + self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { + matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source.into()) + }).map(|edge| edge.target().into()).collect::>() + ); + } + + funcs + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs new file mode 100644 index 00000000..02c5e559 --- /dev/null +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -0,0 +1,315 @@ +use crate::{ContextBuilder, ExprErr, IntoExprErr, Variable}; + +use graph::{ + elem::*, + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, VarType, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl ListAccess for T where T: AnalyzerBackend + Sized {} +pub trait ListAccess: AnalyzerBackend + Sized { + #[tracing::instrument(level = "trace", skip_all)] + fn index_access( + &mut self, + loc: Loc, + parent: NodeIdx, + dyn_builtin: BuiltInNode, + ident: &Identifier, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.variable(ident, ctx, None)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())); + }; + + if matches!(index_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(index_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_index_access(&index_paths, loc, parent.into(), dyn_builtin, ctx) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn match_index_access( + &mut self, + index_paths: &ExprRet, + loc: Loc, + parent: ContextVarNode, + dyn_builtin: BuiltInNode, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match index_paths { + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc), + ExprRet::Single(idx) => { + let parent = parent.first_version(self); + let parent_name = parent.name(self).into_expr_err(loc)?; + let parent_display_name = parent.display_name(self).unwrap(); + + tracing::trace!( + "Index access: {}[{}]", + parent_display_name, + ContextVarNode::from(*idx) + .display_name(self) + .into_expr_err(loc)? + ); + let parent_ty = dyn_builtin; + let parent_stor = parent + .storage(self) + .into_expr_err(loc)? + .as_ref() + .expect("parent didnt have a storage location?"); + let indexed_var = ContextVar::new_from_index( + self, + loc, + parent_name, + parent_display_name, + *parent_stor, + &parent_ty, + ContextVarNode::from(*idx), + ) + .into_expr_err(loc)?; + + let idx_node = self.add_node(Node::ContextVar(indexed_var)); + self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); + self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; + self.add_edge(*idx, idx_node, Edge::Context(ContextEdge::Index)); + ctx.push_expr(ExprRet::Single(idx_node), self) + .into_expr_err(loc)?; + Ok(()) + } + e => Err(ExprErr::UnhandledExprRet( + loc, + format!("Unhandled expression return in index access: {e:?}"), + )), + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn length( + &mut self, + loc: Loc, + input_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(input_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Attempted to perform member access without a left-hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_length(ctx, loc, ret, true) + }) + } + + #[tracing::instrument(level = "trace", skip_all)] + fn tmp_length( + &mut self, + arr: ContextVarNode, + array_ctx: ContextNode, + loc: Loc, + ) -> ContextVarNode { + let arr = arr.first_version(self); + let name = format!("{}.length", arr.name(self).unwrap()); + tracing::trace!("Length access: {}", name); + if let Some(attr_var) = array_ctx.var_by_name_or_recurse(self, &name).unwrap() { + attr_var.latest_version(self) + } else { + let range = if let Ok(Some(size)) = arr.ty(self).unwrap().maybe_array_size(self) { + SolcRange::from(Concrete::from(size)) + } else { + SolcRange::try_from_builtin(&Builtin::Uint(256)) + }; + + let len_var = ContextVar { + loc: Some(loc), + name: arr.name(self).unwrap() + ".length", + display_name: arr.display_name(self).unwrap() + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + range, + ), + }; + let len_node = self.add_node(Node::ContextVar(len_var)); + + let next_arr = self + .advance_var_in_ctx(arr.latest_version(self), loc, array_ctx) + .unwrap(); + if next_arr + .underlying(self) + .unwrap() + .ty + .is_dyn_builtin(self) + .unwrap() + { + if let Some(r) = next_arr.ref_range(self).unwrap() { + let min = r.evaled_range_min(self).unwrap(); + let max = r.evaled_range_max(self).unwrap(); + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + + self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); + array_ctx.add_var(len_node.into(), self).unwrap(); + len_node.into() + } + } + + #[tracing::instrument(level = "trace", skip_all)] + fn match_length( + &mut self, + ctx: ContextNode, + loc: Loc, + elem_path: ExprRet, + update_len_bound: bool, + ) -> Result<(), ExprErr> { + match elem_path { + ExprRet::Null => { + ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; + Ok(()) + } + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Single(arr) => { + let next_arr = self.advance_var_in_ctx( + ContextVarNode::from(arr).latest_version(self), + loc, + ctx, + )?; + let arr = ContextVarNode::from(arr).first_version(self); + let name = format!("{}.length", arr.name(self).into_expr_err(loc)?); + tracing::trace!("Length access: {}", name); + if let Some(len_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + let len_var = len_var.latest_version(self); + let new_len = self.advance_var_in_ctx(len_var, loc, ctx)?; + if update_len_bound + && next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(new_len); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(new_len); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + ctx.push_expr(ExprRet::Single(new_len.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let range = if let Ok(Some(size)) = + arr.ty(self).into_expr_err(loc)?.maybe_array_size(self) + { + SolcRange::from(Concrete::from(size)) + } else { + SolcRange::try_from_builtin(&Builtin::Uint(256)) + }; + + let len_var = ContextVar { + loc: Some(loc), + name, + display_name: arr.display_name(self).into_expr_err(loc)? + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + range, + ), + }; + let len_node = self.add_node(Node::ContextVar(len_var)); + + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_node); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + + self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_node.into(), self).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(len_node), self) + .into_expr_err(loc)?; + Ok(()) + } + } + e => todo!("here: {e:?}"), + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs new file mode 100644 index 00000000..623a2e37 --- /dev/null +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -0,0 +1,269 @@ +use crate::{ + ContextBuilder, Env, ExprErr, IntoExprErr, + StructAccess, BuiltinAccess, ListAccess, + ContractAccess, EnumAccess +}; + +use graph::{ + nodes::{ + BuiltInNode, ContextNode, ContextVar, ContextVarNode, ContractNode, + EnumNode, ExprRet, FunctionNode, StructNode, TyNode, + }, + AnalyzerBackend, Node, TypeNode, VarType, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl MemberAccessParts for T where T: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess {} +pub trait MemberAccessParts: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess {} + +impl MemberAccess for T where T: MemberAccessParts + AnalyzerBackend + Sized {} +pub trait MemberAccess: MemberAccessParts + AnalyzerBackend + Sized { + fn visible_member_funcs( + &mut self, + ctx: ContextNode, + loc: Loc, + member_idx: NodeIdx, + ) -> Result, ExprErr> { + let res = match self.node(member_idx) { + Node::ContextVar(cvar) => match &cvar.ty { + VarType::User(TypeNode::Contract(con_node), _) => { + let mut funcs = con_node.linearized_functions(self); + self + .possible_library_funcs(ctx, con_node.0.into()) + .into_iter() + .for_each(|func| { + let name = func.name(self).unwrap(); + funcs.entry(name).or_insert(func); + }); + funcs.values().copied().collect() + }, + VarType::BuiltIn(bn, _) => self + .possible_library_funcs(ctx, bn.0.into()) + .into_iter() + .collect::>(), + VarType::Concrete(cnode) => { + let b = cnode.underlying(self).unwrap().as_builtin(); + let bn = self.builtin_or_add(b); + self.possible_library_funcs(ctx, bn) + .into_iter() + .collect::>() + } + VarType::User(TypeNode::Struct(sn), _) => self + .possible_library_funcs(ctx, sn.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Enum(en), _) => self + .possible_library_funcs(ctx, en.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Ty(ty), _) => self + .possible_library_funcs(ctx, ty.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Func(func_node), _) => self + .possible_library_funcs(ctx, func_node.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Unresolved(n), _) => { + match self.node(*n) { + Node::Unresolved(ident) => { + return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) + } + _ => unreachable!() + } + } + }, + Node::Contract(_) => ContractNode::from(member_idx).funcs(self), + Node::Concrete(_) + | Node::Ty(_) + | Node::Struct(_) + | Node::Function(_) + | Node::Enum(_) + | Node::Builtin(_) => self + .possible_library_funcs(ctx, member_idx) + .into_iter() + .collect::>(), + e => { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!("This type cannot have member functions: {:?}", e), + )) + } + }; + Ok(res) + } + + /// Gets the array type + #[tracing::instrument(level = "trace", skip_all)] + fn member_access( + &mut self, + loc: Loc, + member_expr: &Expression, + ident: &Identifier, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // TODO: this is wrong as it overwrites a function call of the form elem.length(...) i believe + if ident.name == "length" { + return self.length(loc, member_expr, ctx); + } + + self.parse_ctx_expr(member_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Attempted to perform member access without a left-hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_member(ctx, loc, ident, ret) + }) + } + + fn match_member( + &mut self, + ctx: ContextNode, + loc: Loc, + ident: &Identifier, + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { + ctx.push_expr(self.member_access_inner(loc, idx, ident, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|ret| self.match_member(ctx, loc, ident, ret)), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Null => Ok(()), + } + } + + fn member_access_inner( + &mut self, + loc: Loc, + member_idx: NodeIdx, + ident: &Identifier, + ctx: ContextNode, + ) -> Result { + match self.node(member_idx) { + Node::ContextVar(cvar) => { + self.member_access_var_ty(cvar.clone(), loc, member_idx, ident, ctx) + } + Node::Contract(_c) => self.contract_member_access( + member_idx, + ContractNode::from(member_idx), + ident, + ctx, + loc, + None, + ), + Node::Struct(_c) => self.struct_member_access( + member_idx, + StructNode::from(member_idx), + ident, + ctx, + loc, + None, + ), + Node::Enum(_c) => { + self.enum_member_access(member_idx, EnumNode::from(member_idx), ident, ctx, loc) + } + Node::Ty(_ty) => { + self.ty_member_access(member_idx, TyNode::from(member_idx), ident, ctx, loc, None) + } + Node::Msg(_msg) => self.msg_access(loc, ctx, &ident.name), + Node::Block(_b) => self.block_access(loc, ctx, &ident.name), + Node::Builtin(ref _b) => { + self.builtin_member_access(loc, ctx, BuiltInNode::from(member_idx), false, ident) + } + e => Err(ExprErr::Todo( + loc, + format!("Member access on type: {e:?} is not yet supported"), + )), + } + } + + fn member_access_var_ty( + &mut self, + cvar: ContextVar, + loc: Loc, + member_idx: NodeIdx, + ident: &Identifier, + ctx: ContextNode, + ) -> Result { + match &cvar.ty { + VarType::User(TypeNode::Struct(struct_node), _) => { + self.struct_member_access(member_idx, *struct_node, ident, ctx, loc, Some(cvar)) + } + VarType::User(TypeNode::Enum(enum_node), _) => { + self.enum_member_access(member_idx, *enum_node, ident, ctx, loc) + } + VarType::User(TypeNode::Ty(ty_node), _) => { + self.ty_member_access(member_idx, *ty_node, ident, ctx, loc, Some(cvar)) + } + VarType::User(TypeNode::Contract(con_node), _) => { + self.contract_member_access(member_idx, *con_node, ident, ctx, loc, Some(cvar)) + } + VarType::BuiltIn(bn, _) => self.builtin_member_access( + loc, + ctx, + *bn, + ContextVarNode::from(member_idx) + .is_storage(self) + .into_expr_err(loc)?, + ident, + ), + VarType::Concrete(cn) => { + let builtin = cn.underlying(self).into_expr_err(loc)?.as_builtin(); + let bn = self.builtin_or_add(builtin).into(); + self.builtin_member_access( + loc, + ctx, + bn, + ContextVarNode::from(member_idx) + .is_storage(self) + .into_expr_err(loc)?, + ident, + ) + } + e => Err(ExprErr::UnhandledCombo( + loc, + format!("Unhandled member access: {:?}, {:?}", e, ident), + )), + } + } + + fn ty_member_access( + &mut self, + _member_idx: NodeIdx, + ty_node: TyNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + _maybe_parent: Option, + ) -> Result { + let name = ident.name.split('(').collect::>()[0]; + if let Some(func) = self.library_func_search(ctx, ty_node.0.into(), ident) { + Ok(func) + } else if let Some(func) = self.builtin_fn_or_maybe_add(name) { + Ok(ExprRet::Single(func)) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on struct \"{}\"", + ident.name, + ty_node.name(self).into_expr_err(loc)? + ), + )) + } + } +} diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index 53645a0c..150a0907 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -1,1096 +1,15 @@ -use crate::{ContextBuilder, Env, ExprErr, IntoExprErr, Variable}; - -use graph::{ - elem::*, - nodes::{ - BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ContractNode, - EnumNode, ExprRet, FunctionNode, StructNode, TyNode, - }, - AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, TypeNode, VarType, -}; -use shared::NodeIdx; - -use ethers_core::types::{I256, U256}; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::pt::{Expression, Identifier, Loc}; - -use std::collections::BTreeSet; - -impl MemberAccess for T where T: AnalyzerBackend + Sized {} -pub trait MemberAccess: AnalyzerBackend + Sized { - fn visible_member_funcs( - &mut self, - ctx: ContextNode, - loc: Loc, - member_idx: NodeIdx, - ) -> Result, ExprErr> { - let res = match self.node(member_idx) { - Node::ContextVar(cvar) => match &cvar.ty { - VarType::User(TypeNode::Contract(con_node), _) => { - let mut funcs = con_node.linearized_functions(self); - self - .possible_library_funcs(ctx, con_node.0.into()) - .into_iter() - .for_each(|func| { - let name = func.name(self).unwrap(); - funcs.entry(name).or_insert(func); - }); - funcs.values().copied().collect() - }, - VarType::BuiltIn(bn, _) => self - .possible_library_funcs(ctx, bn.0.into()) - .into_iter() - .collect::>(), - VarType::Concrete(cnode) => { - let b = cnode.underlying(self).unwrap().as_builtin(); - let bn = self.builtin_or_add(b); - self.possible_library_funcs(ctx, bn) - .into_iter() - .collect::>() - } - VarType::User(TypeNode::Struct(sn), _) => self - .possible_library_funcs(ctx, sn.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Enum(en), _) => self - .possible_library_funcs(ctx, en.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Ty(ty), _) => self - .possible_library_funcs(ctx, ty.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Func(func_node), _) => self - .possible_library_funcs(ctx, func_node.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Unresolved(n), _) => { - match self.node(*n) { - Node::Unresolved(ident) => { - return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) - } - _ => unreachable!() - } - } - }, - Node::Contract(_) => ContractNode::from(member_idx).funcs(self), - Node::Concrete(_) - | Node::Ty(_) - | Node::Struct(_) - | Node::Function(_) - | Node::Enum(_) - | Node::Builtin(_) => self - .possible_library_funcs(ctx, member_idx) - .into_iter() - .collect::>(), - e => { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!("This type cannot have member functions: {:?}", e), - )) - } - }; - Ok(res) - } - - /// Gets the array type - #[tracing::instrument(level = "trace", skip_all)] - fn member_access( - &mut self, - loc: Loc, - member_expr: &Expression, - ident: &Identifier, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - // TODO: this is wrong as it overwrites a function call of the form elem.length(...) i believe - if ident.name == "length" { - return self.length(loc, member_expr, ctx); - } - - self.parse_ctx_expr(member_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Attempted to perform member access without a left-hand side".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_member(ctx, loc, ident, ret) - }) - } - - fn match_member( - &mut self, - ctx: ContextNode, - loc: Loc, - ident: &Identifier, - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { - ctx.push_expr(self.member_access_inner(loc, idx, ident, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|ret| self.match_member(ctx, loc, ident, ret)), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Null => Ok(()), - } - } - - fn member_access_var_ty( - &mut self, - cvar: ContextVar, - loc: Loc, - member_idx: NodeIdx, - ident: &Identifier, - ctx: ContextNode, - ) -> Result { - match &cvar.ty { - VarType::User(TypeNode::Struct(struct_node), _) => { - self.struct_member_access(member_idx, *struct_node, ident, ctx, loc, Some(cvar)) - } - VarType::User(TypeNode::Enum(enum_node), _) => { - self.enum_member_access(member_idx, *enum_node, ident, ctx, loc) - } - VarType::User(TypeNode::Ty(ty_node), _) => { - self.ty_member_access(member_idx, *ty_node, ident, ctx, loc, Some(cvar)) - } - VarType::User(TypeNode::Contract(con_node), _) => { - self.contract_member_access(member_idx, *con_node, ident, ctx, loc, Some(cvar)) - } - VarType::BuiltIn(bn, _) => self.builtin_member_access( - loc, - ctx, - *bn, - ContextVarNode::from(member_idx) - .is_storage(self) - .into_expr_err(loc)?, - ident, - ), - VarType::Concrete(cn) => { - let builtin = cn.underlying(self).into_expr_err(loc)?.as_builtin(); - let bn = self.builtin_or_add(builtin).into(); - self.builtin_member_access( - loc, - ctx, - bn, - ContextVarNode::from(member_idx) - .is_storage(self) - .into_expr_err(loc)?, - ident, - ) - } - e => Err(ExprErr::UnhandledCombo( - loc, - format!("Unhandled member access: {:?}, {:?}", e, ident), - )), - } - } - - fn struct_member_access( - &mut self, - member_idx: NodeIdx, - struct_node: StructNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - maybe_parent: Option, - ) -> Result { - let name = format!( - "{}.{}", - struct_node.name(self).into_expr_err(loc)?, - ident.name - ); - tracing::trace!("Struct member access: {}", name); - if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - Ok(ExprRet::Single(attr_var.latest_version(self).into())) - } else if let Some(field) = struct_node.find_field(self, ident) { - let cvar = if let Some(parent) = maybe_parent { - parent - } else { - ContextVar::maybe_from_user_ty(self, loc, struct_node.into()).unwrap() - }; - if let Some(field_cvar) = ContextVar::maybe_new_from_field( - self, - loc, - &cvar, - field.underlying(self).unwrap().clone(), - ) { - let fc_node = self.add_node(Node::ContextVar(field_cvar)); - self.add_edge( - fc_node, - ContextVarNode::from(member_idx).first_version(self), - Edge::Context(ContextEdge::AttrAccess), - ); - ctx.add_var(fc_node.into(), self).into_expr_err(loc)?; - self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(fc_node)) - } else { - panic!("Couldn't create field variable"); - } - } else if let Some(func) = self.library_func_search(ctx, struct_node.0.into(), ident) { - Ok(func) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on struct \"{}\"", - ident.name, - struct_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn enum_member_access( - &mut self, - _member_idx: NodeIdx, - enum_node: EnumNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - ) -> Result { - tracing::trace!("Enum member access: {}", ident.name); - - if let Some(variant) = enum_node - .variants(self) - .into_expr_err(loc)? - .iter() - .find(|variant| **variant == ident.name) - { - let var = - ContextVar::new_from_enum_variant(self, ctx, loc, enum_node, variant.to_string()) - .into_expr_err(loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } else if let Some(ret) = self.library_func_search(ctx, enum_node.0.into(), ident) { - Ok(ret) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on enum \"{}\"", - ident.name, - enum_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn contract_member_access( - &mut self, - member_idx: NodeIdx, - con_node: ContractNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - maybe_parent: Option, - ) -> Result { - tracing::trace!( - "Contract member access: {}.{}", - con_node - .maybe_name(self) - .into_expr_err(loc)? - .unwrap_or_else(|| "interface".to_string()), - ident.name - ); - - if let Some(func) = con_node - .funcs(self) - .into_iter() - .find(|func_node| func_node.name(self).unwrap() == ident.name) - { - if let Some(func_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { - let fn_node = self.add_node(Node::ContextVar(func_cvar)); - // this prevents attaching a dummy node to the parent which could cause a cycle in the graph - if maybe_parent.is_some() { - self.add_edge(fn_node, member_idx, Edge::Context(ContextEdge::FuncAccess)); - } - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unable to construct the function \"{}\" in contract \"{}\"", - ident.name, - con_node.name(self).into_expr_err(loc)? - ), - )) - } - } else if let Some(func) = con_node - .structs(self) - .into_iter() - .find(|struct_node| struct_node.name(self).unwrap() == ident.name) - { - if let Some(struct_cvar) = ContextVar::maybe_from_user_ty(self, loc, func.0.into()) { - let struct_node = self.add_node(Node::ContextVar(struct_cvar)); - // this prevents attaching a dummy node to the parent which could cause a cycle in the graph - if maybe_parent.is_some() { - self.add_edge( - struct_node, - member_idx, - Edge::Context(ContextEdge::StructAccess), - ); - } - return Ok(ExprRet::Single(struct_node)); - } else { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unable to construct the struct \"{}\" in contract \"{}\"", - ident.name, - con_node.name(self).into_expr_err(loc)? - ), - )); - } - } else { - match &*ident.name { - "name" => { - let c = Concrete::from(con_node.name(self).unwrap()); - let cnode = self.add_node(Node::Concrete(c)); - let cvar = ContextVar::new_from_concrete(loc, ctx, cnode.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - "creationCode" | "runtimeCode" => { - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = - ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - "interfaceId" => { - // TODO: actually calculate this - let bn = self.builtin_or_add(Builtin::Bytes(4)); - let cvar = - ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - return Ok(ExprRet::Single(node)); - } - _ => { - return Err(ExprErr::ContractFunctionNotFound( - loc, - format!( - "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", - ident.name, - con_node.name(self).unwrap(), - con_node - .funcs(self) - .iter() - .map(|func| func.name(self).unwrap()) - .collect::>() - ), - )) - } - } - } - } - - fn ty_member_access( - &mut self, - _member_idx: NodeIdx, - ty_node: TyNode, - ident: &Identifier, - ctx: ContextNode, - loc: Loc, - _maybe_parent: Option, - ) -> Result { - let name = ident.name.split('(').collect::>()[0]; - if let Some(func) = self.library_func_search(ctx, ty_node.0.into(), ident) { - Ok(func) - } else if let Some(func) = self.builtin_fn_or_maybe_add(name) { - Ok(ExprRet::Single(func)) - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access \"{}\" on struct \"{}\"", - ident.name, - ty_node.name(self).into_expr_err(loc)? - ), - )) - } - } - - fn member_access_inner( - &mut self, - loc: Loc, - member_idx: NodeIdx, - ident: &Identifier, - ctx: ContextNode, - ) -> Result { - match self.node(member_idx) { - Node::ContextVar(cvar) => { - self.member_access_var_ty(cvar.clone(), loc, member_idx, ident, ctx) - } - Node::Contract(_c) => self.contract_member_access( - member_idx, - ContractNode::from(member_idx), - ident, - ctx, - loc, - None, - ), - Node::Struct(_c) => self.struct_member_access( - member_idx, - StructNode::from(member_idx), - ident, - ctx, - loc, - None, - ), - Node::Enum(_c) => { - self.enum_member_access(member_idx, EnumNode::from(member_idx), ident, ctx, loc) - } - Node::Ty(_ty) => { - self.ty_member_access(member_idx, TyNode::from(member_idx), ident, ctx, loc, None) - } - Node::Msg(_msg) => self.msg_access(loc, ctx, &ident.name), - Node::Block(_b) => self.block_access(loc, ctx, &ident.name), - Node::Builtin(ref _b) => { - self.builtin_member_access(loc, ctx, BuiltInNode::from(member_idx), false, ident) - } - e => Err(ExprErr::Todo( - loc, - format!("Member access on type: {e:?} is not yet supported"), - )), - } - } - - fn builtin_member_access( - &mut self, - loc: Loc, - ctx: ContextNode, - node: BuiltInNode, - is_storage: bool, - ident: &Identifier, - ) -> Result { - tracing::trace!("Looking for builtin member function"); - if let Some(ret) = self.library_func_search(ctx, node.0.into(), ident) { - Ok(ret) - } else { - match node.underlying(self).into_expr_err(loc)?.clone() { - Builtin::Address | Builtin::AddressPayable | Builtin::Payable => { - match &*ident.name { - "delegatecall" - | "call" - | "staticcall" - | "delegatecall(address, bytes)" - | "call(address, bytes)" - | "staticcall(address, bytes)" => { - // TODO: check if the address is known to be a certain type and the function signature is known - // and call into the function - let builtin_name = ident.name.split('(').collect::>()[0]; - let func_node = self.builtin_fn_or_maybe_add(builtin_name).unwrap(); - Ok(ExprRet::Single(func_node)) - } - "code" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - "codehash" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Bytes(32)); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - "balance" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Uint(256)); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - _ if ident.name.starts_with("send") => { - let bn = self.builtin_or_add(Builtin::Bool); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(node)) - } - _ if ident.name.starts_with("transfer") => Ok(ExprRet::Multi(vec![])), - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on address: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - } - } - Builtin::Bool => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on bool: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::String => match ident.name.split('(').collect::>()[0] { - "concat" => { - let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); - Ok(ExprRet::Single(fn_node)) - } - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on string: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - }, - Builtin::Bytes(size) => Err(ExprErr::MemberAccessNotFound( - loc, - format!("Unknown member access on bytes{}: {:?}", size, ident.name), - )), - Builtin::Rational => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on rational: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::DynamicBytes => match ident.name.split('(').collect::>()[0] { - "concat" => { - let fn_node = self.builtin_fn_or_maybe_add("concat").unwrap(); - Ok(ExprRet::Single(fn_node)) - } - _ => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on bytes: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - }, - Builtin::Array(_) => { - if ident.name.starts_with("push") { - if is_storage { - let fn_node = self.builtin_fn_or_maybe_add("push").unwrap(); - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::NonStoragePush( - loc, - "Trying to push to nonstorage array is not supported".to_string(), - )) - } - } else if ident.name.starts_with("pop") { - if is_storage { - let fn_node = self.builtin_fn_or_maybe_add("pop").unwrap(); - Ok(ExprRet::Single(fn_node)) - } else { - Err(ExprErr::NonStoragePush( - loc, - "Trying to pop from nonstorage array is not supported".to_string(), - )) - } - } else { - Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on array[]: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )) - } - } - Builtin::SizedArray(s, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on array[{s}]: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Mapping(_, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on mapping: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Func(_, _) => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown member access on func: {:?}, ctx: {}", - ident.name, - ctx.path(self) - ), - )), - Builtin::Int(size) => { - let max = if size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1) - }; - match &*ident.name { - "max" => { - let c = Concrete::Int(size, max); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.max"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - "min" => { - let min = max * I256::from(-1i32) - I256::from(1i32); - let c = Concrete::Int(size, min); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.min"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - e => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown type attribute on int{size}: {e:?}, ctx: {}", - ctx.path(self) - ), - )), - } - } - Builtin::Uint(size) => match &*ident.name { - "max" => { - let size = size; - let max = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(size)) - 1 - }; - let c = Concrete::Uint(size, max); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("uint{size}.max"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - "min" => { - let min = U256::zero(); - let c = Concrete::from(min); - let node = self.add_node(Node::Concrete(c)).into(); - let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) - .into_expr_err(loc)?; - var.name = format!("int{size}.min"); - var.display_name = var.name.clone(); - var.is_tmp = true; - var.is_symbolic = false; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - Ok(ExprRet::Single(cvar)) - } - e => Err(ExprErr::MemberAccessNotFound( - loc, - format!( - "Unknown type attribute on uint{size}: {e:?}, ctx: {}", - ctx.path(self) - ), - )), - }, - } - } - } - - fn library_func_search( - &mut self, - ctx: ContextNode, - ty: NodeIdx, - ident: &Identifier, - ) -> Option { - self.possible_library_funcs(ctx, ty) - .iter() - .filter_map(|func| { - if let Ok(name) = func.name(self) { - Some((name, func)) - } else { - None - } - }) - .find_map(|(name, func)| { - if name == ident.name { - Some(ExprRet::Single((*func).into())) - } else { - None - } - }) - } - - fn possible_library_funcs(&mut self, ctx: ContextNode, ty: NodeIdx) -> BTreeSet { - let mut funcs: BTreeSet = BTreeSet::new(); - if let Some(associated_contract) = ctx.maybe_associated_contract(self).unwrap() { - // search for contract scoped `using` statements - funcs.extend( - self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { - matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == associated_contract.into()) - }).map(|edge| edge.target().into()).collect::>() - ); - } - - // Search for global `using` funcs - if let Some(source) = ctx.maybe_associated_source(self) { - funcs.extend( - self.graph().edges_directed(ty, Direction::Outgoing).filter(|edge| { - matches!(*edge.weight(), Edge::LibraryFunction(scope) if scope == source.into()) - }).map(|edge| edge.target().into()).collect::>() - ); - } - - funcs - } - - #[tracing::instrument(level = "trace", skip_all)] - fn index_access( - &mut self, - loc: Loc, - parent: NodeIdx, - dyn_builtin: BuiltInNode, - ident: &Identifier, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.variable(ident, ctx, None)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())); - }; - - if matches!(index_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(index_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_index_access(&index_paths, loc, parent.into(), dyn_builtin, ctx) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn match_index_access( - &mut self, - index_paths: &ExprRet, - loc: Loc, - parent: ContextVarNode, - dyn_builtin: BuiltInNode, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - match index_paths { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc), - ExprRet::Single(idx) => { - let parent = parent.first_version(self); - let parent_name = parent.name(self).into_expr_err(loc)?; - let parent_display_name = parent.display_name(self).unwrap(); - - tracing::trace!( - "Index access: {}[{}]", - parent_display_name, - ContextVarNode::from(*idx) - .display_name(self) - .into_expr_err(loc)? - ); - let parent_ty = dyn_builtin; - let parent_stor = parent - .storage(self) - .into_expr_err(loc)? - .as_ref() - .expect("parent didnt have a storage location?"); - let indexed_var = ContextVar::new_from_index( - self, - loc, - parent_name, - parent_display_name, - *parent_stor, - &parent_ty, - ContextVarNode::from(*idx), - ) - .into_expr_err(loc)?; - - let idx_node = self.add_node(Node::ContextVar(indexed_var)); - self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); - self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; - self.add_edge(*idx, idx_node, Edge::Context(ContextEdge::Index)); - ctx.push_expr(ExprRet::Single(idx_node), self) - .into_expr_err(loc)?; - Ok(()) - } - e => Err(ExprErr::UnhandledExprRet( - loc, - format!("Unhandled expression return in index access: {e:?}"), - )), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn length( - &mut self, - loc: Loc, - input_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(input_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Attempted to perform member access without a left-hand side".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_length(ctx, loc, ret, true) - }) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn tmp_length( - &mut self, - arr: ContextVarNode, - array_ctx: ContextNode, - loc: Loc, - ) -> ContextVarNode { - let arr = arr.first_version(self); - let name = format!("{}.length", arr.name(self).unwrap()); - tracing::trace!("Length access: {}", name); - if let Some(attr_var) = array_ctx.var_by_name_or_recurse(self, &name).unwrap() { - attr_var.latest_version(self) - } else { - let range = if let Ok(Some(size)) = arr.ty(self).unwrap().maybe_array_size(self) { - SolcRange::from(Concrete::from(size)) - } else { - SolcRange::try_from_builtin(&Builtin::Uint(256)) - }; - - let len_var = ContextVar { - loc: Some(loc), - name: arr.name(self).unwrap() + ".length", - display_name: arr.display_name(self).unwrap() + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - range, - ), - }; - let len_node = self.add_node(Node::ContextVar(len_var)); - - let next_arr = self - .advance_var_in_ctx(arr.latest_version(self), loc, array_ctx) - .unwrap(); - if next_arr - .underlying(self) - .unwrap() - .ty - .is_dyn_builtin(self) - .unwrap() - { - if let Some(r) = next_arr.ref_range(self).unwrap() { - let min = r.evaled_range_min(self).unwrap(); - let max = r.evaled_range_max(self).unwrap(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); - array_ctx.add_var(len_node.into(), self).unwrap(); - len_node.into() - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn match_length( - &mut self, - ctx: ContextNode, - loc: Loc, - elem_path: ExprRet, - update_len_bound: bool, - ) -> Result<(), ExprErr> { - match elem_path { - ExprRet::Null => { - ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; - Ok(()) - } - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Single(arr) => { - let next_arr = self.advance_var_in_ctx( - ContextVarNode::from(arr).latest_version(self), - loc, - ctx, - )?; - let arr = ContextVarNode::from(arr).first_version(self); - let name = format!("{}.length", arr.name(self).into_expr_err(loc)?); - tracing::trace!("Length access: {}", name); - if let Some(len_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - let len_var = len_var.latest_version(self); - let new_len = self.advance_var_in_ctx(len_var, loc, ctx)?; - if update_len_bound - && next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - ctx.push_expr(ExprRet::Single(new_len.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let range = if let Ok(Some(size)) = - arr.ty(self).into_expr_err(loc)?.maybe_array_size(self) - { - SolcRange::from(Concrete::from(size)) - } else { - SolcRange::try_from_builtin(&Builtin::Uint(256)) - }; - - let len_var = ContextVar { - loc: Some(loc), - name, - display_name: arr.display_name(self).into_expr_err(loc)? + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - range, - ), - }; - let len_node = self.add_node(Node::ContextVar(len_var)); - - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_node.into(), self).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(len_node), self) - .into_expr_err(loc)?; - Ok(()) - } - } - e => todo!("here: {e:?}"), - } - } -} +mod builtin_access; +mod contract_access; +mod enum_access; +mod library_access; +mod list_access; +mod member_trait; +mod struct_access; + +pub use builtin_access::*; +pub use contract_access::*; +pub use enum_access::*; +pub use library_access::*; +pub use list_access::*; +pub use struct_access::*; +pub use member_trait::*; diff --git a/crates/solc-expressions/src/member_access/struct_access.rs b/crates/solc-expressions/src/member_access/struct_access.rs new file mode 100644 index 00000000..3569bfc5 --- /dev/null +++ b/crates/solc-expressions/src/member_access/struct_access.rs @@ -0,0 +1,69 @@ +use crate::{LibraryAccess, ExprErr, IntoExprErr}; + +use graph::{ + nodes::{ + ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Identifier, Loc}; + +impl StructAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} +pub trait StructAccess: LibraryAccess + AnalyzerBackend + Sized { + fn struct_member_access( + &mut self, + member_idx: NodeIdx, + struct_node: StructNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + maybe_parent: Option, + ) -> Result { + let name = format!( + "{}.{}", + struct_node.name(self).into_expr_err(loc)?, + ident.name + ); + tracing::trace!("Struct member access: {}", name); + if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + Ok(ExprRet::Single(attr_var.latest_version(self).into())) + } else if let Some(field) = struct_node.find_field(self, ident) { + let cvar = if let Some(parent) = maybe_parent { + parent + } else { + ContextVar::maybe_from_user_ty(self, loc, struct_node.into()).unwrap() + }; + if let Some(field_cvar) = ContextVar::maybe_new_from_field( + self, + loc, + &cvar, + field.underlying(self).unwrap().clone(), + ) { + let fc_node = self.add_node(Node::ContextVar(field_cvar)); + self.add_edge( + fc_node, + ContextVarNode::from(member_idx).first_version(self), + Edge::Context(ContextEdge::AttrAccess), + ); + ctx.add_var(fc_node.into(), self).into_expr_err(loc)?; + self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(fc_node)) + } else { + panic!("Couldn't create field variable"); + } + } else if let Some(func) = self.library_func_search(ctx, struct_node.0.into(), ident) { + Ok(func) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on struct \"{}\"", + ident.name, + struct_node.name(self).into_expr_err(loc)? + ), + )) + } + } +} \ No newline at end of file From f4859dd4a8b45a2aed6f460f85d6672464928598 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 17:10:19 -0800 Subject: [PATCH 36/71] lint --- crates/solc-expressions/src/array.rs | 2 +- .../src/func_call/intrinsic_call.rs | 3 +- .../src/member_access/builtin_access.rs | 20 +++++++------ .../src/member_access/contract_access.rs | 10 +++---- .../src/member_access/enum_access.rs | 18 ++++++------ .../src/member_access/library_access.rs | 12 ++++---- .../src/member_access/list_access.rs | 8 ++---- .../src/member_access/member_trait.rs | 28 +++++++++++++------ .../solc-expressions/src/member_access/mod.rs | 2 +- .../src/member_access/struct_access.rs | 19 +++++++------ 10 files changed, 66 insertions(+), 56 deletions(-) diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index f5b48f95..b603e39b 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,4 +1,4 @@ -use crate::{ListAccess, require::Require, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; use graph::{ elem::RangeOp, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs index 012a2fb5..a7b9d564 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call.rs @@ -1,6 +1,5 @@ use crate::{ - array::Array, ListAccess, require::Require, ContextBuilder, ExprErr, - FuncCaller, IntoExprErr, + array::Array, require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr, ListAccess, }; use graph::{ diff --git a/crates/solc-expressions/src/member_access/builtin_access.rs b/crates/solc-expressions/src/member_access/builtin_access.rs index 9d96dbaa..b901b282 100644 --- a/crates/solc-expressions/src/member_access/builtin_access.rs +++ b/crates/solc-expressions/src/member_access/builtin_access.rs @@ -1,19 +1,21 @@ -use crate::{LibraryAccess, ExprErr, IntoExprErr}; +use crate::{ExprErr, IntoExprErr, LibraryAccess}; use graph::{ - nodes::{ - BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ExprRet, - }, + nodes::{BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; use ethers_core::types::{I256, U256}; use solang_parser::pt::{Expression, Identifier, Loc}; - -impl BuiltinAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} -pub trait BuiltinAccess: LibraryAccess + AnalyzerBackend + Sized { - fn builtin_member_access( +impl BuiltinAccess for T where + T: LibraryAccess + AnalyzerBackend + Sized +{ +} +pub trait BuiltinAccess: + LibraryAccess + AnalyzerBackend + Sized +{ + fn builtin_member_access( &mut self, loc: Loc, ctx: ContextNode, @@ -285,4 +287,4 @@ pub trait BuiltinAccess: LibraryAccess + AnalyzerBackend ContractAccess for T where T: AnalyzerBackend + Sized {} -pub trait ContractAccess: AnalyzerBackend + Sized { - fn contract_member_access( +pub trait ContractAccess: AnalyzerBackend + Sized { + fn contract_member_access( &mut self, member_idx: NodeIdx, con_node: ContractNode, @@ -127,4 +125,4 @@ pub trait ContractAccess: AnalyzerBackend } } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/member_access/enum_access.rs b/crates/solc-expressions/src/member_access/enum_access.rs index 657b400c..435ce8f9 100644 --- a/crates/solc-expressions/src/member_access/enum_access.rs +++ b/crates/solc-expressions/src/member_access/enum_access.rs @@ -1,19 +1,21 @@ use crate::{ExprErr, IntoExprErr, LibraryAccess}; use graph::{ - nodes::{ - ContextNode, ContextVar, - EnumNode, ExprRet, - }, + nodes::{ContextNode, ContextVar, EnumNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; -impl EnumAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} -pub trait EnumAccess: LibraryAccess + AnalyzerBackend + Sized { - fn enum_member_access( +impl EnumAccess for T where + T: LibraryAccess + AnalyzerBackend + Sized +{ +} +pub trait EnumAccess: + LibraryAccess + AnalyzerBackend + Sized +{ + fn enum_member_access( &mut self, _member_idx: NodeIdx, enum_node: EnumNode, @@ -49,4 +51,4 @@ pub trait EnumAccess: LibraryAccess + AnalyzerBackend LibraryAccess for T where T: AnalyzerBackend + Sized {} -pub trait LibraryAccess: AnalyzerBackend + Sized { - fn library_func_search( +pub trait LibraryAccess: AnalyzerBackend + Sized { + fn library_func_search( &mut self, ctx: ContextNode, ty: NodeIdx, @@ -61,4 +59,4 @@ pub trait LibraryAccess: AnalyzerBackend + funcs } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 02c5e559..3923db87 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -2,9 +2,7 @@ use crate::{ContextBuilder, ExprErr, IntoExprErr, Variable}; use graph::{ elem::*, - nodes::{ - BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, - }, + nodes::{BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, VarType, }; use shared::NodeIdx; @@ -12,7 +10,7 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; impl ListAccess for T where T: AnalyzerBackend + Sized {} -pub trait ListAccess: AnalyzerBackend + Sized { +pub trait ListAccess: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn index_access( &mut self, @@ -312,4 +310,4 @@ pub trait ListAccess: AnalyzerBackend + Si e => todo!("here: {e:?}"), } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index 623a2e37..370114ff 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -1,13 +1,12 @@ use crate::{ - ContextBuilder, Env, ExprErr, IntoExprErr, - StructAccess, BuiltinAccess, ListAccess, - ContractAccess, EnumAccess + BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, IntoExprErr, + ListAccess, StructAccess, }; use graph::{ nodes::{ - BuiltInNode, ContextNode, ContextVar, ContextVarNode, ContractNode, - EnumNode, ExprRet, FunctionNode, StructNode, TyNode, + BuiltInNode, ContextNode, ContextVar, ContextVarNode, ContractNode, EnumNode, ExprRet, + FunctionNode, StructNode, TyNode, }, AnalyzerBackend, Node, TypeNode, VarType, }; @@ -15,11 +14,22 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; -impl MemberAccessParts for T where T: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess {} -pub trait MemberAccessParts: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess {} +impl MemberAccessParts for T where + T: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess +{ +} +pub trait MemberAccessParts: + BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess +{ +} -impl MemberAccess for T where T: MemberAccessParts + AnalyzerBackend + Sized {} -pub trait MemberAccess: MemberAccessParts + AnalyzerBackend + Sized { +impl MemberAccess for T where + T: MemberAccessParts + AnalyzerBackend + Sized +{ +} +pub trait MemberAccess: + MemberAccessParts + AnalyzerBackend + Sized +{ fn visible_member_funcs( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index 150a0907..f86ca279 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -11,5 +11,5 @@ pub use contract_access::*; pub use enum_access::*; pub use library_access::*; pub use list_access::*; -pub use struct_access::*; pub use member_trait::*; +pub use struct_access::*; diff --git a/crates/solc-expressions/src/member_access/struct_access.rs b/crates/solc-expressions/src/member_access/struct_access.rs index 3569bfc5..a17eed14 100644 --- a/crates/solc-expressions/src/member_access/struct_access.rs +++ b/crates/solc-expressions/src/member_access/struct_access.rs @@ -1,18 +1,21 @@ -use crate::{LibraryAccess, ExprErr, IntoExprErr}; +use crate::{ExprErr, IntoExprErr, LibraryAccess}; use graph::{ - nodes::{ - ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode, - }, + nodes::{ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode}, AnalyzerBackend, ContextEdge, Edge, Node, }; use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; -impl StructAccess for T where T: LibraryAccess + AnalyzerBackend + Sized {} -pub trait StructAccess: LibraryAccess + AnalyzerBackend + Sized { - fn struct_member_access( +impl StructAccess for T where + T: LibraryAccess + AnalyzerBackend + Sized +{ +} +pub trait StructAccess: + LibraryAccess + AnalyzerBackend + Sized +{ + fn struct_member_access( &mut self, member_idx: NodeIdx, struct_node: StructNode, @@ -66,4 +69,4 @@ pub trait StructAccess: LibraryAccess + AnalyzerBackend Date: Sun, 10 Dec 2023 19:55:31 -0800 Subject: [PATCH 37/71] rearchitect intrinsic calls --- .../src/func_call/intrinsic_call.rs | 1265 ----------------- .../src/func_call/intrinsic_call/abi.rs | 128 ++ .../src/func_call/intrinsic_call/address.rs | 79 + .../src/func_call/intrinsic_call/array.rs | 200 +++ .../src/func_call/intrinsic_call/block.rs | 55 + .../func_call/intrinsic_call/constructors.rs | 197 +++ .../func_call/intrinsic_call/dyn_builtin.rs | 212 +++ .../intrinsic_call/intrinsic_caller.rs | 154 ++ .../src/func_call/intrinsic_call/mod.rs | 23 + .../src/func_call/intrinsic_call/msg.rs | 39 + .../func_call/intrinsic_call/precompile.rs | 218 +++ .../src/func_call/intrinsic_call/solidity.rs | 91 ++ .../src/func_call/intrinsic_call/types.rs | 223 +++ 13 files changed, 1619 insertions(+), 1265 deletions(-) delete mode 100644 crates/solc-expressions/src/func_call/intrinsic_call.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/abi.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/address.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/array.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/block.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/mod.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/msg.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs create mode 100644 crates/solc-expressions/src/func_call/intrinsic_call/types.rs diff --git a/crates/solc-expressions/src/func_call/intrinsic_call.rs b/crates/solc-expressions/src/func_call/intrinsic_call.rs deleted file mode 100644 index a7b9d564..00000000 --- a/crates/solc-expressions/src/func_call/intrinsic_call.rs +++ /dev/null @@ -1,1265 +0,0 @@ -use crate::{ - array::Array, require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr, ListAccess, -}; - -use graph::{ - elem::*, - nodes::{ - BuiltInNode, Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, - StructNode, TyNode, - }, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, SolcRange, VarType, -}; -use shared::{NodeIdx, Search}; - -use ethers_core::types::U256; -use solang_parser::pt::{Expression, Loc}; - -impl IntrinsicFuncCaller for T where - T: AnalyzerBackend + Sized + GraphBackend + Search -{ -} -pub trait IntrinsicFuncCaller: - AnalyzerBackend + Sized + GraphBackend + Search -{ - /// Calls an intrinsic/builtin function call (casts, require, etc.) - #[tracing::instrument(level = "trace", skip_all)] - fn intrinsic_func_call( - &mut self, - loc: &Loc, - input_exprs: &[Expression], - func_idx: NodeIdx, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - match self.node(func_idx) { - Node::Function(underlying) => { - if let Some(func_name) = &underlying.name { - match &*func_name.name { - "abi.decode" => { - // we skip the first because that is what is being decoded. - // TODO: check if we have a concrete bytes value - fn match_decode( - ctx: ContextNode, - loc: &Loc, - ret: ExprRet, - analyzer: &mut impl AnalyzerBackend, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(expect_builtin) => { - match analyzer.node(expect_builtin) { - Node::Builtin(_) => { - let var = ContextVar::new_from_builtin( - *loc, - expect_builtin.into(), - analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - Node::ContextVar(cvar) => { - let bn = analyzer - .builtin_or_add( - cvar.ty - .as_builtin(analyzer) - .into_expr_err(*loc)?, - ) - .into(); - let var = ContextVar::new_from_builtin( - *loc, bn, analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - e => todo!("Unhandled type in abi.decode: {e:?}"), - } - } - ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { - match_decode(ctx, loc, i.clone(), analyzer) - }), - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) - } - e => panic!("This is invalid solidity: {:?}", e), - } - } - self.parse_ctx_expr(&input_exprs[1], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - match_decode(ctx, &loc, ret, analyzer) - }) - } - "abi.encode" - | "abi.encodePacked" - | "abi.encodeCall" - | "abi.encodeWithSignature" - | "abi.encodeWithSelector" => { - // currently we dont support concrete abi encoding, TODO - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "delegatecall" | "staticcall" | "call" => { - // TODO: Check if we have the code for the address - // if we dont, model it as a unrestricted call that can make other calls - ctx.pop_expr_latest(*loc, self).into_expr_err(*loc)?; - // TODO: try to be smarter based on the address input - let booln = self.builtin_or_add(Builtin::Bool); - let bool_cvar = ContextVar::new_from_builtin(*loc, booln.into(), self) - .into_expr_err(*loc)?; - let bool_node = self.add_node(Node::ContextVar(bool_cvar)); - ctx.add_var(bool_node.into(), self).into_expr_err(*loc)?; - self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); - - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr( - ExprRet::Multi(vec![ - ExprRet::Single(bool_node), - ExprRet::Single(node), - ]), - self, - ) - .into_expr_err(*loc)?; - Ok(()) - } - "code" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "balance" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Uint(256)); - let cvar = ContextVar::new_from_builtin(*loc, bn.into(), self) - .into_expr_err(*loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(*loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(*loc)?; - Ok(()) - } - "require" | "assert" => { - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(input_exprs, ctx) - }) - } - "type" => self.parse_ctx_expr(&input_exprs[0], ctx), - "push" => { - if input_exprs.len() == 1 { - // array.push() is valid syntax. It pushes a new - // empty element onto the expr ret stack - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "array[].push(..) was not an array to push to" - .to_string(), - )); - }; - - let arr = array.expect_single().into_expr_err(loc)?; - let arr = ContextVarNode::from(arr).latest_version(analyzer); - // get length - let len = analyzer.tmp_length(arr, ctx, loc); - - let len_as_idx = - len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; - // set length as index - analyzer.index_into_array_inner( - ctx, - loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(len_as_idx.latest_version(analyzer).into()), - )?; - Ok(()) - }) - } else if input_exprs.len() == 2 { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "array[].push(..) was not an array to push to" - .to_string(), - )); - }; - if matches!(array, ExprRet::CtxKilled(_)) { - ctx.push_expr(array, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "array[].push(..) was not given an element to push" - .to_string(), - )); - }; - - if matches!(new_elem, ExprRet::CtxKilled(_)) { - ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let arr = array.expect_single().into_expr_err(loc)?; - let arr = - ContextVarNode::from(arr).latest_version(analyzer); - // get length - let len = analyzer.tmp_length(arr, ctx, loc); - - let len_as_idx = - len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; - // set length as index - analyzer.index_into_array_inner( - ctx, - loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single( - len_as_idx.latest_version(analyzer).into(), - ), - )?; - let index = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap(); - if matches!(index, ExprRet::CtxKilled(_)) { - ctx.push_expr(index, analyzer).into_expr_err(loc)?; - return Ok(()); - } - // assign index to new_elem - analyzer.match_assign_sides(ctx, loc, &index, &new_elem) - }) - }) - } else { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "array[].push(..) expected 0 or 1 inputs, got: {}", - input_exprs.len() - ), - )); - } - } - "pop" => { - if input_exprs.len() != 1 { - return Err(ExprErr::InvalidFunctionInput( - *loc, - format!( - "array[].pop() expected 0 inputs, got: {}", - input_exprs.len() - ), - )); - } - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "array[].pop() was not an array to pop from".to_string(), - )); - }; - if matches!(array, ExprRet::CtxKilled(_)) { - ctx.push_expr(array, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - // get the array - let arr = array.expect_single().into_expr_err(loc)?; - let arr = ContextVarNode::from(arr).latest_version(analyzer); - - // get length - analyzer.match_length(ctx, loc, array, false)?; - let Some(len) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "array[].pop() was not an array to pop from".to_string(), - )); - }; - let len = len.expect_single().into_expr_err(loc)?; - let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; - next_len - .set_range_min( - analyzer, - Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), - ) - .into_expr_err(loc)?; - next_len - .set_range_max( - analyzer, - Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), - ) - .into_expr_err(loc)?; - - // set length as index - analyzer.index_into_array_inner( - ctx, - loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(next_len.latest_version(analyzer).into()), - ) - }) - } - "concat" => self.concat(loc, input_exprs, ctx), - "keccak256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(_input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "sha256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "ripemd160" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "blockhash" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "blockhash function was not provided a block number" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "gasleft" => { - let var = ContextVar::new_from_builtin( - *loc, - self.builtin_or_add(Builtin::Uint(64)).into(), - self, - ) - .into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), self) - .into_expr_err(*loc)?; - Ok(()) - } - "ecrecover" => { - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let cctx = Context::new_subctx( - ctx, - None, - loc, - None, - Some(func_idx.into()), - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let call_ctx = analyzer.add_node(Node::Context(cctx)); - ctx.set_child_call(call_ctx.into(), analyzer) - .into_expr_err(loc)?; - let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge( - call_node, - func_idx, - Edge::Context(ContextEdge::Call), - ); - analyzer.add_edge( - call_node, - ctx, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - call_ctx, - call_node, - Edge::Context(ContextEdge::Subcontext), - ); - - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "ecrecover did not receive inputs".to_string(), - )); - }; - - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let mut inner_vals = vec![]; - match input { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - inner_vals.push( - ContextVarNode::from(var) - .display_name(analyzer) - .unwrap(), - ); - } - _ => inner_vals.push("".to_string()), - } - let inner_name = - inner_vals.into_iter().collect::>().join(", "); - let mut var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Address).into(), - analyzer, - ) - .into_expr_err(loc)?; - var.display_name = format!("ecrecover({})", inner_name); - var.is_symbolic = true; - var.is_return = true; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Return), - ); - ContextNode::from(call_ctx) - .add_return_node(loc, cvar.into(), analyzer) - .into_expr_err(loc)?; - - let rctx = Context::new_subctx( - call_ctx.into(), - Some(ctx), - loc, - None, - None, - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let ret_ctx = analyzer.add_node(Node::Context(rctx)); - ContextNode::from(call_ctx) - .set_child_call(ret_ctx.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - ret_ctx, - call_ctx, - Edge::Context(ContextEdge::Continue), - ); - - let tmp_ret = ContextVarNode::from(cvar) - .as_tmp( - ContextNode::from(call_ctx) - .underlying(analyzer) - .unwrap() - .loc, - ret_ctx.into(), - analyzer, - ) - .unwrap(); - tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; - tmp_ret.underlying_mut(analyzer).unwrap().display_name = - format!("ecrecover({}).return", inner_name); - ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge( - tmp_ret, - ret_ctx, - Edge::Context(ContextEdge::Variable), - ); - - ContextNode::from(ret_ctx) - .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "addmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "mulmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "wrap" => { - if input_exprs.len() != 2 { - return Err(ExprErr::InvalidFunctionInput(*loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); - } - - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "ecrecover did not receive inputs".to_string(), - )); - }; - input.expect_length(2).into_expr_err(loc)?; - let ret = input.as_vec(); - let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; - let var = ContextVar::new_from_ty( - loc, - TyNode::from(wrapping_ty), - ctx, - analyzer, - ) - .into_expr_err(loc)?; - let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; - let cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new( - Elem::from(to_be_wrapped), - RangeOp::Cast, - Elem::from(cvar), - )); - next.set_range_min(analyzer, expr.clone()) - .into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - "unwrap" => { - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "ecrecover did not receive inputs".to_string(), - )); - }; - input.expect_length(2).into_expr_err(loc)?; - let ret = input.as_vec(); - let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; - let mut var = ContextVar::new_from_builtin( - loc, - BuiltInNode::from( - TyNode::from(wrapping_ty) - .underlying(analyzer) - .into_expr_err(loc)? - .ty, - ), - analyzer, - ) - .into_expr_err(loc)?; - let to_be_unwrapped = ret[1].expect_single().into_expr_err(loc)?; - var.display_name = format!( - "{}.unwrap({})", - TyNode::from(wrapping_ty) - .name(analyzer) - .into_expr_err(loc)?, - ContextVarNode::from(to_be_unwrapped) - .display_name(analyzer) - .into_expr_err(loc)? - ); - - let cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) - .into_expr_err(loc)?; - cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) - .into_expr_err(loc)?; - let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; - let expr = Elem::Expr(RangeExpr::new( - Elem::from(to_be_unwrapped), - RangeOp::Cast, - Elem::from(cvar), - )); - next.set_range_min(analyzer, expr.clone()) - .into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - e => Err(ExprErr::Todo( - *loc, - format!("builtin function: {e:?} doesn't exist or isn't implemented"), - )), - } - } else { - panic!("unnamed builtin?") - } - } - Node::Builtin(Builtin::Array(_)) => { - // create a new list - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); - }; - - if matches!(len_var, ExprRet::CtxKilled(_)) { - ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let len_cvar = len_var.expect_single().into_expr_err(loc)?; - - let ty = VarType::try_from_idx(analyzer, func_idx); - - let new_arr = ContextVar { - loc: Some(loc), - name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), - display_name: "arr".to_string(), - storage: None, - is_tmp: true, - is_symbolic: false, - is_return: false, - tmp_of: None, - ty: ty.expect("No type for node"), - }; - - let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); - - let len_var = ContextVar { - loc: Some(loc), - name: arr.name(analyzer).into_expr_err(loc)? + ".length", - display_name: arr.display_name(analyzer).unwrap() + ".length", - storage: None, - is_tmp: true, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: ContextVarNode::from(len_cvar) - .underlying(analyzer) - .into_expr_err(loc)? - .ty - .clone(), - }; - - let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); - analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(arr, analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); - - // update the length - if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { - let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; - let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - - ctx.push_expr(ExprRet::Single(arr.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - Node::Builtin(ty) => { - // it is a cast - let ty = ty.clone(); - fn cast_match( - ctx: ContextNode, - loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ty: &Builtin, - ret: ExprRet, - func_idx: NodeIdx, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, loc, kind).into_expr_err(loc) - } - ExprRet::Null => Ok(()), - ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { - let new_var = ContextVarNode::from(cvar) - .as_cast_tmp(loc, ctx, ty.clone(), analyzer) - .into_expr_err(loc)?; - - new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = - VarType::try_from_idx(analyzer, func_idx).expect(""); - // cast the ranges - if let Some(r) = ContextVarNode::from(cvar) - .range(analyzer) - .into_expr_err(loc)? - { - let curr_range = - SolcRange::try_from_builtin(ty).expect("No default range"); - let mut min = r - .range_min() - .into_owned() - .cast(curr_range.range_min().into_owned()); - - min.cache_minimize(analyzer).into_expr_err(loc)?; - let mut max = r - .range_max() - .into_owned() - .cast(curr_range.range_max().into_owned()); - - max.cache_maximize(analyzer).into_expr_err(loc)?; - - let existing_max = - r.evaled_range_max(analyzer).into_expr_err(loc)?; - // Check if the max value has changed once the cast is applied. - // If it hasnt, then the cast had no effect and we should adjust the naming - // to not muddle the CLI - if let Some(std::cmp::Ordering::Equal) = max - .maximize(analyzer) - .into_expr_err(loc)? - .range_ord(&existing_max) - { - // its a noop, reflect that in the naming - new_var.underlying_mut(analyzer).unwrap().display_name = - ContextVarNode::from(cvar) - .display_name(analyzer) - .into_expr_err(loc)?; - } - - new_var.set_range_min(analyzer, min).into_expr_err(loc)?; - new_var.set_range_max(analyzer, max).into_expr_err(loc)?; - // cast the range exclusions - TODO: verify this is correct - let mut exclusions = r.range_exclusions(); - exclusions.iter_mut().for_each(|range| { - *range = - range.clone().cast(curr_range.range_min().into_owned()); - }); - new_var - .set_range_exclusions(analyzer, exclusions) - .into_expr_err(loc)?; - } - - ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| cast_match(ctx, loc, analyzer, ty, i, func_idx)), - } - } - - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - cast_match(ctx, loc, analyzer, &ty, ret, func_idx) - }) - } - Node::ContextVar(_c) => { - // its a user type - // TODO: figure out if we actually need to do anything? - // input_exprs - // .iter() - // .try_for_each(|expr| self.parse_ctx_expr(expr, ctx))?; - - // self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - // }) - - ctx.push_expr(ExprRet::Single(func_idx), self) - .into_expr_err(*loc)?; - Ok(()) - } - Node::Contract(_) => { - if !input_exprs.is_empty() { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - } - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if !input_exprs.is_empty() { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "Contract creation failed".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - } - - let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { - Some(v) => v, - None => { - return Err(ExprErr::VarBadType( - loc, - format!( - "Could not create context variable from user type: {:?}", - analyzer.node(func_idx) - ), - )) - } - }; - // let idx = ret.expect_single().into_expr_err(loc)?; - let contract_cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - // contract_cvar - // .set_range_min(analyzer, Elem::from(idx)) - // .into_expr_err(loc)?; - // contract_cvar - // .set_range_max(analyzer, Elem::from(idx)) - // .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - Node::Unresolved(_) => { - self.parse_inputs(ctx, *loc, input_exprs)?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Function call failed".to_string())) - }; - - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let visible_funcs = ctx.visible_funcs(analyzer).into_expr_err(loc)? - .iter() - .map(|func| func.name(analyzer).unwrap()) - .collect::>(); - - if let Node::Unresolved(ident) = analyzer.node(func_idx) { - Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not find function: \"{}{}\", context: {}, visible functions: {:#?}", - ident.name, - inputs.try_as_func_input_str(analyzer), - ctx.path(analyzer), - visible_funcs - ) - )) - } else { - unreachable!() - } - }) - } - Node::Struct(_) => { - // struct construction - let strukt = StructNode::from(func_idx); - let var = - ContextVar::new_from_struct(*loc, strukt, ctx, self).into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "Struct Function call failed".to_string(), - )); - }; - - let inputs = inputs.as_vec(); - // set struct fields - strukt - .fields(analyzer) - .iter() - .zip(inputs) - .try_for_each(|(field, input)| { - let field_cvar = ContextVar::maybe_new_from_field( - analyzer, - loc, - ContextVarNode::from(cvar) - .underlying(analyzer) - .into_expr_err(loc)?, - field.underlying(analyzer).unwrap().clone(), - ) - .expect("Invalid struct field"); - - let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); - analyzer.add_edge( - fc_node, - cvar, - Edge::Context(ContextEdge::AttrAccess), - ); - analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; - let field_as_ret = ExprRet::Single(fc_node); - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; - let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - Ok(()) - })?; - - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc) - }) - } - e => Err(ExprErr::FunctionNotFound(*loc, format!("{e:?}"))), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn concat( - &mut self, - loc: &Loc, - input_exprs: &[Expression], - ctx: ContextNode, - ) -> Result<(), ExprErr> { - input_exprs[1..].iter().try_for_each(|expr| { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let input = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or(ExprRet::Null); - ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) - }) - })?; - - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())); - }; - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let inputs = inputs.as_vec(); - if inputs.is_empty() { - ctx.push_expr(ExprRet::Multi(vec![]), analyzer) - .into_expr_err(loc)?; - Ok(()) - } else { - let start = &inputs[0]; - if inputs.len() > 1 { - analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) - } else { - analyzer.match_concat(ctx, loc, start.clone(), &[], None) - } - } - }) - } - - fn match_concat( - &mut self, - ctx: ContextNode, - loc: Loc, - curr: ExprRet, - inputs: &[ExprRet], - accum_node: Option, - ) -> Result<(), ExprErr> { - if let Some(accum_node) = accum_node { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => { - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } else { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - let acc = ContextVarNode::from(var) - .as_tmp(loc, ctx, self) - .into_expr_err(loc)?; - inputs - .iter() - .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) - .collect::, ExprErr>>()?; - ctx.push_expr(ExprRet::Single(acc.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => Err(ExprErr::NoRhs( - loc, - "No input provided to concat function".to_string(), - )), - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } - } - - fn concat_inner( - &mut self, - loc: Loc, - accum: ContextVarNode, - right: ContextVarNode, - ) -> Result<(), ExprErr> { - match ( - accum.ty(self).into_expr_err(loc)?, - right.ty(self).into_expr_err(loc)?, - ) { - (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { - let new_ty = match ( - accum_cnode.underlying(self).into_expr_err(loc)?, - right_cnode.underlying(self).into_expr_err(loc)?, - ) { - (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (a, b) => { - // Invalid solidity - return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); - } - }; - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { - let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; - // let val = match underlying { - // Concrete::String(val) => { - // val - // .chars() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // v.encode_utf8(&mut bytes[..]); - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // Concrete::DynBytes(val) => { - // val - // .iter() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // bytes[0] = *v; - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) - // }; - // TODO: Extend with bn - - let range = SolcRange::from(underlying.clone()).unwrap(); - let min = range.min.clone().concat(r2.min.clone()); - let max = range.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; - - let new_ty = - VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { - // TODO: improve length calculation here - let min = r.min.clone().concat(r2.min.clone()); - let max = r.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; - Ok(()) - } - (_, _) => Ok(()), - } - } -} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs new file mode 100644 index 00000000..15ed452c --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -0,0 +1,128 @@ +use crate::{ + ContextBuilder, ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl AbiCaller for T where T: AnalyzerBackend + Sized {} +pub trait AbiCaller: AnalyzerBackend + Sized { + fn abi_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "abi.decode" => { + // we skip the first because that is what is being decoded. + // TODO: check if we have a concrete bytes value + fn match_decode( + ctx: ContextNode, + loc: &Loc, + ret: ExprRet, + analyzer: &mut impl AnalyzerBackend, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(expect_builtin) => { + match analyzer.node(expect_builtin) { + Node::Builtin(_) => { + let var = ContextVar::new_from_builtin( + *loc, + expect_builtin.into(), + analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + Node::ContextVar(cvar) => { + let bn = analyzer + .builtin_or_add( + cvar.ty + .as_builtin(analyzer) + .into_expr_err(*loc)?, + ) + .into(); + let var = ContextVar::new_from_builtin( + *loc, bn, analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + e => todo!("Unhandled type in abi.decode: {e:?}"), + } + } + ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { + match_decode(ctx, loc, i.clone(), analyzer) + }), + ExprRet::CtxKilled(kind) => { + ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) + } + e => panic!("This is invalid solidity: {:?}", e), + } + } + self.parse_ctx_expr(&input_exprs[1], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + match_decode(ctx, &loc, ret, analyzer) + }) + } + "abi.encode" + | "abi.encodePacked" + | "abi.encodeCall" + | "abi.encodeWithSignature" + | "abi.encodeWithSelector" => { + // currently we dont support concrete abi encoding, TODO + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find abi function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs new file mode 100644 index 00000000..af687a35 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -0,0 +1,79 @@ +use crate::{ + ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl AddressCaller for T where T: AnalyzerBackend + Sized {} +pub trait AddressCaller: AnalyzerBackend + Sized { + fn address_call(&mut self, func_name: String, _input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "delegatecall" | "staticcall" | "call" => { + // TODO: Check if we have the code for the address + // if we dont, model it as a unrestricted call that can make other calls + ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; + // TODO: try to be smarter based on the address input + let booln = self.builtin_or_add(Builtin::Bool); + let bool_cvar = ContextVar::new_from_builtin(loc, booln.into(), self) + .into_expr_err(loc)?; + let bool_node = self.add_node(Node::ContextVar(bool_cvar)); + ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; + self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); + + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr( + ExprRet::Multi(vec![ + ExprRet::Single(bool_node), + ExprRet::Single(node), + ]), + self, + ) + .into_expr_err(loc)?; + Ok(()) + } + "code" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + "balance" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Uint(256)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) + .into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin address function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs new file mode 100644 index 00000000..c1ede935 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -0,0 +1,200 @@ +use crate::{ + array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess, +}; + +use graph::{ + elem::*, + nodes::{ + Concrete, ContextNode, ContextVarNode, ExprRet, + }, + AnalyzerBackend, +}; + +use ethers_core::types::U256; +use solang_parser::pt::{Expression, Loc}; + +impl ArrayCaller for T where T: AnalyzerBackend + Sized {} +pub trait ArrayCaller: AnalyzerBackend + Sized { + fn array_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "push" => { + if input_exprs.len() == 1 { + // array.push() is valid syntax. It pushes a new + // empty element onto the expr ret stack + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].push(..) was not an array to push to" + .to_string(), + )); + }; + + let arr = array.expect_single().into_expr_err(loc)?; + let arr = ContextVarNode::from(arr).latest_version(analyzer); + // get length + let len = analyzer.tmp_length(arr, ctx, loc); + + let len_as_idx = + len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + )?; + Ok(()) + }) + } else if input_exprs.len() == 2 { + // array.push(value) + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].push(..) was not an array to push to" + .to_string(), + )); + }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(new_elem) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "array[].push(..) was not given an element to push" + .to_string(), + )); + }; + + if matches!(new_elem, ExprRet::CtxKilled(_)) { + ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let arr = array.expect_single().into_expr_err(loc)?; + let arr = + ContextVarNode::from(arr).latest_version(analyzer); + // get length + let len = analyzer.tmp_length(arr, ctx, loc); + + let len_as_idx = + len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single( + len_as_idx.latest_version(analyzer).into(), + ), + )?; + let index = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap(); + if matches!(index, ExprRet::CtxKilled(_)) { + ctx.push_expr(index, analyzer).into_expr_err(loc)?; + return Ok(()); + } + // assign index to new_elem + analyzer.match_assign_sides(ctx, loc, &index, &new_elem) + }) + }) + } else { + return Err(ExprErr::InvalidFunctionInput( + loc, + format!( + "array[].push(..) expected 0 or 1 inputs, got: {}", + input_exprs.len() + ), + )); + } + } + "pop" => { + if input_exprs.len() != 1 { + return Err(ExprErr::InvalidFunctionInput( + loc, + format!( + "array[].pop() expected 0 inputs, got: {}", + input_exprs.len() + ), + )); + } + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].pop() was not an array to pop from".to_string(), + )); + }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + // get the array + let arr = array.expect_single().into_expr_err(loc)?; + let arr = ContextVarNode::from(arr).latest_version(analyzer); + + // get length + analyzer.match_length(ctx, loc, array, false)?; + let Some(len) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "array[].pop() was not an array to pop from".to_string(), + )); + }; + let len = len.expect_single().into_expr_err(loc)?; + let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; + next_len + .set_range_min( + analyzer, + Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), + ) + .into_expr_err(loc)?; + next_len + .set_range_max( + analyzer, + Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), + ) + .into_expr_err(loc)?; + + // set length as index + analyzer.index_into_array_inner( + ctx, + loc, + ExprRet::Single(arr.latest_version(analyzer).into()), + ExprRet::Single(next_len.latest_version(analyzer).into()), + ) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin array function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} + + diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs new file mode 100644 index 00000000..5757b0ff --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -0,0 +1,55 @@ +use crate::{ + ContextBuilder, ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl BlockCaller for T where T: AnalyzerBackend + Sized {} +pub trait BlockCaller: AnalyzerBackend + Sized { + fn block_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "blockhash" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "blockhash function was not provided a block number" + .to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin block function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs new file mode 100644 index 00000000..bfa88e5e --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -0,0 +1,197 @@ +use crate::{ + ContextBuilder, ExprErr, FuncCaller, IntoExprErr, +}; + +use graph::{ + elem::*, + nodes::{ + ContextNode, ContextVar, ContextVarNode, ExprRet, + StructNode, + }, + AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, +}; +use shared::NodeIdx; + +use solang_parser::pt::{Expression, Loc}; + +impl ConstructorCaller for T where T: AnalyzerBackend + Sized {} +pub trait ConstructorCaller: AnalyzerBackend + Sized { + fn construct_array(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + // create a new list + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); + }; + + if matches!(len_var, ExprRet::CtxKilled(_)) { + ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let len_cvar = len_var.expect_single().into_expr_err(loc)?; + + let ty = VarType::try_from_idx(analyzer, func_idx); + + let new_arr = ContextVar { + loc: Some(loc), + name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), + display_name: "arr".to_string(), + storage: None, + is_tmp: true, + is_symbolic: false, + is_return: false, + tmp_of: None, + ty: ty.expect("No type for node"), + }; + + let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); + + let len_var = ContextVar { + loc: Some(loc), + name: arr.name(analyzer).into_expr_err(loc)? + ".length", + display_name: arr.display_name(analyzer).unwrap() + ".length", + storage: None, + is_tmp: true, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: ContextVarNode::from(len_cvar) + .underlying(analyzer) + .into_expr_err(loc)? + .ty + .clone(), + }; + + let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); + analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(arr, analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); + + // update the length + if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { + let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; + let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + + ctx.push_expr(ExprRet::Single(arr.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + + fn construct_contract(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + // construct a new contract + if !input_exprs.is_empty() { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + } + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + if !input_exprs.is_empty() { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Contract creation failed".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + } + + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(func_idx) + ), + )) + } + }; + // let idx = ret.expect_single().into_expr_err(loc)?; + let contract_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + // contract_cvar + // .set_range_min(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; + // contract_cvar + // .set_range_max(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + + fn construct_struct(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + // struct construction + let strukt = StructNode::from(func_idx); + let var = + ContextVar::new_from_struct(loc, strukt, ctx, self).into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Struct Function call failed".to_string(), + )); + }; + + let inputs = inputs.as_vec(); + // set struct fields + strukt + .fields(analyzer) + .iter() + .zip(inputs) + .try_for_each(|(field, input)| { + let field_cvar = ContextVar::maybe_new_from_field( + analyzer, + loc, + ContextVarNode::from(cvar) + .underlying(analyzer) + .into_expr_err(loc)?, + field.underlying(analyzer).unwrap().clone(), + ) + .expect("Invalid struct field"); + + let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); + analyzer.add_edge( + fc_node, + cvar, + Edge::Context(ContextEdge::AttrAccess), + ); + analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; + let field_as_ret = ExprRet::Single(fc_node); + analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; + let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + Ok(()) + })?; + + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc) + }) + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs new file mode 100644 index 00000000..93e0d859 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -0,0 +1,212 @@ +use crate::{ + ContextBuilder, ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, Concrete, ContextNode, ContextVarNode, ExprRet, + }, + AnalyzerBackend, Node, SolcRange, VarType, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl DynBuiltinCaller for T where T: AnalyzerBackend + Sized {} +pub trait DynBuiltinCaller: AnalyzerBackend + Sized { + fn dyn_builtin_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "concat" => self.concat(&loc, input_exprs, ctx), + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin dynamic builtin function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } + + + #[tracing::instrument(level = "trace", skip_all)] + fn concat( + &mut self, + loc: &Loc, + input_exprs: &[Expression], + ctx: ContextNode, + ) -> Result<(), ExprErr> { + input_exprs[1..].iter().try_for_each(|expr| { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let input = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or(ExprRet::Null); + ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) + }) + })?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())); + }; + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let inputs = inputs.as_vec(); + if inputs.is_empty() { + ctx.push_expr(ExprRet::Multi(vec![]), analyzer) + .into_expr_err(loc)?; + Ok(()) + } else { + let start = &inputs[0]; + if inputs.len() > 1 { + analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) + } else { + analyzer.match_concat(ctx, loc, start.clone(), &[], None) + } + } + }) + } + + fn match_concat( + &mut self, + ctx: ContextNode, + loc: Loc, + curr: ExprRet, + inputs: &[ExprRet], + accum_node: Option, + ) -> Result<(), ExprErr> { + if let Some(accum_node) = accum_node { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => { + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } else { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + let acc = ContextVarNode::from(var) + .as_tmp(loc, ctx, self) + .into_expr_err(loc)?; + inputs + .iter() + .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) + .collect::, ExprErr>>()?; + ctx.push_expr(ExprRet::Single(acc.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => Err(ExprErr::NoRhs( + loc, + "No input provided to concat function".to_string(), + )), + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } + } + + fn concat_inner( + &mut self, + loc: Loc, + accum: ContextVarNode, + right: ContextVarNode, + ) -> Result<(), ExprErr> { + match ( + accum.ty(self).into_expr_err(loc)?, + right.ty(self).into_expr_err(loc)?, + ) { + (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { + let new_ty = match ( + accum_cnode.underlying(self).into_expr_err(loc)?, + right_cnode.underlying(self).into_expr_err(loc)?, + ) { + (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (a, b) => { + // Invalid solidity + return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); + } + }; + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { + let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; + // let val = match underlying { + // Concrete::String(val) => { + // val + // .chars() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // v.encode_utf8(&mut bytes[..]); + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // Concrete::DynBytes(val) => { + // val + // .iter() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // bytes[0] = *v; + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) + // }; + // TODO: Extend with bn + + let range = SolcRange::from(underlying.clone()).unwrap(); + let min = range.min.clone().concat(r2.min.clone()); + let max = range.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; + + let new_ty = + VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { + // TODO: improve length calculation here + let min = r.min.clone().concat(r2.min.clone()); + let max = r.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; + Ok(()) + } + (_, _) => Ok(()), + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs new file mode 100644 index 00000000..4ebd7f7d --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -0,0 +1,154 @@ +use crate::{ + ContextBuilder, ExprErr, FuncCaller, IntoExprErr, + intrinsic_call::{ + MsgCaller, AbiCaller, AddressCaller, ArrayCaller, + BlockCaller, DynBuiltinCaller, PrecompileCaller, + SolidityCaller, TypesCaller, ConstructorCaller + } +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ExprRet, + }, + AnalyzerBackend, Node, +}; +use shared::{NodeIdx}; + +use solang_parser::pt::{Expression, Loc}; + +pub trait CallerParts: AbiCaller + AddressCaller + ArrayCaller + + BlockCaller + DynBuiltinCaller + PrecompileCaller + + SolidityCaller + TypesCaller + ConstructorCaller + MsgCaller {} + +impl CallerParts for T where T: AbiCaller + AddressCaller + ArrayCaller + + BlockCaller + DynBuiltinCaller + PrecompileCaller + + SolidityCaller + TypesCaller + ConstructorCaller + MsgCaller {} + + + +impl IntrinsicFuncCaller for T where + T: AnalyzerBackend + Sized + CallerParts +{ +} +pub trait IntrinsicFuncCaller: + AnalyzerBackend + Sized + CallerParts +{ + /// Calls an intrinsic/builtin function call (casts, require, etc.) + #[tracing::instrument(level = "trace", skip_all)] + fn intrinsic_func_call( + &mut self, + loc: &Loc, + input_exprs: &[Expression], + func_idx: NodeIdx, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match self.node(func_idx) { + Node::Function(underlying) => { + if let Some(func_name) = &underlying.name { + match &*func_name.name { + // abi + _ if func_name.name.starts_with("abi.") => { + self.abi_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // address + "delegatecall" | "staticcall" | "call" | "code" | "balance" => { + self.address_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // array + "push" | "pop" => { + self.array_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // block + "blockhash" => { + self.block_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // dynamic sized builtins + "concat" => { + self.dyn_builtin_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // msg + "gasleft" => { + self.msg_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // precompiles + "sha256" | "ripemd160" | "ecrecover" => { + self.precompile_call(func_name.name.clone(), func_idx, input_exprs, *loc, ctx) + } + // solidity + "keccak256" | "addmod" | "mulmod" | "require" | "assert" => { + self.solidity_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + // typing + "type" | "wrap" | "unwrap" => { + self.types_call(func_name.name.clone(), input_exprs, *loc, ctx) + } + e => Err(ExprErr::Todo( + *loc, + format!("builtin function: {e:?} doesn't exist or isn't implemented"), + )), + } + } else { + panic!("unnamed builtin?") + } + } + Node::Builtin(Builtin::Array(_)) => { + // construct a new array + self.construct_array(func_idx, input_exprs, *loc, ctx) + } + Node::Contract(_) => { + // construct a new contract + self.construct_contract(func_idx, input_exprs, *loc, ctx) + } + Node::Struct(_) => { + // construct a struct + self.construct_struct(func_idx, input_exprs, *loc, ctx) + } + Node::Builtin(ty) => { + // cast to type + self.cast(ty.clone(), func_idx, input_exprs, *loc, ctx) + } + Node::ContextVar(_c) => { + // its a user type, just push it onto the stack + ctx.push_expr(ExprRet::Single(func_idx), self) + .into_expr_err(*loc)?; + Ok(()) + } + Node::Unresolved(_) => { + // Try to give a nice error + self.parse_inputs(ctx, *loc, input_exprs)?; + + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Function call failed".to_string())) + }; + + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let visible_funcs = ctx.visible_funcs(analyzer).into_expr_err(loc)? + .iter() + .map(|func| func.name(analyzer).unwrap()) + .collect::>(); + + if let Node::Unresolved(ident) = analyzer.node(func_idx) { + Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find function: \"{}{}\", context: {}, visible functions: {:#?}", + ident.name, + inputs.try_as_func_input_str(analyzer), + ctx.path(analyzer), + visible_funcs + ) + )) + } else { + unreachable!() + } + }) + } + e => Err(ExprErr::FunctionNotFound(*loc, format!("Unhandled function call type: {e:?}"))), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs new file mode 100644 index 00000000..d3a50e38 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs @@ -0,0 +1,23 @@ +mod abi; +mod address; +mod array; +mod block; +mod constructors; +mod dyn_builtin; +mod intrinsic_caller; +mod msg; +mod precompile; +mod solidity; +mod types; + +pub use abi::*; +pub use address::*; +pub use array::*; +pub use block::*; +pub use constructors::*; +pub use dyn_builtin::*; +pub use intrinsic_caller::*; +pub use msg::*; +pub use precompile::*; +pub use solidity::*; +pub use types::*; \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs new file mode 100644 index 00000000..249679d8 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs @@ -0,0 +1,39 @@ +use crate::{ + ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl MsgCaller for T where T: AnalyzerBackend + Sized {} +pub trait MsgCaller: AnalyzerBackend + Sized { + fn msg_call(&mut self, func_name: String, _input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "gasleft" => { + let var = ContextVar::new_from_builtin( + loc, + self.builtin_or_add(Builtin::Uint(64)).into(), + self, + ) + .into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin msg function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs new file mode 100644 index 00000000..0e8e1e0e --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -0,0 +1,218 @@ +use crate::{ + ContextBuilder, ExprErr, FuncCaller, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; +use shared::{NodeIdx}; + +use solang_parser::pt::{Expression, Loc}; + +impl PrecompileCaller for T where T: AnalyzerBackend + Sized {} +pub trait PrecompileCaller: AnalyzerBackend + Sized { + fn precompile_call(&mut self, func_name: String, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "sha256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "ripemd160" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "ecrecover" => { + self.parse_inputs(ctx, loc, input_exprs)?; + + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let cctx = Context::new_subctx( + ctx, + None, + loc, + None, + Some(func_idx.into()), + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let call_ctx = analyzer.add_node(Node::Context(cctx)); + ctx.set_child_call(call_ctx.into(), analyzer) + .into_expr_err(loc)?; + let call_node = analyzer.add_node(Node::FunctionCall); + analyzer.add_edge( + call_node, + func_idx, + Edge::Context(ContextEdge::Call), + ); + analyzer.add_edge( + call_node, + ctx, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + call_ctx, + call_node, + Edge::Context(ContextEdge::Subcontext), + ); + + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); + }; + + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let mut inner_vals = vec![]; + match input { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + inner_vals.push( + ContextVarNode::from(var) + .display_name(analyzer) + .unwrap(), + ); + } + _ => inner_vals.push("".to_string()), + } + let inner_name = + inner_vals.into_iter().collect::>().join(", "); + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Address).into(), + analyzer, + ) + .into_expr_err(loc)?; + var.display_name = format!("ecrecover({})", inner_name); + var.is_symbolic = true; + var.is_return = true; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Return), + ); + ContextNode::from(call_ctx) + .add_return_node(loc, cvar.into(), analyzer) + .into_expr_err(loc)?; + + let rctx = Context::new_subctx( + call_ctx.into(), + Some(ctx), + loc, + None, + None, + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let ret_ctx = analyzer.add_node(Node::Context(rctx)); + ContextNode::from(call_ctx) + .set_child_call(ret_ctx.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + ret_ctx, + call_ctx, + Edge::Context(ContextEdge::Continue), + ); + + let tmp_ret = ContextVarNode::from(cvar) + .as_tmp( + ContextNode::from(call_ctx) + .underlying(analyzer) + .unwrap() + .loc, + ret_ctx.into(), + analyzer, + ) + .unwrap(); + tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; + tmp_ret.underlying_mut(analyzer).unwrap().display_name = + format!("ecrecover({}).return", inner_name); + ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; + analyzer.add_edge( + tmp_ret, + ret_ctx, + Edge::Context(ContextEdge::Variable), + ); + + ContextNode::from(ret_ctx) + .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find precompile function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs new file mode 100644 index 00000000..4b5e7edb --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -0,0 +1,91 @@ +use crate::{ + require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr, +}; + +use graph::{ + nodes::{ + Builtin, ContextNode, ContextVar, ExprRet, + }, + AnalyzerBackend, Node, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl SolidityCaller for T where T: AnalyzerBackend + Sized {} +pub trait SolidityCaller: AnalyzerBackend + Sized { + fn solidity_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "keccak256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(_input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding" + .to_string(), + )); + }; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "addmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, loc, input_exprs)?; + + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "mulmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "require" | "assert" => { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.handle_require(input_exprs, ctx) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin solidity function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs new file mode 100644 index 00000000..611d40d6 --- /dev/null +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -0,0 +1,223 @@ +use crate::{ + ContextBuilder, ExprErr, FuncCaller, IntoExprErr, +}; + +use graph::{ + elem::*, + nodes::{ + BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode, + }, + AnalyzerBackend, GraphBackend, Node, Range, SolcRange, VarType, +}; +use shared::{NodeIdx}; + +use solang_parser::pt::{Expression, Loc}; + +impl TypesCaller for T where T: AnalyzerBackend + Sized {} +pub trait TypesCaller: AnalyzerBackend + Sized { + fn types_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + match &*func_name { + "type" => self.parse_ctx_expr(&input_exprs[0], ctx), + "wrap" => { + if input_exprs.len() != 2 { + return Err(ExprErr::InvalidFunctionInput(loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); + } + + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); + }; + input.expect_length(2).into_expr_err(loc)?; + let ret = input.as_vec(); + let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; + let var = ContextVar::new_from_ty( + loc, + TyNode::from(wrapping_ty), + ctx, + analyzer, + ) + .into_expr_err(loc)?; + let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; + let expr = Elem::Expr(RangeExpr::new( + Elem::from(to_be_wrapped), + RangeOp::Cast, + Elem::from(cvar), + )); + next.set_range_min(analyzer, expr.clone()) + .into_expr_err(loc)?; + next.set_range_max(analyzer, expr).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + "unwrap" => { + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); + }; + input.expect_length(2).into_expr_err(loc)?; + let ret = input.as_vec(); + let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; + let mut var = ContextVar::new_from_builtin( + loc, + BuiltInNode::from( + TyNode::from(wrapping_ty) + .underlying(analyzer) + .into_expr_err(loc)? + .ty, + ), + analyzer, + ) + .into_expr_err(loc)?; + let to_be_unwrapped = ret[1].expect_single().into_expr_err(loc)?; + var.display_name = format!( + "{}.unwrap({})", + TyNode::from(wrapping_ty) + .name(analyzer) + .into_expr_err(loc)?, + ContextVarNode::from(to_be_unwrapped) + .display_name(analyzer) + .into_expr_err(loc)? + ); + + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; + cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) + .into_expr_err(loc)?; + let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; + let expr = Elem::Expr(RangeExpr::new( + Elem::from(to_be_unwrapped), + RangeOp::Cast, + Elem::from(cvar), + )); + next.set_range_min(analyzer, expr.clone()) + .into_expr_err(loc)?; + next.set_range_max(analyzer, expr).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin types function: \"{func_name}\", context: {}", + ctx.path(self), + ) + )) + } + } + + fn cast(&mut self, ty: Builtin, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + // it is a cast + fn cast_match( + ctx: ContextNode, + loc: Loc, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ty: &Builtin, + ret: ExprRet, + func_idx: NodeIdx, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::CtxKilled(kind) => { + ctx.kill(analyzer, loc, kind).into_expr_err(loc) + } + ExprRet::Null => Ok(()), + ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { + let new_var = ContextVarNode::from(cvar) + .as_cast_tmp(loc, ctx, ty.clone(), analyzer) + .into_expr_err(loc)?; + + new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = + VarType::try_from_idx(analyzer, func_idx).expect(""); + // cast the ranges + if let Some(r) = ContextVarNode::from(cvar) + .range(analyzer) + .into_expr_err(loc)? + { + let curr_range = + SolcRange::try_from_builtin(ty).expect("No default range"); + let mut min = r + .range_min() + .into_owned() + .cast(curr_range.range_min().into_owned()); + + min.cache_minimize(analyzer).into_expr_err(loc)?; + let mut max = r + .range_max() + .into_owned() + .cast(curr_range.range_max().into_owned()); + + max.cache_maximize(analyzer).into_expr_err(loc)?; + + let existing_max = + r.evaled_range_max(analyzer).into_expr_err(loc)?; + // Check if the max value has changed once the cast is applied. + // If it hasnt, then the cast had no effect and we should adjust the naming + // to not muddle the CLI + if let Some(std::cmp::Ordering::Equal) = max + .maximize(analyzer) + .into_expr_err(loc)? + .range_ord(&existing_max) + { + // its a noop, reflect that in the naming + new_var.underlying_mut(analyzer).unwrap().display_name = + ContextVarNode::from(cvar) + .display_name(analyzer) + .into_expr_err(loc)?; + } + + new_var.set_range_min(analyzer, min).into_expr_err(loc)?; + new_var.set_range_max(analyzer, max).into_expr_err(loc)?; + // cast the range exclusions - TODO: verify this is correct + let mut exclusions = r.range_exclusions(); + exclusions.iter_mut().for_each(|range| { + *range = + range.clone().cast(curr_range.range_min().into_owned()); + }); + new_var + .set_range_exclusions(analyzer, exclusions) + .into_expr_err(loc)?; + } + + ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| cast_match(ctx, loc, analyzer, ty, i, func_idx)), + } + } + + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Cast had no target type".to_string())); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + cast_match(ctx, loc, analyzer, &ty, ret, func_idx) + }) + } +} \ No newline at end of file From c328bcda606b8b5fb2900a0809e0f2f693193e59 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 19:55:50 -0800 Subject: [PATCH 38/71] lint --- .../src/func_call/intrinsic_call/abi.rs | 210 +++++---- .../src/func_call/intrinsic_call/address.rs | 124 +++--- .../src/func_call/intrinsic_call/array.rs | 63 ++- .../src/func_call/intrinsic_call/block.rs | 91 ++-- .../func_call/intrinsic_call/constructors.rs | 378 +++++++++-------- .../func_call/intrinsic_call/dyn_builtin.rs | 398 +++++++++--------- .../intrinsic_call/intrinsic_caller.rs | 68 +-- .../src/func_call/intrinsic_call/mod.rs | 2 +- .../src/func_call/intrinsic_call/msg.rs | 52 +-- .../func_call/intrinsic_call/precompile.rs | 358 +++++++--------- .../src/func_call/intrinsic_call/solidity.rs | 150 ++++--- .../src/func_call/intrinsic_call/types.rs | 70 ++- 12 files changed, 955 insertions(+), 1009 deletions(-) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 15ed452c..29316aa9 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -1,11 +1,7 @@ -use crate::{ - ContextBuilder, ExprErr, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ - Builtin, ContextNode, ContextVar, ExprRet, - }, + nodes::{Builtin, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; @@ -13,116 +9,102 @@ use solang_parser::pt::{Expression, Loc}; impl AbiCaller for T where T: AnalyzerBackend + Sized {} pub trait AbiCaller: AnalyzerBackend + Sized { - fn abi_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn abi_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { - "abi.decode" => { - // we skip the first because that is what is being decoded. - // TODO: check if we have a concrete bytes value - fn match_decode( - ctx: ContextNode, - loc: &Loc, - ret: ExprRet, - analyzer: &mut impl AnalyzerBackend, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(expect_builtin) => { - match analyzer.node(expect_builtin) { - Node::Builtin(_) => { - let var = ContextVar::new_from_builtin( - *loc, - expect_builtin.into(), - analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - Node::ContextVar(cvar) => { - let bn = analyzer - .builtin_or_add( - cvar.ty - .as_builtin(analyzer) - .into_expr_err(*loc)?, - ) - .into(); - let var = ContextVar::new_from_builtin( - *loc, bn, analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(*loc)?; - Ok(()) - } - e => todo!("Unhandled type in abi.decode: {e:?}"), - } - } - ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { - match_decode(ctx, loc, i.clone(), analyzer) - }), - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) - } - e => panic!("This is invalid solidity: {:?}", e), - } - } - self.parse_ctx_expr(&input_exprs[1], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - match_decode(ctx, &loc, ret, analyzer) - }) - } - "abi.encode" - | "abi.encodePacked" - | "abi.encodeCall" - | "abi.encodeWithSignature" - | "abi.encodeWithSelector" => { - // currently we dont support concrete abi encoding, TODO - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(loc)?; - Ok(()) - } - _ => Err(ExprErr::FunctionNotFound( + "abi.decode" => { + // we skip the first because that is what is being decoded. + // TODO: check if we have a concrete bytes value + fn match_decode( + ctx: ContextNode, + loc: &Loc, + ret: ExprRet, + analyzer: &mut impl AnalyzerBackend, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(expect_builtin) => match analyzer.node(expect_builtin) { + Node::Builtin(_) => { + let var = ContextVar::new_from_builtin( + *loc, + expect_builtin.into(), + analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + Node::ContextVar(cvar) => { + let bn = analyzer + .builtin_or_add( + cvar.ty.as_builtin(analyzer).into_expr_err(*loc)?, + ) + .into(); + let var = ContextVar::new_from_builtin(*loc, bn, analyzer) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + e => todo!("Unhandled type in abi.decode: {e:?}"), + }, + ExprRet::Multi(inner) => inner + .iter() + .try_for_each(|i| match_decode(ctx, loc, i.clone(), analyzer)), + ExprRet::CtxKilled(kind) => { + ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) + } + e => panic!("This is invalid solidity: {:?}", e), + } + } + self.parse_ctx_expr(&input_exprs[1], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + match_decode(ctx, &loc, ret, analyzer) + }) + } + "abi.encode" + | "abi.encodePacked" + | "abi.encodeCall" + | "abi.encodeWithSignature" + | "abi.encodeWithSelector" => { + // currently we dont support concrete abi encoding, TODO + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( loc, format!( "Could not find abi function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) - } - } -} \ No newline at end of file + ), + )), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs index af687a35..67fbf8d1 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -1,11 +1,7 @@ -use crate::{ - ExprErr, IntoExprErr, -}; +use crate::{ExprErr, IntoExprErr}; use graph::{ - nodes::{ - Builtin, ContextNode, ContextVar, ExprRet, - }, + nodes::{Builtin, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; @@ -13,67 +9,67 @@ use solang_parser::pt::{Expression, Loc}; impl AddressCaller for T where T: AnalyzerBackend + Sized {} pub trait AddressCaller: AnalyzerBackend + Sized { - fn address_call(&mut self, func_name: String, _input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn address_call( + &mut self, + func_name: String, + _input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { - "delegatecall" | "staticcall" | "call" => { - // TODO: Check if we have the code for the address - // if we dont, model it as a unrestricted call that can make other calls - ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; - // TODO: try to be smarter based on the address input - let booln = self.builtin_or_add(Builtin::Bool); - let bool_cvar = ContextVar::new_from_builtin(loc, booln.into(), self) - .into_expr_err(loc)?; - let bool_node = self.add_node(Node::ContextVar(bool_cvar)); - ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; - self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); + "delegatecall" | "staticcall" | "call" => { + // TODO: Check if we have the code for the address + // if we dont, model it as a unrestricted call that can make other calls + ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; + // TODO: try to be smarter based on the address input + let booln = self.builtin_or_add(Builtin::Bool); + let bool_cvar = + ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; + let bool_node = self.add_node(Node::ContextVar(bool_cvar)); + ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; + self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr( - ExprRet::Multi(vec![ - ExprRet::Single(bool_node), - ExprRet::Single(node), - ]), - self, - ) - .into_expr_err(loc)?; - Ok(()) - } - "code" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(loc)?; - Ok(()) - } - "balance" => { - // TODO: try to be smarter based on the address input - let bn = self.builtin_or_add(Builtin::Uint(256)); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self) - .into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(node), self) - .into_expr_err(loc)?; - Ok(()) - } - _ => Err(ExprErr::FunctionNotFound( + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr( + ExprRet::Multi(vec![ExprRet::Single(bool_node), ExprRet::Single(node)]), + self, + ) + .into_expr_err(loc)?; + Ok(()) + } + "code" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + "balance" => { + // TODO: try to be smarter based on the address input + let bn = self.builtin_or_add(Builtin::Uint(256)); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(node), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( loc, format!( "Could not find builtin address function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) - } - } -} \ No newline at end of file + ), + )), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index c1ede935..58a93628 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,12 +1,8 @@ -use crate::{ - array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess, -}; +use crate::{array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; use graph::{ elem::*, - nodes::{ - Concrete, ContextNode, ContextVarNode, ExprRet, - }, + nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, }; @@ -15,7 +11,13 @@ use solang_parser::pt::{Expression, Loc}; impl ArrayCaller for T where T: AnalyzerBackend + Sized {} pub trait ArrayCaller: AnalyzerBackend + Sized { - fn array_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn array_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { "push" => { if input_exprs.len() == 1 { @@ -23,13 +25,11 @@ pub trait ArrayCaller: AnalyzerBackend + S // empty element onto the expr ret stack self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, - "array[].push(..) was not an array to push to" - .to_string(), + "array[].push(..) was not an array to push to".to_string(), )); }; @@ -38,8 +38,7 @@ pub trait ArrayCaller: AnalyzerBackend + S // get length let len = analyzer.tmp_length(arr, ctx, loc); - let len_as_idx = - len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; // set length as index analyzer.index_into_array_inner( ctx, @@ -53,13 +52,11 @@ pub trait ArrayCaller: AnalyzerBackend + S // array.push(value) self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, - "array[].push(..) was not an array to push to" - .to_string(), + "array[].push(..) was not an array to push to".to_string(), )); }; if matches!(array, ExprRet::CtxKilled(_)) { @@ -68,14 +65,12 @@ pub trait ArrayCaller: AnalyzerBackend + S } analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(new_elem) = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? + let Some(new_elem) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, - "array[].push(..) was not given an element to push" - .to_string(), + "array[].push(..) was not given an element to push".to_string(), )); }; @@ -85,21 +80,17 @@ pub trait ArrayCaller: AnalyzerBackend + S } let arr = array.expect_single().into_expr_err(loc)?; - let arr = - ContextVarNode::from(arr).latest_version(analyzer); + let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length let len = analyzer.tmp_length(arr, ctx, loc); - let len_as_idx = - len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; + let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; // set length as index analyzer.index_into_array_inner( ctx, loc, ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single( - len_as_idx.latest_version(analyzer).into(), - ), + ExprRet::Single(len_as_idx.latest_version(analyzer).into()), )?; let index = ctx .pop_expr_latest(loc, analyzer) @@ -135,9 +126,7 @@ pub trait ArrayCaller: AnalyzerBackend + S } self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, "array[].pop() was not an array to pop from".to_string(), @@ -154,9 +143,7 @@ pub trait ArrayCaller: AnalyzerBackend + S // get length analyzer.match_length(ctx, loc, array, false)?; - let Some(len) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(len) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, "array[].pop() was not an array to pop from".to_string(), @@ -191,10 +178,8 @@ pub trait ArrayCaller: AnalyzerBackend + S format!( "Could not find builtin array function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) + ), + )), } } } - - diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index 5757b0ff..b29f08c1 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -1,11 +1,7 @@ -use crate::{ - ContextBuilder, ExprErr, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ - Builtin, ContextNode, ContextVar, ExprRet, - }, + nodes::{Builtin, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, Node, }; @@ -13,43 +9,46 @@ use solang_parser::pt::{Expression, Loc}; impl BlockCaller for T where T: AnalyzerBackend + Sized {} pub trait BlockCaller: AnalyzerBackend + Sized { - fn block_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - match &*func_name { - "blockhash" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "blockhash function was not provided a block number" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - _ => Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not find builtin block function: \"{func_name}\", context: {}", - ctx.path(self), - ) - )) - } - } -} \ No newline at end of file + fn block_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match &*func_name { + "blockhash" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "blockhash function was not provided a block number".to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin block function: \"{func_name}\", context: {}", + ctx.path(self), + ), + )), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index bfa88e5e..86bed531 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -1,197 +1,201 @@ -use crate::{ - ContextBuilder, ExprErr, FuncCaller, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; use graph::{ elem::*, - nodes::{ - ContextNode, ContextVar, ContextVarNode, ExprRet, - StructNode, - }, + nodes::{ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode}, AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, }; use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; -impl ConstructorCaller for T where T: AnalyzerBackend + Sized {} +impl ConstructorCaller for T where + T: AnalyzerBackend + Sized +{ +} pub trait ConstructorCaller: AnalyzerBackend + Sized { - fn construct_array(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - // create a new list - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); - }; - - if matches!(len_var, ExprRet::CtxKilled(_)) { - ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let len_cvar = len_var.expect_single().into_expr_err(loc)?; - - let ty = VarType::try_from_idx(analyzer, func_idx); - - let new_arr = ContextVar { - loc: Some(loc), - name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), - display_name: "arr".to_string(), - storage: None, - is_tmp: true, - is_symbolic: false, - is_return: false, - tmp_of: None, - ty: ty.expect("No type for node"), - }; - - let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); - - let len_var = ContextVar { - loc: Some(loc), - name: arr.name(analyzer).into_expr_err(loc)? + ".length", - display_name: arr.display_name(analyzer).unwrap() + ".length", - storage: None, - is_tmp: true, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: ContextVarNode::from(len_cvar) - .underlying(analyzer) - .into_expr_err(loc)? - .ty - .clone(), - }; - - let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); - analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(arr, analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); - - // update the length - if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { - let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; - let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - - ctx.push_expr(ExprRet::Single(arr.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - - fn construct_contract(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - // construct a new contract - if !input_exprs.is_empty() { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - } - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - if !input_exprs.is_empty() { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "Contract creation failed".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - } - - let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { - Some(v) => v, - None => { - return Err(ExprErr::VarBadType( - loc, - format!( - "Could not create context variable from user type: {:?}", - analyzer.node(func_idx) - ), - )) - } - }; - // let idx = ret.expect_single().into_expr_err(loc)?; - let contract_cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - // contract_cvar - // .set_range_min(analyzer, Elem::from(idx)) - // .into_expr_err(loc)?; - // contract_cvar - // .set_range_max(analyzer, Elem::from(idx)) - // .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) - .into_expr_err(loc) - }) - } - - fn construct_struct(&mut self, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - // struct construction - let strukt = StructNode::from(func_idx); - let var = - ContextVar::new_from_struct(loc, strukt, ctx, self).into_expr_err(loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - - self.parse_inputs(ctx, loc, input_exprs)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "Struct Function call failed".to_string(), - )); - }; - - let inputs = inputs.as_vec(); - // set struct fields - strukt - .fields(analyzer) - .iter() - .zip(inputs) - .try_for_each(|(field, input)| { - let field_cvar = ContextVar::maybe_new_from_field( - analyzer, - loc, - ContextVarNode::from(cvar) - .underlying(analyzer) - .into_expr_err(loc)?, - field.underlying(analyzer).unwrap().clone(), - ) - .expect("Invalid struct field"); - - let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); - analyzer.add_edge( - fc_node, - cvar, - Edge::Context(ContextEdge::AttrAccess), - ); - analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; - let field_as_ret = ExprRet::Single(fc_node); - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; - let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - Ok(()) - })?; - - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc) - }) - } -} \ No newline at end of file + fn construct_array( + &mut self, + func_idx: NodeIdx, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // create a new list + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); + }; + + if matches!(len_var, ExprRet::CtxKilled(_)) { + ctx.push_expr(len_var, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let len_cvar = len_var.expect_single().into_expr_err(loc)?; + + let ty = VarType::try_from_idx(analyzer, func_idx); + + let new_arr = ContextVar { + loc: Some(loc), + name: format!("tmp_arr{}", ctx.new_tmp(analyzer).into_expr_err(loc)?), + display_name: "arr".to_string(), + storage: None, + is_tmp: true, + is_symbolic: false, + is_return: false, + tmp_of: None, + ty: ty.expect("No type for node"), + }; + + let arr = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_arr))); + + let len_var = ContextVar { + loc: Some(loc), + name: arr.name(analyzer).into_expr_err(loc)? + ".length", + display_name: arr.display_name(analyzer).unwrap() + ".length", + storage: None, + is_tmp: true, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: ContextVarNode::from(len_cvar) + .underlying(analyzer) + .into_expr_err(loc)? + .ty + .clone(), + }; + + let len_cvar = analyzer.add_node(Node::ContextVar(len_var)); + analyzer.add_edge(arr, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(arr, analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); + + // update the length + if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { + let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; + let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.len = Elem::from(len_cvar); + arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc)?; + } + } + + ctx.push_expr(ExprRet::Single(arr.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + + fn construct_contract( + &mut self, + func_idx: NodeIdx, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // construct a new contract + if !input_exprs.is_empty() { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + } + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + if !input_exprs.is_empty() { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Contract creation failed".to_string())); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + } + + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, func_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(func_idx) + ), + )) + } + }; + // let idx = ret.expect_single().into_expr_err(loc)?; + let contract_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + // contract_cvar + // .set_range_min(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; + // contract_cvar + // .set_range_max(analyzer, Elem::from(idx)) + // .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + }) + } + + fn construct_struct( + &mut self, + func_idx: NodeIdx, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // struct construction + let strukt = StructNode::from(func_idx); + let var = ContextVar::new_from_struct(loc, strukt, ctx, self).into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "Struct Function call failed".to_string(), + )); + }; + + let inputs = inputs.as_vec(); + // set struct fields + strukt + .fields(analyzer) + .iter() + .zip(inputs) + .try_for_each(|(field, input)| { + let field_cvar = ContextVar::maybe_new_from_field( + analyzer, + loc, + ContextVarNode::from(cvar) + .underlying(analyzer) + .into_expr_err(loc)?, + field.underlying(analyzer).unwrap().clone(), + ) + .expect("Invalid struct field"); + + let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); + analyzer.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess)); + analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; + let field_as_ret = ExprRet::Single(fc_node); + analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; + let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + Ok(()) + })?; + + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc) + }) + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index 93e0d859..b0143eb2 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,212 +1,214 @@ -use crate::{ - ContextBuilder, ExprErr, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ - Builtin, Concrete, ContextNode, ContextVarNode, ExprRet, - }, + nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, Node, SolcRange, VarType, }; use solang_parser::pt::{Expression, Loc}; -impl DynBuiltinCaller for T where T: AnalyzerBackend + Sized {} +impl DynBuiltinCaller for T where T: AnalyzerBackend + Sized +{} pub trait DynBuiltinCaller: AnalyzerBackend + Sized { - fn dyn_builtin_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - match &*func_name { - "concat" => self.concat(&loc, input_exprs, ctx), - _ => Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not find builtin dynamic builtin function: \"{func_name}\", context: {}", - ctx.path(self), - ) - )) - } - } - + fn dyn_builtin_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + match &*func_name { + "concat" => self.concat(&loc, input_exprs, ctx), + _ => Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not find builtin dynamic builtin function: \"{func_name}\", context: {}", + ctx.path(self), + ), + )), + } + } - #[tracing::instrument(level = "trace", skip_all)] - fn concat( - &mut self, - loc: &Loc, - input_exprs: &[Expression], - ctx: ContextNode, - ) -> Result<(), ExprErr> { - input_exprs[1..].iter().try_for_each(|expr| { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let input = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or(ExprRet::Null); - ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) - }) - })?; + #[tracing::instrument(level = "trace", skip_all)] + fn concat( + &mut self, + loc: &Loc, + input_exprs: &[Expression], + ctx: ContextNode, + ) -> Result<(), ExprErr> { + input_exprs[1..].iter().try_for_each(|expr| { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let input = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or(ExprRet::Null); + ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) + }) + })?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())); - }; - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let inputs = inputs.as_vec(); - if inputs.is_empty() { - ctx.push_expr(ExprRet::Multi(vec![]), analyzer) - .into_expr_err(loc)?; - Ok(()) - } else { - let start = &inputs[0]; - if inputs.len() > 1 { - analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) - } else { - analyzer.match_concat(ctx, loc, start.clone(), &[], None) - } - } - }) - } + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Concatenation failed".to_string())); + }; + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let inputs = inputs.as_vec(); + if inputs.is_empty() { + ctx.push_expr(ExprRet::Multi(vec![]), analyzer) + .into_expr_err(loc)?; + Ok(()) + } else { + let start = &inputs[0]; + if inputs.len() > 1 { + analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) + } else { + analyzer.match_concat(ctx, loc, start.clone(), &[], None) + } + } + }) + } - fn match_concat( - &mut self, - ctx: ContextNode, - loc: Loc, - curr: ExprRet, - inputs: &[ExprRet], - accum_node: Option, - ) -> Result<(), ExprErr> { - if let Some(accum_node) = accum_node { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => { - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } else { - match curr.flatten() { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - let acc = ContextVarNode::from(var) - .as_tmp(loc, ctx, self) - .into_expr_err(loc)?; - inputs - .iter() - .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) - .collect::, ExprErr>>()?; - ctx.push_expr(ExprRet::Single(acc.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - ExprRet::Null => Err(ExprErr::NoRhs( - loc, - "No input provided to concat function".to_string(), - )), - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - } - } - } + fn match_concat( + &mut self, + ctx: ContextNode, + loc: Loc, + curr: ExprRet, + inputs: &[ExprRet], + accum_node: Option, + ) -> Result<(), ExprErr> { + if let Some(accum_node) = accum_node { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => { + ctx.push_expr(ExprRet::Single(accum_node.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } else { + match curr.flatten() { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + let acc = ContextVarNode::from(var) + .as_tmp(loc, ctx, self) + .into_expr_err(loc)?; + inputs + .iter() + .map(|i| self.match_concat(ctx, loc, i.clone(), inputs, Some(acc))) + .collect::, ExprErr>>()?; + ctx.push_expr(ExprRet::Single(acc.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + ExprRet::Null => Err(ExprErr::NoRhs( + loc, + "No input provided to concat function".to_string(), + )), + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + } + } + } - fn concat_inner( - &mut self, - loc: Loc, - accum: ContextVarNode, - right: ContextVarNode, - ) -> Result<(), ExprErr> { - match ( - accum.ty(self).into_expr_err(loc)?, - right.ty(self).into_expr_err(loc)?, - ) { - (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { - let new_ty = match ( - accum_cnode.underlying(self).into_expr_err(loc)?, - right_cnode.underlying(self).into_expr_err(loc)?, - ) { - (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { - let new_val = accum_node.clone().concat(right_node).unwrap(); - let new_cnode = self.add_node(Node::Concrete(new_val)); - VarType::Concrete(new_cnode.into()) - } - (a, b) => { - // Invalid solidity - return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); - } - }; - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { - let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; - // let val = match underlying { - // Concrete::String(val) => { - // val - // .chars() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // v.encode_utf8(&mut bytes[..]); - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // Concrete::DynBytes(val) => { - // val - // .iter() - // .enumerate() - // .map(|(i, v)| { - // let idx = Elem::from(Concrete::from(U256::from(i))); - // let mut bytes = [0x00; 32]; - // bytes[0] = *v; - // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - // (idx, v) - // }) - // .collect::>() - // } - // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) - // }; - // TODO: Extend with bn + fn concat_inner( + &mut self, + loc: Loc, + accum: ContextVarNode, + right: ContextVarNode, + ) -> Result<(), ExprErr> { + match ( + accum.ty(self).into_expr_err(loc)?, + right.ty(self).into_expr_err(loc)?, + ) { + (VarType::Concrete(accum_cnode), VarType::Concrete(right_cnode)) => { + let new_ty = match ( + accum_cnode.underlying(self).into_expr_err(loc)?, + right_cnode.underlying(self).into_expr_err(loc)?, + ) { + (accum_node @ Concrete::String(..), right_node @ Concrete::String(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (accum_node @ Concrete::DynBytes(..), right_node @ Concrete::DynBytes(..)) => { + let new_val = accum_node.clone().concat(right_node).unwrap(); + let new_cnode = self.add_node(Node::Concrete(new_val)); + VarType::Concrete(new_cnode.into()) + } + (a, b) => { + // Invalid solidity + return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: {a:?} for left hand side and type: {b:?} for right hand side"))); + } + }; + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::Concrete(accum_cnode), VarType::BuiltIn(_bn, Some(r2))) => { + let underlying = accum_cnode.underlying(self).into_expr_err(loc)?; + // let val = match underlying { + // Concrete::String(val) => { + // val + // .chars() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // v.encode_utf8(&mut bytes[..]); + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // Concrete::DynBytes(val) => { + // val + // .iter() + // .enumerate() + // .map(|(i, v)| { + // let idx = Elem::from(Concrete::from(U256::from(i))); + // let mut bytes = [0x00; 32]; + // bytes[0] = *v; + // let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + // (idx, v) + // }) + // .collect::>() + // } + // b => return Err(ExprErr::InvalidFunctionInput(loc, format!("Type mismatch: expected String or Bytes for concat input but found: {b:?}"))) + // }; + // TODO: Extend with bn - let range = SolcRange::from(underlying.clone()).unwrap(); - let min = range.min.clone().concat(r2.min.clone()); - let max = range.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; + let range = SolcRange::from(underlying.clone()).unwrap(); + let min = range.min.clone().concat(r2.min.clone()); + let max = range.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; - let new_ty = - VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); - accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; - Ok(()) - } - (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { - // TODO: improve length calculation here - let min = r.min.clone().concat(r2.min.clone()); - let max = r.max.clone().concat(r2.max.clone()); - accum.set_range_min(self, min).into_expr_err(loc)?; - accum.set_range_max(self, max).into_expr_err(loc)?; - Ok(()) - } - (_, _) => Ok(()), - } - } -} \ No newline at end of file + let new_ty = + VarType::BuiltIn(self.builtin_or_add(Builtin::String).into(), Some(range)); + accum.underlying_mut(self).into_expr_err(loc)?.ty = new_ty; + Ok(()) + } + (VarType::BuiltIn(_bn, Some(r)), VarType::BuiltIn(_bn2, Some(r2))) => { + // TODO: improve length calculation here + let min = r.min.clone().concat(r2.min.clone()); + let max = r.max.clone().concat(r2.max.clone()); + accum.set_range_min(self, min).into_expr_err(loc)?; + accum.set_range_max(self, max).into_expr_err(loc)?; + Ok(()) + } + (_, _) => Ok(()), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index 4ebd7f7d..2b57ba7c 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -1,31 +1,46 @@ use crate::{ - ContextBuilder, ExprErr, FuncCaller, IntoExprErr, intrinsic_call::{ - MsgCaller, AbiCaller, AddressCaller, ArrayCaller, - BlockCaller, DynBuiltinCaller, PrecompileCaller, - SolidityCaller, TypesCaller, ConstructorCaller - } + AbiCaller, AddressCaller, ArrayCaller, BlockCaller, ConstructorCaller, DynBuiltinCaller, + MsgCaller, PrecompileCaller, SolidityCaller, TypesCaller, + }, + ContextBuilder, ExprErr, FuncCaller, IntoExprErr, }; use graph::{ - nodes::{ - Builtin, ContextNode, ExprRet, - }, + nodes::{Builtin, ContextNode, ExprRet}, AnalyzerBackend, Node, }; -use shared::{NodeIdx}; +use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; -pub trait CallerParts: AbiCaller + AddressCaller + ArrayCaller + - BlockCaller + DynBuiltinCaller + PrecompileCaller + - SolidityCaller + TypesCaller + ConstructorCaller + MsgCaller {} - -impl CallerParts for T where T: AbiCaller + AddressCaller + ArrayCaller + - BlockCaller + DynBuiltinCaller + PrecompileCaller + - SolidityCaller + TypesCaller + ConstructorCaller + MsgCaller {} - +pub trait CallerParts: + AbiCaller + + AddressCaller + + ArrayCaller + + BlockCaller + + DynBuiltinCaller + + PrecompileCaller + + SolidityCaller + + TypesCaller + + ConstructorCaller + + MsgCaller +{ +} +impl CallerParts for T where + T: AbiCaller + + AddressCaller + + ArrayCaller + + BlockCaller + + DynBuiltinCaller + + PrecompileCaller + + SolidityCaller + + TypesCaller + + ConstructorCaller + + MsgCaller +{ +} impl IntrinsicFuncCaller for T where T: AnalyzerBackend + Sized + CallerParts @@ -68,13 +83,15 @@ pub trait IntrinsicFuncCaller: self.dyn_builtin_call(func_name.name.clone(), input_exprs, *loc, ctx) } // msg - "gasleft" => { - self.msg_call(func_name.name.clone(), input_exprs, *loc, ctx) - } + "gasleft" => self.msg_call(func_name.name.clone(), input_exprs, *loc, ctx), // precompiles - "sha256" | "ripemd160" | "ecrecover" => { - self.precompile_call(func_name.name.clone(), func_idx, input_exprs, *loc, ctx) - } + "sha256" | "ripemd160" | "ecrecover" => self.precompile_call( + func_name.name.clone(), + func_idx, + input_exprs, + *loc, + ctx, + ), // solidity "keccak256" | "addmod" | "mulmod" | "require" | "assert" => { self.solidity_call(func_name.name.clone(), input_exprs, *loc, ctx) @@ -148,7 +165,10 @@ pub trait IntrinsicFuncCaller: } }) } - e => Err(ExprErr::FunctionNotFound(*loc, format!("Unhandled function call type: {e:?}"))), + e => Err(ExprErr::FunctionNotFound( + *loc, + format!("Unhandled function call type: {e:?}"), + )), } } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs index d3a50e38..0345a08a 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs @@ -20,4 +20,4 @@ pub use intrinsic_caller::*; pub use msg::*; pub use precompile::*; pub use solidity::*; -pub use types::*; \ No newline at end of file +pub use types::*; diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs index 249679d8..cf3f371f 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs @@ -1,11 +1,7 @@ -use crate::{ - ExprErr, IntoExprErr, -}; +use crate::{ExprErr, IntoExprErr}; use graph::{ - nodes::{ - Builtin, ContextNode, ContextVar, ExprRet, - }, + nodes::{Builtin, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, Node, }; @@ -13,27 +9,33 @@ use solang_parser::pt::{Expression, Loc}; impl MsgCaller for T where T: AnalyzerBackend + Sized {} pub trait MsgCaller: AnalyzerBackend + Sized { - fn msg_call(&mut self, func_name: String, _input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn msg_call( + &mut self, + func_name: String, + _input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { - "gasleft" => { - let var = ContextVar::new_from_builtin( - loc, - self.builtin_or_add(Builtin::Uint(64)).into(), - self, - ) - .into_expr_err(loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), self) - .into_expr_err(loc)?; - Ok(()) - } - _ => Err(ExprErr::FunctionNotFound( + "gasleft" => { + let var = ContextVar::new_from_builtin( + loc, + self.builtin_or_add(Builtin::Uint(64)).into(), + self, + ) + .into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), self) + .into_expr_err(loc)?; + Ok(()) + } + _ => Err(ExprErr::FunctionNotFound( loc, format!( "Could not find builtin msg function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) - } - } -} \ No newline at end of file + ), + )), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 0e8e1e0e..9ddfc467 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,218 +1,182 @@ -use crate::{ - ContextBuilder, ExprErr, FuncCaller, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; use graph::{ - nodes::{ - Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, - }, + nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::{NodeIdx}; +use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; -impl PrecompileCaller for T where T: AnalyzerBackend + Sized {} +impl PrecompileCaller for T where T: AnalyzerBackend + Sized +{} pub trait PrecompileCaller: AnalyzerBackend + Sized { - fn precompile_call(&mut self, func_name: String, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn precompile_call( + &mut self, + func_name: String, + func_idx: NodeIdx, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { - "sha256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "ripemd160" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "ecrecover" => { - self.parse_inputs(ctx, loc, input_exprs)?; + "sha256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding".to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "ripemd160" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding".to_string(), + )); + }; + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "ecrecover" => { + self.parse_inputs(ctx, loc, input_exprs)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let cctx = Context::new_subctx( - ctx, - None, - loc, - None, - Some(func_idx.into()), - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let call_ctx = analyzer.add_node(Node::Context(cctx)); - ctx.set_child_call(call_ctx.into(), analyzer) - .into_expr_err(loc)?; - let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge( - call_node, - func_idx, - Edge::Context(ContextEdge::Call), - ); - analyzer.add_edge( - call_node, - ctx, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - call_ctx, - call_node, - Edge::Context(ContextEdge::Subcontext), - ); + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let cctx = Context::new_subctx( + ctx, + None, + loc, + None, + Some(func_idx.into()), + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let call_ctx = analyzer.add_node(Node::Context(cctx)); + ctx.set_child_call(call_ctx.into(), analyzer) + .into_expr_err(loc)?; + let call_node = analyzer.add_node(Node::FunctionCall); + analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); + analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); + analyzer.add_edge(call_ctx, call_node, Edge::Context(ContextEdge::Subcontext)); - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "ecrecover did not receive inputs".to_string(), - )); - }; + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "ecrecover did not receive inputs".to_string(), + )); + }; - if matches!(input, ExprRet::CtxKilled(_)) { - ctx.push_expr(input, analyzer).into_expr_err(loc)?; - return Ok(()); - } + if matches!(input, ExprRet::CtxKilled(_)) { + ctx.push_expr(input, analyzer).into_expr_err(loc)?; + return Ok(()); + } - let mut inner_vals = vec![]; - match input { - ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - inner_vals.push( - ContextVarNode::from(var) - .display_name(analyzer) - .unwrap(), - ); - } - _ => inner_vals.push("".to_string()), - } - let inner_name = - inner_vals.into_iter().collect::>().join(", "); - let mut var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Address).into(), - analyzer, - ) - .into_expr_err(loc)?; - var.display_name = format!("ecrecover({})", inner_name); - var.is_symbolic = true; - var.is_return = true; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Return), - ); - ContextNode::from(call_ctx) - .add_return_node(loc, cvar.into(), analyzer) - .into_expr_err(loc)?; + let mut inner_vals = vec![]; + match input { + ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { + inner_vals + .push(ContextVarNode::from(var).display_name(analyzer).unwrap()); + } + _ => inner_vals.push("".to_string()), + } + let inner_name = inner_vals.into_iter().collect::>().join(", "); + let mut var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Address).into(), + analyzer, + ) + .into_expr_err(loc)?; + var.display_name = format!("ecrecover({})", inner_name); + var.is_symbolic = true; + var.is_return = true; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); + ContextNode::from(call_ctx) + .add_return_node(loc, cvar.into(), analyzer) + .into_expr_err(loc)?; - let rctx = Context::new_subctx( - call_ctx.into(), - Some(ctx), - loc, - None, - None, - true, - analyzer, - None, - ) - .into_expr_err(loc)?; - let ret_ctx = analyzer.add_node(Node::Context(rctx)); - ContextNode::from(call_ctx) - .set_child_call(ret_ctx.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - ret_ctx, - call_ctx, - Edge::Context(ContextEdge::Continue), - ); + let rctx = Context::new_subctx( + call_ctx.into(), + Some(ctx), + loc, + None, + None, + true, + analyzer, + None, + ) + .into_expr_err(loc)?; + let ret_ctx = analyzer.add_node(Node::Context(rctx)); + ContextNode::from(call_ctx) + .set_child_call(ret_ctx.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge(ret_ctx, call_ctx, Edge::Context(ContextEdge::Continue)); - let tmp_ret = ContextVarNode::from(cvar) - .as_tmp( - ContextNode::from(call_ctx) - .underlying(analyzer) - .unwrap() - .loc, - ret_ctx.into(), - analyzer, - ) - .unwrap(); - tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; - tmp_ret.underlying_mut(analyzer).unwrap().display_name = - format!("ecrecover({}).return", inner_name); - ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge( - tmp_ret, - ret_ctx, - Edge::Context(ContextEdge::Variable), - ); + let tmp_ret = ContextVarNode::from(cvar) + .as_tmp( + ContextNode::from(call_ctx) + .underlying(analyzer) + .unwrap() + .loc, + ret_ctx.into(), + analyzer, + ) + .unwrap(); + tmp_ret.underlying_mut(analyzer).unwrap().is_return = true; + tmp_ret.underlying_mut(analyzer).unwrap().display_name = + format!("ecrecover({}).return", inner_name); + ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; + analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); - ContextNode::from(ret_ctx) - .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - _ => Err(ExprErr::FunctionNotFound( + ContextNode::from(ret_ctx) + .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + _ => Err(ExprErr::FunctionNotFound( loc, format!( "Could not find precompile function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) - } - } + ), + )), + } + } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index 4b5e7edb..28c48ddb 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -1,11 +1,7 @@ -use crate::{ - require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr, -}; +use crate::{require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; use graph::{ - nodes::{ - Builtin, ContextNode, ContextVar, ExprRet, - }, + nodes::{Builtin, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, Node, }; @@ -13,79 +9,81 @@ use solang_parser::pt::{Expression, Loc}; impl SolidityCaller for T where T: AnalyzerBackend + Sized {} pub trait SolidityCaller: AnalyzerBackend + Sized { - fn solidity_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn solidity_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { - "keccak256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(_input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "abi.decode was not given the types for decoding" - .to_string(), - )); - }; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "addmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, loc, input_exprs)?; + "keccak256" => { + self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(_input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "abi.decode was not given the types for decoding".to_string(), + )); + }; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "addmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, loc, input_exprs)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "mulmod" => { - // TODO: actually calcuate this if possible - self.parse_inputs(ctx, loc, input_exprs)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Uint(256)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - } - "require" | "assert" => { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(input_exprs, ctx) - }) - } - _ => Err(ExprErr::FunctionNotFound( + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "mulmod" => { + // TODO: actually calcuate this if possible + self.parse_inputs(ctx, loc, input_exprs)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Uint(256)).into(), + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + } + "require" | "assert" => self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.handle_require(input_exprs, ctx) + }), + _ => Err(ExprErr::FunctionNotFound( loc, format!( "Could not find builtin solidity function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) - } - } -} \ No newline at end of file + ), + )), + } + } +} diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 611d40d6..9751151f 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,21 +1,23 @@ -use crate::{ - ContextBuilder, ExprErr, FuncCaller, IntoExprErr, -}; +use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; use graph::{ elem::*, - nodes::{ - BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode, - }, + nodes::{BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode}, AnalyzerBackend, GraphBackend, Node, Range, SolcRange, VarType, }; -use shared::{NodeIdx}; +use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; impl TypesCaller for T where T: AnalyzerBackend + Sized {} pub trait TypesCaller: AnalyzerBackend + Sized { - fn types_call(&mut self, func_name: String, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn types_call( + &mut self, + func_name: String, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { match &*func_name { "type" => self.parse_ctx_expr(&input_exprs[0], ctx), "wrap" => { @@ -25,9 +27,7 @@ pub trait TypesCaller: AnalyzerBackend + S self.parse_inputs(ctx, loc, input_exprs)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, "ecrecover did not receive inputs".to_string(), @@ -36,16 +36,11 @@ pub trait TypesCaller: AnalyzerBackend + S input.expect_length(2).into_expr_err(loc)?; let ret = input.as_vec(); let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; - let var = ContextVar::new_from_ty( - loc, - TyNode::from(wrapping_ty), - ctx, - analyzer, - ) - .into_expr_err(loc)?; + let var = + ContextVar::new_from_ty(loc, TyNode::from(wrapping_ty), ctx, analyzer) + .into_expr_err(loc)?; let to_be_wrapped = ret[1].expect_single().into_expr_err(loc)?; - let cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; let expr = Elem::Expr(RangeExpr::new( Elem::from(to_be_wrapped), @@ -62,9 +57,7 @@ pub trait TypesCaller: AnalyzerBackend + S "unwrap" => { self.parse_inputs(ctx, loc, input_exprs)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, "ecrecover did not receive inputs".to_string(), @@ -95,8 +88,7 @@ pub trait TypesCaller: AnalyzerBackend + S .into_expr_err(loc)? ); - let cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) .into_expr_err(loc)?; cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) @@ -119,12 +111,19 @@ pub trait TypesCaller: AnalyzerBackend + S format!( "Could not find builtin types function: \"{func_name}\", context: {}", ctx.path(self), - ) - )) + ), + )), } } - fn cast(&mut self, ty: Builtin, func_idx: NodeIdx, input_exprs: &[Expression], loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + fn cast( + &mut self, + ty: Builtin, + func_idx: NodeIdx, + input_exprs: &[Expression], + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { // it is a cast fn cast_match( ctx: ContextNode, @@ -135,9 +134,7 @@ pub trait TypesCaller: AnalyzerBackend + S func_idx: NodeIdx, ) -> Result<(), ExprErr> { match ret { - ExprRet::CtxKilled(kind) => { - ctx.kill(analyzer, loc, kind).into_expr_err(loc) - } + ExprRet::CtxKilled(kind) => ctx.kill(analyzer, loc, kind).into_expr_err(loc), ExprRet::Null => Ok(()), ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { let new_var = ContextVarNode::from(cvar) @@ -151,8 +148,7 @@ pub trait TypesCaller: AnalyzerBackend + S .range(analyzer) .into_expr_err(loc)? { - let curr_range = - SolcRange::try_from_builtin(ty).expect("No default range"); + let curr_range = SolcRange::try_from_builtin(ty).expect("No default range"); let mut min = r .range_min() .into_owned() @@ -166,8 +162,7 @@ pub trait TypesCaller: AnalyzerBackend + S max.cache_maximize(analyzer).into_expr_err(loc)?; - let existing_max = - r.evaled_range_max(analyzer).into_expr_err(loc)?; + let existing_max = r.evaled_range_max(analyzer).into_expr_err(loc)?; // Check if the max value has changed once the cast is applied. // If it hasnt, then the cast had no effect and we should adjust the naming // to not muddle the CLI @@ -188,8 +183,7 @@ pub trait TypesCaller: AnalyzerBackend + S // cast the range exclusions - TODO: verify this is correct let mut exclusions = r.range_exclusions(); exclusions.iter_mut().for_each(|range| { - *range = - range.clone().cast(curr_range.range_min().into_owned()); + *range = range.clone().cast(curr_range.range_min().into_owned()); }); new_var .set_range_exclusions(analyzer, exclusions) @@ -220,4 +214,4 @@ pub trait TypesCaller: AnalyzerBackend + S cast_match(ctx, loc, analyzer, &ty, ret, func_idx) }) } -} \ No newline at end of file +} From 0fa23dca7eb0115733b16a4fe186b8e802572783 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Sun, 10 Dec 2023 20:04:46 -0800 Subject: [PATCH 39/71] improve error messages --- crates/solc-expressions/src/func_call/intrinsic_call/abi.rs | 5 ++++- .../src/func_call/intrinsic_call/precompile.rs | 4 ++-- .../src/func_call/intrinsic_call/solidity.rs | 2 +- .../solc-expressions/src/func_call/intrinsic_call/types.rs | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 29316aa9..3307fb04 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -65,7 +65,10 @@ pub trait AbiCaller: AnalyzerBackend + Siz ExprRet::CtxKilled(kind) => { ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) } - e => panic!("This is invalid solidity: {:?}", e), + e => Err(ExprErr::ParseError( + *loc, + format!("This is invalid solidity: {:?}", e), + )), } } self.parse_ctx_expr(&input_exprs[1], ctx)?; diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 9ddfc467..64c7f09f 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -26,7 +26,7 @@ pub trait PrecompileCaller: AnalyzerBackend else { return Err(ExprErr::NoRhs( loc, - "abi.decode was not given the types for decoding".to_string(), + "keccak256 call was not given inputs".to_string(), )); }; let var = ContextVar::new_from_builtin( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 9751151f..ee5b421c 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -30,7 +30,7 @@ pub trait TypesCaller: AnalyzerBackend + S let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, - "ecrecover did not receive inputs".to_string(), + ".wrap(..) did not receive an input".to_string(), )); }; input.expect_length(2).into_expr_err(loc)?; @@ -60,7 +60,7 @@ pub trait TypesCaller: AnalyzerBackend + S let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, - "ecrecover did not receive inputs".to_string(), + ".unwrap(..) did not receive an input".to_string(), )); }; input.expect_length(2).into_expr_err(loc)?; From b4243e9a5f81c3a69e34d0d9d7695460c5d37bd3 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 11 Dec 2023 10:56:48 -0800 Subject: [PATCH 40/71] mostly documentation and some reorg --- crates/solc-expressions/src/array.rs | 1 + crates/solc-expressions/src/bin_op.rs | 1 + crates/solc-expressions/src/cmp.rs | 1 + crates/solc-expressions/src/cond_op.rs | 3 + .../src/context_builder/mod.rs | 26 +- crates/solc-expressions/src/env.rs | 3 +- .../src/func_call/func_caller.rs | 380 ++++++ .../solc-expressions/src/func_call/helper.rs | 585 ++++++++ .../src/func_call/internal_call.rs | 175 +-- .../src/func_call/intrinsic_call/abi.rs | 5 +- .../src/func_call/intrinsic_call/address.rs | 3 + .../src/func_call/intrinsic_call/array.rs | 3 + .../src/func_call/intrinsic_call/block.rs | 3 + .../func_call/intrinsic_call/constructors.rs | 11 +- .../func_call/intrinsic_call/dyn_builtin.rs | 6 + .../intrinsic_call/intrinsic_caller.rs | 7 +- .../src/func_call/intrinsic_call/mod.rs | 1 + .../src/func_call/intrinsic_call/msg.rs | 3 + .../func_call/intrinsic_call/precompile.rs | 9 +- .../src/func_call/intrinsic_call/solidity.rs | 9 +- .../src/func_call/intrinsic_call/types.rs | 6 +- crates/solc-expressions/src/func_call/mod.rs | 1195 +---------------- .../src/func_call/modifier.rs | 285 +++- .../src/func_call/namespaced_call.rs | 16 +- crates/solc-expressions/src/lib.rs | 11 +- crates/solc-expressions/src/list.rs | 2 +- crates/solc-expressions/src/literal.rs | 1 + crates/solc-expressions/src/loops.rs | 5 + .../src/member_access/builtin_access.rs | 3 + .../src/member_access/contract_access.rs | 3 + .../src/member_access/enum_access.rs | 3 + .../src/member_access/library_access.rs | 4 + .../src/member_access/list_access.rs | 6 + .../src/member_access/member_trait.rs | 161 +-- .../solc-expressions/src/member_access/mod.rs | 3 + .../src/member_access/struct_access.rs | 2 + crates/solc-expressions/src/require.rs | 3 + crates/solc-expressions/src/variable.rs | 3 +- crates/solc-expressions/src/yul/mod.rs | 382 +----- .../solc-expressions/src/yul/yul_builder.rs | 388 ++++++ .../solc-expressions/src/yul/yul_cond_op.rs | 11 +- crates/solc-expressions/src/yul/yul_funcs.rs | 2 +- 42 files changed, 1960 insertions(+), 1770 deletions(-) create mode 100644 crates/solc-expressions/src/func_call/func_caller.rs create mode 100644 crates/solc-expressions/src/func_call/helper.rs create mode 100644 crates/solc-expressions/src/yul/yul_builder.rs diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index b603e39b..2045d818 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -12,6 +12,7 @@ use solang_parser::{ }; impl Array for T where T: AnalyzerBackend + Sized {} +/// Handles arrays pub trait Array: AnalyzerBackend + Sized { /// Gets the array type #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 712cfe7b..5f855b1b 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -13,6 +13,7 @@ use ethers_core::types::{I256, U256}; use solang_parser::pt::{Expression, Loc}; impl BinOp for T where T: AnalyzerBackend + Sized {} +/// Handles binary operations (`+`, `-`, `/`, etc.) pub trait BinOp: AnalyzerBackend + Sized { /// Evaluate and execute a binary operation expression #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 771e54e4..948e34a2 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -13,6 +13,7 @@ use solang_parser::pt::{Expression, Loc}; use std::cmp::Ordering; impl Cmp for T where T: AnalyzerBackend + Sized {} +/// Handles comparator operations, i.e: `!` pub trait Cmp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn not(&mut self, loc: Loc, lhs_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 00ac50e9..f96e3307 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -11,8 +11,10 @@ use solang_parser::pt::{Expression, Loc, Statement}; impl CondOp for T where T: AnalyzerBackend + Require + Sized {} +/// Handles conditional operations, like `if .. else ..` and ternary operations pub trait CondOp: AnalyzerBackend + Require + Sized { #[tracing::instrument(level = "trace", skip_all)] + /// Handles a conditional operation like `if .. else ..` fn cond_op_stmt( &mut self, loc: Loc, @@ -126,6 +128,7 @@ pub trait CondOp: AnalyzerBackend + Requir }) } + /// Handles a conditional expression like `if .. else ..` /// When we have a conditional operator, we create a fork in the context. One side of the fork is /// if the expression is true, the other is if it is false. #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 0f97cd16..c959f033 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1,5 +1,6 @@ +//! Trait and blanket implementation for the core parsing loop use crate::{ - func_call::FuncCaller, loops::Looper, yul::YulBuilder, ExprErr, ExprParser, IntoExprErr, + func_call::{func_caller::FuncCaller, modifier::ModifierCaller}, loops::Looper, yul::YulBuilder, ExprErr, ExprParser, IntoExprErr, }; use graph::{ @@ -24,9 +25,11 @@ impl ContextBuilder for T where { } +/// Dispatcher for building up a context of a function pub trait ContextBuilder: AnalyzerBackend + Sized + ExprParser { + /// Performs setup for parsing a solidity statement fn parse_ctx_statement( &mut self, stmt: &Statement, @@ -61,6 +64,7 @@ pub trait ContextBuilder: } #[tracing::instrument(level = "trace", skip_all)] + /// Performs parsing of a solidity statement fn parse_ctx_stmt_inner( &mut self, stmt: &Statement, @@ -525,6 +529,7 @@ pub trait ContextBuilder: } } + /// TODO: rename this. Sometimes we dont want to kill a context if we hit an error fn widen_if_limit_hit(&mut self, ctx: ContextNode, maybe_err: Result<(), ExprErr>) -> bool { match maybe_err { Err(ExprErr::FunctionCallBlockTodo(_, _s)) => { @@ -549,6 +554,7 @@ pub trait ContextBuilder: } } + /// Match on the [`ExprRet`]s of a return statement and performs the return fn return_match(&mut self, ctx: ContextNode, loc: &Loc, paths: &ExprRet) { match paths { ExprRet::CtxKilled(kind) => { @@ -582,6 +588,7 @@ pub trait ContextBuilder: } } + /// Match on the [`ExprRet`]s of a variable definition fn match_var_def( &mut self, ctx: ContextNode, @@ -702,6 +709,7 @@ pub trait ContextBuilder: } } + /// Perform setup for parsing an expression fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { if !ctx.killed_or_ret(self).unwrap() { let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; @@ -719,6 +727,7 @@ pub trait ContextBuilder: } #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self).replace('.', "\n\t.")))] + /// Perform parsing of an expression fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { use Expression::*; // println!( @@ -1128,6 +1137,7 @@ pub trait ContextBuilder: } } + /// Match on the [`ExprRet`]s of a pre-or-post in/decrement and performs it fn match_in_de_crement( &mut self, ctx: ContextNode, @@ -1217,6 +1227,7 @@ pub trait ContextBuilder: } #[tracing::instrument(level = "trace", skip_all)] + /// Parse an assignment expression fn assign_exprs( &mut self, loc: Loc, @@ -1255,6 +1266,7 @@ pub trait ContextBuilder: }) } + /// Match on the [`ExprRet`]s of an assignment expression fn match_assign_sides( &mut self, ctx: ContextNode, @@ -1312,6 +1324,7 @@ pub trait ContextBuilder: } } + /// Perform an assignment fn assign( &mut self, loc: Loc, @@ -1442,6 +1455,8 @@ pub trait ContextBuilder: } #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + /// Creates a newer version of a variable in the context. It may or may not actually + /// create this new variable depending on if there are two successively identical version. fn advance_var_in_ctx( &mut self, cvar_node: ContextVarNode, @@ -1452,6 +1467,8 @@ pub trait ContextBuilder: } #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + /// Creates a new version of a variable in a context. Takes an additional parameter + /// denoting whether or not to force the creation, skipping an optimization. fn advance_var_in_ctx_forcible( &mut self, cvar_node: ContextVarNode, @@ -1526,6 +1543,7 @@ pub trait ContextBuilder: Ok(ContextVarNode::from(new_cvarnode)) } + /// Creates a new version of a variable in it's current context fn advance_var_in_curr_ctx( &mut self, cvar_node: ContextVarNode, @@ -1554,6 +1572,7 @@ pub trait ContextBuilder: Ok(ContextVarNode::from(new_cvarnode)) } + /// fn advance_var_underlying(&mut self, cvar_node: ContextVarNode, loc: Loc) -> &mut ContextVar { assert_eq!(None, cvar_node.next_version(self)); let mut new_cvar = cvar_node @@ -1569,6 +1588,9 @@ pub trait ContextBuilder: .unwrap() } + /// Apply an expression or statement to all *live* edges of a context. This is used everywhere + /// to ensure we only ever update *live* contexts. If a context has a subcontext, we *never* + /// want to update the original context. We only ever want to operate on the latest edges. fn apply_to_edges( &mut self, ctx: ContextNode, @@ -1602,6 +1624,8 @@ pub trait ContextBuilder: } } + /// The inverse of [`apply_to_edges`], used only for modifiers because modifiers have extremely weird + /// dynamics. fn take_from_edge( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index e203455e..54060832 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,4 +1,4 @@ -use crate::{func_call::FuncCaller, ExprErr, IntoExprErr}; +use crate::{func_call::helper::CallerHelper, func_call::modifier::ModifierCaller, ExprErr, IntoExprErr}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, @@ -9,6 +9,7 @@ use shared::StorageLocation; use solang_parser::pt::{Expression, Identifier, Loc}; impl Env for T where T: AnalyzerBackend + Sized {} +/// Handles environment based things like `msg`, `block`, etc. pub trait Env: AnalyzerBackend + Sized { fn env_variable( &mut self, diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs new file mode 100644 index 00000000..8b06d943 --- /dev/null +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -0,0 +1,380 @@ +//! Traits & blanket implementations that facilitate performing various forms of function calls. + +use crate::{ + func_call::modifier::ModifierCaller, + internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, + namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, IntoExprErr, + helper::CallerHelper, +}; + +use graph::{ + nodes::{ + Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, ModifierState, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, +}; +use shared::{NodeIdx}; + +use solang_parser::pt::{Expression, Loc, NamedArgument}; + +use std::collections::BTreeMap; + +impl FuncCaller for T where + T: AnalyzerBackend + Sized + GraphBackend + CallerHelper +{ +} +/// A trait for calling a function +pub trait FuncCaller: + GraphBackend + AnalyzerBackend + Sized +{ + #[tracing::instrument(level = "trace", skip_all)] + /// Perform a function call with named inputs + fn named_fn_call_expr( + &mut self, + ctx: ContextNode, + loc: &Loc, + func_expr: &Expression, + input_exprs: &[NamedArgument], + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + match func_expr { + MemberAccess(loc, member_expr, ident) => { + self.call_name_spaced_named_func(ctx, loc, member_expr, ident, input_exprs) + } + Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), + e => Err(ExprErr::IntrinsicNamedArgs( + *loc, + format!("Cannot call intrinsic functions with named arguments. Call: {e:?}"), + )), + } + } + #[tracing::instrument(level = "trace", skip_all)] + /// Perform a function call + fn fn_call_expr( + &mut self, + ctx: ContextNode, + loc: &Loc, + func_expr: &Expression, + input_exprs: &[Expression], + ) -> Result<(), ExprErr> { + use solang_parser::pt::Expression::*; + match func_expr { + MemberAccess(loc, member_expr, ident) => { + self.call_name_spaced_func(ctx, loc, member_expr, ident, input_exprs) + } + Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, input_exprs), + _ => { + self.parse_ctx_expr(func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Function call to nonexistent function".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + }) + } + } + } + + /// Perform an intrinsic function call + fn match_intrinsic_fallback( + &mut self, + ctx: ContextNode, + loc: &Loc, + input_exprs: &[Expression], + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + ExprRet::Single(func_idx) | ExprRet::SingleLiteral(func_idx) => { + self.intrinsic_func_call(loc, input_exprs, func_idx, ctx) + } + ExprRet::Multi(inner) => inner + .into_iter() + .try_for_each(|ret| self.match_intrinsic_fallback(ctx, loc, input_exprs, ret)), + ExprRet::CtxKilled(kind) => ctx.kill(self, *loc, kind).into_expr_err(*loc), + ExprRet::Null => Ok(()), + } + } + + /// Setups up storage variables for a function call and calls it + fn setup_fn_call( + &mut self, + loc: &Loc, + inputs: &ExprRet, + func_idx: NodeIdx, + ctx: ContextNode, + func_call_str: Option<&str>, + ) -> Result<(), ExprErr> { + // if we have a single match thats our function + let var = match ContextVar::maybe_from_user_ty(self, *loc, func_idx) { + Some(v) => v, + None => panic!( + "Could not create context variable from user type: {:?}", + self.node(func_idx) + ), + }; + + let new_cvarnode = self.add_node(Node::ContextVar(var)); + ctx.add_var(new_cvarnode.into(), self).into_expr_err(*loc)?; + self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); + if let Some(func_node) = ContextVarNode::from(new_cvarnode) + .ty(self) + .into_expr_err(*loc)? + .func_node(self) + { + self.func_call(ctx, *loc, inputs, func_node, func_call_str, None) + } else { + unreachable!() + } + } + + /// Matches the input kinds and performs the call + fn func_call( + &mut self, + ctx: ContextNode, + loc: Loc, + input_paths: &ExprRet, + func: FunctionNode, + func_call_str: Option<&str>, + modifier_state: Option, + ) -> Result<(), ExprErr> { + let params = func.params(self); + let input_paths = input_paths.clone().flatten(); + if input_paths.has_killed() { + return ctx + .kill(self, loc, input_paths.killed_kind().unwrap()) + .into_expr_err(loc); + } + match input_paths { + ExprRet::Single(input_var) | ExprRet::SingleLiteral(input_var) => { + // if we get a single var, we expect the func to only take a single + // variable + self.func_call_inner( + false, + ctx, + func, + loc, + vec![ContextVarNode::from(input_var).latest_version(self)], + params, + func_call_str, + modifier_state, + ) + } + ExprRet::Multi(ref inputs) => { + if ExprRet::Multi(inputs.to_vec()).flatten().has_killed() { + return ctx + .kill( + self, + loc, + ExprRet::Multi(inputs.to_vec()).killed_kind().unwrap(), + ) + .into_expr_err(loc); + } + // check if the inputs length matchs func params length + // if they do, check that none are forks + if inputs.len() == params.len() { + let input_vars = inputs + .iter() + .map(|expr_ret| { + let var = expr_ret.expect_single().into_expr_err(loc)?; + Ok(ContextVarNode::from(var).latest_version(self)) + }) + .collect::, ExprErr>>()?; + self.func_call_inner( + false, + ctx, + func, + loc, + input_vars, + params, + func_call_str, + modifier_state, + ) + } else { + Err(ExprErr::InvalidFunctionInput( + loc, + format!( + "Length mismatch: {inputs:?} {params:?}, inputs as vars: {}, ctx: {}", + ExprRet::Multi(inputs.to_vec()).debug_str(self), + ctx.path(self) + ), + )) + } + } + e => todo!("here: {:?}", e), + } + } + + /// Checks if there are any modifiers and executes them prior to executing the function + #[tracing::instrument(level = "trace", skip_all)] + fn func_call_inner( + &mut self, + entry_call: bool, + ctx: ContextNode, + func_node: FunctionNode, + loc: Loc, + inputs: Vec, + params: Vec, + func_call_str: Option<&str>, + modifier_state: Option, + ) -> Result<(), ExprErr> { + // pseudocode: + // 1. Create context for the call + // 2. Check for modifiers + // 3. Call modifier 0, then 1, then 2, ... then N. + // 4. Call this function + // 5. Finish modifier N.. then 2, then 1, then 0 + let callee_ctx = if entry_call { + ctx + } else { + self.create_call_ctx(ctx, loc, func_node, modifier_state)? + }; + + // TODO: implement joining + // if !entry_call { + // let mapping = params + // .iter() + // .zip(inputs.iter()) + // .map(|(param, input)| (*input, *param)) + // .collect::>(); + // ctx.join(func_node, &mapping, self); + // } + + // handle remapping of variable names and bringing variables into the new context + let renamed_inputs = + self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; + + // begin modifier handling by making sure modifiers were set + if !func_node.modifiers_set(self).into_expr_err(loc)? { + self.set_modifiers(func_node, ctx)?; + } + + // get modifiers + let mods = func_node.modifiers(self); + self.apply_to_edges(callee_ctx, loc, &|analyzer, callee_ctx, loc| { + if let Some(mod_state) = &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state { + // we are iterating through modifiers + if mod_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = mod_state.clone(); + mstate.num += 1; + analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, mstate) + } else { + // out of modifiers, execute the actual function call + analyzer.execute_call_inner( + loc, + ctx, + callee_ctx, + func_node, + &renamed_inputs, + func_call_str, + ) + } + } else if !mods.is_empty() { + // we have modifiers and havent executed them, start the process of executing them + let state = + ModifierState::new(0, loc, func_node, callee_ctx, ctx, renamed_inputs.clone()); + analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, state) + } else { + // no modifiers, just execute the function + analyzer.execute_call_inner( + loc, + ctx, + callee_ctx, + func_node, + &renamed_inputs, + func_call_str, + ) + } + }) + } + + + /// Actually executes the function + #[tracing::instrument(level = "trace", skip_all)] + fn execute_call_inner( + &mut self, + loc: Loc, + caller_ctx: ContextNode, + callee_ctx: ContextNode, + func_node: FunctionNode, + _renamed_inputs: &BTreeMap, + func_call_str: Option<&str>, + ) -> Result<(), ExprErr> { + if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { + // add return nodes into the subctx + func_node + .returns(self) + .collect::>() + .into_iter() + .for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + callee_ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); + } + }); + + self.parse_ctx_statement(&body, false, Some(callee_ctx)); + self.ctx_rets(loc, caller_ctx, callee_ctx) + } else { + let ret_ctx = Context::new_subctx( + callee_ctx, + Some(caller_ctx), + loc, + None, + None, + false, + self, + caller_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone(), + ) + .unwrap(); + let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); + self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); + + let res = callee_ctx + .set_child_call(ret_subctx, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { + func_node + .returns(analyzer) + .collect::>() + .into_iter() + .try_for_each(|ret| { + let underlying = ret.underlying(analyzer).unwrap(); + let mut var = + ContextVar::new_from_func_ret(ctx, analyzer, underlying.clone()) + .unwrap() + .expect("No type for return variable?"); + if let Some(func_call) = &func_call_str { + var.name = + format!("{}_{}", func_call, callee_ctx.new_tmp(analyzer).unwrap()); + var.display_name = func_call.to_string(); + } + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc)?; + Ok(()) + }) + }) + } + } +} diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs new file mode 100644 index 00000000..fe1e0dcd --- /dev/null +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -0,0 +1,585 @@ +//! Helper traits & blanket implementations that help facilitate performing function calls. +use crate::{ + ContextBuilder, ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + CallFork, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, FunctionReturnNode, ModifierState, + }, + AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, +}; +use shared::{NodeIdx, StorageLocation}; + +use solang_parser::pt::{Expression, Loc}; + +use std::{ + cell::RefCell, + collections::BTreeMap, + rc::Rc +}; + +impl CallerHelper for T where T: AnalyzerBackend + Sized {} +/// Helper trait for performing function calls +pub trait CallerHelper: AnalyzerBackend + Sized { + /// Maps inputs to function parameters such that if there is a renaming i.e. `a(uint256 x)` is called via `a(y)`, + /// we map `y -> x` for future lookups + fn map_inputs_to_params( + &mut self, + loc: Loc, + entry_call: bool, + params: Vec, + inputs: Vec, + callee_ctx: ContextNode, + ) -> Result, ExprErr> { + Ok(params + .iter() + .zip(inputs.iter()) + .filter_map(|(param, input)| { + if !entry_call { + if let Some(name) = + self.add_if_err(param.maybe_name(self).into_expr_err(loc))? + { + let res = input + .latest_version(self) + .underlying(self) + .into_expr_err(loc) + .cloned(); + let mut new_cvar = self.add_if_err(res)?; + new_cvar.loc = Some(param.loc(self).unwrap()); + new_cvar.name = name.clone(); + new_cvar.display_name = name; + new_cvar.is_tmp = false; + new_cvar.storage = if let Some(StorageLocation::Storage(_)) = + param.underlying(self).unwrap().storage + { + new_cvar.storage + } else { + None + }; + + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) + { + let ty = new_cvar.ty.clone(); + if !ty.ty_eq(¶m_ty, self).unwrap() { + if let Some(new_ty) = ty.try_cast(¶m_ty, self).unwrap() { + new_cvar.ty = new_ty; + } + } + } + + let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + self.add_edge( + node, + input.latest_version(self), + Edge::Context(ContextEdge::InputVariable), + ); + + if let (Some(r), Some(r2)) = + (node.range(self).unwrap(), param.range(self).unwrap()) + { + let new_min = + r.range_min().into_owned().cast(r2.range_min().into_owned()); + let new_max = + r.range_max().into_owned().cast(r2.range_max().into_owned()); + let res = node.try_set_range_min(self, new_min).into_expr_err(loc); + self.add_if_err(res); + let res = node.try_set_range_max(self, new_max).into_expr_err(loc); + self.add_if_err(res); + let res = node + .try_set_range_exclusions(self, r.exclusions) + .into_expr_err(loc); + self.add_if_err(res); + } + callee_ctx.add_var(node, self).unwrap(); + self.add_edge(node, callee_ctx, Edge::Context(ContextEdge::Variable)); + Some((*input, node)) + } else { + None + } + } else { + None + } + }) + .collect::>()) + } + + #[tracing::instrument(level = "trace", skip_all)] + /// Parses input expressions into [`ExprRet`]s and adds them to the expr ret stack + fn parse_inputs( + &mut self, + ctx: ContextNode, + loc: Loc, + inputs: &[Expression], + ) -> Result<(), ExprErr> { + let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { + Rc::new(RefCell::new(true)) + } else { + Rc::new(RefCell::new(false)) + }; + + inputs.iter().try_for_each(|input| { + self.parse_ctx_expr(input, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + })?; + if !inputs.is_empty() { + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + } + + /// Creates a new context for a call + fn create_call_ctx( + &mut self, + curr_ctx: ContextNode, + loc: Loc, + func_node: FunctionNode, + modifier_state: Option, + ) -> Result { + let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; + let ctx = Context::new_subctx( + curr_ctx, + None, + loc, + None, + Some(func_node), + fn_ext, + self, + modifier_state, + ) + .into_expr_err(loc)?; + let callee_ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + curr_ctx + .set_child_call(callee_ctx, self) + .into_expr_err(loc)?; + let ctx_fork = self.add_node(Node::FunctionCall); + self.add_edge(ctx_fork, curr_ctx, Edge::Context(ContextEdge::Subcontext)); + self.add_edge(ctx_fork, func_node, Edge::Context(ContextEdge::Call)); + self.add_edge( + NodeIdx::from(callee_ctx.0), + ctx_fork, + Edge::Context(ContextEdge::Subcontext), + ); + Ok(callee_ctx) + } + + /// Disambiguates a function call by their inputs (length & type) + fn disambiguate_fn_call( + &mut self, + fn_name: &str, + literals: Vec, + input_paths: &ExprRet, + funcs: &[FunctionNode], + ) -> Option { + let input_paths = input_paths.clone().flatten(); + // try to find the function based on naive signature + // This doesnt do type inference on NumberLiterals (i.e. 100 could be uintX or intX, and there could + // be a function that takes an int256 but we evaled as uint256) + let fn_sig = format!("{}{}", fn_name, input_paths.try_as_func_input_str(self)); + if let Some(func) = funcs.iter().find(|func| func.name(self).unwrap() == fn_sig) { + return Some(*func); + } + + // filter by input len + let inputs = input_paths.as_flat_vec(); + let funcs: Vec<&FunctionNode> = funcs + .iter() + .filter(|func| func.params(self).len() == inputs.len()) + .collect(); + + if funcs.len() == 1 { + return Some(*funcs[0]); + } + + if !literals.iter().any(|i| *i) { + None + } else { + let funcs = funcs + .iter() + .filter(|func| { + let params = func.params(self); + params + .iter() + .zip(&inputs) + .enumerate() + .all(|(i, (param, input))| { + let param_ty = VarType::try_from_idx(self, (*param).into()).unwrap(); + let input_ty = ContextVarNode::from(*input).ty(self).unwrap(); + if param_ty.ty_eq(input_ty, self).unwrap() { + true + } else if literals[i] { + let possibilities = ContextVarNode::from(*input) + .ty(self) + .unwrap() + .possible_builtins_from_ty_inf(self); + let param_ty = param.ty(self).unwrap(); + match self.node(param_ty) { + Node::Builtin(b) => possibilities.contains(b), + _ => false, + } + } else { + false + } + }) + }) + .collect::>(); + if funcs.len() == 1 { + Some(**funcs[0]) + } else { + // this would be invalid solidity, likely the user needs to perform a cast + None + } + } + } + + /// Handle returns for a function call + fn ctx_rets( + &mut self, + loc: Loc, + caller_ctx: ContextNode, + callee_ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!( + "Handling function call return for: {}, {}, depth: {:?}, {:?}", + caller_ctx.path(self), + callee_ctx.path(self), + caller_ctx.depth(self), + callee_ctx.depth(self), + ); + match callee_ctx.underlying(self).into_expr_err(loc)?.child { + Some(CallFork::Fork(w1, w2)) => { + self.ctx_rets(loc, caller_ctx, w1)?; + self.ctx_rets(loc, caller_ctx, w2)?; + Ok(()) + } + Some(CallFork::Call(c)) + if c.underlying(self).into_expr_err(loc)?.depth + >= caller_ctx.underlying(self).into_expr_err(loc)?.depth => + { + // follow rabbit hole + self.ctx_rets(loc, caller_ctx, c)?; + Ok(()) + } + _ => { + if callee_ctx.is_killed(self).into_expr_err(loc)? { + return Ok(()); + } + let callee_depth = callee_ctx.underlying(self).into_expr_err(loc)?.depth; + let caller_depth = caller_ctx.underlying(self).into_expr_err(loc)?.depth; + if callee_depth != caller_depth { + let ctx = Context::new_subctx( + callee_ctx, + Some(caller_ctx), + loc, + None, + None, + false, + self, + caller_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone(), + ) + .unwrap(); + let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); + self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); + + let res = callee_ctx + .set_child_call(ret_subctx, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + + if rets.is_empty() { + let func_rets: Vec = callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .collect(); + func_rets + .iter() + .filter_map(|ret| { + let n: String = ret.maybe_name(self).ok()??; + let ret_loc: Loc = ret.loc(self).ok()?; + Some((n, ret_loc)) + }) + .collect::>() + .into_iter() + .try_for_each(|(name, ret_loc)| { + if let Some(cvar) = callee_ctx + .var_by_name_or_recurse(self, &name) + .into_expr_err(loc)? + { + let cvar = cvar.latest_version(self); + // let ret_loc = ret.loc(self).into_expr_err(loc)?; + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Return), + ); + } + Ok(()) + })?; + + // add unnamed rets + func_rets + .into_iter() + .filter(|ret| ret.maybe_name(self).unwrap().is_none()) + .collect::>() + .iter() + .try_for_each(|ret| { + let ret_loc = ret.loc(self).into_expr_err(loc)?; + let cvar = ContextVar::new_from_func_ret( + callee_ctx, + self, + ret.underlying(self).into_expr_err(loc)?.clone(), + ) + .into_expr_err(loc)? + .unwrap(); + let cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); + callee_ctx.add_var(cvar, self).into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Variable), + ); + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); + Ok(()) + })?; + rets = callee_ctx.underlying(self).unwrap().ret.clone(); + } + + let handle_rets = rets.iter().all(|(_, node)| node.is_some()); + if handle_rets { + let ret = rets + .into_iter() + .enumerate() + .map(|(i, (_, node))| { + let tmp_ret = node + .unwrap() + .as_tmp( + callee_ctx.underlying(self).unwrap().loc, + ret_subctx, + self, + ) + .unwrap(); + tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; + tmp_ret + .underlying_mut(self) + .into_expr_err(loc)? + .display_name = format!( + "{}.{}", + callee_ctx.associated_fn_name(self).unwrap(), + i + ); + ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; + self.add_edge( + tmp_ret, + ret_subctx, + Edge::Context(ContextEdge::Variable), + ); + Ok(ExprRet::Single(tmp_ret.into())) + }) + .collect::>()?; + ret_subctx + .push_expr(ExprRet::Multi(ret), self) + .into_expr_err(loc)?; + } + Ok(()) + } else { + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + + if rets.is_empty() { + callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .filter_map(|ret| { + let n: String = ret.maybe_name(self).ok()??; + let ret_loc: Loc = ret.loc(self).ok()?; + Some((n, ret_loc)) + }) + .collect::>() + .into_iter() + .try_for_each(|(name, ret_loc)| { + if let Some(cvar) = callee_ctx + .var_by_name_or_recurse(self, &name) + .into_expr_err(loc)? + { + let cvar = cvar.latest_version(self); + // let ret_loc = ret.loc(self).into_expr_err(loc)?; + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge( + cvar, + callee_ctx, + Edge::Context(ContextEdge::Return), + ); + } + Ok(()) + })?; + rets = callee_ctx.underlying(self).unwrap().ret.clone(); + } + if rets.iter().all(|(_, node)| node.is_some()) { + callee_ctx + .push_expr( + ExprRet::Multi( + rets.iter() + .map(|(_, node)| ExprRet::Single((node.unwrap()).into())) + .collect(), + ), + self, + ) + .into_expr_err(loc) + } else { + Ok(()) + } + } + } + } + } + + /// Inherit the input changes from a function call + fn inherit_input_changes( + &mut self, + loc: Loc, + to_ctx: ContextNode, + from_ctx: ContextNode, + renamed_inputs: &BTreeMap, + ) -> Result<(), ExprErr> { + if to_ctx != from_ctx { + self.apply_to_edges(to_ctx, loc, &|analyzer, to_ctx, loc| { + renamed_inputs + .iter() + .try_for_each(|(input_var, updated_var)| { + let new_input = analyzer.advance_var_in_ctx( + input_var.latest_version(analyzer), + loc, + to_ctx, + )?; + let latest_updated = updated_var.latest_version(analyzer); + if let Some(updated_var_range) = + latest_updated.range(analyzer).into_expr_err(loc)? + { + let res = new_input + .set_range_min(analyzer, updated_var_range.range_min().into_owned()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_input + .set_range_max(analyzer, updated_var_range.range_max().into_owned()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_input + .set_range_exclusions( + analyzer, + updated_var_range.range_exclusions(), + ) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + Ok(()) + }) + })?; + } + Ok(()) + } + + /// Inherit the input changes from a function call + fn modifier_inherit_return(&mut self, mod_ctx: ContextNode, fn_ctx: ContextNode) { + let ret = fn_ctx.underlying(self).unwrap().ret.clone(); + mod_ctx.underlying_mut(self).unwrap().ret = ret; + } + + /// Inherit the storage changes from a function call + fn inherit_storage_changes( + &mut self, + loc: Loc, + inheritor_ctx: ContextNode, + grantor_ctx: ContextNode, + ) -> Result<(), ExprErr> { + if inheritor_ctx != grantor_ctx { + return self.apply_to_edges(inheritor_ctx, loc, &|analyzer, inheritor_ctx, loc| { + let vars = grantor_ctx.local_vars(analyzer).clone(); + vars.iter().try_for_each(|(name, old_var)| { + let var = old_var.latest_version(analyzer); + let underlying = var.underlying(analyzer).into_expr_err(loc)?; + if var.is_storage(analyzer).into_expr_err(loc)? { + if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { + let new_inheritor_var = analyzer + .advance_var_in_ctx( + inheritor_var, + underlying.loc.expect("No loc for val change"), + inheritor_ctx, + ) + .unwrap(); + let _ = new_inheritor_var + .set_range_min(analyzer, r.range_min().into_owned()); + let _ = new_inheritor_var + .set_range_max(analyzer, r.range_max().into_owned()); + let _ = new_inheritor_var + .set_range_exclusions(analyzer, r.range_exclusions()); + } + } else { + let new_in_inheritor = + analyzer.add_node(Node::ContextVar(underlying.clone())); + inheritor_ctx + .add_var(new_in_inheritor.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + new_in_inheritor, + inheritor_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + new_in_inheritor, + var, + Edge::Context(ContextEdge::InheritedVariable), + ); + } + } + Ok(()) + }) + }); + } + Ok(()) + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index e9a417a1..d7e615f0 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,4 +1,6 @@ -use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; +//! Traits & blanket implementations that facilitate performing locally scoped function calls. + +use crate::{func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, @@ -8,13 +10,15 @@ use graph::{ use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; impl InternalFuncCaller for T where - T: AnalyzerBackend + Sized + GraphBackend + T: AnalyzerBackend + Sized + GraphBackend + CallerHelper { } +/// A trait for performing internally scoped function calls (i.e. *NOT* `MyContract.func(...)`) pub trait InternalFuncCaller: - AnalyzerBackend + Sized + GraphBackend + AnalyzerBackend + Sized + GraphBackend + CallerHelper { #[tracing::instrument(level = "trace", skip_all)] + /// Perform a named function call fn call_internal_named_func( &mut self, ctx: ContextNode, @@ -186,7 +190,7 @@ pub trait InternalFuncCaller: tracing::trace!("function call: {}(..)", ident.name); // It is a function call, check if we have the ident in scope let funcs = ctx.visible_funcs(self).into_expr_err(*loc)?; - // println!("visible funcs: {:#?}", funcs.iter().map(|f| f.name(self).unwrap()).collect::>()); + // filter down all funcs to those that match let possible_funcs = funcs .iter() @@ -198,89 +202,88 @@ pub trait InternalFuncCaller: .copied() .collect::>(); - if possible_funcs.is_empty() { - // this is a builtin, cast, or unknown function? - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let ret = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let ret = ret.flatten(); - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) - }) - } else if possible_funcs.len() == 1 { - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let inputs = inputs.flatten(); - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.setup_fn_call(&ident.loc, &inputs, (possible_funcs[0]).into(), ctx, None) - }) - } else { - // this is the annoying case due to function overloading & type inference on number literals - self.parse_inputs(ctx, *loc, input_exprs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or_else(|| ExprRet::Multi(vec![])); - let inputs = inputs.flatten(); - if matches!(inputs, ExprRet::CtxKilled(_)) { - ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let resizeables: Vec<_> = inputs.as_flat_vec() - .iter() - .map(|idx| { - match VarType::try_from_idx(analyzer, *idx) { - Some(VarType::BuiltIn(bn, _)) => { - matches!(analyzer.node(bn), Node::Builtin(Builtin::Uint(_)) | Node::Builtin(Builtin::Int(_)) | Node::Builtin(Builtin::Bytes(_))) - // match analyzer.node(bn) { - // Node::Builtin(Builtin::Uint(s)) if s < &256 => true, - // Node::Builtin(Builtin::Int(s)) if s < &256 => true, - // Node::Builtin(Builtin::Bytes(s)) if s < &32 => true, - // _ => false - // } - } - Some(VarType::Concrete(c)) => { - matches!(analyzer.node(c), Node::Concrete(Concrete::Uint(_, _)) | Node::Concrete(Concrete::Int(_, _)) | Node::Concrete(Concrete::Bytes(_, _))) + match possible_funcs.len() { + 0 => { + // this is a builtin, cast, or unknown function + self.parse_ctx_expr(func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let ret = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let ret = ret.flatten(); + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + }) + } + 1 => { + // there is only a single possible function + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let inputs = inputs.flatten(); + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.setup_fn_call(&ident.loc, &inputs, (possible_funcs[0]).into(), ctx, None) + }) + } + _ => { + // this is the annoying case due to function overloading & type inference on number literals + self.parse_inputs(ctx, *loc, input_exprs)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let inputs = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or_else(|| ExprRet::Multi(vec![])); + let inputs = inputs.flatten(); + if matches!(inputs, ExprRet::CtxKilled(_)) { + ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let resizeables: Vec<_> = inputs.as_flat_vec() + .iter() + .map(|idx| { + match VarType::try_from_idx(analyzer, *idx) { + Some(VarType::BuiltIn(bn, _)) => { + matches!(analyzer.node(bn), Node::Builtin(Builtin::Uint(_)) | Node::Builtin(Builtin::Int(_)) | Node::Builtin(Builtin::Bytes(_))) + } + Some(VarType::Concrete(c)) => { + matches!(analyzer.node(c), Node::Concrete(Concrete::Uint(_, _)) | Node::Concrete(Concrete::Int(_, _)) | Node::Concrete(Concrete::Bytes(_, _))) + } + _ => false } - _ => false - } - }) - .collect(); - if let Some(func) = analyzer.disambiguate_fn_call( - &ident.name, - resizeables, - &inputs, - &possible_funcs, - ) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) - } else { - Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not disambiguate function, default input types: {}, possible functions: {:#?}", - inputs.try_as_func_input_str(analyzer), - possible_funcs - .iter() - .map(|i| i.name(analyzer).unwrap()) - .collect::>() - ), - )) - } - }) + }) + .collect(); + if let Some(func) = analyzer.disambiguate_fn_call( + &ident.name, + resizeables, + &inputs, + &possible_funcs, + ) { + analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + } else { + Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not disambiguate function, default input types: {}, possible functions: {:#?}", + inputs.try_as_func_input_str(analyzer), + possible_funcs + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect::>() + ), + )) + } + }) + } } } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 3307fb04..d2507e2e 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -8,7 +8,10 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; impl AbiCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling abi-namespaced intrinsic functions pub trait AbiCaller: AnalyzerBackend + Sized { + /// Perform an `abi.<..>` function call fn abi_call( &mut self, func_name: String, @@ -91,7 +94,7 @@ pub trait AbiCaller: AnalyzerBackend + Siz | "abi.encodeCall" | "abi.encodeWithSignature" | "abi.encodeWithSelector" => { - // currently we dont support concrete abi encoding, TODO + // TODO: Support concrete abi encoding let bn = self.builtin_or_add(Builtin::DynamicBytes); let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; let node = self.add_node(Node::ContextVar(cvar)); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs index 67fbf8d1..8303d01d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -8,7 +8,10 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; impl AddressCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling address-based intrinsic functions pub trait AddressCaller: AnalyzerBackend + Sized { + /// Perform an `address.<..>` function call fn address_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 58a93628..8a898252 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -10,7 +10,10 @@ use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; impl ArrayCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling array-based intrinsic functions pub trait ArrayCaller: AnalyzerBackend + Sized { + /// Perform an `array.<..>` function call fn array_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index b29f08c1..67e9ea18 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -8,7 +8,10 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; impl BlockCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling block-based intrinsic functions pub trait BlockCaller: AnalyzerBackend + Sized { + /// Perform a `block` function call fn block_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 86bed531..71735a84 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; use graph::{ elem::*, @@ -10,10 +10,13 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; impl ConstructorCaller for T where - T: AnalyzerBackend + Sized + T: AnalyzerBackend + Sized + CallerHelper { } -pub trait ConstructorCaller: AnalyzerBackend + Sized { + +/// Trait for constructing compound types like contracts, structs and arrays +pub trait ConstructorCaller: AnalyzerBackend + Sized + CallerHelper { + /// Construct an array fn construct_array( &mut self, func_idx: NodeIdx, @@ -97,6 +100,7 @@ pub trait ConstructorCaller: AnalyzerBackend DynBuiltinCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling dynamic builtin-based intrinsic functions, like `concat` pub trait DynBuiltinCaller: AnalyzerBackend + Sized { + /// Perform a dynamic builtin type's builtin function call fn dyn_builtin_call( &mut self, func_name: String, @@ -30,6 +33,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend CallerParts for T where + TypesCaller + ConstructorCaller + MsgCaller + + CallerHelper { } @@ -46,6 +49,8 @@ impl IntrinsicFuncCaller for T where T: AnalyzerBackend + Sized + CallerParts { } + +/// Perform calls to intrinsic functions like `abi.encode`, `array.push`, `require`, and constructors etc. pub trait IntrinsicFuncCaller: AnalyzerBackend + Sized + CallerParts { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs index 0345a08a..9a33e6da 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/mod.rs @@ -1,3 +1,4 @@ +//! Traits & blanket implementations that facilitate performing intrinsic function calls. mod abi; mod address; mod array; diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs index cf3f371f..d2b3f1d5 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs @@ -8,7 +8,10 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; impl MsgCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling msg-based intrinsic functions, like `gasleft` pub trait MsgCaller: AnalyzerBackend + Sized { + /// Perform a msg's builtin function call, like `gasleft()` fn msg_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 64c7f09f..bfe38af9 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; use graph::{ nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, @@ -8,9 +8,12 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; -impl PrecompileCaller for T where T: AnalyzerBackend + Sized +impl PrecompileCaller for T where T: AnalyzerBackend + Sized + CallerHelper {} -pub trait PrecompileCaller: AnalyzerBackend + Sized { + +/// Trait for calling precompile intrinsic functions, like `ecrecover` +pub trait PrecompileCaller: AnalyzerBackend + Sized + CallerHelper { + /// Perform a precompile's function call, like `ecrecover` fn precompile_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index e8fd3f11..acbf38ce 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; +use crate::{require::Require, ContextBuilder, ExprErr, func_call::helper::CallerHelper, IntoExprErr}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, @@ -7,8 +7,11 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; -impl SolidityCaller for T where T: AnalyzerBackend + Sized {} -pub trait SolidityCaller: AnalyzerBackend + Sized { +impl SolidityCaller for T where T: AnalyzerBackend + Sized + CallerHelper {} + +/// Trait for calling solidity's intrinsic functions, like `keccak256` +pub trait SolidityCaller: AnalyzerBackend + Sized + CallerHelper { + /// Perform a solidity intrinsic function call, like `keccak256` fn solidity_call( &mut self, func_name: String, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index ee5b421c..82875d94 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, FuncCaller, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; use graph::{ elem::*, @@ -10,7 +10,10 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; impl TypesCaller for T where T: AnalyzerBackend + Sized {} + +/// Trait for calling type-based intrinsic functions, like `wrap` pub trait TypesCaller: AnalyzerBackend + Sized { + /// Perform a type-based intrinsic function call, like `wrap` fn types_call( &mut self, func_name: String, @@ -116,6 +119,7 @@ pub trait TypesCaller: AnalyzerBackend + S } } + /// Perform a cast of a type fn cast( &mut self, ty: Builtin, diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index 33c82738..a4ea9278 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,1197 +1,6 @@ -use crate::{ - internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, - namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, IntoExprErr, -}; - -use graph::{ - nodes::{ - CallFork, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, FunctionReturnNode, ModifierState, - }, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, VarType, -}; -use shared::{NodeIdx, StorageLocation}; - -use solang_parser::helpers::CodeLocation; -use solang_parser::pt::{Expression, Loc, NamedArgument}; -use std::cell::RefCell; -use std::collections::BTreeMap; -use std::rc::Rc; - +pub mod helper; pub mod internal_call; pub mod intrinsic_call; pub mod modifier; pub mod namespaced_call; - -impl FuncCaller for T where - T: AnalyzerBackend + Sized + GraphBackend -{ -} -pub trait FuncCaller: - GraphBackend + AnalyzerBackend + Sized -{ - #[tracing::instrument(level = "trace", skip_all)] - fn named_fn_call_expr( - &mut self, - ctx: ContextNode, - loc: &Loc, - func_expr: &Expression, - input_exprs: &[NamedArgument], - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_named_func(ctx, loc, member_expr, ident, input_exprs) - } - Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), - e => Err(ExprErr::IntrinsicNamedArgs( - *loc, - format!("Cannot call intrinsic functions with named arguments. Call: {e:?}"), - )), - } - } - #[tracing::instrument(level = "trace", skip_all)] - fn fn_call_expr( - &mut self, - ctx: ContextNode, - loc: &Loc, - func_expr: &Expression, - input_exprs: &[Expression], - ) -> Result<(), ExprErr> { - use solang_parser::pt::Expression::*; - match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_func(ctx, loc, member_expr, ident, input_exprs) - } - Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, input_exprs), - _ => { - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Function call to nonexistent function".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) - }) - } - } - } - - fn match_intrinsic_fallback( - &mut self, - ctx: ContextNode, - loc: &Loc, - input_exprs: &[Expression], - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - ExprRet::Single(func_idx) | ExprRet::SingleLiteral(func_idx) => { - self.intrinsic_func_call(loc, input_exprs, func_idx, ctx) - } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|ret| self.match_intrinsic_fallback(ctx, loc, input_exprs, ret)), - ExprRet::CtxKilled(kind) => ctx.kill(self, *loc, kind).into_expr_err(*loc), - ExprRet::Null => Ok(()), - } - } - - /// Disambiguates a function call by their inputs (length & type) - fn disambiguate_fn_call( - &mut self, - fn_name: &str, - literals: Vec, - input_paths: &ExprRet, - funcs: &[FunctionNode], - ) -> Option { - let input_paths = input_paths.clone().flatten(); - // try to find the function based on naive signature - // This doesnt do type inference on NumberLiterals (i.e. 100 could be uintX or intX, and there could - // be a function that takes an int256 but we evaled as uint256) - let fn_sig = format!("{}{}", fn_name, input_paths.try_as_func_input_str(self)); - if let Some(func) = funcs.iter().find(|func| func.name(self).unwrap() == fn_sig) { - return Some(*func); - } - - // filter by input len - let inputs = input_paths.as_flat_vec(); - let funcs: Vec<&FunctionNode> = funcs - .iter() - .filter(|func| func.params(self).len() == inputs.len()) - .collect(); - - if funcs.len() == 1 { - return Some(*funcs[0]); - } - - if !literals.iter().any(|i| *i) { - None - } else { - let funcs = funcs - .iter() - .filter(|func| { - let params = func.params(self); - params - .iter() - .zip(&inputs) - .enumerate() - .all(|(i, (param, input))| { - let param_ty = VarType::try_from_idx(self, (*param).into()).unwrap(); - let input_ty = ContextVarNode::from(*input).ty(self).unwrap(); - if param_ty.ty_eq(input_ty, self).unwrap() { - true - } else if literals[i] { - let possibilities = ContextVarNode::from(*input) - .ty(self) - .unwrap() - .possible_builtins_from_ty_inf(self); - let param_ty = param.ty(self).unwrap(); - match self.node(param_ty) { - Node::Builtin(b) => possibilities.contains(b), - _ => false, - } - } else { - false - } - }) - }) - .collect::>(); - if funcs.len() == 1 { - Some(**funcs[0]) - } else { - // this would be invalid solidity, likely the user needs to perform a cast - None - } - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_inputs( - &mut self, - ctx: ContextNode, - loc: Loc, - inputs: &[Expression], - ) -> Result<(), ExprErr> { - let append = if ctx.underlying(self).into_expr_err(loc)?.tmp_expr.is_empty() { - Rc::new(RefCell::new(true)) - } else { - Rc::new(RefCell::new(false)) - }; - - inputs.iter().try_for_each(|input| { - self.parse_ctx_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Inputs did not have left hand sides".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) - })?; - if !inputs.is_empty() { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Inputs did not have left hand sides".to_string(), - )); - }; - ctx.push_expr(ret, analyzer).into_expr_err(loc) - }) - } else { - Ok(()) - } - } - - /// Setups up storage variables for a function call and calls it - fn setup_fn_call( - &mut self, - loc: &Loc, - inputs: &ExprRet, - func_idx: NodeIdx, - ctx: ContextNode, - func_call_str: Option<&str>, - ) -> Result<(), ExprErr> { - // if we have a single match thats our function - let var = match ContextVar::maybe_from_user_ty(self, *loc, func_idx) { - Some(v) => v, - None => panic!( - "Could not create context variable from user type: {:?}", - self.node(func_idx) - ), - }; - - let new_cvarnode = self.add_node(Node::ContextVar(var)); - ctx.add_var(new_cvarnode.into(), self).into_expr_err(*loc)?; - self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); - if let Some(func_node) = ContextVarNode::from(new_cvarnode) - .ty(self) - .into_expr_err(*loc)? - .func_node(self) - { - self.func_call(ctx, *loc, inputs, func_node, func_call_str, None) - } else { - unreachable!() - } - } - - /// Matches the input kinds and performs the call - fn func_call( - &mut self, - ctx: ContextNode, - loc: Loc, - input_paths: &ExprRet, - func: FunctionNode, - func_call_str: Option<&str>, - modifier_state: Option, - ) -> Result<(), ExprErr> { - let params = func.params(self); - let input_paths = input_paths.clone().flatten(); - if input_paths.has_killed() { - return ctx - .kill(self, loc, input_paths.killed_kind().unwrap()) - .into_expr_err(loc); - } - match input_paths { - ExprRet::Single(input_var) | ExprRet::SingleLiteral(input_var) => { - // if we get a single var, we expect the func to only take a single - // variable - self.func_call_inner( - false, - ctx, - func, - loc, - vec![ContextVarNode::from(input_var).latest_version(self)], - params, - func_call_str, - modifier_state, - ) - } - ExprRet::Multi(ref inputs) => { - if ExprRet::Multi(inputs.to_vec()).flatten().has_killed() { - return ctx - .kill( - self, - loc, - ExprRet::Multi(inputs.to_vec()).killed_kind().unwrap(), - ) - .into_expr_err(loc); - } - // check if the inputs length matchs func params length - // if they do, check that none are forks - if inputs.len() == params.len() { - let input_vars = inputs - .iter() - .map(|expr_ret| { - let var = expr_ret.expect_single().into_expr_err(loc)?; - Ok(ContextVarNode::from(var).latest_version(self)) - }) - .collect::, ExprErr>>()?; - self.func_call_inner( - false, - ctx, - func, - loc, - input_vars, - params, - func_call_str, - modifier_state, - ) - } else { - Err(ExprErr::InvalidFunctionInput( - loc, - format!( - "Length mismatch: {inputs:?} {params:?}, inputs as vars: {}, ctx: {}", - ExprRet::Multi(inputs.to_vec()).debug_str(self), - ctx.path(self) - ), - )) - } - } - e => todo!("here: {:?}", e), - } - } - - fn create_call_ctx( - &mut self, - curr_ctx: ContextNode, - loc: Loc, - func_node: FunctionNode, - modifier_state: Option, - ) -> Result { - let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; - let ctx = Context::new_subctx( - curr_ctx, - None, - loc, - None, - Some(func_node), - fn_ext, - self, - modifier_state, - ) - .into_expr_err(loc)?; - let callee_ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - curr_ctx - .set_child_call(callee_ctx, self) - .into_expr_err(loc)?; - let ctx_fork = self.add_node(Node::FunctionCall); - self.add_edge(ctx_fork, curr_ctx, Edge::Context(ContextEdge::Subcontext)); - self.add_edge(ctx_fork, func_node, Edge::Context(ContextEdge::Call)); - self.add_edge( - NodeIdx::from(callee_ctx.0), - ctx_fork, - Edge::Context(ContextEdge::Subcontext), - ); - Ok(callee_ctx) - } - - /// Maps inputs to function parameters such that if there is a renaming i.e. `a(uint256 x)` is called via `a(y)`, - /// we map `y -> x` for future lookups - fn map_inputs_to_params( - &mut self, - loc: Loc, - entry_call: bool, - params: Vec, - inputs: Vec, - callee_ctx: ContextNode, - ) -> Result, ExprErr> { - Ok(params - .iter() - .zip(inputs.iter()) - .filter_map(|(param, input)| { - if !entry_call { - if let Some(name) = - self.add_if_err(param.maybe_name(self).into_expr_err(loc))? - { - let res = input - .latest_version(self) - .underlying(self) - .into_expr_err(loc) - .cloned(); - let mut new_cvar = self.add_if_err(res)?; - new_cvar.loc = Some(param.loc(self).unwrap()); - new_cvar.name = name.clone(); - new_cvar.display_name = name; - new_cvar.is_tmp = false; - new_cvar.storage = if let Some(StorageLocation::Storage(_)) = - param.underlying(self).unwrap().storage - { - new_cvar.storage - } else { - None - }; - - if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) - { - let ty = new_cvar.ty.clone(); - if !ty.ty_eq(¶m_ty, self).unwrap() { - if let Some(new_ty) = ty.try_cast(¶m_ty, self).unwrap() { - new_cvar.ty = new_ty; - } - } - } - - let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); - self.add_edge( - node, - input.latest_version(self), - Edge::Context(ContextEdge::InputVariable), - ); - - if let (Some(r), Some(r2)) = - (node.range(self).unwrap(), param.range(self).unwrap()) - { - let new_min = - r.range_min().into_owned().cast(r2.range_min().into_owned()); - let new_max = - r.range_max().into_owned().cast(r2.range_max().into_owned()); - let res = node.try_set_range_min(self, new_min).into_expr_err(loc); - self.add_if_err(res); - let res = node.try_set_range_max(self, new_max).into_expr_err(loc); - self.add_if_err(res); - let res = node - .try_set_range_exclusions(self, r.exclusions) - .into_expr_err(loc); - self.add_if_err(res); - } - callee_ctx.add_var(node, self).unwrap(); - self.add_edge(node, callee_ctx, Edge::Context(ContextEdge::Variable)); - Some((*input, node)) - } else { - None - } - } else { - None - } - }) - .collect::>()) - } - - /// Checks if there are any modifiers and executes them prior to executing the function - #[tracing::instrument(level = "trace", skip_all)] - fn func_call_inner( - &mut self, - entry_call: bool, - ctx: ContextNode, - func_node: FunctionNode, - loc: Loc, - inputs: Vec, - params: Vec, - func_call_str: Option<&str>, - modifier_state: Option, - ) -> Result<(), ExprErr> { - // pseudocode: - // 1. Create context for the call - // 2. Check for modifiers - // 3. Call modifier 0, then 1, then 2, ... then N. - // 4. Call this function - // 5. Finish modifier N.. then 2, then 1, then 0 - let callee_ctx = if entry_call { - ctx - } else { - self.create_call_ctx(ctx, loc, func_node, modifier_state)? - }; - - // TODO: implement joining - // if !entry_call { - // let mapping = params - // .iter() - // .zip(inputs.iter()) - // .map(|(param, input)| (*input, *param)) - // .collect::>(); - // ctx.join(func_node, &mapping, self); - // } - - // handle remapping of variable names and bringing variables into the new context - let renamed_inputs = - self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; - - // begin modifier handling by making sure modifiers were set - if !func_node.modifiers_set(self).into_expr_err(loc)? { - self.set_modifiers(func_node, ctx)?; - } - - // get modifiers - let mods = func_node.modifiers(self); - self.apply_to_edges(callee_ctx, loc, &|analyzer, callee_ctx, loc| { - if let Some(mod_state) = &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state { - // we are iterating through modifiers - if mod_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = mod_state.clone(); - mstate.num += 1; - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, mstate) - } else { - // out of modifiers, execute the actual function call - analyzer.execute_call_inner( - loc, - ctx, - callee_ctx, - func_node, - &renamed_inputs, - func_call_str, - ) - } - } else if !mods.is_empty() { - // we have modifiers and havent executed them, start the process of executing them - let state = - ModifierState::new(0, loc, func_node, callee_ctx, ctx, renamed_inputs.clone()); - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, state) - } else { - // no modifiers, just execute the function - analyzer.execute_call_inner( - loc, - ctx, - callee_ctx, - func_node, - &renamed_inputs, - func_call_str, - ) - } - }) - } - - /// Actually executes the function - #[tracing::instrument(level = "trace", skip_all)] - fn execute_call_inner( - &mut self, - loc: Loc, - caller_ctx: ContextNode, - callee_ctx: ContextNode, - func_node: FunctionNode, - _renamed_inputs: &BTreeMap, - func_call_str: Option<&str>, - ) -> Result<(), ExprErr> { - if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { - // add return nodes into the subctx - func_node - .returns(self) - .collect::>() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - callee_ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); - } - }); - - self.parse_ctx_statement(&body, false, Some(callee_ctx)); - self.ctx_rets(loc, caller_ctx, callee_ctx) - } else { - let ret_ctx = Context::new_subctx( - callee_ctx, - Some(caller_ctx), - loc, - None, - None, - false, - self, - caller_ctx - .underlying(self) - .into_expr_err(loc)? - .modifier_state - .clone(), - ) - .unwrap(); - let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); - - let res = callee_ctx - .set_child_call(ret_subctx, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { - func_node - .returns(analyzer) - .collect::>() - .into_iter() - .try_for_each(|ret| { - let underlying = ret.underlying(analyzer).unwrap(); - let mut var = - ContextVar::new_from_func_ret(ctx, analyzer, underlying.clone()) - .unwrap() - .expect("No type for return variable?"); - if let Some(func_call) = &func_call_str { - var.name = - format!("{}_{}", func_call, callee_ctx.new_tmp(analyzer).unwrap()); - var.display_name = func_call.to_string(); - } - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Return)); - ctx.push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc)?; - Ok(()) - }) - }) - } - } - - fn ctx_rets( - &mut self, - loc: Loc, - caller_ctx: ContextNode, - callee_ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!( - "Handling function call return for: {}, {}, depth: {:?}, {:?}", - caller_ctx.path(self), - callee_ctx.path(self), - caller_ctx.depth(self), - callee_ctx.depth(self), - ); - match callee_ctx.underlying(self).into_expr_err(loc)?.child { - Some(CallFork::Fork(w1, w2)) => { - self.ctx_rets(loc, caller_ctx, w1)?; - self.ctx_rets(loc, caller_ctx, w2)?; - Ok(()) - } - Some(CallFork::Call(c)) - if c.underlying(self).into_expr_err(loc)?.depth - >= caller_ctx.underlying(self).into_expr_err(loc)?.depth => - { - // follow rabbit hole - self.ctx_rets(loc, caller_ctx, c)?; - Ok(()) - } - _ => { - if callee_ctx.is_killed(self).into_expr_err(loc)? { - return Ok(()); - } - let callee_depth = callee_ctx.underlying(self).into_expr_err(loc)?.depth; - let caller_depth = caller_ctx.underlying(self).into_expr_err(loc)?.depth; - if callee_depth != caller_depth { - let ctx = Context::new_subctx( - callee_ctx, - Some(caller_ctx), - loc, - None, - None, - false, - self, - caller_ctx - .underlying(self) - .into_expr_err(loc)? - .modifier_state - .clone(), - ) - .unwrap(); - let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); - - let res = callee_ctx - .set_child_call(ret_subctx, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); - - if rets.is_empty() { - let func_rets: Vec = callee_ctx - .associated_fn(self) - .into_expr_err(loc)? - .returns(self) - .collect(); - func_rets - .iter() - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) - .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; - - // add unnamed rets - func_rets - .into_iter() - .filter(|ret| ret.maybe_name(self).unwrap().is_none()) - .collect::>() - .iter() - .try_for_each(|ret| { - let ret_loc = ret.loc(self).into_expr_err(loc)?; - let cvar = ContextVar::new_from_func_ret( - callee_ctx, - self, - ret.underlying(self).into_expr_err(loc)?.clone(), - ) - .into_expr_err(loc)? - .unwrap(); - let cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); - callee_ctx.add_var(cvar, self).into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Variable), - ); - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } - - let handle_rets = rets.iter().all(|(_, node)| node.is_some()); - if handle_rets { - let ret = rets - .into_iter() - .enumerate() - .map(|(i, (_, node))| { - let tmp_ret = node - .unwrap() - .as_tmp( - callee_ctx.underlying(self).unwrap().loc, - ret_subctx, - self, - ) - .unwrap(); - tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; - tmp_ret - .underlying_mut(self) - .into_expr_err(loc)? - .display_name = format!( - "{}.{}", - callee_ctx.associated_fn_name(self).unwrap(), - i - ); - ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; - self.add_edge( - tmp_ret, - ret_subctx, - Edge::Context(ContextEdge::Variable), - ); - Ok(ExprRet::Single(tmp_ret.into())) - }) - .collect::>()?; - ret_subctx - .push_expr(ExprRet::Multi(ret), self) - .into_expr_err(loc)?; - } - Ok(()) - } else { - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); - - if rets.is_empty() { - callee_ctx - .associated_fn(self) - .into_expr_err(loc)? - .returns(self) - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) - .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } - if rets.iter().all(|(_, node)| node.is_some()) { - callee_ctx - .push_expr( - ExprRet::Multi( - rets.iter() - .map(|(_, node)| ExprRet::Single((node.unwrap()).into())) - .collect(), - ), - self, - ) - .into_expr_err(loc) - } else { - Ok(()) - } - } - } - } - } - - /// Calls a modifier for a function - #[tracing::instrument(level = "trace", skip_all)] - fn call_modifier_for_fn( - &mut self, - loc: Loc, - func_ctx: ContextNode, - func_node: FunctionNode, - mod_state: ModifierState, - ) -> Result<(), ExprErr> { - let mod_node = func_node.modifiers(self)[mod_state.num]; - tracing::trace!( - "calling modifier {} for func {}", - mod_node.name(self).into_expr_err(loc)?, - func_node.name(self).into_expr_err(loc)? - ); - - let input_exprs = func_node - .modifier_input_vars(mod_state.num, self) - .into_expr_err(loc)?; - - input_exprs - .iter() - .try_for_each(|expr| self.parse_ctx_expr(expr, func_ctx))?; - self.apply_to_edges(func_ctx, loc, &|analyzer, ctx, loc| { - let input_paths = if input_exprs.is_empty() { - ExprRet::Multi(vec![]) - } else { - let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - format!("No inputs to modifier, expected: {}", input_exprs.len()), - )); - }; - - if matches!(input_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(input_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - input_paths - }; - - analyzer.func_call( - ctx, - loc, - &input_paths, - mod_node, - None, - Some(mod_state.clone()), - ) - }) - } - - /// Resumes the parent function of a modifier - #[tracing::instrument(level = "trace", skip_all)] - fn resume_from_modifier( - &mut self, - ctx: ContextNode, - modifier_state: ModifierState, - ) -> Result<(), ExprErr> { - let mods = modifier_state.parent_fn.modifiers(self); - self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { - if modifier_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = modifier_state.clone(); - mstate.num += 1; - - let loc = mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc; - - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - loc, - None, - None, - false, - analyzer, - Some(modifier_state.clone()), - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; - - analyzer.call_modifier_for_fn( - mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc, - new_parent_subctx, - mstate.parent_fn, - mstate, - )?; - Ok(()) - } else { - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - modifier_state.loc, - None, - None, - false, - analyzer, - None, - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; - - // actually execute the parent function - analyzer.execute_call_inner( - modifier_state.loc, - ctx, - new_parent_subctx, - modifier_state.parent_fn, - &modifier_state.renamed_inputs, - None, - )?; - - fn inherit_return_from_call( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - loc: Loc, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - let mctx = - Context::new_subctx(ctx, Some(ctx), loc, None, None, false, analyzer, None) - .unwrap(); - let modifier_after_subctx = - ContextNode::from(analyzer.add_node(Node::Context(mctx))); - - ctx.set_child_call(modifier_after_subctx, analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - modifier_after_subctx, - ctx, - Edge::Context(ContextEdge::Continue), - ); - - let ret = ctx.underlying(analyzer).unwrap().ret.clone(); - modifier_after_subctx.underlying_mut(analyzer).unwrap().ret = ret; - Ok(()) - } - - analyzer.apply_to_edges(new_parent_subctx, loc, &|analyzer, ctx, _loc| { - inherit_return_from_call(analyzer, modifier_state.loc, ctx) - }) - - // if edges.is_empty() { - // inherit_return_from_call(analyzer, modifier_state.loc, new_parent_subctx)?; - // } else { - // edges.iter().try_for_each(|i| { - // inherit_return_from_call(analyzer, modifier_state.loc, *i)?; - // Ok(()) - // })?; - // } - // Ok(()) - } - }) - } - - /// Inherit the input changes from a function call - fn inherit_input_changes( - &mut self, - loc: Loc, - to_ctx: ContextNode, - from_ctx: ContextNode, - renamed_inputs: &BTreeMap, - ) -> Result<(), ExprErr> { - if to_ctx != from_ctx { - self.apply_to_edges(to_ctx, loc, &|analyzer, to_ctx, loc| { - renamed_inputs - .iter() - .try_for_each(|(input_var, updated_var)| { - let new_input = analyzer.advance_var_in_ctx( - input_var.latest_version(analyzer), - loc, - to_ctx, - )?; - let latest_updated = updated_var.latest_version(analyzer); - if let Some(updated_var_range) = - latest_updated.range(analyzer).into_expr_err(loc)? - { - let res = new_input - .set_range_min(analyzer, updated_var_range.range_min().into_owned()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_input - .set_range_max(analyzer, updated_var_range.range_max().into_owned()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_input - .set_range_exclusions( - analyzer, - updated_var_range.range_exclusions(), - ) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - } - Ok(()) - }) - })?; - } - Ok(()) - } - - /// Inherit the input changes from a function call - fn modifier_inherit_return(&mut self, mod_ctx: ContextNode, fn_ctx: ContextNode) { - let ret = fn_ctx.underlying(self).unwrap().ret.clone(); - mod_ctx.underlying_mut(self).unwrap().ret = ret; - } - - /// Inherit the storage changes from a function call - fn inherit_storage_changes( - &mut self, - loc: Loc, - inheritor_ctx: ContextNode, - grantor_ctx: ContextNode, - ) -> Result<(), ExprErr> { - if inheritor_ctx != grantor_ctx { - return self.apply_to_edges(inheritor_ctx, loc, &|analyzer, inheritor_ctx, loc| { - let vars = grantor_ctx.local_vars(analyzer).clone(); - vars.iter().try_for_each(|(name, old_var)| { - let var = old_var.latest_version(analyzer); - let underlying = var.underlying(analyzer).into_expr_err(loc)?; - if var.is_storage(analyzer).into_expr_err(loc)? { - if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { - let new_inheritor_var = analyzer - .advance_var_in_ctx( - inheritor_var, - underlying.loc.expect("No loc for val change"), - inheritor_ctx, - ) - .unwrap(); - let _ = new_inheritor_var - .set_range_min(analyzer, r.range_min().into_owned()); - let _ = new_inheritor_var - .set_range_max(analyzer, r.range_max().into_owned()); - let _ = new_inheritor_var - .set_range_exclusions(analyzer, r.range_exclusions()); - } - } else { - let new_in_inheritor = - analyzer.add_node(Node::ContextVar(underlying.clone())); - inheritor_ctx - .add_var(new_in_inheritor.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - new_in_inheritor, - inheritor_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - new_in_inheritor, - var, - Edge::Context(ContextEdge::InheritedVariable), - ); - } - } - Ok(()) - }) - }); - } - Ok(()) - } - - fn modifiers( - &mut self, - ctx: ContextNode, - func: FunctionNode, - ) -> Result, ExprErr> { - use std::fmt::Write; - let binding = func.underlying(self).unwrap().clone(); - let modifiers = binding.modifiers_as_base(); - if modifiers.is_empty() { - Ok(vec![]) - } else { - let res = modifiers - .iter() - .map(|modifier| { - assert_eq!(modifier.name.identifiers.len(), 1); - // construct arg string for function selector - let mut mod_name = format!("{}", modifier.name.identifiers[0]); - if let Some(args) = &modifier.args { - let args_str = args - .iter() - .map(|expr| { - let mctx = Context::new_subctx( - ctx, - None, - Loc::Implicit, - None, - None, - false, - self, - None, - ) - .into_expr_err(Loc::Implicit)?; - let callee_ctx = - ContextNode::from(self.add_node(Node::Context(mctx))); - let _res = ctx.set_child_call(callee_ctx, self); - self.parse_ctx_expr(expr, callee_ctx)?; - let f: Vec = - self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { - if let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - { - Ok(ret.try_as_func_input_str(analyzer)) - } else { - Err(ExprErr::ParseError( - loc, - "Bad modifier parse".to_string(), - )) - } - })?; - - ctx.delete_child(self).into_expr_err(expr.loc())?; - Ok(f.first().unwrap().clone()) - }) - .collect::, ExprErr>>()? - .join(", "); - let _ = write!(mod_name, "{args_str}"); - } else { - let _ = write!(mod_name, "()"); - } - let _ = write!(mod_name, ""); - let found: Option = ctx - .visible_modifiers(self) - .unwrap() - .iter() - .find(|modifier| modifier.name(self).unwrap() == mod_name) - .copied(); - Ok(found) - }) - .collect::>, ExprErr>>()? - .into_iter() - .flatten() - .collect::>(); - Ok(res) - } - } - - fn set_modifiers(&mut self, func: FunctionNode, ctx: ContextNode) -> Result<(), ExprErr> { - let modifiers = self.modifiers(ctx, func)?; - modifiers - .iter() - .enumerate() - .for_each(|(i, modifier)| self.add_edge(*modifier, func, Edge::FuncModifier(i))); - func.underlying_mut(self).unwrap().modifiers_set = true; - Ok(()) - } -} +pub mod func_caller; diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index a6d56a05..bec4128e 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -1,31 +1,288 @@ -use crate::{ExprErr, FuncCaller, IntoExprErr}; +//! Traits & blanket implementations that facilitate performing modifier function calls. + +use crate::helper::CallerHelper; +use crate::{ + ContextBuilder, ExprErr, IntoExprErr, func_caller::FuncCaller +}; use graph::{ - nodes::{ContextNode, ExprRet, FunctionNode}, - AnalyzerBackend, GraphBackend, + nodes::{ + Context, ContextNode, ExprRet, FunctionNode, ModifierState, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; -use solang_parser::pt::{Expression, Loc}; +use solang_parser::pt::{Expression, Loc, CodeLocation}; impl ModifierCaller for T where - T: AnalyzerBackend + Sized + GraphBackend + T: AnalyzerBackend + Sized + GraphBackend + FuncCaller + CallerHelper { } +/// A trait for dealing with modifier calls pub trait ModifierCaller: - GraphBackend + AnalyzerBackend + Sized + GraphBackend + AnalyzerBackend + Sized + FuncCaller + CallerHelper { - fn handle_modifiers( + /// Calls a modifier for a function + #[tracing::instrument(level = "trace", skip_all)] + fn call_modifier_for_fn( &mut self, - ctx: ContextNode, loc: Loc, - _input_paths: &ExprRet, + func_ctx: ContextNode, + func_node: FunctionNode, + mod_state: ModifierState, + ) -> Result<(), ExprErr> { + let mod_node = func_node.modifiers(self)[mod_state.num]; + tracing::trace!( + "calling modifier {} for func {}", + mod_node.name(self).into_expr_err(loc)?, + func_node.name(self).into_expr_err(loc)? + ); + + let input_exprs = func_node + .modifier_input_vars(mod_state.num, self) + .into_expr_err(loc)?; + + input_exprs + .iter() + .try_for_each(|expr| self.parse_ctx_expr(expr, func_ctx))?; + self.apply_to_edges(func_ctx, loc, &|analyzer, ctx, loc| { + let input_paths = if input_exprs.is_empty() { + ExprRet::Multi(vec![]) + } else { + let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + format!("No inputs to modifier, expected: {}", input_exprs.len()), + )); + }; + + if matches!(input_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(input_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + input_paths + }; + + analyzer.func_call( + ctx, + loc, + &input_paths, + mod_node, + None, + Some(mod_state.clone()), + ) + }) + } + + /// Resumes the parent function of a modifier + #[tracing::instrument(level = "trace", skip_all)] + fn resume_from_modifier( + &mut self, + ctx: ContextNode, + modifier_state: ModifierState, + ) -> Result<(), ExprErr> { + let mods = modifier_state.parent_fn.modifiers(self); + self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { + if modifier_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = modifier_state.clone(); + mstate.num += 1; + + let loc = mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc; + + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + loc, + None, + None, + false, + analyzer, + Some(modifier_state.clone()), + ) + .unwrap(); + let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); + + analyzer.add_edge( + new_parent_subctx, + modifier_state.parent_ctx, + Edge::Context(ContextEdge::Continue), + ); + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; + + analyzer.call_modifier_for_fn( + mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc, + new_parent_subctx, + mstate.parent_fn, + mstate, + )?; + Ok(()) + } else { + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + modifier_state.loc, + None, + None, + false, + analyzer, + None, + ) + .unwrap(); + let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); + + analyzer.add_edge( + new_parent_subctx, + modifier_state.parent_ctx, + Edge::Context(ContextEdge::Continue), + ); + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; + + // actually execute the parent function + analyzer.execute_call_inner( + modifier_state.loc, + ctx, + new_parent_subctx, + modifier_state.parent_fn, + &modifier_state.renamed_inputs, + None, + )?; + + fn inherit_return_from_call( + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + let mctx = + Context::new_subctx(ctx, Some(ctx), loc, None, None, false, analyzer, None) + .unwrap(); + let modifier_after_subctx = + ContextNode::from(analyzer.add_node(Node::Context(mctx))); + + ctx.set_child_call(modifier_after_subctx, analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + modifier_after_subctx, + ctx, + Edge::Context(ContextEdge::Continue), + ); + + let ret = ctx.underlying(analyzer).unwrap().ret.clone(); + modifier_after_subctx.underlying_mut(analyzer).unwrap().ret = ret; + Ok(()) + } + + analyzer.apply_to_edges(new_parent_subctx, loc, &|analyzer, ctx, _loc| { + inherit_return_from_call(analyzer, modifier_state.loc, ctx) + }) + + // if edges.is_empty() { + // inherit_return_from_call(analyzer, modifier_state.loc, new_parent_subctx)?; + // } else { + // edges.iter().try_for_each(|i| { + // inherit_return_from_call(analyzer, modifier_state.loc, *i)?; + // Ok(()) + // })?; + // } + // Ok(()) + } + }) + } + + /// Gets the modifiers for a function + fn modifiers( + &mut self, + ctx: ContextNode, func: FunctionNode, - _func_call_str: Option, - ) -> Result { - if !func.modifiers_set(self).into_expr_err(loc)? { - self.set_modifiers(func, ctx)?; + ) -> Result, ExprErr> { + use std::fmt::Write; + let binding = func.underlying(self).unwrap().clone(); + let modifiers = binding.modifiers_as_base(); + if modifiers.is_empty() { + Ok(vec![]) + } else { + let res = modifiers + .iter() + .map(|modifier| { + assert_eq!(modifier.name.identifiers.len(), 1); + // construct arg string for function selector + let mut mod_name = format!("{}", modifier.name.identifiers[0]); + if let Some(args) = &modifier.args { + let args_str = args + .iter() + .map(|expr| { + let mctx = Context::new_subctx( + ctx, + None, + Loc::Implicit, + None, + None, + false, + self, + None, + ) + .into_expr_err(Loc::Implicit)?; + let callee_ctx = + ContextNode::from(self.add_node(Node::Context(mctx))); + let _res = ctx.set_child_call(callee_ctx, self); + self.parse_ctx_expr(expr, callee_ctx)?; + let f: Vec = + self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { + if let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + { + Ok(ret.try_as_func_input_str(analyzer)) + } else { + Err(ExprErr::ParseError( + loc, + "Bad modifier parse".to_string(), + )) + } + })?; + + ctx.delete_child(self).into_expr_err(expr.loc())?; + Ok(f.first().unwrap().clone()) + }) + .collect::, ExprErr>>()? + .join(", "); + let _ = write!(mod_name, "{args_str}"); + } else { + let _ = write!(mod_name, "()"); + } + let _ = write!(mod_name, ""); + let found: Option = ctx + .visible_modifiers(self) + .unwrap() + .iter() + .find(|modifier| modifier.name(self).unwrap() == mod_name) + .copied(); + Ok(found) + }) + .collect::>, ExprErr>>()? + .into_iter() + .flatten() + .collect::>(); + Ok(res) } + } - todo!() + /// Sets the modifiers for a function + fn set_modifiers(&mut self, func: FunctionNode, ctx: ContextNode) -> Result<(), ExprErr> { + let modifiers = self.modifiers(ctx, func)?; + modifiers + .iter() + .enumerate() + .for_each(|(i, modifier)| self.add_edge(*modifier, func, Edge::FuncModifier(i))); + func.underlying_mut(self).unwrap().modifiers_set = true; + Ok(()) } } diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 1086c7d9..2c2778c2 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,6 +1,9 @@ +//! Traits & blanket implementations that facilitate performing namespaced function calls. + use crate::{ - intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, - FuncCaller, IntoExprErr, + func_call::helper::CallerHelper, + func_call::func_caller::FuncCaller, + intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, IntoExprErr, }; use graph::{ @@ -13,13 +16,15 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; impl NameSpaceFuncCaller for T where - T: AnalyzerBackend + Sized + GraphBackend + T: AnalyzerBackend + Sized + GraphBackend + CallerHelper { } +/// A trait for performing namespaced function calls (i.e. `MyContract.myFunc(...)`) pub trait NameSpaceFuncCaller: - AnalyzerBackend + Sized + GraphBackend + AnalyzerBackend + Sized + GraphBackend + CallerHelper { #[tracing::instrument(level = "trace", skip_all)] + /// TODO: Call a namedspaced named input function, i.e. `MyContract.myFunc({a: 1, b: 2})` fn call_name_spaced_named_func( &mut self, ctx: ContextNode, @@ -33,6 +38,7 @@ pub trait NameSpaceFuncCaller: } #[tracing::instrument(level = "trace", skip_all)] + /// Call a namedspaced function, i.e. `MyContract.myFunc(...)` fn call_name_spaced_func( &mut self, ctx: ContextNode, @@ -153,6 +159,7 @@ pub trait NameSpaceFuncCaller: }) } + /// Match the expression return for getting the member node fn match_namespaced_member( &mut self, ctx: ContextNode, @@ -178,6 +185,7 @@ pub trait NameSpaceFuncCaller: } #[tracing::instrument(level = "trace", skip_all)] + /// Actually perform the namespaced function call fn call_name_spaced_func_inner( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index b3e4ace9..2e903258 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -13,7 +13,7 @@ mod loops; mod member_access; mod require; mod variable; -mod yul; +pub mod yul; pub use array::*; pub use bin_op::*; @@ -28,8 +28,8 @@ pub use loops::*; pub use member_access::*; pub use require::*; pub use variable::*; -pub use yul::*; +/// Supertrait for parsing expressions pub trait ExprParser: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env { @@ -39,7 +39,9 @@ impl ExprParser for T where { } +/// Convert some error into an expression error by attaching a code source location pub trait IntoExprErr { + /// Convert into a ExprErr fn into_expr_err(self, loc: Loc) -> Result; } @@ -53,6 +55,7 @@ impl IntoExprErr for Result { } #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +/// An error that arose from the analyzer when interpreting expressions and statements pub enum ExprErr { ParseError(Loc, String), NoLhs(Loc, String), @@ -81,12 +84,14 @@ pub enum ExprErr { } impl ExprErr { + /// Convert from a graph error pub fn from_graph_err(loc: Loc, graph_err: graph::GraphError) -> Self { Self::GraphError(loc, graph_err) } } impl ExprErr { + /// Get the code source location of the error pub fn loc(&self) -> Loc { use ExprErr::*; match self { @@ -115,6 +120,7 @@ impl ExprErr { } } + /// Get the error message pub fn msg(&self) -> &str { use ExprErr::*; match self { @@ -152,6 +158,7 @@ impl ExprErr { } } + /// Get the top-level report message pub fn report_msg(&self) -> &str { use ExprErr::*; match self { diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index a3af89d9..39af7787 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -8,7 +8,7 @@ use graph::{ use solang_parser::pt::{Expression, Loc, Parameter, ParameterList}; impl List for T where T: AnalyzerBackend + Sized {} - +/// Dealing with list parsing and operations pub trait List: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index 242834ae..de1d0837 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -13,6 +13,7 @@ use std::str::FromStr; impl Literal for T where T: AnalyzerBackend + Sized {} +/// Dealing with literal expression and parsing them into nodes pub trait Literal: AnalyzerBackend + Sized { fn number_literal( &mut self, diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index c7aec51a..bb02b142 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -11,10 +11,13 @@ impl Looper for T where T: AnalyzerBackend + Sized + GraphBackend { } + +/// Dealing with loops pub trait Looper: GraphBackend + AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] + /// Handles a for loop. Needs improvement fn for_loop( &mut self, loc: Loc, @@ -38,6 +41,7 @@ pub trait Looper: } } + /// Resets all variables referenced in the loop because we don't elegantly handle loops fn reset_vars(&mut self, loc: Loc, ctx: ContextNode, body: &Statement) -> Result<(), ExprErr> { let og_ctx = ctx; let sctx = Context::new_subctx(ctx, None, loc, None, None, false, self, None) @@ -81,6 +85,7 @@ pub trait Looper: }) } + /// Handles a while-loop fn while_loop( &mut self, loc: Loc, diff --git a/crates/solc-expressions/src/member_access/builtin_access.rs b/crates/solc-expressions/src/member_access/builtin_access.rs index b901b282..04ad8278 100644 --- a/crates/solc-expressions/src/member_access/builtin_access.rs +++ b/crates/solc-expressions/src/member_access/builtin_access.rs @@ -12,9 +12,12 @@ impl BuiltinAccess for T where T: LibraryAccess + AnalyzerBackend + Sized { } + +/// Trait for performing member access on builtin types pub trait BuiltinAccess: LibraryAccess + AnalyzerBackend + Sized { + /// Perform member access on builtin types fn builtin_member_access( &mut self, loc: Loc, diff --git a/crates/solc-expressions/src/member_access/contract_access.rs b/crates/solc-expressions/src/member_access/contract_access.rs index 28945a58..860558a8 100644 --- a/crates/solc-expressions/src/member_access/contract_access.rs +++ b/crates/solc-expressions/src/member_access/contract_access.rs @@ -9,7 +9,10 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; impl ContractAccess for T where T: AnalyzerBackend + Sized {} + +/// Trait for performing member access on a Contract pub trait ContractAccess: AnalyzerBackend + Sized { + /// Perform member access on a contract fn contract_member_access( &mut self, member_idx: NodeIdx, diff --git a/crates/solc-expressions/src/member_access/enum_access.rs b/crates/solc-expressions/src/member_access/enum_access.rs index 435ce8f9..c373e772 100644 --- a/crates/solc-expressions/src/member_access/enum_access.rs +++ b/crates/solc-expressions/src/member_access/enum_access.rs @@ -12,9 +12,12 @@ impl EnumAccess for T where T: LibraryAccess + AnalyzerBackend + Sized { } + +/// Trait for performing member access on an enum pub trait EnumAccess: LibraryAccess + AnalyzerBackend + Sized { + /// Perform member access on an enum fn enum_member_access( &mut self, _member_idx: NodeIdx, diff --git a/crates/solc-expressions/src/member_access/library_access.rs b/crates/solc-expressions/src/member_access/library_access.rs index 4a5d234d..164b5f0b 100644 --- a/crates/solc-expressions/src/member_access/library_access.rs +++ b/crates/solc-expressions/src/member_access/library_access.rs @@ -12,7 +12,10 @@ use solang_parser::pt::{Expression, Identifier}; use std::collections::BTreeSet; impl LibraryAccess for T where T: AnalyzerBackend + Sized {} + +/// Trait for getting library functions for a type pub trait LibraryAccess: AnalyzerBackend + Sized { + /// Search for a library function by name fn library_func_search( &mut self, ctx: ContextNode, @@ -37,6 +40,7 @@ pub trait LibraryAccess: AnalyzerBackend + }) } + /// Get all possible library functions fn possible_library_funcs(&mut self, ctx: ContextNode, ty: NodeIdx) -> BTreeSet { let mut funcs: BTreeSet = BTreeSet::new(); if let Some(associated_contract) = ctx.maybe_associated_contract(self).unwrap() { diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 3923db87..79657c65 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -10,8 +10,10 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Identifier, Loc}; impl ListAccess for T where T: AnalyzerBackend + Sized {} +/// Handles list/array member access (indices, length, etc) pub trait ListAccess: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] + /// Access an index of a list/array fn index_access( &mut self, loc: Loc, @@ -35,6 +37,7 @@ pub trait ListAccess: AnalyzerBackend + Si } #[tracing::instrument(level = "trace", skip_all)] + /// Match on the [`ExprRet`] of a index access expression fn match_index_access( &mut self, index_paths: &ExprRet, @@ -91,6 +94,7 @@ pub trait ListAccess: AnalyzerBackend + Si } #[tracing::instrument(level = "trace", skip_all)] + /// Get the length member of an array/list fn length( &mut self, loc: Loc, @@ -114,6 +118,7 @@ pub trait ListAccess: AnalyzerBackend + Si } #[tracing::instrument(level = "trace", skip_all)] + /// Get the length member of an array/list and create it as a temporary variable fn tmp_length( &mut self, arr: ContextVarNode, @@ -188,6 +193,7 @@ pub trait ListAccess: AnalyzerBackend + Si } #[tracing::instrument(level = "trace", skip_all)] + /// Get the length member of an array/list fn match_length( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index 370114ff..fd8c7129 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -18,6 +18,8 @@ impl MemberAccessParts for T where T: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess { } + +/// Supertrait that coalesces various member access traits pub trait MemberAccessParts: BuiltinAccess + ContractAccess + EnumAccess + ListAccess + StructAccess { @@ -27,85 +29,12 @@ impl MemberAccess for T where T: MemberAccessParts + AnalyzerBackend + Sized { } + +/// Toplevel trait for performing member access. Utilizes other `..Access` traits pub trait MemberAccess: MemberAccessParts + AnalyzerBackend + Sized { - fn visible_member_funcs( - &mut self, - ctx: ContextNode, - loc: Loc, - member_idx: NodeIdx, - ) -> Result, ExprErr> { - let res = match self.node(member_idx) { - Node::ContextVar(cvar) => match &cvar.ty { - VarType::User(TypeNode::Contract(con_node), _) => { - let mut funcs = con_node.linearized_functions(self); - self - .possible_library_funcs(ctx, con_node.0.into()) - .into_iter() - .for_each(|func| { - let name = func.name(self).unwrap(); - funcs.entry(name).or_insert(func); - }); - funcs.values().copied().collect() - }, - VarType::BuiltIn(bn, _) => self - .possible_library_funcs(ctx, bn.0.into()) - .into_iter() - .collect::>(), - VarType::Concrete(cnode) => { - let b = cnode.underlying(self).unwrap().as_builtin(); - let bn = self.builtin_or_add(b); - self.possible_library_funcs(ctx, bn) - .into_iter() - .collect::>() - } - VarType::User(TypeNode::Struct(sn), _) => self - .possible_library_funcs(ctx, sn.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Enum(en), _) => self - .possible_library_funcs(ctx, en.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Ty(ty), _) => self - .possible_library_funcs(ctx, ty.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Func(func_node), _) => self - .possible_library_funcs(ctx, func_node.0.into()) - .into_iter() - .collect::>(), - VarType::User(TypeNode::Unresolved(n), _) => { - match self.node(*n) { - Node::Unresolved(ident) => { - return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) - } - _ => unreachable!() - } - } - }, - Node::Contract(_) => ContractNode::from(member_idx).funcs(self), - Node::Concrete(_) - | Node::Ty(_) - | Node::Struct(_) - | Node::Function(_) - | Node::Enum(_) - | Node::Builtin(_) => self - .possible_library_funcs(ctx, member_idx) - .into_iter() - .collect::>(), - e => { - return Err(ExprErr::MemberAccessNotFound( - loc, - format!("This type cannot have member functions: {:?}", e), - )) - } - }; - Ok(res) - } - - /// Gets the array type + /// Entry function for perform a member access #[tracing::instrument(level = "trace", skip_all)] fn member_access( &mut self, @@ -135,6 +64,7 @@ pub trait MemberAccess: }) } + /// Match on [`ExprRet`]s and call the member access for each fn match_member( &mut self, ctx: ContextNode, @@ -156,6 +86,7 @@ pub trait MemberAccess: } } + /// Perform the member access fn member_access_inner( &mut self, loc: Loc, @@ -201,6 +132,83 @@ pub trait MemberAccess: } } + /// Get visible functions for this member + fn visible_member_funcs( + &mut self, + ctx: ContextNode, + loc: Loc, + member_idx: NodeIdx, + ) -> Result, ExprErr> { + let res = match self.node(member_idx) { + Node::ContextVar(cvar) => match &cvar.ty { + VarType::User(TypeNode::Contract(con_node), _) => { + let mut funcs = con_node.linearized_functions(self); + self + .possible_library_funcs(ctx, con_node.0.into()) + .into_iter() + .for_each(|func| { + let name = func.name(self).unwrap(); + funcs.entry(name).or_insert(func); + }); + funcs.values().copied().collect() + }, + VarType::BuiltIn(bn, _) => self + .possible_library_funcs(ctx, bn.0.into()) + .into_iter() + .collect::>(), + VarType::Concrete(cnode) => { + let b = cnode.underlying(self).unwrap().as_builtin(); + let bn = self.builtin_or_add(b); + self.possible_library_funcs(ctx, bn) + .into_iter() + .collect::>() + } + VarType::User(TypeNode::Struct(sn), _) => self + .possible_library_funcs(ctx, sn.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Enum(en), _) => self + .possible_library_funcs(ctx, en.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Ty(ty), _) => self + .possible_library_funcs(ctx, ty.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Func(func_node), _) => self + .possible_library_funcs(ctx, func_node.0.into()) + .into_iter() + .collect::>(), + VarType::User(TypeNode::Unresolved(n), _) => { + match self.node(*n) { + Node::Unresolved(ident) => { + return Err(ExprErr::Unresolved(loc, format!("The type \"{}\" is currently unresolved but should have been resolved by now. This is a bug.", ident.name))) + } + _ => unreachable!() + } + } + }, + Node::Contract(_) => ContractNode::from(member_idx).funcs(self), + Node::Concrete(_) + | Node::Ty(_) + | Node::Struct(_) + | Node::Function(_) + | Node::Enum(_) + | Node::Builtin(_) => self + .possible_library_funcs(ctx, member_idx) + .into_iter() + .collect::>(), + e => { + return Err(ExprErr::MemberAccessNotFound( + loc, + format!("This type cannot have member functions: {:?}", e), + )) + } + }; + Ok(res) + } + + /// Perform member access for a variable type fn member_access_var_ty( &mut self, cvar: ContextVar, @@ -251,6 +259,7 @@ pub trait MemberAccess: } } + /// Perform a `TyNode` member access fn ty_member_access( &mut self, _member_idx: NodeIdx, diff --git a/crates/solc-expressions/src/member_access/mod.rs b/crates/solc-expressions/src/member_access/mod.rs index f86ca279..59766091 100644 --- a/crates/solc-expressions/src/member_access/mod.rs +++ b/crates/solc-expressions/src/member_access/mod.rs @@ -1,3 +1,6 @@ +//! This module consists of traits & blanket implementations that facilitate performing member access operations +//! like `MyStruct.field` or `MyContract.myFunc` + mod builtin_access; mod contract_access; mod enum_access; diff --git a/crates/solc-expressions/src/member_access/struct_access.rs b/crates/solc-expressions/src/member_access/struct_access.rs index a17eed14..41d252a5 100644 --- a/crates/solc-expressions/src/member_access/struct_access.rs +++ b/crates/solc-expressions/src/member_access/struct_access.rs @@ -12,9 +12,11 @@ impl StructAccess for T where T: LibraryAccess + AnalyzerBackend + Sized { } +/// Trait for performing member accesses on Structs pub trait StructAccess: LibraryAccess + AnalyzerBackend + Sized { + /// Perform member access on a struct fn struct_member_access( &mut self, member_idx: NodeIdx, diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 01fc710e..e51f0b9e 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -19,6 +19,8 @@ use solang_parser::{ use std::cmp::Ordering; impl Require for T where T: Variable + BinOp + Sized + AnalyzerBackend {} + +/// Deals with require and assert statements, as well as adjusts bounds for variables pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Inverts a comparator expression fn inverse_expr(&self, expr: Expression) -> Expression { @@ -582,6 +584,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } } + /// Do matching on [`ExprRet`]s to actually perform the require statement evaluation fn handle_require_inner( &mut self, ctx: ContextNode, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index ba91ba49..f4640931 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -8,9 +8,10 @@ use graph::{ use solang_parser::pt::{Expression, Identifier}; impl Variable for T where T: AnalyzerBackend + Sized {} - +/// Deals with variable retrieval pub trait Variable: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] + /// Get a variable based on an identifier fn variable( &mut self, ident: &Identifier, diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index a6eb5228..aa6f8d1a 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -1,380 +1,8 @@ -use crate::{ContextBuilder, ExprErr, ExprParser, IntoExprErr}; - -use graph::{ - nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, Node, VarType, -}; - -use solang_parser::{ - helpers::CodeLocation, - pt::{Expression, Loc, YulExpression, YulFor, YulStatement, YulSwitch}, -}; +//! Traits and blanket implementations for parsing with yul statements and expressions +mod yul_builder; mod yul_cond_op; -pub use yul_cond_op::*; - mod yul_funcs; -pub use yul_funcs::*; - -impl YulBuilder for T where - T: AnalyzerBackend + Sized + ExprParser -{ -} -pub trait YulBuilder: - AnalyzerBackend + Sized + ExprParser -{ - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) - where - Self: Sized, - { - if let Some(true) = self.add_if_err(ctx.is_ended(self).into_expr_err(stmt.loc())) { - return; - } - if let Some(live_edges) = self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { - if live_edges.is_empty() { - self.parse_ctx_yul_stmt_inner(stmt, ctx) - } else { - live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_yul_stmt_inner(stmt, *fork_ctx); - }); - } - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_ctx_yul_stmt_inner(&mut self, stmt: &YulStatement, ctx: ContextNode) - where - Self: Sized, - { - use YulStatement::*; - // println!("ctx: {}, yul stmt: {:?}", ctx.path(self), stmt); - - let res = ctx - .pop_expr_latest(stmt.loc(), self) - .into_expr_err(stmt.loc()); - let _ = self.add_if_err(res); - - if ctx.is_killed(self).unwrap() { - return; - } - let ret = self.apply_to_edges(ctx, stmt.loc(), &|analyzer, ctx, _loc| { - match stmt { - Assign(loc, yul_exprs, yul_expr) => { - match yul_exprs - .iter() - .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) - { - Ok(()) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_side) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "No left hand side assignments in yul block".to_string(), - )); - }; - if matches!(lhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_side) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "No right hand side assignments in yul block".to_string(), - )); - }; - - if matches!(rhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_sides(ctx, loc, &lhs_side, &rhs_side) - }) - }), - Err(e) => Err(e), - } - } - VariableDeclaration(loc, yul_idents, maybe_yul_expr) => { - let nodes = yul_idents - .iter() - .map(|ident| { - let b_ty = analyzer.builtin_or_add(Builtin::Uint(256)); - let var = ContextVar { - loc: Some(ident.loc), - name: ident.id.name.clone(), - display_name: ident.id.name.clone(), - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), - }; - let cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - ctx.add_var(cvar, analyzer).unwrap(); - analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - analyzer.advance_var_in_ctx(cvar, *loc, ctx).unwrap() - }) - .collect::>(); - - if let Some(yul_expr) = maybe_yul_expr { - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "No right hand side assignments in yul block".to_string(), - )); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.match_assign_yul(ctx, loc, &nodes, ret) - }) - } else { - Ok(()) - } - } - If(loc, yul_expr, yul_block) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let ret = analyzer.yul_cond_op_stmt(loc, yul_expr, yul_block, ctx); - let _ = analyzer.add_if_err(ret); - Ok(()) - }) - } - For(YulFor { - loc, - init_block: _, - condition: _, - post_block: _, - execution_block: _, - }) => { - let sctx = - Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) - .into_expr_err(*loc)?; - let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); - ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; - analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { - let vars = subctx.local_vars(analyzer).clone(); - vars.iter().for_each(|(name, var)| { - // widen to max range - if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = var - .underlying(analyzer) - .unwrap() - .ty - .default_range(analyzer) - .unwrap() - { - let new_inheritor_var = analyzer - .advance_var_in_ctx(inheritor_var, loc, ctx) - .unwrap(); - let res = new_inheritor_var - .set_range_min(analyzer, r.min) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - let res = new_inheritor_var - .set_range_max(analyzer, r.max) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - } - } - }); - Ok(()) - }) - } - Switch(YulSwitch { - loc, - condition, - cases, - default, - }) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.yul_switch_stmt( - loc, - condition.clone(), - cases.to_vec(), - default.clone(), - ctx, - ) - }), - Leave(loc) => Err(ExprErr::Todo( - *loc, - "Yul `leave` statements are not currently supported".to_string(), - )), - Break(loc) => Err(ExprErr::Todo( - *loc, - "Yul `break` statements are not currently supported".to_string(), - )), - Continue(loc) => Err(ExprErr::Todo( - *loc, - "Yul `continue` statements are not currently supported".to_string(), - )), - Block(yul_block) => { - yul_block - .statements - .iter() - .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); - Ok(()) - } - FunctionDefinition(yul_func_def) => Err(ExprErr::Todo( - yul_func_def.loc(), - "Yul `function` defintions are not currently supported".to_string(), - )), - FunctionCall(yul_func_call) => analyzer.yul_func_call(yul_func_call, ctx), - Error(loc) => Err(ExprErr::ParseError( - *loc, - "Could not parse this yul statement".to_string(), - )), - } - }); - let _ = self.add_if_err(ret); - } - - #[tracing::instrument(level = "trace", skip_all)] - fn parse_ctx_yul_expr( - &mut self, - expr: &YulExpression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - tracing::trace!("Parsing yul expression: {expr:?}"); - - let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; - if edges.is_empty() { - self.parse_ctx_yul_expr_inner(expr, ctx) - } else { - edges - .iter() - .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(expr, *fork_ctx))?; - Ok(()) - } - } - - fn parse_ctx_yul_expr_inner( - &mut self, - expr: &YulExpression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - use YulExpression::*; - match expr { - BoolLiteral(loc, b, _) => self.bool_literal(ctx, *loc, *b), - NumberLiteral(loc, int, expr, _unit) => { - self.number_literal(ctx, *loc, int, expr, false) - } - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), - HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), - StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), - Variable(ident) => { - self.variable(ident, ctx, None)?; - self.apply_to_edges(ctx, ident.loc, &|analyzer, edge_ctx, loc| { - if let Some(ret) = edge_ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { - if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?) - .is_memory(analyzer) - .into_expr_err(loc)? - { - // its a memory based variable, push a uint instead - let b = Builtin::Uint(256); - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(b).into(), - analyzer, - ) - .into_expr_err(loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - edge_ctx - .push_expr(ExprRet::Single(node), analyzer) - .into_expr_err(loc) - } else { - edge_ctx.push_expr(ret, analyzer).into_expr_err(loc) - } - } else { - Err(ExprErr::Unresolved( - ident.loc, - format!("Could not find variable with name: {}", ident.name), - )) - } - }) - } - FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), - SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( - expr.loc(), - "Yul member access not yet supported".to_string(), - )), - } - } - - fn match_assign_yul( - &mut self, - _ctx: ContextNode, - loc: Loc, - nodes: &[ContextVarNode], - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret { - s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => { - self.match_assign_yul_inner(loc, &nodes[0], s)?; - } - ExprRet::Multi(inner) => { - if inner.len() == nodes.len() { - inner - .into_iter() - .zip(nodes.iter()) - .map(|(ret, node)| self.match_assign_yul_inner(loc, node, ret)) - .collect::, ExprErr>>()?; - } else { - return Err(ExprErr::Todo( - loc, - format!("Differing number of assignees and assignors in yul expression, assignors: {}, assignees: {}", nodes.len(), inner.len()), - )); - }; - } - ExprRet::CtxKilled(_kind) => {} - ExprRet::Null => {} - } - - Ok(()) - } - - fn match_assign_yul_inner( - &mut self, - loc: Loc, - node: &ContextVarNode, - ret: ExprRet, - ) -> Result<(), ExprErr> { - match ret.flatten() { - ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { - let assign = ContextVarNode::from(idx); - let assign_ty = assign.underlying(self).into_expr_err(loc)?.ty.clone(); - if assign_ty.is_dyn(self).into_expr_err(loc)? { - let b_ty = self.builtin_or_add(Builtin::Bytes(32)); - node.underlying_mut(self).into_expr_err(loc)?.ty = - VarType::try_from_idx(self, b_ty).unwrap(); - } else { - node.underlying_mut(self).into_expr_err(loc)?.ty = assign_ty; - } - } - ExprRet::Multi(_inner) => { - return Err(ExprErr::Todo( - loc, - "Multi in single assignment yul expression is unhandled".to_string(), - )) - } - ExprRet::CtxKilled(..) => {} - ExprRet::Null => {} - } - Ok(()) - } -} +pub use yul_builder::*; +pub use yul_cond_op::*; +pub use yul_funcs::*; \ No newline at end of file diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs new file mode 100644 index 00000000..652ed9b2 --- /dev/null +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -0,0 +1,388 @@ +//! Trait and blanket implementation for parsing yul-based statements and expressions + +use crate::{ + ContextBuilder, ExprErr, ExprParser, IntoExprErr, + yul::YulFuncCaller, + yul::YulCondOp +}; + +use graph::{ + nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, +}; + +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc, YulExpression, YulFor, YulStatement, YulSwitch}, +}; + + +impl YulBuilder for T where + T: AnalyzerBackend + Sized + ExprParser +{ +} +/// Trait that processes Yul statements and expressions +pub trait YulBuilder: + AnalyzerBackend + Sized + ExprParser +{ + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + /// Parse a yul statement + fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) + where + Self: Sized, + { + if let Some(true) = self.add_if_err(ctx.is_ended(self).into_expr_err(stmt.loc())) { + return; + } + if let Some(live_edges) = self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { + if live_edges.is_empty() { + self.parse_ctx_yul_stmt_inner(stmt, ctx) + } else { + live_edges.iter().for_each(|fork_ctx| { + self.parse_ctx_yul_stmt_inner(stmt, *fork_ctx); + }); + } + } + } + + #[tracing::instrument(level = "trace", skip_all)] + /// After doing some setup in `parse_ctx_yul_statement`, actually parse a yul statement + fn parse_ctx_yul_stmt_inner(&mut self, stmt: &YulStatement, ctx: ContextNode) + where + Self: Sized, + { + use YulStatement::*; + // println!("ctx: {}, yul stmt: {:?}", ctx.path(self), stmt); + + let res = ctx + .pop_expr_latest(stmt.loc(), self) + .into_expr_err(stmt.loc()); + let _ = self.add_if_err(res); + + if ctx.is_killed(self).unwrap() { + return; + } + let ret = self.apply_to_edges(ctx, stmt.loc(), &|analyzer, ctx, _loc| { + match stmt { + Assign(loc, yul_exprs, yul_expr) => { + match yul_exprs + .iter() + .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) + { + Ok(()) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_side) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "No left hand side assignments in yul block".to_string(), + )); + }; + if matches!(lhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_side) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No right hand side assignments in yul block".to_string(), + )); + }; + + if matches!(rhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_sides(ctx, loc, &lhs_side, &rhs_side) + }) + }), + Err(e) => Err(e), + } + } + VariableDeclaration(loc, yul_idents, maybe_yul_expr) => { + let nodes = yul_idents + .iter() + .map(|ident| { + let b_ty = analyzer.builtin_or_add(Builtin::Uint(256)); + let var = ContextVar { + loc: Some(ident.loc), + name: ident.id.name.clone(), + display_name: ident.id.name.clone(), + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), + }; + let cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + ctx.add_var(cvar, analyzer).unwrap(); + analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + analyzer.advance_var_in_ctx(cvar, *loc, ctx).unwrap() + }) + .collect::>(); + + if let Some(yul_expr) = maybe_yul_expr { + analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No right hand side assignments in yul block".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_yul(ctx, loc, &nodes, ret) + }) + } else { + Ok(()) + } + } + If(loc, yul_expr, yul_block) => { + analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let ret = analyzer.yul_cond_op_stmt(loc, yul_expr, yul_block, ctx); + let _ = analyzer.add_if_err(ret); + Ok(()) + }) + } + For(YulFor { + loc, + init_block: _, + condition: _, + post_block: _, + execution_block: _, + }) => { + let sctx = + Context::new_subctx(ctx, None, *loc, None, None, false, analyzer, None) + .into_expr_err(*loc)?; + let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); + ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; + analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { + let vars = subctx.local_vars(analyzer).clone(); + vars.iter().for_each(|(name, var)| { + // widen to max range + if let Some(inheritor_var) = ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = var + .underlying(analyzer) + .unwrap() + .ty + .default_range(analyzer) + .unwrap() + { + let new_inheritor_var = analyzer + .advance_var_in_ctx(inheritor_var, loc, ctx) + .unwrap(); + let res = new_inheritor_var + .set_range_min(analyzer, r.min) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_inheritor_var + .set_range_max(analyzer, r.max) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + } + }); + Ok(()) + }) + } + Switch(YulSwitch { + loc, + condition, + cases, + default, + }) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.yul_switch_stmt( + loc, + condition.clone(), + cases.to_vec(), + default.clone(), + ctx, + ) + }), + Leave(loc) => Err(ExprErr::Todo( + *loc, + "Yul `leave` statements are not currently supported".to_string(), + )), + Break(loc) => Err(ExprErr::Todo( + *loc, + "Yul `break` statements are not currently supported".to_string(), + )), + Continue(loc) => Err(ExprErr::Todo( + *loc, + "Yul `continue` statements are not currently supported".to_string(), + )), + Block(yul_block) => { + yul_block + .statements + .iter() + .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); + Ok(()) + } + FunctionDefinition(yul_func_def) => Err(ExprErr::Todo( + yul_func_def.loc(), + "Yul `function` defintions are not currently supported".to_string(), + )), + FunctionCall(yul_func_call) => analyzer.yul_func_call(yul_func_call, ctx), + Error(loc) => Err(ExprErr::ParseError( + *loc, + "Could not parse this yul statement".to_string(), + )), + } + }); + let _ = self.add_if_err(ret); + } + + #[tracing::instrument(level = "trace", skip_all)] + /// Parse a yul expression + fn parse_ctx_yul_expr( + &mut self, + expr: &YulExpression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + tracing::trace!("Parsing yul expression: {expr:?}"); + + let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; + if edges.is_empty() { + self.parse_ctx_yul_expr_inner(expr, ctx) + } else { + edges + .iter() + .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(expr, *fork_ctx))?; + Ok(()) + } + } + + /// After performing some setup in `parse_ctx_yul_expr`, actually parse the yul expression + fn parse_ctx_yul_expr_inner( + &mut self, + expr: &YulExpression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + use YulExpression::*; + match expr { + BoolLiteral(loc, b, _) => self.bool_literal(ctx, *loc, *b), + NumberLiteral(loc, int, expr, _unit) => { + self.number_literal(ctx, *loc, int, expr, false) + } + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), + HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), + StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), + Variable(ident) => { + self.variable(ident, ctx, None)?; + self.apply_to_edges(ctx, ident.loc, &|analyzer, edge_ctx, loc| { + if let Some(ret) = edge_ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { + if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?) + .is_memory(analyzer) + .into_expr_err(loc)? + { + // its a memory based variable, push a uint instead + let b = Builtin::Uint(256); + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(b).into(), + analyzer, + ) + .into_expr_err(loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + edge_ctx + .push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(loc) + } else { + edge_ctx.push_expr(ret, analyzer).into_expr_err(loc) + } + } else { + Err(ExprErr::Unresolved( + ident.loc, + format!("Could not find variable with name: {}", ident.name), + )) + } + }) + } + FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), + SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( + expr.loc(), + "Yul member access not yet supported".to_string(), + )), + } + } + + /// Match [`ExprRet`] from the sides of an `YulAssign` to perform the assignment + fn match_assign_yul( + &mut self, + _ctx: ContextNode, + loc: Loc, + nodes: &[ContextVarNode], + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret { + s @ ExprRet::Single(_) | s @ ExprRet::SingleLiteral(_) => { + self.match_assign_yul_inner(loc, &nodes[0], s)?; + } + ExprRet::Multi(inner) => { + if inner.len() == nodes.len() { + inner + .into_iter() + .zip(nodes.iter()) + .map(|(ret, node)| self.match_assign_yul_inner(loc, node, ret)) + .collect::, ExprErr>>()?; + } else { + return Err(ExprErr::Todo( + loc, + format!("Differing number of assignees and assignors in yul expression, assignors: {}, assignees: {}", nodes.len(), inner.len()), + )); + }; + } + ExprRet::CtxKilled(_kind) => {} + ExprRet::Null => {} + } + + Ok(()) + } + + /// Perform the actual yul assignment + fn match_assign_yul_inner( + &mut self, + loc: Loc, + node: &ContextVarNode, + ret: ExprRet, + ) -> Result<(), ExprErr> { + match ret.flatten() { + ExprRet::Single(idx) | ExprRet::SingleLiteral(idx) => { + let assign = ContextVarNode::from(idx); + let assign_ty = assign.underlying(self).into_expr_err(loc)?.ty.clone(); + if assign_ty.is_dyn(self).into_expr_err(loc)? { + let b_ty = self.builtin_or_add(Builtin::Bytes(32)); + node.underlying_mut(self).into_expr_err(loc)?.ty = + VarType::try_from_idx(self, b_ty).unwrap(); + } else { + node.underlying_mut(self).into_expr_err(loc)?.ty = assign_ty; + } + } + ExprRet::Multi(_inner) => { + return Err(ExprErr::Todo( + loc, + "Multi in single assignment yul expression is unhandled".to_string(), + )) + } + ExprRet::CtxKilled(..) => {} + ExprRet::Null => {} + } + Ok(()) + } +} diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index 8faf7127..7f5f74a2 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, YulBuilder}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, yul::YulBuilder}; use graph::{ elem::*, @@ -17,10 +17,13 @@ impl YulCondOp for T where T: AnalyzerBackend + Require + Sized { } + +/// Trait for dealing with conditional operations in yul pub trait YulCondOp: AnalyzerBackend + Require + Sized { #[tracing::instrument(level = "trace", skip_all)] + /// Handle a yul conditional operation statement fn yul_cond_op_stmt( &mut self, loc: Loc, @@ -98,6 +101,7 @@ pub trait YulCondOp: } #[tracing::instrument(level = "trace", skip_all)] + /// Handle a yul if-else fn yul_if_else( &mut self, loc: Loc, @@ -172,6 +176,7 @@ pub trait YulCondOp: }) } + /// Helper for the `true` evaluation of a yul conditional fn match_yul_true( &mut self, ctx: ContextNode, @@ -214,6 +219,7 @@ pub trait YulCondOp: Ok(()) } + /// Helper for the `false` evaluation of a yul conditional fn match_yul_false( &mut self, ctx: ContextNode, @@ -258,6 +264,7 @@ pub trait YulCondOp: } #[tracing::instrument(level = "trace", skip_all)] + /// Handle a yul swithc statement by converting it into an if-else chain fn yul_switch_stmt( &mut self, loc: Loc, @@ -274,6 +281,7 @@ pub trait YulCondOp: } #[derive(Clone, Debug)] +/// A yul-based if-else chain, which represents a switch statement pub struct IfElseChain { pub if_expr: YulExpression, pub true_stmt: YulStatement, @@ -281,6 +289,7 @@ pub struct IfElseChain { } #[derive(Clone, Debug)] +/// Wrapper over a switch statement that denotes either another else statement or the default case pub enum ElseOrDefault { Else(Box), Default(YulStatement), diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 0d28f98e..922a8f89 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,4 +1,4 @@ -use crate::{BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, YulBuilder}; +use crate::{BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, yul::YulBuilder}; use graph::{ elem::*, From 310804a5ac63f53c165154e96da4aacb6e35f6d7 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 11 Dec 2023 11:45:09 -0800 Subject: [PATCH 41/71] split statement and expression parsers --- crates/pyrometer/src/analyzer.rs | 2 +- crates/solc-expressions/src/array.rs | 2 +- crates/solc-expressions/src/assign.rs | 242 +++ crates/solc-expressions/src/bin_op.rs | 2 +- crates/solc-expressions/src/cmp.rs | 2 +- crates/solc-expressions/src/cond_op.rs | 2 +- .../src/context_builder/expr.rs | 393 +++++ .../src/context_builder/mod.rs | 1525 +---------------- .../src/context_builder/stmt.rs | 528 ++++++ .../src/func_call/func_caller.rs | 2 +- .../solc-expressions/src/func_call/helper.rs | 2 +- .../src/func_call/internal_call.rs | 2 +- .../src/func_call/intrinsic_call/abi.rs | 2 +- .../src/func_call/intrinsic_call/array.rs | 2 +- .../src/func_call/intrinsic_call/block.rs | 2 +- .../func_call/intrinsic_call/constructors.rs | 2 +- .../func_call/intrinsic_call/dyn_builtin.rs | 2 +- .../func_call/intrinsic_call/precompile.rs | 2 +- .../src/func_call/intrinsic_call/solidity.rs | 2 +- .../src/func_call/intrinsic_call/types.rs | 2 +- .../src/func_call/modifier.rs | 3 +- .../src/func_call/namespaced_call.rs | 1 + crates/solc-expressions/src/lib.rs | 12 +- crates/solc-expressions/src/list.rs | 2 +- crates/solc-expressions/src/loops.rs | 2 +- .../src/member_access/list_access.rs | 2 +- .../src/member_access/member_trait.rs | 2 +- .../src/pre_post_in_decrement.rs | 184 ++ crates/solc-expressions/src/require.rs | 2 +- crates/solc-expressions/src/variable.rs | 265 ++- .../solc-expressions/src/yul/yul_builder.rs | 6 +- crates/solc-expressions/src/yul/yul_funcs.rs | 2 +- 32 files changed, 1654 insertions(+), 1549 deletions(-) create mode 100644 crates/solc-expressions/src/assign.rs create mode 100644 crates/solc-expressions/src/context_builder/expr.rs create mode 100644 crates/solc-expressions/src/context_builder/stmt.rs create mode 100644 crates/solc-expressions/src/pre_post_in_decrement.rs diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 2877fed5..364130d0 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -3,7 +3,7 @@ use crate::builtin_fns; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; -use solc_expressions::{ContextBuilder, ExprErr, IntoExprErr}; +use solc_expressions::{StatementParser, ExprErr, IntoExprErr}; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; use petgraph::{graph::*, Directed}; diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 2045d818..616d4722 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; +use crate::{ExpressionParser, variable::Variable, require::Require, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; use graph::{ elem::RangeOp, diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs new file mode 100644 index 00000000..a95280e4 --- /dev/null +++ b/crates/solc-expressions/src/assign.rs @@ -0,0 +1,242 @@ +use crate::{variable::Variable, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; + +use graph::{ + elem::Elem, GraphError, Range, + nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, +}; + +use solang_parser::pt::{Expression, Loc}; + +impl Assign for T where T: AnalyzerBackend + Sized {} +/// Handles assignments +pub trait Assign: AnalyzerBackend + Sized { +#[tracing::instrument(level = "trace", skip_all)] + /// Parse an assignment expression + fn assign_exprs( + &mut self, + loc: Loc, + lhs_expr: &Expression, + rhs_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(rhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "Assign operation had no right hand side".to_string(), + )); + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.parse_ctx_expr(lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Assign operation had no left hand side".to_string(), + )); + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_assign_sides(ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; + Ok(()) + }) + }) + } + + /// Match on the [`ExprRet`]s of an assignment expression + fn match_assign_sides( + &mut self, + ctx: ContextNode, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: &ExprRet, + ) -> Result<(), ExprErr> { + match (lhs_paths, rhs_paths) { + (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), + (ExprRet::CtxKilled(kind), _) | (_, ExprRet::CtxKilled(kind)) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + let res = rhs_cvar + .literal_cast_from(&lhs_cvar, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { + let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + .into_expr_err(loc)?; + Ok(()) + } + (l @ ExprRet::Single(_), ExprRet::Multi(rhs_sides)) => rhs_sides + .iter() + .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, l, expr_ret)), + (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { + lhs_sides + .iter() + .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, expr_ret, r)) + } + (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( + |(lhs_expr_ret, rhs_expr_ret)| { + self.match_assign_sides(ctx, loc, lhs_expr_ret, rhs_expr_ret) + }, + ) + } else { + rhs_sides.iter().try_for_each(|rhs_expr_ret| { + self.match_assign_sides(ctx, loc, lhs_paths, rhs_expr_ret) + }) + } + } + (e, f) => todo!("any: {:?} {:?}", e, f), + } + } + + /// Perform an assignment + fn assign( + &mut self, + loc: Loc, + lhs_cvar: ContextVarNode, + rhs_cvar: ContextVarNode, + ctx: ContextNode, + ) -> Result { + tracing::trace!( + "assigning: {} to {}", + rhs_cvar.display_name(self).unwrap(), + lhs_cvar.display_name(self).unwrap(), + ); + + let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( + Elem::from(rhs_cvar.latest_version(self)), + Elem::from(rhs_cvar.latest_version(self)), + ); + + let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; + new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = + rhs_cvar.tmp_of(self).into_expr_err(loc)?; + if lhs_cvar.is_storage(self).into_expr_err(loc)? { + self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); + } + + if rhs_cvar.underlying(self).into_expr_err(loc)?.is_return { + if let Some(rhs_ctx) = rhs_cvar.maybe_ctx(self) { + self.add_edge( + rhs_cvar, + new_lhs, + Edge::Context(ContextEdge::ReturnAssign( + rhs_ctx.underlying(self).unwrap().ext_fn_call.is_some(), + )), + ); + } else { + return Err(ExprErr::GraphError( + loc, + GraphError::DetachedVariable(format!( + "No context for variable: {}, node idx: {}, curr ctx: {}, lhs ctx: {}", + rhs_cvar.display_name(self).unwrap(), + rhs_cvar.0, + ctx.path(self), + lhs_cvar.ctx(self).path(self) + )), + )); + } + } + + if !lhs_cvar.ty_eq(&rhs_cvar, self).into_expr_err(loc)? { + let cast_to_min = match lhs_cvar.range_min(self).into_expr_err(loc)? { + Some(v) => v, + None => { + return Err(ExprErr::BadRange( + loc, + format!( + "No range during cast? {:?}, {:?}", + lhs_cvar.underlying(self).unwrap(), + rhs_cvar.underlying(self).unwrap(), + ), + )) + } + }; + + let cast_to_max = match lhs_cvar.range_max(self).into_expr_err(loc)? { + Some(v) => v, + None => { + return Err(ExprErr::BadRange( + loc, + format!( + "No range during cast? {:?}, {:?}", + lhs_cvar.underlying(self).unwrap(), + rhs_cvar.underlying(self).unwrap(), + ), + )) + } + }; + + let _ = new_lhs.try_set_range_min(self, new_lower_bound.cast(cast_to_min)); + let _ = new_lhs.try_set_range_max(self, new_upper_bound.cast(cast_to_max)); + } else { + let _ = new_lhs.try_set_range_min(self, new_lower_bound); + let _ = new_lhs.try_set_range_max(self, new_upper_bound); + } + if let Some(rhs_range) = rhs_cvar.ref_range(self).into_expr_err(loc)? { + let res = new_lhs + .try_set_range_exclusions(self, rhs_range.exclusions.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(arr) = lhs_cvar.index_to_array(self) { + if let Some(index) = lhs_cvar.index_access_to_index(self) { + let next_arr = self.advance_var_in_ctx(arr, loc, ctx)?; + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { + let min = r.evaled_range_min(self).into_expr_err(loc)?; + let max = r.evaled_range_max(self).into_expr_err(loc)?; + + if let Some(mut rd) = min.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); + let res = next_arr + .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + + if let Some(mut rd) = max.maybe_range_dyn() { + rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); + let res = next_arr + .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .into_expr_err(loc); + let _ = self.add_if_err(res); + } + } + } + } + } + + // advance the rhs variable to avoid recursion issues + self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; + Ok(ExprRet::Single(new_lhs.into())) + } +} + \ No newline at end of file diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 5f855b1b..da328dea 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{variable::Variable, require::Require, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 948e34a2..bd3fe7f8 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index f96e3307..df688f58 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, StatementParser, ExpressionParser}; use graph::{ nodes::{Context, ContextNode}, diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs new file mode 100644 index 00000000..407f2c5c --- /dev/null +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -0,0 +1,393 @@ +use crate::{ + context_builder::ContextBuilder, + variable::Variable, + func_call::{func_caller::FuncCaller}, ExprErr, ExprTyParser, IntoExprErr, +}; + +use graph::{ + elem::*, + nodes::{ + Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, +}; + +use ethers_core::types::{I256}; +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc}, +}; + + +impl ExpressionParser for T where + T: AnalyzerBackend + Sized + ExprTyParser +{ +} + +/// Solidity expression parser +pub trait ExpressionParser: + AnalyzerBackend + Sized + ExprTyParser +{ + /// Perform setup for parsing an expression + fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + if !ctx.killed_or_ret(self).unwrap() { + let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; + if edges.is_empty() { + self.parse_ctx_expr_inner(expr, ctx) + } else { + edges + .iter() + .try_for_each(|fork_ctx| self.parse_ctx_expr(expr, *fork_ctx))?; + Ok(()) + } + } else { + Ok(()) + } + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self).replace('.', "\n\t.")))] + /// Perform parsing of an expression + fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + use Expression::*; + // tracing::trace!( + // "ctx: {}, current stack: {:?}, \nexpr: {:?}\n", + // ctx.underlying(self).unwrap().path, + // ctx.underlying(self) + // .unwrap() + // .expr_ret_stack + // .iter() + // .map(|i| i.debug_str(self)) + // .collect::>(), + // expr + // ); + match expr { + // literals + NumberLiteral(loc, int, exp, _unit) => self.number_literal(ctx, *loc, int, exp, false), + AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), + StringLiteral(lits) => lits + .iter() + .try_for_each(|lit| self.string_literal(ctx, lit.loc, &lit.string)), + BoolLiteral(loc, b) => self.bool_literal(ctx, *loc, *b), + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), + HexLiteral(hexes) => self.hex_literals(ctx, hexes), + RationalNumberLiteral(loc, integer, fraction, exp, unit) => { + self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) + } + Negate(_loc, expr) => match &**expr { + NumberLiteral(loc, int, exp, _unit) => { + self.number_literal(ctx, *loc, int, exp, true) + } + HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), + e => { + self.parse_ctx_expr(e, ctx)?; + self.apply_to_edges(ctx, e.loc(), &|analyzer, ctx, loc| { + tracing::trace!("Negate variable pop"); + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No variable present to negate".to_string(), + )); + }; + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + // Solidity is dumb and used to allow negation of unsigned integers. + // That means we have to cast this as a int256. + let var = rhs_paths.expect_single().into_expr_err(loc)?; + + let zero = + analyzer.add_node(Node::Concrete(Concrete::from(I256::from(0i32)))); + let zero = ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + zero.into(), + analyzer, + ) + .into_expr_err(loc)?; + let zero = analyzer.add_node(Node::ContextVar(zero)); + let new_underlying = ContextVarNode::from(var) + .underlying(analyzer) + .into_expr_err(loc)? + .clone() + .as_cast_tmp(loc, ctx, Builtin::Int(256), analyzer) + .into_expr_err(loc)?; + let node = analyzer.add_node(Node::ContextVar(new_underlying)); + ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + + ContextVarNode::from(node) + .cast_from(&ContextVarNode::from(zero), analyzer) + .into_expr_err(loc)?; + + let lhs_paths = ExprRet::Single(zero); + analyzer.op_match( + ctx, + loc, + &lhs_paths, + &ExprRet::Single( + ContextVarNode::from(node).latest_version(analyzer).into(), + ), + RangeOp::Sub(true), + false, + ) + }) + } // e => todo!("UnaryMinus unexpected rhs: {e:?}"), + }, + UnaryPlus(_loc, e) => todo!("UnaryPlus unexpected rhs: {e:?}"), + + // Binary ops + Power(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) + } + Add(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignAdd(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Subtract(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignSubtract(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Multiply(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), + false, + ), + AssignMultiply(loc, lhs_expr, rhs_expr) => self.op_expr( + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), + true, + ), + Divide(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), false) + } + AssignDivide(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), true) + } + Modulo(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) + } + AssignModulo(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) + } + ShiftLeft(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) + } + AssignShiftLeft(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) + } + ShiftRight(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) + } + AssignShiftRight(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) + } + ConditionalOperator(loc, if_expr, true_expr, false_expr) => { + self.cond_op_expr(*loc, if_expr, true_expr, false_expr, ctx) + } + + // Bitwise ops + BitwiseAnd(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) + } + AssignAnd(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) + } + BitwiseXor(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) + } + AssignXor(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) + } + BitwiseOr(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) + } + AssignOr(loc, lhs_expr, rhs_expr) => { + self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) + } + BitwiseNot(loc, lhs_expr) => self.bit_not(*loc, lhs_expr, ctx), + + // assign + Assign(loc, lhs_expr, rhs_expr) => self.assign_exprs(*loc, lhs_expr, rhs_expr, ctx), + List(loc, params) => self.list(ctx, *loc, params), + // array + ArraySubscript(_loc, ty_expr, None) => self.array_ty(ty_expr, ctx), + ArraySubscript(loc, ty_expr, Some(index_expr)) => { + self.index_into_array(*loc, ty_expr, index_expr, ctx) + } + ArraySlice(loc, _lhs_expr, _maybe_middle_expr, _maybe_rhs) => Err(ExprErr::Todo( + *loc, + "Array slicing not currently supported".to_string(), + )), + ArrayLiteral(loc, _) => Err(ExprErr::Todo( + *loc, + "Array literal not currently supported".to_string(), + )), + + // Comparator + Equal(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Eq, rhs, ctx), + NotEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Neq, rhs, ctx), + Less(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lt, rhs, ctx), + More(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gt, rhs, ctx), + LessEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lte, rhs, ctx), + MoreEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gte, rhs, ctx), + + // Logical + Not(loc, expr) => self.not(*loc, expr, ctx), + And(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::And, rhs, ctx), + Or(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Or, rhs, ctx), + + // Function calls + FunctionCallBlock(loc, _func_expr, _input_exprs) => { + // TODO: update msg node + Err(ExprErr::Todo( + *loc, + "Function call block is unsupported. We shouldn't have hit this code path" + .to_string(), + )) + } + NamedFunctionCall(loc, func_expr, input_args) => { + self.named_fn_call_expr(ctx, loc, func_expr, input_args) + } + FunctionCall(loc, func_expr, input_exprs) => { + let updated_func_expr = match **func_expr { + FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { + // we dont currently handle the `{value: .. gas: ..}` msg updating + self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); + inner_func_expr.clone() + } + _ => func_expr.clone(), + }; + + self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) + } + // member + New(_loc, expr) => self.parse_ctx_expr(expr, ctx), + This(loc) => { + let var = ContextVar::new_from_contract( + *loc, + ctx.associated_contract(self).into_expr_err(*loc)?, + self, + ) + .into_expr_err(*loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr(ExprRet::Single(cvar), self) + .into_expr_err(*loc)?; + Ok(()) + } + MemberAccess(loc, member_expr, ident) => { + self.member_access(*loc, member_expr, ident, ctx) + } + + Delete(loc, expr) => { + fn delete_match( + ctx: ContextNode, + loc: &Loc, + analyzer: &mut (impl GraphBackend + + AnalyzerBackend), + ret: ExprRet, + ) { + match ret { + ExprRet::CtxKilled(kind) => { + let _ = ctx.kill(analyzer, *loc, kind); + } + ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { + let mut new_var = + analyzer.advance_var_in_ctx(cvar.into(), *loc, ctx).unwrap(); + let res = new_var.sol_delete_range(analyzer).into_expr_err(*loc); + let _ = analyzer.add_if_err(res); + } + ExprRet::Multi(inner) => { + inner + .iter() + .for_each(|i| delete_match(ctx, loc, analyzer, i.clone())); + } + ExprRet::Null => {} + } + } + + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + tracing::trace!("Delete variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "Delete operation had no right hand side".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + delete_match(ctx, &loc, analyzer, ret); + Ok(()) + }) + } + + // de/increment stuff + PreIncrement(loc, expr) => self.pre_increment(expr, *loc, ctx), + PostIncrement(loc, expr) => self.post_increment(expr, *loc, ctx), + PreDecrement(loc, expr) => self.pre_decrement(expr, *loc, ctx), + PostDecrement(loc, expr) => self.post_decrement(expr, *loc, ctx), + + // Misc. + Variable(ident) => self.variable(ident, ctx, None), + Type(loc, ty) => { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(idx) = self.builtins().get(&builtin) { + ctx.push_expr(ExprRet::Single(*idx), self) + .into_expr_err(*loc)?; + Ok(()) + } else { + let idx = self.add_node(Node::Builtin(builtin.clone())); + self.builtins_mut().insert(builtin, idx); + ctx.push_expr(ExprRet::Single(idx), self) + .into_expr_err(*loc)?; + Ok(()) + } + } else { + ctx.push_expr(ExprRet::Null, self).into_expr_err(*loc)?; + Ok(()) + } + } + Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index c959f033..a26a7a87 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1,533 +1,32 @@ //! Trait and blanket implementation for the core parsing loop use crate::{ - func_call::{func_caller::FuncCaller, modifier::ModifierCaller}, loops::Looper, yul::YulBuilder, ExprErr, ExprParser, IntoExprErr, + ExprErr, IntoExprErr, }; use graph::{ - elem::*, nodes::{ - Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, FunctionReturnNode, KilledKind, + ContextNode, ContextVarNode, ExprRet, KilledKind, }, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, Range, VarType, + AnalyzerBackend, ContextEdge, Edge, GraphError, }; -use shared::NodeIdx; -use ethers_core::types::{I256, U256}; -use petgraph::{visit::EdgeRef, Direction}; -use solang_parser::{ - helpers::CodeLocation, - pt::{Expression, Loc, Statement, VariableDeclaration, YulStatement}, -}; +use solang_parser::pt::{Expression, Loc}; impl ContextBuilder for T where - T: AnalyzerBackend + Sized + ExprParser + T: AnalyzerBackend + Sized + StatementParser { } +mod stmt; +mod expr; + +pub use stmt::*; +pub use expr::*; + /// Dispatcher for building up a context of a function pub trait ContextBuilder: - AnalyzerBackend + Sized + ExprParser + AnalyzerBackend + Sized + StatementParser { - /// Performs setup for parsing a solidity statement - fn parse_ctx_statement( - &mut self, - stmt: &Statement, - unchecked: bool, - parent_ctx: Option + Clone + Copy>, - ) where - Self: Sized, - { - if let Some(parent) = parent_ctx { - match self.node(parent) { - Node::Context(_) => { - let ctx = ContextNode::from(parent.into()); - if !ctx.killed_or_ret(self).unwrap() { - if let Some(live_edges) = - self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) - { - if live_edges.is_empty() { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) - } else { - live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_stmt_inner(stmt, unchecked, Some(*fork_ctx)); - }); - } - } - } - } - _ => self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx), - } - } else { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - /// Performs parsing of a solidity statement - fn parse_ctx_stmt_inner( - &mut self, - stmt: &Statement, - unchecked: bool, - parent_ctx: Option + Clone + Copy>, - ) where - Self: Sized, - { - use Statement::*; - // println!("stmt: {:#?}, node: {:#?}", stmt, if let Some(node) = parent_ctx { Some(self.node(node.into())) } else { None}); - // if let Some(ctx) = parent_ctx { - // if let Node::Context(_) = self.node(ctx) { - // println!("ctx: {}, {:#?}", ContextNode::from(ctx.into()).path(self), stmt); - // } - // } - - // at the end of a statement we shouldn't have anything in the stack? - if let Some(ctx) = parent_ctx { - if let Node::Context(_) = self.node(ctx) { - let c = ContextNode::from(ctx.into()); - let _ = c.pop_expr_latest(stmt.loc(), self); - if unchecked { - let _ = c.set_unchecked(self); - } else { - let _ = c.unset_unchecked(self); - } - - if c.killed_or_ret(self).unwrap() { - return; - } - } - } - - match stmt { - Block { - loc, - unchecked, - statements, - } => { - tracing::trace!("parsing block"); - let parent = parent_ctx.expect("Free floating contexts shouldn't happen"); - let mut entry_loc = None; - let mut mods_set = false; - let ctx_node = match self.node(parent) { - Node::Function(fn_node) => { - mods_set = fn_node.modifiers_set; - entry_loc = Some(fn_node.loc); - let ctx = Context::new( - FunctionNode::from(parent.into()), - self.add_if_err( - FunctionNode::from(parent.into()) - .name(self) - .into_expr_err(stmt.loc()), - ) - .unwrap(), - *loc, - ); - let ctx_node = self.add_node(Node::Context(ctx)); - self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Context)); - - ctx_node - } - Node::Context(_) => { - // let ctx = Context::new_subctx( - // ContextNode::from(parent.into()), - // *loc, - // false, - // self, - // ); - // let ctx_node = self.add_node(Node::Context(ctx)); - // self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Subcontext)); - // ctx_node - parent.into() - } - e => todo!( - "Expected a context to be created by a function or context but got: {:?}", - e - ), - }; - - // optionally add named input and named outputs into context - let (params, inputs): (Vec<_>, Vec<_>) = self - .graph() - .edges_directed(parent.into(), Direction::Incoming) - .filter(|edge| *edge.weight() == Edge::FunctionParam) - .map(|edge| FunctionParamNode::from(edge.source())) - .collect::>() - .into_iter() - .filter_map(|param_node| { - let res = param_node - .underlying(self) - .into_expr_err(stmt.loc()) - .cloned(); - let func_param = self.add_if_err(res)?; - if let Some(cvar) = ContextVar::maybe_new_from_func_param(self, func_param) - { - let cvar_node = self.add_node(Node::ContextVar(cvar)); - ContextNode::from(ctx_node) - .add_var(cvar_node.into(), self) - .unwrap(); - self.add_edge( - cvar_node, - ctx_node, - Edge::Context(ContextEdge::Variable), - ); - - self.add_edge( - cvar_node, - ctx_node, - Edge::Context(ContextEdge::CalldataVariable), - ); - - Some((param_node, ContextVarNode::from(cvar_node))) - } else { - None - } - }) - .unzip(); - - self.graph() - .edges_directed(parent.into(), Direction::Incoming) - .filter(|edge| *edge.weight() == Edge::FunctionReturn) - .map(|edge| FunctionReturnNode::from(edge.source())) - .collect::>() - .iter() - .for_each(|ret_node| { - let res = ret_node.underlying(self).into_expr_err(stmt.loc()).cloned(); - let func_ret = self.add_if_err(res).unwrap(); - if let Some(cvar) = ContextVar::maybe_new_from_func_ret(self, func_ret) { - let cvar_node = self.add_node(Node::ContextVar(cvar)); - ContextNode::from(ctx_node) - .add_var(cvar_node.into(), self) - .unwrap(); - self.add_edge( - cvar_node, - ctx_node, - Edge::Context(ContextEdge::Variable), - ); - } - }); - - if let Some(fn_loc) = entry_loc { - if !mods_set { - let parent = FunctionNode::from(parent.into()); - let _ = self - .set_modifiers(parent, ctx_node.into()) - .map_err(|e| self.add_expr_err(e)); - } - - let res = self.func_call_inner( - true, - ctx_node.into(), - parent.into().into(), - fn_loc, - inputs, - params, - None, - None, - ); - if self.widen_if_limit_hit(ctx_node.into(), res) { - return; - } - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad funciton call"); - let res = ContextNode::from(ctx_node) - .kill( - analyzer, - fn_loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(fn_loc); - let _ = analyzer.add_if_err(res); - } - Ok(()) - }); - - if self.widen_if_limit_hit(ctx_node.into(), res) { - return; - } - - return; - } - - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, _loc| { - statements - .iter() - .for_each(|stmt| analyzer.parse_ctx_statement(stmt, *unchecked, Some(ctx))); - Ok(()) - }); - if self.widen_if_limit_hit(ctx_node.into(), res) {} - } - VariableDefinition(loc, var_decl, maybe_expr) => { - let ctx = ContextNode::from( - parent_ctx - .expect("No context for variable definition?") - .into(), - ); - tracing::trace!( - "parsing variable definition, {:?} {var_decl:?}", - ctx.path(self) - ); - - if let Some(rhs) = maybe_expr { - match self.parse_ctx_expr(rhs, ctx) { - Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - let Some(rhs_paths) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - format!( - "Variable definition had no right hand side, {}", - ctx.path(analyzer) - ), - )); - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(&var_decl.ty, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "Variable definition had no left hand side" - .to_string(), - )); - }; - - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer) - .into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_var_def( - ctx, - var_decl, - loc, - &lhs_paths, - Some(&rhs_paths), - )?; - Ok(()) - }) - } else { - Ok(()) - } - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - ret => { - let _ = self.widen_if_limit_hit(ctx, ret); - } - } - } else { - let res = self.parse_ctx_expr(&var_decl.ty, ctx); - if self.widen_if_limit_hit(ctx, res) { - return; - } - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "Variable definition had no left hand side".to_string(), - )); - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, None)?; - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - } - Args(_loc, _args) => { - tracing::trace!("parsing args, {_args:?}"); - } - If(loc, if_expr, true_expr, maybe_false_expr) => { - tracing::trace!("parsing if, {if_expr:?}"); - let ctx = ContextNode::from(parent_ctx.expect("Dangling if statement").into()); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.cond_op_stmt(loc, if_expr, true_expr, maybe_false_expr, ctx) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - While(loc, cond, body) => { - tracing::trace!("parsing while, {cond:?}"); - if let Some(parent) = parent_ctx { - let res = self.apply_to_edges( - ContextNode::from(parent.into()), - *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, cond, body), - ); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - Expression(loc, expr) => { - tracing::trace!("parsing expr, {expr:?}"); - if let Some(parent) = parent_ctx { - let ctx = parent.into().into(); - match self.parse_ctx_expr(expr, ctx) { - Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad expr"); - ContextNode::from(parent.into()) - .kill( - analyzer, - loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(loc)?; - } - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - e => { - let _ = self.widen_if_limit_hit(ctx, e); - } - } - } - } - For(loc, maybe_for_start, maybe_for_middle, maybe_for_end, maybe_for_body) => { - tracing::trace!("parsing for loop"); - if let Some(parent) = parent_ctx { - let res = - self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { - analyzer.for_loop( - loc, - ctx, - maybe_for_start, - maybe_for_middle, - maybe_for_end, - maybe_for_body, - ) - }); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - DoWhile(loc, while_stmt, while_expr) => { - tracing::trace!("parsing `do while`, {while_expr:?}"); - if let Some(parent) = parent_ctx { - let res = self.apply_to_edges( - ContextNode::from(parent.into()), - *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, while_expr, while_stmt), - ); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } - Continue(_loc) => { - tracing::trace!("parsing continue"); - // TODO: We cheat in loops by just widening so continues dont matter yet - } - Break(_loc) => { - tracing::trace!("parsing break"); - // TODO: We cheat in loops by just widening so breaks dont matter yet - } - Assembly { - loc, - dialect: _, - flags: _, - block: yul_block, - } => { - tracing::trace!("parsing assembly"); - let ctx = ContextNode::from( - parent_ctx - .expect("No context for variable definition?") - .into(), - ); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(&YulStatement::Block(yul_block.clone()), ctx); - Ok(()) - }); - let _ = self.widen_if_limit_hit(ctx, res); - } - Return(loc, maybe_ret_expr) => { - tracing::trace!("parsing return"); - if let Some(ret_expr) = maybe_ret_expr { - if let Some(parent) = parent_ctx { - let res = self.parse_ctx_expr(ret_expr, parent.into().into()); - if self.widen_if_limit_hit(parent.into().into(), res) { - return; - } - let res = self.apply_to_edges( - parent.into().into(), - *loc, - &|analyzer, ctx, loc| { - let Ok(Some(ret)) = ctx.pop_expr_latest(loc, analyzer) else { - return Err(ExprErr::NoLhs( - loc, - "Return did not have a associated expression".to_string(), - )); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - let paths = ret.flatten(); - if paths.is_killed() { - tracing::trace!("killing due to bad return"); - let res = ContextNode::from(parent.into()) - .kill(analyzer, loc, paths.killed_kind().unwrap()) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - return Ok(()); - } - analyzer.return_match(ctx, &loc, &paths); - Ok(()) - }, - ); - let _ = self.widen_if_limit_hit(parent.into().into(), res); - } - } else if let Some(parent) = parent_ctx { - let res = - self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { - let res = ctx.add_empty_return(loc, analyzer).into_expr_err(loc); - analyzer.add_if_err(res); - Ok(()) - }); - if self.widen_if_limit_hit(parent.into().into(), res) { - return; - } - } - } - Revert(loc, _maybe_err_path, _exprs) => { - tracing::trace!("parsing revert"); - if let Some(parent) = parent_ctx { - let parent = ContextNode::from(parent.into()); - let res = self.apply_to_edges(parent, *loc, &|analyzer, ctx, loc| { - let res = ctx - .kill(analyzer, loc, KilledKind::Revert) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - Ok(()) - }); - let _ = self.add_if_err(res); - } - } - RevertNamedArgs(_loc, _maybe_err_path, _named_args) => { - tracing::trace!("parsing named revert"); - todo!("revert named args") - } - Emit(_loc, _emit_expr) => {} - Try(_loc, _try_expr, _maybe_returns, _clauses) => {} - Error(_loc) => {} - } - } /// TODO: rename this. Sometimes we dont want to kill a context if we hit an error fn widen_if_limit_hit(&mut self, ctx: ContextNode, maybe_err: Result<(), ExprErr>) -> bool { @@ -588,1006 +87,6 @@ pub trait ContextBuilder: } } - /// Match on the [`ExprRet`]s of a variable definition - fn match_var_def( - &mut self, - ctx: ContextNode, - var_decl: &VariableDeclaration, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: Option<&ExprRet>, - ) -> Result { - match (lhs_paths, rhs_paths) { - (ExprRet::CtxKilled(kind), _) | (_, Some(ExprRet::CtxKilled(kind))) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(true) - } - (ExprRet::Single(ty), Some(ExprRet::SingleLiteral(rhs))) => { - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let res = rhs_cvar.literal_cast_from_ty(ty, self).into_expr_err(loc); - let _ = self.add_if_err(res); - self.match_var_def( - ctx, - var_decl, - loc, - lhs_paths, - Some(&ExprRet::Single(rhs_cvar.into())), - ) - } - (ExprRet::Single(ty), Some(ExprRet::Single(rhs))) => { - let name = var_decl.name.clone().expect("Variable wasn't named"); - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let var = ContextVar { - loc: Some(loc), - name: name.to_string(), - display_name: name.to_string(), - storage: var_decl.storage.as_ref().map(|s| s.clone().into()), - is_tmp: false, - is_symbolic: true, - tmp_of: None, - is_return: false, - ty, - }; - let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); - ctx.add_var(lhs, self).into_expr_err(loc)?; - self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); - let rhs = ContextVarNode::from(*rhs); - - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let _ = analyzer.assign(loc, lhs, rhs, ctx)?; - // match_assign_ret(analyzer, ctx, ret); - Ok(()) - })?; - - Ok(false) - } - (ExprRet::Single(ty), None) => { - let name = var_decl.name.clone().expect("Variable wasn't named"); - let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); - let var = ContextVar { - loc: Some(loc), - name: name.to_string(), - display_name: name.to_string(), - storage: var_decl.storage.as_ref().map(|s| s.clone().into()), - is_tmp: false, - is_symbolic: true, - tmp_of: None, - is_return: false, - ty, - }; - let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); - ctx.add_var(lhs, self).into_expr_err(loc)?; - self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); - Ok(false) - } - (l @ ExprRet::Single(_lhs), Some(ExprRet::Multi(rhs_sides))) => Ok(rhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, l, Some(expr_ret))) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), r @ Some(ExprRet::Single(_))) => Ok(lhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, r)) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), None) => Ok(lhs_sides - .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, None)) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)), - (ExprRet::Multi(lhs_sides), Some(ExprRet::Multi(rhs_sides))) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - Ok(lhs_sides - .iter() - .zip(rhs_sides.iter()) - .map(|(lhs_expr_ret, rhs_expr_ret)| { - self.match_var_def(ctx, var_decl, loc, lhs_expr_ret, Some(rhs_expr_ret)) - }) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)) - } else { - Ok(rhs_sides - .iter() - .map(|rhs_expr_ret| { - self.match_var_def(ctx, var_decl, loc, lhs_paths, Some(rhs_expr_ret)) - }) - .collect::, ExprErr>>()? - .iter() - .all(|e| *e)) - } - } - (_e, _f) => Err(ExprErr::Todo( - loc, - "Unhandled ExprRet combination in `match_var_def`".to_string(), - )), - } - } - - /// Perform setup for parsing an expression - fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - if !ctx.killed_or_ret(self).unwrap() { - let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; - if edges.is_empty() { - self.parse_ctx_expr_inner(expr, ctx) - } else { - edges - .iter() - .try_for_each(|fork_ctx| self.parse_ctx_expr(expr, *fork_ctx))?; - Ok(()) - } - } else { - Ok(()) - } - } - - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self).replace('.', "\n\t.")))] - /// Perform parsing of an expression - fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - use Expression::*; - // println!( - // "ctx: {}, current stack: {:?}, \nexpr: {:?}\n", - // ctx.underlying(self).unwrap().path, - // ctx.underlying(self) - // .unwrap() - // .expr_ret_stack - // .iter() - // .map(|i| i.debug_str(self)) - // .collect::>(), - // expr - // ); - match expr { - // literals - NumberLiteral(loc, int, exp, _unit) => self.number_literal(ctx, *loc, int, exp, false), - AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), - StringLiteral(lits) => lits - .iter() - .try_for_each(|lit| self.string_literal(ctx, lit.loc, &lit.string)), - BoolLiteral(loc, b) => self.bool_literal(ctx, *loc, *b), - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), - HexLiteral(hexes) => self.hex_literals(ctx, hexes), - RationalNumberLiteral(loc, integer, fraction, exp, unit) => { - self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) - } - Negate(_loc, expr) => match &**expr { - NumberLiteral(loc, int, exp, _unit) => { - self.number_literal(ctx, *loc, int, exp, true) - } - HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), - e => { - self.parse_ctx_expr(e, ctx)?; - self.apply_to_edges(ctx, e.loc(), &|analyzer, ctx, loc| { - tracing::trace!("Negate variable pop"); - let Some(rhs_paths) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "No variable present to negate".to_string(), - )); - }; - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - // Solidity is dumb and used to allow negation of unsigned integers. - // That means we have to cast this as a int256. - let var = rhs_paths.expect_single().into_expr_err(loc)?; - - let zero = - analyzer.add_node(Node::Concrete(Concrete::from(I256::from(0i32)))); - let zero = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero.into(), - analyzer, - ) - .into_expr_err(loc)?; - let zero = analyzer.add_node(Node::ContextVar(zero)); - let new_underlying = ContextVarNode::from(var) - .underlying(analyzer) - .into_expr_err(loc)? - .clone() - .as_cast_tmp(loc, ctx, Builtin::Int(256), analyzer) - .into_expr_err(loc)?; - let node = analyzer.add_node(Node::ContextVar(new_underlying)); - ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - - ContextVarNode::from(node) - .cast_from(&ContextVarNode::from(zero), analyzer) - .into_expr_err(loc)?; - - let lhs_paths = ExprRet::Single(zero); - analyzer.op_match( - ctx, - loc, - &lhs_paths, - &ExprRet::Single( - ContextVarNode::from(node).latest_version(analyzer).into(), - ), - RangeOp::Sub(true), - false, - ) - }) - } // e => todo!("UnaryMinus unexpected rhs: {e:?}"), - }, - UnaryPlus(_loc, e) => todo!("UnaryPlus unexpected rhs: {e:?}"), - - // Binary ops - Power(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) - } - Add(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignAdd(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Add(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Subtract(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignSubtract(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Sub(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Multiply(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), - false, - ), - AssignMultiply(loc, lhs_expr, rhs_expr) => self.op_expr( - *loc, - lhs_expr, - rhs_expr, - ctx, - RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), - true, - ), - Divide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), false) - } - AssignDivide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), true) - } - Modulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) - } - AssignModulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) - } - ShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) - } - AssignShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) - } - ShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) - } - AssignShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) - } - ConditionalOperator(loc, if_expr, true_expr, false_expr) => { - self.cond_op_expr(*loc, if_expr, true_expr, false_expr, ctx) - } - - // Bitwise ops - BitwiseAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) - } - AssignAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) - } - BitwiseXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) - } - AssignXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) - } - BitwiseOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) - } - AssignOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) - } - BitwiseNot(loc, lhs_expr) => self.bit_not(*loc, lhs_expr, ctx), - - // assign - Assign(loc, lhs_expr, rhs_expr) => self.assign_exprs(*loc, lhs_expr, rhs_expr, ctx), - List(loc, params) => self.list(ctx, *loc, params), - // array - ArraySubscript(_loc, ty_expr, None) => self.array_ty(ty_expr, ctx), - ArraySubscript(loc, ty_expr, Some(index_expr)) => { - self.index_into_array(*loc, ty_expr, index_expr, ctx) - } - ArraySlice(loc, _lhs_expr, _maybe_middle_expr, _maybe_rhs) => Err(ExprErr::Todo( - *loc, - "Array slicing not currently supported".to_string(), - )), - ArrayLiteral(loc, _) => Err(ExprErr::Todo( - *loc, - "Array literal not currently supported".to_string(), - )), - - // Comparator - Equal(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Eq, rhs, ctx), - NotEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Neq, rhs, ctx), - Less(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lt, rhs, ctx), - More(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gt, rhs, ctx), - LessEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lte, rhs, ctx), - MoreEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gte, rhs, ctx), - - // Logical - Not(loc, expr) => self.not(*loc, expr, ctx), - And(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::And, rhs, ctx), - Or(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Or, rhs, ctx), - - // Function calls - FunctionCallBlock(loc, _func_expr, _input_exprs) => { - // TODO: update msg node - Err(ExprErr::Todo( - *loc, - "Function call block is unsupported. We shouldn't have hit this code path" - .to_string(), - )) - } - NamedFunctionCall(loc, func_expr, input_args) => { - self.named_fn_call_expr(ctx, loc, func_expr, input_args) - } - FunctionCall(loc, func_expr, input_exprs) => { - let updated_func_expr = match **func_expr { - FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { - // we dont currently handle the `{value: .. gas: ..}` msg updating - self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); - inner_func_expr.clone() - } - _ => func_expr.clone(), - }; - - self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) - } - // member - New(_loc, expr) => self.parse_ctx_expr(expr, ctx), - This(loc) => { - let var = ContextVar::new_from_contract( - *loc, - ctx.associated_contract(self).into_expr_err(*loc)?, - self, - ) - .into_expr_err(*loc)?; - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).into_expr_err(*loc)?; - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr(ExprRet::Single(cvar), self) - .into_expr_err(*loc)?; - Ok(()) - } - MemberAccess(loc, member_expr, ident) => { - self.member_access(*loc, member_expr, ident, ctx) - } - - Delete(loc, expr) => { - fn delete_match( - ctx: ContextNode, - loc: &Loc, - analyzer: &mut (impl GraphBackend - + AnalyzerBackend), - ret: ExprRet, - ) { - match ret { - ExprRet::CtxKilled(kind) => { - let _ = ctx.kill(analyzer, *loc, kind); - } - ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { - let mut new_var = - analyzer.advance_var_in_ctx(cvar.into(), *loc, ctx).unwrap(); - let res = new_var.sol_delete_range(analyzer).into_expr_err(*loc); - let _ = analyzer.add_if_err(res); - } - ExprRet::Multi(inner) => { - inner - .iter() - .for_each(|i| delete_match(ctx, loc, analyzer, i.clone())); - } - ExprRet::Null => {} - } - } - - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("Delete variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "Delete operation had no right hand side".to_string(), - )); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - delete_match(ctx, &loc, analyzer, ret); - Ok(()) - }) - } - - // de/increment stuff - PreIncrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PreIncrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "PreIncrement operation had no right hand side".to_string(), - )); - }; - - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, true, true, loc, &ret) - }) - } - PostIncrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PostIncrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "PostIncrement operation had no right hand side".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, false, true, loc, &ret) - }) - } - PreDecrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PreDecrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "PreDecrement operation had no right hand side".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, true, false, loc, &ret) - }) - } - PostDecrement(loc, expr) => { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - tracing::trace!("PostDecrement variable pop"); - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "PostDecrement operation had no right hand side".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_in_de_crement(ctx, false, false, loc, &ret) - }) - } - - // Misc. - Variable(ident) => self.variable(ident, ctx, None), - Type(loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { - if let Some(idx) = self.builtins().get(&builtin) { - ctx.push_expr(ExprRet::Single(*idx), self) - .into_expr_err(*loc)?; - Ok(()) - } else { - let idx = self.add_node(Node::Builtin(builtin.clone())); - self.builtins_mut().insert(builtin, idx); - ctx.push_expr(ExprRet::Single(idx), self) - .into_expr_err(*loc)?; - Ok(()) - } - } else { - ctx.push_expr(ExprRet::Null, self).into_expr_err(*loc)?; - Ok(()) - } - } - Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), - } - } - - /// Match on the [`ExprRet`]s of a pre-or-post in/decrement and performs it - fn match_in_de_crement( - &mut self, - ctx: ContextNode, - pre: bool, - increment: bool, - loc: Loc, - rhs: &ExprRet, - ) -> Result<(), ExprErr> { - match rhs { - ExprRet::CtxKilled(kind) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(()) - } - ExprRet::SingleLiteral(var) => { - let res = ContextVarNode::from(*var) - .try_increase_size(self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) - } - ExprRet::Single(var) => { - let cvar = ContextVarNode::from(*var); - let elem = Elem::from(cvar); - let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); - // if let Some(r) = cvar.range(self).into_expr_err(loc)? { - if increment { - if pre { - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() + one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - let res = new_cvar.set_range_max(self, elem + one).into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() + one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem + one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(dup.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - } else if pre { - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem - one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar - .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - new_cvar - .set_range_max(self, elem - one) - .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(dup.into()), self) - .into_expr_err(loc)?; - Ok(()) - } - // } else { - // panic!("No range in post-increment") - // } - } - ExprRet::Multi(inner) => inner - .iter() - .try_for_each(|expr| self.match_in_de_crement(ctx, pre, increment, loc, expr)), - ExprRet::Null => Ok(()), - } - } - - #[tracing::instrument(level = "trace", skip_all)] - /// Parse an assignment expression - fn assign_exprs( - &mut self, - loc: Loc, - lhs_expr: &Expression, - rhs_expr: &Expression, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(rhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( - loc, - "Assign operation had no right hand side".to_string(), - )); - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Assign operation had no left hand side".to_string(), - )); - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_assign_sides(ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; - Ok(()) - }) - }) - } - - /// Match on the [`ExprRet`]s of an assignment expression - fn match_assign_sides( - &mut self, - ctx: ContextNode, - loc: Loc, - lhs_paths: &ExprRet, - rhs_paths: &ExprRet, - ) -> Result<(), ExprErr> { - match (lhs_paths, rhs_paths) { - (_, ExprRet::Null) | (ExprRet::Null, _) => Ok(()), - (ExprRet::CtxKilled(kind), _) | (_, ExprRet::CtxKilled(kind)) => { - ctx.kill(self, loc, *kind).into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let res = rhs_cvar - .literal_cast_from(&lhs_cvar, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { - let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); - let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) - .into_expr_err(loc)?; - Ok(()) - } - (l @ ExprRet::Single(_), ExprRet::Multi(rhs_sides)) => rhs_sides - .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, l, expr_ret)), - (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { - lhs_sides - .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, expr_ret, r)) - } - (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { - // try to zip sides if they are the same length - if lhs_sides.len() == rhs_sides.len() { - lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( - |(lhs_expr_ret, rhs_expr_ret)| { - self.match_assign_sides(ctx, loc, lhs_expr_ret, rhs_expr_ret) - }, - ) - } else { - rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.match_assign_sides(ctx, loc, lhs_paths, rhs_expr_ret) - }) - } - } - (e, f) => todo!("any: {:?} {:?}", e, f), - } - } - - /// Perform an assignment - fn assign( - &mut self, - loc: Loc, - lhs_cvar: ContextVarNode, - rhs_cvar: ContextVarNode, - ctx: ContextNode, - ) -> Result { - tracing::trace!( - "assigning: {} to {}", - rhs_cvar.display_name(self).unwrap(), - lhs_cvar.display_name(self).unwrap(), - ); - - let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( - Elem::from(rhs_cvar.latest_version(self)), - Elem::from(rhs_cvar.latest_version(self)), - ); - - let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; - new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = - rhs_cvar.tmp_of(self).into_expr_err(loc)?; - if lhs_cvar.is_storage(self).into_expr_err(loc)? { - self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); - } - - if rhs_cvar.underlying(self).into_expr_err(loc)?.is_return { - if let Some(rhs_ctx) = rhs_cvar.maybe_ctx(self) { - self.add_edge( - rhs_cvar, - new_lhs, - Edge::Context(ContextEdge::ReturnAssign( - rhs_ctx.underlying(self).unwrap().ext_fn_call.is_some(), - )), - ); - } else { - return Err(ExprErr::GraphError( - loc, - GraphError::DetachedVariable(format!( - "No context for variable: {}, node idx: {}, curr ctx: {}, lhs ctx: {}", - rhs_cvar.display_name(self).unwrap(), - rhs_cvar.0, - ctx.path(self), - lhs_cvar.ctx(self).path(self) - )), - )); - } - } - - if !lhs_cvar.ty_eq(&rhs_cvar, self).into_expr_err(loc)? { - let cast_to_min = match lhs_cvar.range_min(self).into_expr_err(loc)? { - Some(v) => v, - None => { - return Err(ExprErr::BadRange( - loc, - format!( - "No range during cast? {:?}, {:?}", - lhs_cvar.underlying(self).unwrap(), - rhs_cvar.underlying(self).unwrap(), - ), - )) - } - }; - - let cast_to_max = match lhs_cvar.range_max(self).into_expr_err(loc)? { - Some(v) => v, - None => { - return Err(ExprErr::BadRange( - loc, - format!( - "No range during cast? {:?}, {:?}", - lhs_cvar.underlying(self).unwrap(), - rhs_cvar.underlying(self).unwrap(), - ), - )) - } - }; - - let _ = new_lhs.try_set_range_min(self, new_lower_bound.cast(cast_to_min)); - let _ = new_lhs.try_set_range_max(self, new_upper_bound.cast(cast_to_max)); - } else { - let _ = new_lhs.try_set_range_min(self, new_lower_bound); - let _ = new_lhs.try_set_range_max(self, new_upper_bound); - } - if let Some(rhs_range) = rhs_cvar.ref_range(self).into_expr_err(loc)? { - let res = new_lhs - .try_set_range_exclusions(self, rhs_range.exclusions.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(arr) = lhs_cvar.index_to_array(self) { - if let Some(index) = lhs_cvar.index_access_to_index(self) { - let next_arr = self.advance_var_in_ctx(arr, loc, ctx)?; - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - } - } - - // advance the rhs variable to avoid recursion issues - self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; - Ok(ExprRet::Single(new_lhs.into())) - } - - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - /// Creates a newer version of a variable in the context. It may or may not actually - /// create this new variable depending on if there are two successively identical version. - fn advance_var_in_ctx( - &mut self, - cvar_node: ContextVarNode, - loc: Loc, - ctx: ContextNode, - ) -> Result { - self.advance_var_in_ctx_forcible(cvar_node, loc, ctx, false) - } - - #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] - /// Creates a new version of a variable in a context. Takes an additional parameter - /// denoting whether or not to force the creation, skipping an optimization. - fn advance_var_in_ctx_forcible( - &mut self, - cvar_node: ContextVarNode, - loc: Loc, - ctx: ContextNode, - force: bool, - ) -> Result { - tracing::trace!( - "advancing variable: {}", - cvar_node.display_name(self).into_expr_err(loc)? - ); - if let Some(cvar) = cvar_node.next_version(self) { - panic!( - "Not latest version of: {}", - cvar.display_name(self).unwrap() - ); - } - if let Some(child) = ctx.underlying(self).into_expr_err(loc)?.child { - return Err(ExprErr::GraphError( - loc, - GraphError::VariableUpdateInOldContext(format!( - "Variable update of {} in old context: parent: {}, child: {:#?}", - cvar_node.display_name(self).unwrap(), - ctx.path(self), - child - )), - )); - } - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - // get the old context - let new_cvarnode; - - 'a: { - if let Some(old_ctx) = cvar_node.maybe_ctx(self) { - if !force { - // get the previous version to remove and prevent spurious nodes - if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { - let prev_version = prev.underlying(self).into_expr_err(loc)?; - // check if there was no change between the previous version and the latest version - if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { - // there was no change in the current context, just give them the current variable - new_cvarnode = cvar_node.into(); - break 'a; - } - } - } - - new_cvar.loc = Some(loc); - new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - if old_ctx != ctx { - ctx.add_var(new_cvarnode.into(), self).into_expr_err(loc)?; - self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); - self.add_edge( - new_cvarnode, - cvar_node.0, - Edge::Context(ContextEdge::InheritedVariable), - ); - } else { - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - } - } else { - new_cvar.loc = Some(loc); - new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - } - } - - Ok(ContextVarNode::from(new_cvarnode)) - } - - /// Creates a new version of a variable in it's current context - fn advance_var_in_curr_ctx( - &mut self, - cvar_node: ContextVarNode, - loc: Loc, - ) -> Result { - tracing::trace!( - "advancing variable: {}", - cvar_node.display_name(self).into_expr_err(loc)? - ); - if let Some(cvar) = cvar_node.next_version(self) { - panic!( - "Not latest version of: {}", - cvar.display_name(self).unwrap() - ); - } - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - new_cvar.loc = Some(loc); - - let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - - Ok(ContextVarNode::from(new_cvarnode)) - } - - /// - fn advance_var_underlying(&mut self, cvar_node: ContextVarNode, loc: Loc) -> &mut ContextVar { - assert_eq!(None, cvar_node.next_version(self)); - let mut new_cvar = cvar_node - .latest_version(self) - .underlying(self) - .unwrap() - .clone(); - new_cvar.loc = Some(loc); - let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); - self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); - ContextVarNode::from(new_cvarnode) - .underlying_mut(self) - .unwrap() - } - /// Apply an expression or statement to all *live* edges of a context. This is used everywhere /// to ensure we only ever update *live* contexts. If a context has a subcontext, we *never* /// want to update the original context. We only ever want to operate on the latest edges. diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs new file mode 100644 index 00000000..526b6ae4 --- /dev/null +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -0,0 +1,528 @@ + +use crate::{ + context_builder::ContextBuilder, + ExpressionParser, + func_call::{func_caller::FuncCaller, modifier::ModifierCaller}, loops::Looper, yul::YulBuilder, ExprErr, IntoExprErr, +}; + +use graph::{ + nodes::{ + Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, FunctionReturnNode, KilledKind, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; +use shared::NodeIdx; + + +use petgraph::{visit::EdgeRef, Direction}; +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Statement, YulStatement}, +}; + + +impl StatementParser for T where + T: AnalyzerBackend + Sized + ExpressionParser +{ +} + +/// Solidity statement parser +pub trait StatementParser: + AnalyzerBackend + Sized + ExpressionParser +{ + /// Performs setup for parsing a solidity statement + fn parse_ctx_statement( + &mut self, + stmt: &Statement, + unchecked: bool, + parent_ctx: Option + Clone + Copy>, + ) where + Self: Sized, + { + if let Some(parent) = parent_ctx { + match self.node(parent) { + Node::Context(_) => { + let ctx = ContextNode::from(parent.into()); + if !ctx.killed_or_ret(self).unwrap() { + if let Some(live_edges) = + self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) + { + if live_edges.is_empty() { + self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + } else { + live_edges.iter().for_each(|fork_ctx| { + self.parse_ctx_stmt_inner(stmt, unchecked, Some(*fork_ctx)); + }); + } + } + } + } + _ => self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx), + } + } else { + self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + } + } + + #[tracing::instrument(level = "trace", skip_all)] + /// Performs parsing of a solidity statement + fn parse_ctx_stmt_inner( + &mut self, + stmt: &Statement, + unchecked: bool, + parent_ctx: Option + Clone + Copy>, + ) where + Self: Sized, + { + use Statement::*; + // tracing::trace!("stmt: {:#?}, node: {:#?}", stmt, if let Some(node) = parent_ctx { Some(self.node(node.into())) } else { None}); + + // at the end of a statement we shouldn't have anything in the stack? + if let Some(ctx) = parent_ctx { + if let Node::Context(_) = self.node(ctx) { + let c = ContextNode::from(ctx.into()); + let _ = c.pop_expr_latest(stmt.loc(), self); + if unchecked { + let _ = c.set_unchecked(self); + } else { + let _ = c.unset_unchecked(self); + } + + if c.killed_or_ret(self).unwrap() { + return; + } + } + } + + match stmt { + Block { + loc, + unchecked, + statements, + } => { + tracing::trace!("parsing block"); + let parent = parent_ctx.expect("Free floating contexts shouldn't happen"); + let mut entry_loc = None; + let mut mods_set = false; + let ctx_node = match self.node(parent) { + Node::Function(fn_node) => { + mods_set = fn_node.modifiers_set; + entry_loc = Some(fn_node.loc); + let ctx = Context::new( + FunctionNode::from(parent.into()), + self.add_if_err( + FunctionNode::from(parent.into()) + .name(self) + .into_expr_err(stmt.loc()), + ) + .unwrap(), + *loc, + ); + let ctx_node = self.add_node(Node::Context(ctx)); + self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Context)); + + ctx_node + } + Node::Context(_) => { + // let ctx = Context::new_subctx( + // ContextNode::from(parent.into()), + // *loc, + // false, + // self, + // ); + // let ctx_node = self.add_node(Node::Context(ctx)); + // self.add_edge(ctx_node, parent, Edge::Context(ContextEdge::Subcontext)); + // ctx_node + parent.into() + } + e => todo!( + "Expected a context to be created by a function or context but got: {:?}", + e + ), + }; + + // optionally add named input and named outputs into context + let (params, inputs): (Vec<_>, Vec<_>) = self + .graph() + .edges_directed(parent.into(), Direction::Incoming) + .filter(|edge| *edge.weight() == Edge::FunctionParam) + .map(|edge| FunctionParamNode::from(edge.source())) + .collect::>() + .into_iter() + .filter_map(|param_node| { + let res = param_node + .underlying(self) + .into_expr_err(stmt.loc()) + .cloned(); + let func_param = self.add_if_err(res)?; + if let Some(cvar) = ContextVar::maybe_new_from_func_param(self, func_param) + { + let cvar_node = self.add_node(Node::ContextVar(cvar)); + ContextNode::from(ctx_node) + .add_var(cvar_node.into(), self) + .unwrap(); + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::Variable), + ); + + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::CalldataVariable), + ); + + Some((param_node, ContextVarNode::from(cvar_node))) + } else { + None + } + }) + .unzip(); + + self.graph() + .edges_directed(parent.into(), Direction::Incoming) + .filter(|edge| *edge.weight() == Edge::FunctionReturn) + .map(|edge| FunctionReturnNode::from(edge.source())) + .collect::>() + .iter() + .for_each(|ret_node| { + let res = ret_node.underlying(self).into_expr_err(stmt.loc()).cloned(); + let func_ret = self.add_if_err(res).unwrap(); + if let Some(cvar) = ContextVar::maybe_new_from_func_ret(self, func_ret) { + let cvar_node = self.add_node(Node::ContextVar(cvar)); + ContextNode::from(ctx_node) + .add_var(cvar_node.into(), self) + .unwrap(); + self.add_edge( + cvar_node, + ctx_node, + Edge::Context(ContextEdge::Variable), + ); + } + }); + + if let Some(fn_loc) = entry_loc { + if !mods_set { + let parent = FunctionNode::from(parent.into()); + let _ = self + .set_modifiers(parent, ctx_node.into()) + .map_err(|e| self.add_expr_err(e)); + } + + let res = self.func_call_inner( + true, + ctx_node.into(), + parent.into().into(), + fn_loc, + inputs, + params, + None, + None, + ); + if self.widen_if_limit_hit(ctx_node.into(), res) { + return; + } + let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad funciton call"); + let res = ContextNode::from(ctx_node) + .kill( + analyzer, + fn_loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(fn_loc); + let _ = analyzer.add_if_err(res); + } + Ok(()) + }); + + if self.widen_if_limit_hit(ctx_node.into(), res) { + return; + } + + return; + } + + let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, _loc| { + statements + .iter() + .for_each(|stmt| analyzer.parse_ctx_statement(stmt, *unchecked, Some(ctx))); + Ok(()) + }); + if self.widen_if_limit_hit(ctx_node.into(), res) {} + } + VariableDefinition(loc, var_decl, maybe_expr) => { + let ctx = ContextNode::from( + parent_ctx + .expect("No context for variable definition?") + .into(), + ); + tracing::trace!( + "parsing variable definition, {:?} {var_decl:?}", + ctx.path(self) + ); + + if let Some(rhs) = maybe_expr { + match self.parse_ctx_expr(rhs, ctx) { + Ok(()) => { + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + let Some(rhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + format!( + "Variable definition had no right hand side, {}", + ctx.path(analyzer) + ), + )); + }; + + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.parse_ctx_expr(&var_decl.ty, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side" + .to_string(), + )); + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer) + .into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def( + ctx, + var_decl, + loc, + &lhs_paths, + Some(&rhs_paths), + )?; + Ok(()) + }) + } else { + Ok(()) + } + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + ret => { + let _ = self.widen_if_limit_hit(ctx, ret); + } + } + } else { + let res = self.parse_ctx_expr(&var_decl.ty, ctx); + if self.widen_if_limit_hit(ctx, res) { + return; + } + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side".to_string(), + )); + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, None)?; + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + } + Args(_loc, _args) => { + tracing::trace!("parsing args, {_args:?}"); + } + If(loc, if_expr, true_expr, maybe_false_expr) => { + tracing::trace!("parsing if, {if_expr:?}"); + let ctx = ContextNode::from(parent_ctx.expect("Dangling if statement").into()); + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.cond_op_stmt(loc, if_expr, true_expr, maybe_false_expr, ctx) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + While(loc, cond, body) => { + tracing::trace!("parsing while, {cond:?}"); + if let Some(parent) = parent_ctx { + let res = self.apply_to_edges( + ContextNode::from(parent.into()), + *loc, + &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, cond, body), + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + Expression(loc, expr) => { + tracing::trace!("parsing expr, {expr:?}"); + if let Some(parent) = parent_ctx { + let ctx = parent.into().into(); + match self.parse_ctx_expr(expr, ctx) { + Ok(()) => { + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad expr"); + ContextNode::from(parent.into()) + .kill( + analyzer, + loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(loc)?; + } + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + e => { + let _ = self.widen_if_limit_hit(ctx, e); + } + } + } + } + For(loc, maybe_for_start, maybe_for_middle, maybe_for_end, maybe_for_body) => { + tracing::trace!("parsing for loop"); + if let Some(parent) = parent_ctx { + let res = + self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { + analyzer.for_loop( + loc, + ctx, + maybe_for_start, + maybe_for_middle, + maybe_for_end, + maybe_for_body, + ) + }); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + DoWhile(loc, while_stmt, while_expr) => { + tracing::trace!("parsing `do while`, {while_expr:?}"); + if let Some(parent) = parent_ctx { + let res = self.apply_to_edges( + ContextNode::from(parent.into()), + *loc, + &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, while_expr, while_stmt), + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } + Continue(_loc) => { + tracing::trace!("parsing continue"); + // TODO: We cheat in loops by just widening so continues dont matter yet + } + Break(_loc) => { + tracing::trace!("parsing break"); + // TODO: We cheat in loops by just widening so breaks dont matter yet + } + Assembly { + loc, + dialect: _, + flags: _, + block: yul_block, + } => { + tracing::trace!("parsing assembly"); + let ctx = ContextNode::from( + parent_ctx + .expect("No context for variable definition?") + .into(), + ); + let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { + analyzer.parse_ctx_yul_statement(&YulStatement::Block(yul_block.clone()), ctx); + Ok(()) + }); + let _ = self.widen_if_limit_hit(ctx, res); + } + Return(loc, maybe_ret_expr) => { + tracing::trace!("parsing return"); + if let Some(ret_expr) = maybe_ret_expr { + if let Some(parent) = parent_ctx { + let res = self.parse_ctx_expr(ret_expr, parent.into().into()); + if self.widen_if_limit_hit(parent.into().into(), res) { + return; + } + let res = self.apply_to_edges( + parent.into().into(), + *loc, + &|analyzer, ctx, loc| { + let Ok(Some(ret)) = ctx.pop_expr_latest(loc, analyzer) else { + return Err(ExprErr::NoLhs( + loc, + "Return did not have a associated expression".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + let paths = ret.flatten(); + if paths.is_killed() { + tracing::trace!("killing due to bad return"); + let res = ContextNode::from(parent.into()) + .kill(analyzer, loc, paths.killed_kind().unwrap()) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + return Ok(()); + } + analyzer.return_match(ctx, &loc, &paths); + Ok(()) + }, + ); + let _ = self.widen_if_limit_hit(parent.into().into(), res); + } + } else if let Some(parent) = parent_ctx { + let res = + self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { + let res = ctx.add_empty_return(loc, analyzer).into_expr_err(loc); + analyzer.add_if_err(res); + Ok(()) + }); + if self.widen_if_limit_hit(parent.into().into(), res) { + return; + } + } + } + Revert(loc, _maybe_err_path, _exprs) => { + tracing::trace!("parsing revert"); + if let Some(parent) = parent_ctx { + let parent = ContextNode::from(parent.into()); + let res = self.apply_to_edges(parent, *loc, &|analyzer, ctx, loc| { + let res = ctx + .kill(analyzer, loc, KilledKind::Revert) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + Ok(()) + }); + let _ = self.add_if_err(res); + } + } + RevertNamedArgs(_loc, _maybe_err_path, _named_args) => { + tracing::trace!("parsing named revert"); + todo!("revert named args") + } + Emit(_loc, _emit_expr) => {} + Try(_loc, _try_expr, _maybe_returns, _clauses) => {} + Error(_loc) => {} + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 8b06d943..39f859ca 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -4,7 +4,7 @@ use crate::{ func_call::modifier::ModifierCaller, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, IntoExprErr, - helper::CallerHelper, + helper::CallerHelper, ExpressionParser, StatementParser, }; use graph::{ diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index fe1e0dcd..732f9b0c 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -1,6 +1,6 @@ //! Helper traits & blanket implementations that help facilitate performing function calls. use crate::{ - ContextBuilder, ExprErr, IntoExprErr, + ContextBuilder, ExprErr, IntoExprErr, variable::Variable, ExpressionParser }; use graph::{ diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index d7e615f0..5200c111 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,6 +1,6 @@ //! Traits & blanket implementations that facilitate performing locally scoped function calls. -use crate::{func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser, assign::Assign}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index d2507e2e..f85c060f 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 8a898252..f3a14803 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,4 +1,4 @@ -use crate::{array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; +use crate::{array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess, ExpressionParser, assign::Assign, variable::Variable}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index 67e9ea18..53ede044 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 71735a84..61859472 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser, assign::Assign}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index 1afc8477..f06e7421 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index bfe38af9..ec0616fc 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser}; use graph::{ nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index acbf38ce..7614d827 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, func_call::helper::CallerHelper, IntoExprErr}; +use crate::{require::Require, ContextBuilder, ExprErr, func_call::helper::CallerHelper, IntoExprErr, ExpressionParser}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 82875d94..5d1d5a7f 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser, variable::Variable}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index bec4128e..5d32c98b 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -1,8 +1,7 @@ //! Traits & blanket implementations that facilitate performing modifier function calls. -use crate::helper::CallerHelper; use crate::{ - ContextBuilder, ExprErr, IntoExprErr, func_caller::FuncCaller + helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr, func_caller::FuncCaller, ExpressionParser }; use graph::{ diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 2c2778c2..e123f644 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -4,6 +4,7 @@ use crate::{ func_call::helper::CallerHelper, func_call::func_caller::FuncCaller, intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, IntoExprErr, + ExpressionParser }; use graph::{ diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index 2e903258..46f202cc 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -1,6 +1,7 @@ use solang_parser::pt::Loc; mod array; +mod assign; mod bin_op; mod cmp; mod cond_op; @@ -13,9 +14,11 @@ mod loops; mod member_access; mod require; mod variable; +mod pre_post_in_decrement; pub mod yul; pub use array::*; +pub use assign::*; pub use bin_op::*; pub use cmp::*; pub use cond_op::*; @@ -28,14 +31,15 @@ pub use loops::*; pub use member_access::*; pub use require::*; pub use variable::*; +pub use pre_post_in_decrement::*; /// Supertrait for parsing expressions -pub trait ExprParser: - BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env +pub trait ExprTyParser: + BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env + PrePostIncDecrement + Assign { } -impl ExprParser for T where - T: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env +impl ExprTyParser for T where + T: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env + PrePostIncDecrement + Assign { } diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 39af7787..1846d1a5 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; use graph::{ nodes::{ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index bb02b142..27bcdd5f 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr}; +use crate::{variable::Variable, ContextBuilder, ExprErr, IntoExprErr, StatementParser}; use graph::{ nodes::{Context, ContextNode}, diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 79657c65..0b28f68d 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, Variable}; +use crate::{ContextBuilder, ExprErr, IntoExprErr, Variable, ExpressionParser}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index fd8c7129..8395c539 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -1,6 +1,6 @@ use crate::{ BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, IntoExprErr, - ListAccess, StructAccess, + ListAccess, StructAccess, ExpressionParser }; use graph::{ diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs new file mode 100644 index 00000000..6886b2fa --- /dev/null +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -0,0 +1,184 @@ +use crate::{ + context_builder::ContextBuilder, + variable::Variable, ExprErr, IntoExprErr, ExpressionParser +}; + +use graph::{ + elem::*, + nodes::{ + Concrete, ContextNode, ContextVarNode, ExprRet, + }, + AnalyzerBackend, +}; + +use ethers_core::types::{U256}; +use solang_parser::{ + pt::{Expression, Loc}, +}; + +impl PrePostIncDecrement for T where T: AnalyzerBackend + Sized {} +/// Handles pre and post increment and decrement +pub trait PrePostIncDecrement: AnalyzerBackend + Sized { + /// Handle a preincrement + fn pre_increment(&mut self, expr: &Expression, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + tracing::trace!("PreIncrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PreIncrement operation had no right hand side".to_string(), + )); + }; + + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, true, true, loc, &ret) + }) + } + + /// Handle a postincrement + fn post_increment(&mut self, expr: &Expression, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + tracing::trace!("PostIncrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PostIncrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, false, true, loc, &ret) + }) + } + + /// Handle a predecrement + fn pre_decrement(&mut self, expr: &Expression, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + tracing::trace!("PreDecrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PreDecrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, true, false, loc, &ret) + }) + } + + /// Handle a postdecrement + fn post_decrement(&mut self, expr: &Expression, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + tracing::trace!("PostDecrement variable pop"); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs( + loc, + "PostDecrement operation had no right hand side".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_in_de_crement(ctx, false, false, loc, &ret) + }) + } + + /// Match on the [`ExprRet`]s of a pre-or-post in/decrement and performs it + fn match_in_de_crement( + &mut self, + ctx: ContextNode, + pre: bool, + increment: bool, + loc: Loc, + rhs: &ExprRet, + ) -> Result<(), ExprErr> { + match rhs { + ExprRet::CtxKilled(kind) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(()) + } + ExprRet::SingleLiteral(var) => { + let res = ContextVarNode::from(*var) + .try_increase_size(self) + .into_expr_err(loc); + let _ = self.add_if_err(res); + self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) + } + ExprRet::Single(var) => { + let cvar = ContextVarNode::from(*var); + let elem = Elem::from(cvar); + let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); + // if let Some(r) = cvar.range(self).into_expr_err(loc)? { + if increment { + if pre { + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() + one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + let res = new_cvar.set_range_max(self, elem + one).into_expr_err(loc); + let _ = self.add_if_err(res); + ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() + one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem + one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(dup.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + } else if pre { + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() - one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem - one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + .into_expr_err(loc)?; + Ok(()) + } else { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; + let res = new_cvar + .set_range_min(self, elem.clone() - one.clone()) + .into_expr_err(loc); + let _ = self.add_if_err(res); + new_cvar + .set_range_max(self, elem - one) + .into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(dup.into()), self) + .into_expr_err(loc)?; + Ok(()) + } + } + ExprRet::Multi(inner) => inner + .iter() + .try_for_each(|expr| self.match_in_de_crement(ctx, pre, increment, loc, expr)), + ExprRet::Null => Ok(()), + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index e51f0b9e..b490bbd6 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,4 +1,4 @@ -use crate::{BinOp, ContextBuilder, ExprErr, IntoExprErr, Variable}; +use crate::{ExpressionParser, BinOp, ContextBuilder, ExprErr, IntoExprErr, Variable}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index f4640931..59607d76 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,14 +1,14 @@ -use crate::{env::Env, ContextBuilder, ExprErr, IntoExprErr}; +use crate::{assign::Assign, env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ContextNode, ContextVar, ExprRet, VarNode}, - AnalyzerBackend, ContextEdge, Edge, Node, + nodes::{ContextVarNode, ContextNode, ContextVar, ExprRet, VarNode}, + GraphError, AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; -use solang_parser::pt::{Expression, Identifier}; +use solang_parser::pt::{VariableDeclaration, Loc, Expression, Identifier}; impl Variable for T where T: AnalyzerBackend + Sized {} -/// Deals with variable retrieval +/// Deals with variable retrieval, parsing, and versioning pub trait Variable: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] /// Get a variable based on an identifier @@ -155,4 +155,259 @@ pub trait Variable: AnalyzerBackend + Size Ok(()) } } + + /// Match on the [`ExprRet`]s of a variable definition and construct the variable + fn match_var_def( + &mut self, + ctx: ContextNode, + var_decl: &VariableDeclaration, + loc: Loc, + lhs_paths: &ExprRet, + rhs_paths: Option<&ExprRet>, + ) -> Result { + match (lhs_paths, rhs_paths) { + (ExprRet::CtxKilled(kind), _) | (_, Some(ExprRet::CtxKilled(kind))) => { + ctx.kill(self, loc, *kind).into_expr_err(loc)?; + Ok(true) + } + (ExprRet::Single(ty), Some(ExprRet::SingleLiteral(rhs))) => { + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); + let res = rhs_cvar.literal_cast_from_ty(ty, self).into_expr_err(loc); + let _ = self.add_if_err(res); + self.match_var_def( + ctx, + var_decl, + loc, + lhs_paths, + Some(&ExprRet::Single(rhs_cvar.into())), + ) + } + (ExprRet::Single(ty), Some(ExprRet::Single(rhs))) => { + let name = var_decl.name.clone().expect("Variable wasn't named"); + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let var = ContextVar { + loc: Some(loc), + name: name.to_string(), + display_name: name.to_string(), + storage: var_decl.storage.as_ref().map(|s| s.clone().into()), + is_tmp: false, + is_symbolic: true, + tmp_of: None, + is_return: false, + ty, + }; + let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); + ctx.add_var(lhs, self).into_expr_err(loc)?; + self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); + let rhs = ContextVarNode::from(*rhs); + + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let _ = analyzer.assign(loc, lhs, rhs, ctx)?; + // match_assign_ret(analyzer, ctx, ret); + Ok(()) + })?; + + Ok(false) + } + (ExprRet::Single(ty), None) => { + let name = var_decl.name.clone().expect("Variable wasn't named"); + let ty = VarType::try_from_idx(self, *ty).expect("Not a known type"); + let var = ContextVar { + loc: Some(loc), + name: name.to_string(), + display_name: name.to_string(), + storage: var_decl.storage.as_ref().map(|s| s.clone().into()), + is_tmp: false, + is_symbolic: true, + tmp_of: None, + is_return: false, + ty, + }; + let lhs = ContextVarNode::from(self.add_node(Node::ContextVar(var))); + ctx.add_var(lhs, self).into_expr_err(loc)?; + self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); + Ok(false) + } + (l @ ExprRet::Single(_lhs), Some(ExprRet::Multi(rhs_sides))) => Ok(rhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, l, Some(expr_ret))) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), r @ Some(ExprRet::Single(_))) => Ok(lhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, r)) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), None) => Ok(lhs_sides + .iter() + .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, None)) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)), + (ExprRet::Multi(lhs_sides), Some(ExprRet::Multi(rhs_sides))) => { + // try to zip sides if they are the same length + if lhs_sides.len() == rhs_sides.len() { + Ok(lhs_sides + .iter() + .zip(rhs_sides.iter()) + .map(|(lhs_expr_ret, rhs_expr_ret)| { + self.match_var_def(ctx, var_decl, loc, lhs_expr_ret, Some(rhs_expr_ret)) + }) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)) + } else { + Ok(rhs_sides + .iter() + .map(|rhs_expr_ret| { + self.match_var_def(ctx, var_decl, loc, lhs_paths, Some(rhs_expr_ret)) + }) + .collect::, ExprErr>>()? + .iter() + .all(|e| *e)) + } + } + (_e, _f) => Err(ExprErr::Todo( + loc, + "Unhandled ExprRet combination in `match_var_def`".to_string(), + )), + } + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + /// Creates a newer version of a variable in the context. It may or may not actually + /// create this new variable depending on if there are two successively identical version. + fn advance_var_in_ctx( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result { + self.advance_var_in_ctx_forcible(cvar_node, loc, ctx, false) + } + + #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] + /// Creates a new version of a variable in a context. Takes an additional parameter + /// denoting whether or not to force the creation, skipping an optimization. + fn advance_var_in_ctx_forcible( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ctx: ContextNode, + force: bool, + ) -> Result { + tracing::trace!( + "advancing variable: {}", + cvar_node.display_name(self).into_expr_err(loc)? + ); + if let Some(cvar) = cvar_node.next_version(self) { + panic!( + "Not latest version of: {}", + cvar.display_name(self).unwrap() + ); + } + if let Some(child) = ctx.underlying(self).into_expr_err(loc)?.child { + return Err(ExprErr::GraphError( + loc, + GraphError::VariableUpdateInOldContext(format!( + "Variable update of {} in old context: parent: {}, child: {:#?}", + cvar_node.display_name(self).unwrap(), + ctx.path(self), + child + )), + )); + } + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + // get the old context + let new_cvarnode; + + 'a: { + if let Some(old_ctx) = cvar_node.maybe_ctx(self) { + if !force { + // get the previous version to remove and prevent spurious nodes + if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { + let prev_version = prev.underlying(self).into_expr_err(loc)?; + // check if there was no change between the previous version and the latest version + if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { + // there was no change in the current context, just give them the current variable + new_cvarnode = cvar_node.into(); + break 'a; + } + } + } + + new_cvar.loc = Some(loc); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + if old_ctx != ctx { + ctx.add_var(new_cvarnode.into(), self).into_expr_err(loc)?; + self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); + self.add_edge( + new_cvarnode, + cvar_node.0, + Edge::Context(ContextEdge::InheritedVariable), + ); + } else { + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } else { + new_cvar.loc = Some(loc); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } + + Ok(ContextVarNode::from(new_cvarnode)) + } + + /// Creates a new version of a variable in it's current context + fn advance_var_in_curr_ctx( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ) -> Result { + tracing::trace!( + "advancing variable: {}", + cvar_node.display_name(self).into_expr_err(loc)? + ); + if let Some(cvar) = cvar_node.next_version(self) { + panic!( + "Not latest version of: {}", + cvar.display_name(self).unwrap() + ); + } + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + new_cvar.loc = Some(loc); + + let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + + Ok(ContextVarNode::from(new_cvarnode)) + } + + /// Clones a variable and adds it to the graph + fn advance_var_underlying(&mut self, cvar_node: ContextVarNode, loc: Loc) -> &mut ContextVar { + assert_eq!(None, cvar_node.next_version(self)); + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .unwrap() + .clone(); + new_cvar.loc = Some(loc); + let new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + ContextVarNode::from(new_cvarnode) + .underlying_mut(self) + .unwrap() + } } diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 652ed9b2..02b798c0 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -1,7 +1,7 @@ //! Trait and blanket implementation for parsing yul-based statements and expressions use crate::{ - ContextBuilder, ExprErr, ExprParser, IntoExprErr, + ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, yul::YulFuncCaller, yul::YulCondOp }; @@ -18,12 +18,12 @@ use solang_parser::{ impl YulBuilder for T where - T: AnalyzerBackend + Sized + ExprParser + T: AnalyzerBackend + Sized + ExpressionParser { } /// Trait that processes Yul statements and expressions pub trait YulBuilder: - AnalyzerBackend + Sized + ExprParser + AnalyzerBackend + Sized + ExpressionParser { #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] /// Parse a yul statement diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 922a8f89..f67454f5 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,4 +1,4 @@ -use crate::{BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, yul::YulBuilder}; +use crate::{variable::Variable, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, yul::YulBuilder}; use graph::{ elem::*, From 951ae0f136736fa5cc5e501b94e8f5eca948c20f Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 11 Dec 2023 11:45:57 -0800 Subject: [PATCH 42/71] lint --- crates/pyrometer/src/analyzer.rs | 2 +- crates/solc-expressions/src/array.rs | 5 +- crates/solc-expressions/src/assign.rs | 9 +-- crates/solc-expressions/src/bin_op.rs | 4 +- crates/solc-expressions/src/cmp.rs | 2 +- crates/solc-expressions/src/cond_op.rs | 4 +- .../src/context_builder/expr.rs | 16 ++-- .../src/context_builder/mod.rs | 13 +--- .../src/context_builder/stmt.rs | 17 ++-- crates/solc-expressions/src/env.rs | 4 +- .../src/func_call/func_caller.rs | 14 ++-- .../solc-expressions/src/func_call/helper.rs | 12 +-- .../src/func_call/internal_call.rs | 13 +++- .../src/func_call/intrinsic_call/abi.rs | 2 +- .../src/func_call/intrinsic_call/array.rs | 5 +- .../src/func_call/intrinsic_call/block.rs | 2 +- .../func_call/intrinsic_call/constructors.rs | 9 ++- .../func_call/intrinsic_call/dyn_builtin.rs | 2 +- .../intrinsic_call/intrinsic_caller.rs | 3 +- .../func_call/intrinsic_call/precompile.rs | 14 +++- .../src/func_call/intrinsic_call/solidity.rs | 14 +++- .../src/func_call/intrinsic_call/types.rs | 5 +- crates/solc-expressions/src/func_call/mod.rs | 2 +- .../src/func_call/modifier.rs | 21 +++-- .../src/func_call/namespaced_call.rs | 7 +- crates/solc-expressions/src/lib.rs | 30 ++++++- crates/solc-expressions/src/list.rs | 2 +- .../src/member_access/list_access.rs | 2 +- .../src/member_access/member_trait.rs | 4 +- .../src/pre_post_in_decrement.rs | 78 ++++++++++++------- crates/solc-expressions/src/require.rs | 2 +- crates/solc-expressions/src/variable.rs | 6 +- crates/solc-expressions/src/yul/mod.rs | 2 +- .../solc-expressions/src/yul/yul_builder.rs | 5 +- .../solc-expressions/src/yul/yul_cond_op.rs | 2 +- crates/solc-expressions/src/yul/yul_funcs.rs | 4 +- 36 files changed, 205 insertions(+), 133 deletions(-) diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 364130d0..6a3cb304 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -3,7 +3,7 @@ use crate::builtin_fns; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; -use solc_expressions::{StatementParser, ExprErr, IntoExprErr}; +use solc_expressions::{ExprErr, IntoExprErr, StatementParser}; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; use petgraph::{graph::*, Directed}; diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 616d4722..26f9480a 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,4 +1,7 @@ -use crate::{ExpressionParser, variable::Variable, require::Require, ContextBuilder, ExprErr, IntoExprErr, ListAccess}; +use crate::{ + require::Require, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, + ListAccess, +}; use graph::{ elem::RangeOp, diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index a95280e4..a103a503 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -1,9 +1,9 @@ -use crate::{variable::Variable, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ - elem::Elem, GraphError, Range, + elem::Elem, nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, + AnalyzerBackend, ContextEdge, Edge, GraphError, Range, }; use solang_parser::pt::{Expression, Loc}; @@ -11,7 +11,7 @@ use solang_parser::pt::{Expression, Loc}; impl Assign for T where T: AnalyzerBackend + Sized {} /// Handles assignments pub trait Assign: AnalyzerBackend + Sized { -#[tracing::instrument(level = "trace", skip_all)] + #[tracing::instrument(level = "trace", skip_all)] /// Parse an assignment expression fn assign_exprs( &mut self, @@ -239,4 +239,3 @@ pub trait Assign: AnalyzerBackend + Sized Ok(ExprRet::Single(new_lhs.into())) } } - \ No newline at end of file diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index da328dea..86ff6d67 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -1,4 +1,6 @@ -use crate::{variable::Variable, require::Require, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ + require::Require, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, +}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index bd3fe7f8..ed67222d 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index df688f58..999e2489 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -1,4 +1,6 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, StatementParser, ExpressionParser}; +use crate::{ + require::Require, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, StatementParser, +}; use graph::{ nodes::{Context, ContextNode}, diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index 407f2c5c..3a551e69 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -1,24 +1,20 @@ use crate::{ - context_builder::ContextBuilder, - variable::Variable, - func_call::{func_caller::FuncCaller}, ExprErr, ExprTyParser, IntoExprErr, + context_builder::ContextBuilder, func_call::func_caller::FuncCaller, variable::Variable, + ExprErr, ExprTyParser, IntoExprErr, }; use graph::{ elem::*, - nodes::{ - Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, - }, + nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; -use ethers_core::types::{I256}; +use ethers_core::types::I256; use solang_parser::{ helpers::CodeLocation, pt::{Expression, Loc}, }; - impl ExpressionParser for T where T: AnalyzerBackend + Sized + ExprTyParser { @@ -28,7 +24,7 @@ impl ExpressionParser for T where pub trait ExpressionParser: AnalyzerBackend + Sized + ExprTyParser { - /// Perform setup for parsing an expression + /// Perform setup for parsing an expression fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { if !ctx.killed_or_ret(self).unwrap() { let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; @@ -390,4 +386,4 @@ pub trait ExpressionParser: Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index a26a7a87..35b58142 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -1,12 +1,8 @@ //! Trait and blanket implementation for the core parsing loop -use crate::{ - ExprErr, IntoExprErr, -}; +use crate::{ExprErr, IntoExprErr}; use graph::{ - nodes::{ - ContextNode, ContextVarNode, ExprRet, KilledKind, - }, + nodes::{ContextNode, ContextVarNode, ExprRet, KilledKind}, AnalyzerBackend, ContextEdge, Edge, GraphError, }; @@ -17,17 +13,16 @@ impl ContextBuilder for T where { } -mod stmt; mod expr; +mod stmt; -pub use stmt::*; pub use expr::*; +pub use stmt::*; /// Dispatcher for building up a context of a function pub trait ContextBuilder: AnalyzerBackend + Sized + StatementParser { - /// TODO: rename this. Sometimes we dont want to kill a context if we hit an error fn widen_if_limit_hit(&mut self, ctx: ContextNode, maybe_err: Result<(), ExprErr>) -> bool { match maybe_err { diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs index 526b6ae4..50a1d6b6 100644 --- a/crates/solc-expressions/src/context_builder/stmt.rs +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -1,27 +1,26 @@ - use crate::{ - context_builder::ContextBuilder, - ExpressionParser, - func_call::{func_caller::FuncCaller, modifier::ModifierCaller}, loops::Looper, yul::YulBuilder, ExprErr, IntoExprErr, + context_builder::ContextBuilder, + func_call::{func_caller::FuncCaller, modifier::ModifierCaller}, + loops::Looper, + yul::YulBuilder, + ExprErr, ExpressionParser, IntoExprErr, }; use graph::{ nodes::{ - Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, FunctionReturnNode, KilledKind, + Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, + FunctionReturnNode, KilledKind, }, AnalyzerBackend, ContextEdge, Edge, Node, }; use shared::NodeIdx; - use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ helpers::CodeLocation, pt::{Expression, Statement, YulStatement}, }; - impl StatementParser for T where T: AnalyzerBackend + Sized + ExpressionParser { @@ -525,4 +524,4 @@ pub trait StatementParser: Error(_loc) => {} } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 54060832..17c73755 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -1,4 +1,6 @@ -use crate::{func_call::helper::CallerHelper, func_call::modifier::ModifierCaller, ExprErr, IntoExprErr}; +use crate::{ + func_call::helper::CallerHelper, func_call::modifier::ModifierCaller, ExprErr, IntoExprErr, +}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 39f859ca..7418cd60 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,20 +1,19 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. use crate::{ - func_call::modifier::ModifierCaller, - internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, - namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, IntoExprErr, - helper::CallerHelper, ExpressionParser, StatementParser, + func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, + intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, + ExprErr, ExpressionParser, IntoExprErr, StatementParser, }; use graph::{ nodes::{ - Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, ModifierState, + Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, + ModifierState, }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; -use shared::{NodeIdx}; +use shared::NodeIdx; use solang_parser::pt::{Expression, Loc, NamedArgument}; @@ -296,7 +295,6 @@ pub trait FuncCaller: }) } - /// Actually executes the function #[tracing::instrument(level = "trace", skip_all)] fn execute_call_inner( diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 732f9b0c..62446fd3 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -1,7 +1,5 @@ //! Helper traits & blanket implementations that help facilitate performing function calls. -use crate::{ - ContextBuilder, ExprErr, IntoExprErr, variable::Variable, ExpressionParser -}; +use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ nodes::{ @@ -14,11 +12,7 @@ use shared::{NodeIdx, StorageLocation}; use solang_parser::pt::{Expression, Loc}; -use std::{ - cell::RefCell, - collections::BTreeMap, - rc::Rc -}; +use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; impl CallerHelper for T where T: AnalyzerBackend + Sized {} /// Helper trait for performing function calls @@ -582,4 +576,4 @@ pub trait CallerHelper: AnalyzerBackend + } Ok(()) } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 5200c111..c053b4e3 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,6 +1,9 @@ //! Traits & blanket implementations that facilitate performing locally scoped function calls. -use crate::{func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr, ExpressionParser, assign::Assign}; +use crate::{ + assign::Assign, func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, + ExprErr, ExpressionParser, IntoExprErr, +}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, @@ -232,7 +235,13 @@ pub trait InternalFuncCaller: ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.setup_fn_call(&ident.loc, &inputs, (possible_funcs[0]).into(), ctx, None) + analyzer.setup_fn_call( + &ident.loc, + &inputs, + (possible_funcs[0]).into(), + ctx, + None, + ) }) } _ => { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index f85c060f..84e7befb 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index f3a14803..059b0fcd 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,4 +1,7 @@ -use crate::{array::Array, ContextBuilder, ExprErr, IntoExprErr, ListAccess, ExpressionParser, assign::Assign, variable::Variable}; +use crate::{ + array::Array, assign::Assign, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, ListAccess, +}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index 53ede044..edb12ead 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 61859472..a6f4717a 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -1,4 +1,7 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser, assign::Assign}; +use crate::{ + assign::Assign, func_call::helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, +}; use graph::{ elem::*, @@ -15,7 +18,9 @@ impl ConstructorCaller for T where } /// Trait for constructing compound types like contracts, structs and arrays -pub trait ConstructorCaller: AnalyzerBackend + Sized + CallerHelper { +pub trait ConstructorCaller: + AnalyzerBackend + Sized + CallerHelper +{ /// Construct an array fn construct_array( &mut self, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index f06e7421..ef7a610e 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index 21b83e57..a6126edf 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -1,9 +1,10 @@ use crate::{ + func_call::helper::CallerHelper, intrinsic_call::{ AbiCaller, AddressCaller, ArrayCaller, BlockCaller, ConstructorCaller, DynBuiltinCaller, MsgCaller, PrecompileCaller, SolidityCaller, TypesCaller, }, - ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper + ContextBuilder, ExprErr, IntoExprErr, }; use graph::{ diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index ec0616fc..9bcb866c 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,4 +1,6 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser}; +use crate::{ + func_call::helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, +}; use graph::{ nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, @@ -8,11 +10,15 @@ use shared::NodeIdx; use solang_parser::pt::{Expression, Loc}; -impl PrecompileCaller for T where T: AnalyzerBackend + Sized + CallerHelper -{} +impl PrecompileCaller for T where + T: AnalyzerBackend + Sized + CallerHelper +{ +} /// Trait for calling precompile intrinsic functions, like `ecrecover` -pub trait PrecompileCaller: AnalyzerBackend + Sized + CallerHelper { +pub trait PrecompileCaller: + AnalyzerBackend + Sized + CallerHelper +{ /// Perform a precompile's function call, like `ecrecover` fn precompile_call( &mut self, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index 7614d827..70b5e76d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -1,4 +1,7 @@ -use crate::{require::Require, ContextBuilder, ExprErr, func_call::helper::CallerHelper, IntoExprErr, ExpressionParser}; +use crate::{ + func_call::helper::CallerHelper, require::Require, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, +}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, @@ -7,10 +10,15 @@ use graph::{ use solang_parser::pt::{Expression, Loc}; -impl SolidityCaller for T where T: AnalyzerBackend + Sized + CallerHelper {} +impl SolidityCaller for T where + T: AnalyzerBackend + Sized + CallerHelper +{ +} /// Trait for calling solidity's intrinsic functions, like `keccak256` -pub trait SolidityCaller: AnalyzerBackend + Sized + CallerHelper { +pub trait SolidityCaller: + AnalyzerBackend + Sized + CallerHelper +{ /// Perform a solidity intrinsic function call, like `keccak256` fn solidity_call( &mut self, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 5d1d5a7f..a0379fbc 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,4 +1,7 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, func_call::helper::CallerHelper, ExpressionParser, variable::Variable}; +use crate::{ + func_call::helper::CallerHelper, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, +}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index a4ea9278..ac6bd0c2 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,6 +1,6 @@ +pub mod func_caller; pub mod helper; pub mod internal_call; pub mod intrinsic_call; pub mod modifier; pub mod namespaced_call; -pub mod func_caller; diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index 5d32c98b..321781ef 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -1,25 +1,32 @@ //! Traits & blanket implementations that facilitate performing modifier function calls. use crate::{ - helper::CallerHelper, ContextBuilder, ExprErr, IntoExprErr, func_caller::FuncCaller, ExpressionParser + func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, }; use graph::{ - nodes::{ - Context, ContextNode, ExprRet, FunctionNode, ModifierState, - }, + nodes::{Context, ContextNode, ExprRet, FunctionNode, ModifierState}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; -use solang_parser::pt::{Expression, Loc, CodeLocation}; +use solang_parser::pt::{CodeLocation, Expression, Loc}; impl ModifierCaller for T where - T: AnalyzerBackend + Sized + GraphBackend + FuncCaller + CallerHelper + T: AnalyzerBackend + + Sized + + GraphBackend + + FuncCaller + + CallerHelper { } /// A trait for dealing with modifier calls pub trait ModifierCaller: - GraphBackend + AnalyzerBackend + Sized + FuncCaller + CallerHelper + GraphBackend + + AnalyzerBackend + + Sized + + FuncCaller + + CallerHelper { /// Calls a modifier for a function #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index e123f644..b6079862 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,10 +1,9 @@ //! Traits & blanket implementations that facilitate performing namespaced function calls. use crate::{ - func_call::helper::CallerHelper, - func_call::func_caller::FuncCaller, - intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, IntoExprErr, - ExpressionParser + func_call::func_caller::FuncCaller, func_call::helper::CallerHelper, + intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, + ExpressionParser, IntoExprErr, }; use graph::{ diff --git a/crates/solc-expressions/src/lib.rs b/crates/solc-expressions/src/lib.rs index 46f202cc..95fe792b 100644 --- a/crates/solc-expressions/src/lib.rs +++ b/crates/solc-expressions/src/lib.rs @@ -12,9 +12,9 @@ mod list; mod literal; mod loops; mod member_access; +mod pre_post_in_decrement; mod require; mod variable; -mod pre_post_in_decrement; pub mod yul; pub use array::*; @@ -29,17 +29,39 @@ pub use list::*; pub use literal::*; pub use loops::*; pub use member_access::*; +pub use pre_post_in_decrement::*; pub use require::*; pub use variable::*; -pub use pre_post_in_decrement::*; /// Supertrait for parsing expressions pub trait ExprTyParser: - BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env + PrePostIncDecrement + Assign + BinOp + + Require + + Variable + + Literal + + Array + + MemberAccess + + Cmp + + CondOp + + List + + Env + + PrePostIncDecrement + + Assign { } impl ExprTyParser for T where - T: BinOp + Require + Variable + Literal + Array + MemberAccess + Cmp + CondOp + List + Env + PrePostIncDecrement + Assign + T: BinOp + + Require + + Variable + + Literal + + Array + + MemberAccess + + Cmp + + CondOp + + List + + Env + + PrePostIncDecrement + + Assign { } diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 1846d1a5..332f451f 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ nodes::{ContextNode, ContextVar, ExprRet}, diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 0b28f68d..354f971c 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -1,4 +1,4 @@ -use crate::{ContextBuilder, ExprErr, IntoExprErr, Variable, ExpressionParser}; +use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index 8395c539..893db13d 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -1,6 +1,6 @@ use crate::{ - BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, IntoExprErr, - ListAccess, StructAccess, ExpressionParser + BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, ExpressionParser, + IntoExprErr, ListAccess, StructAccess, }; use graph::{ diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index 6886b2fa..48417121 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -1,27 +1,32 @@ use crate::{ - context_builder::ContextBuilder, - variable::Variable, ExprErr, IntoExprErr, ExpressionParser + context_builder::ContextBuilder, variable::Variable, ExprErr, ExpressionParser, IntoExprErr, }; use graph::{ elem::*, - nodes::{ - Concrete, ContextNode, ContextVarNode, ExprRet, - }, + nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, }; -use ethers_core::types::{U256}; -use solang_parser::{ - pt::{Expression, Loc}, -}; +use ethers_core::types::U256; +use solang_parser::pt::{Expression, Loc}; -impl PrePostIncDecrement for T where T: AnalyzerBackend + Sized {} +impl PrePostIncDecrement for T where + T: AnalyzerBackend + Sized +{ +} /// Handles pre and post increment and decrement -pub trait PrePostIncDecrement: AnalyzerBackend + Sized { - /// Handle a preincrement - fn pre_increment(&mut self, expr: &Expression, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; +pub trait PrePostIncDecrement: + AnalyzerBackend + Sized +{ + /// Handle a preincrement + fn pre_increment( + &mut self, + expr: &Expression, + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { tracing::trace!("PreIncrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -37,11 +42,16 @@ pub trait PrePostIncDecrement: AnalyzerBackend Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; + /// Handle a postincrement + fn post_increment( + &mut self, + expr: &Expression, + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { tracing::trace!("PostIncrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -56,11 +66,16 @@ pub trait PrePostIncDecrement: AnalyzerBackend Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; + /// Handle a predecrement + fn pre_decrement( + &mut self, + expr: &Expression, + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { tracing::trace!("PreDecrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -75,11 +90,16 @@ pub trait PrePostIncDecrement: AnalyzerBackend Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; + /// Handle a postdecrement + fn post_decrement( + &mut self, + expr: &Expression, + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { tracing::trace!("PostDecrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -94,9 +114,9 @@ pub trait PrePostIncDecrement: AnalyzerBackend Ok(()), } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index b490bbd6..f37318bb 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,4 +1,4 @@ -use crate::{ExpressionParser, BinOp, ContextBuilder, ExprErr, IntoExprErr, Variable}; +use crate::{BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 59607d76..fb713c49 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,11 +1,11 @@ use crate::{assign::Assign, env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ContextVarNode, ContextNode, ContextVar, ExprRet, VarNode}, - GraphError, AnalyzerBackend, ContextEdge, Edge, Node, VarType, + nodes::{ContextNode, ContextVar, ContextVarNode, ExprRet, VarNode}, + AnalyzerBackend, ContextEdge, Edge, GraphError, Node, VarType, }; -use solang_parser::pt::{VariableDeclaration, Loc, Expression, Identifier}; +use solang_parser::pt::{Expression, Identifier, Loc, VariableDeclaration}; impl Variable for T where T: AnalyzerBackend + Sized {} /// Deals with variable retrieval, parsing, and versioning diff --git a/crates/solc-expressions/src/yul/mod.rs b/crates/solc-expressions/src/yul/mod.rs index aa6f8d1a..d7a4fd29 100644 --- a/crates/solc-expressions/src/yul/mod.rs +++ b/crates/solc-expressions/src/yul/mod.rs @@ -5,4 +5,4 @@ mod yul_cond_op; mod yul_funcs; pub use yul_builder::*; pub use yul_cond_op::*; -pub use yul_funcs::*; \ No newline at end of file +pub use yul_funcs::*; diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 02b798c0..f3f43c53 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -1,9 +1,7 @@ //! Trait and blanket implementation for parsing yul-based statements and expressions use crate::{ - ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, - yul::YulFuncCaller, - yul::YulCondOp + yul::YulCondOp, yul::YulFuncCaller, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; use graph::{ @@ -16,7 +14,6 @@ use solang_parser::{ pt::{Expression, Loc, YulExpression, YulFor, YulStatement, YulSwitch}, }; - impl YulBuilder for T where T: AnalyzerBackend + Sized + ExpressionParser { diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index 7f5f74a2..f7bc1737 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -1,4 +1,4 @@ -use crate::{require::Require, ContextBuilder, ExprErr, IntoExprErr, yul::YulBuilder}; +use crate::{require::Require, yul::YulBuilder, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ elem::*, diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index f67454f5..c725e930 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,4 +1,6 @@ -use crate::{variable::Variable, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, yul::YulBuilder}; +use crate::{ + variable::Variable, yul::YulBuilder, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, +}; use graph::{ elem::*, From 6a559ae4765d6081ba54d0c4bf34b1c6405065d1 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 18 Dec 2023 15:10:52 -0800 Subject: [PATCH 43/71] fully refactor dynamic types adds rangeops for dynamic types --- crates/analyzers/src/bounds.rs | 2 +- crates/analyzers/src/func_analyzer/mod.rs | 72 ++-- .../src/var_analyzer/report_display.rs | 2 +- crates/cli/src/main.rs | 10 +- crates/graph/src/graph_elements.rs | 2 +- crates/graph/src/nodes/builtin.rs | 77 ++++- crates/graph/src/nodes/concrete.rs | 141 +++++++- crates/graph/src/nodes/context/querying.rs | 1 - crates/graph/src/nodes/context/solving.rs | 14 +- crates/graph/src/nodes/context/var/node.rs | 62 +++- crates/graph/src/nodes/context/var/ranging.rs | 21 +- crates/graph/src/nodes/context/var/typing.rs | 183 ++++++++-- .../graph/src/nodes/context/var/underlying.rs | 54 +-- .../graph/src/nodes/context/var/versioning.rs | 21 ++ crates/graph/src/range/elem/elem_enum.rs | 226 +++++++++++-- crates/graph/src/range/elem/elem_trait.rs | 2 +- crates/graph/src/range/elem/expr.rs | 72 +++- crates/graph/src/range/elem/map_or_array.rs | 169 ++++++++-- crates/graph/src/range/elem/mod.rs | 15 + crates/graph/src/range/elem/reference.rs | 3 - crates/graph/src/range/exec/bitwise.rs | 1 + crates/graph/src/range/exec/cast.rs | 105 +++--- crates/graph/src/range/exec/exec_op.rs | 276 ++++++++++++++- crates/graph/src/range/exec/max.rs | 11 + .../src/range/exec/{ => mem_ops}/concat.rs | 58 ++-- .../graph/src/range/exec/mem_ops/mem_set.rs | 219 ++++++++++++ crates/graph/src/range/exec/mem_ops/mod.rs | 19 ++ crates/graph/src/range/exec/min.rs | 19 ++ crates/graph/src/range/exec/mod.rs | 2 +- crates/graph/src/range/exec_traits.rs | 35 +- crates/graph/src/range/range_string.rs | 59 ++-- crates/graph/src/range/range_trait.rs | 4 +- crates/graph/src/range/solc_range.rs | 51 ++- crates/graph/src/solvers/atoms.rs | 8 +- crates/graph/src/solvers/brute.rs | 14 +- crates/graph/src/var_type.rs | 252 +++++++------- crates/pyrometer/src/graph_backend.rs | 17 +- crates/pyrometer/tests/test_data/cast.sol | 7 +- .../pyrometer/tests/test_data/dyn_types.sol | 20 +- crates/pyrometer/tests/test_data/math.sol | 12 + crates/solc-expressions/src/array.rs | 296 +++++++++++++--- crates/solc-expressions/src/assign.rs | 50 +-- crates/solc-expressions/src/bin_op.rs | 9 +- crates/solc-expressions/src/cmp.rs | 13 - .../src/func_call/internal_call.rs | 2 +- .../src/func_call/intrinsic_call/array.rs | 241 +++++++++---- .../func_call/intrinsic_call/constructors.rs | 12 +- .../func_call/intrinsic_call/dyn_builtin.rs | 58 +++- .../src/func_call/intrinsic_call/types.rs | 57 +--- .../src/member_access/list_access.rs | 318 ++++++------------ .../src/member_access/struct_access.rs | 2 +- crates/solc-expressions/src/require.rs | 128 +++---- crates/solc-expressions/src/yul/yul_funcs.rs | 7 +- 53 files changed, 2464 insertions(+), 1067 deletions(-) rename crates/graph/src/range/exec/{ => mem_ops}/concat.rs (73%) create mode 100644 crates/graph/src/range/exec/mem_ops/mem_set.rs create mode 100644 crates/graph/src/range/exec/mem_ops/mod.rs diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index 4a1cc911..1cbf8ab6 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -88,7 +88,7 @@ impl OrderedAnalysis { init: false, name: ba.var_display_name.clone(), loc: LocSpan(bound_change.0 .1), - order: i as i32, + order: (bound_change.0.end() - bound_change.0.start()) as i32, //i as i32, // storage: ba.storage.clone(), ctx: ba.ctx, ctx_conditionals: ba.conditionals(analyzer), diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index a5161b29..85ad1231 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -61,51 +61,37 @@ impl<'a> FunctionVarsBoundAnalysis { .map(|var| (var.display_name(analyzer).unwrap(), var)) .collect::>(); // create the bound strings - let mut ranges = BTreeMap::default(); - deps.iter().for_each(|(_, dep)| { - let range = dep.ref_range(analyzer).unwrap().unwrap(); - let r = range.into_flattened_range(analyzer).unwrap(); - ranges.insert(*dep, r); - }); - let atoms = ranges - .iter() - .filter_map(|(_dep, range)| { - if let Some(atom) = range.min.atomize() { - Some(atom) - } else { - range.max.atomize() - } - }) - .collect::>(); - let mut handled_atom = vec![]; - let mut bounds_string: Vec = vec![]; - atoms.iter().enumerate().for_each(|(i, atom)| { - let atom_str = atom.to_range_string(true, analyzer).s; - if !handled_atom.contains(&atom_str) { - handled_atom.push(atom_str.clone()); - bounds_string.push(format!("{}. {}", i + 1, atom_str)) - } - }); - let bounds_string = bounds_string.into_iter().collect::>().join("\n"); + // let atoms = ctx.dep_atoms(analyzer).unwrap(); + // println!("had {} atoms", atoms.len()); + // let mut handled_atom = vec![]; + // let mut bounds_string: Vec = vec![]; + // atoms.iter().enumerate().for_each(|(i, atom)| { + // let atom_str = atom.to_range_string(true, analyzer).s; + // if !handled_atom.contains(&atom_str) { + // handled_atom.push(atom_str.clone()); + // bounds_string.push(format!("{}. {}", i + 1, atom_str)) + // } + // }); + // let bounds_string = bounds_string.into_iter().collect::>().join("\n"); - // let bounds_string = deps - // .iter() - // .enumerate() - // .filter_map(|(i, (name, cvar))| { - // let range = cvar.ref_range(analyzer).unwrap()?; + let bounds_string = deps + .iter() + .enumerate() + .filter_map(|(i, (name, cvar))| { + let range = cvar.ref_range(analyzer).unwrap()?; - // let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); - // let ret = parts.into_iter().fold( - // format!("{}. {name}", i + 1), - // |mut acc, part| { - // acc = acc.to_string(); - // acc - // }, - // ); - // Some(format!("{ret}\n")) - // }) - // .collect::>() - // .join(""); + let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); + let ret = parts.into_iter().fold( + format!("{}. {name}", i + 1), + |mut acc, part| { + acc = acc.to_string(); + acc + }, + ); + Some(format!("{ret}\n")) + }) + .collect::>() + .join(""); let mut report = Report::build( self.report_kind(), self.ctx_loc.source(), diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index 006a594d..2507b26f 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -40,7 +40,7 @@ impl ReportDisplay for VarBoundAnalysis { init: false, name: self.var_display_name.clone(), loc: bound_change.0.clone(), - order: i as i32, + order: (bound_change.0.end() - bound_change.0.start()) as i32, storage: self.storage, ctx: self.ctx, ctx_conditionals: self.conditionals(analyzer), diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index f06726a2..5053dc3f 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -345,11 +345,11 @@ fn main() { all_edges.push(ctx); all_edges.iter().for_each(|c| { let rets = c.return_nodes(&analyzer).unwrap(); - if c.path(&analyzer).starts_with(r#"step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64)"#) - && rets.iter().take(1).any(|ret| { - let range = ret.1.ref_range(&analyzer).unwrap().unwrap(); - range.evaled_range_min(&analyzer).unwrap().range_eq(&Elem::from(Concrete::from(I256::from(-1)))) - }) + // if c.path(&analyzer).starts_with(r#"step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64)"#) + // && rets.iter().take(1).any(|ret| { + // let range = ret.1.ref_range(&analyzer).unwrap().unwrap(); + // range.evaled_range_min(&analyzer).unwrap().range_eq(&Elem::from(Concrete::from(I256::from(-1)))) + // }) { // step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64).fork{ false }.fork{ true }.fork{ true }.fork{ false }"#.to_string()) { // println!("{:#?}", c.ctx_deps_as_controllables_str(&analyzer).unwrap()); if let Some(mut solver) = BruteBinSearchSolver::maybe_new(c.ctx_deps(&analyzer).unwrap(), &analyzer).unwrap() { diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index d8d2060b..7b760ea5 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -337,7 +337,7 @@ pub enum ContextEdge { /// A connection between a variable and a parent variable where the child is some attribute on the parent /// (i.e. `.length`) - AttrAccess, + AttrAccess(&'static str), /// A connection between a variable and the index that was used to create the variable from an IndexAccess Index, /// A connection between a variable and a parent variable where the child is some index into the parent diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index e684e48e..f657d59d 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -231,19 +231,19 @@ impl Builtin { Builtin::Uint(_) => SolcRange::from(Concrete::from(U256::from(0))), Builtin::Bytes(s) => SolcRange::from(Concrete::Bytes(*s, H256::zero())), Builtin::DynamicBytes | Builtin::Array(_) | Builtin::Mapping(_, _) => { - let zero = Elem::ConcreteDyn(Box::new(RangeDyn::new( + let zero = Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::zero())), Default::default(), Loc::Implicit, - ))); + )); Some(SolcRange::new(zero.clone(), zero, vec![])) } Builtin::SizedArray(s, _) => { - let sized = Elem::ConcreteDyn(Box::new(RangeDyn::new( + let sized = Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(*s)), Default::default(), Loc::Implicit, - ))); + )); Some(SolcRange::new(sized.clone(), sized, vec![])) } Builtin::Rational | Builtin::Func(_, _) => None, @@ -390,6 +390,75 @@ impl Builtin { } } + pub fn zero_concrete(&self) -> Option { + match self { + Builtin::Uint(size) => { + Some(Concrete::Uint(*size, U256::zero())) + } + Builtin::Int(size) => { + Some(Concrete::Int(*size, I256::from_raw(U256::zero()))) + } + Builtin::Bytes(size) => { + let h = H256::default(); + Some(Concrete::Bytes(*size, h)) + } + Builtin::Address => Some(Concrete::Address(Address::from_slice(&[0x00; 20]))), + Builtin::Bool => Some(Concrete::Bool(false)), + _ => None, + } + } + + pub fn max_concrete(&self) -> Option { + match self { + Builtin::Uint(size) => { + let max = if *size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(*size)) - 1 + }; + Some(Concrete::Uint(*size, max)) + } + Builtin::Int(size) => { + let max: I256 = + I256::from_raw((U256::from(1u8) << U256::from(*size - 1)) - U256::from(1)); + Some(Concrete::Int(*size, max)) + } + Builtin::Bytes(size) => { + let size = *size as u16 * 8; + let max = if size == 256 { + U256::MAX + } else { + U256::from(2).pow(U256::from(size)) - 1 + }; + + let mut h = H256::default(); + max.to_big_endian(h.as_mut()); + Some(Concrete::Bytes((size / 8) as u8, h)) + } + Builtin::Address => Some(Concrete::Address(Address::from_slice(&[0xff; 20]))), + Builtin::Bool => Some(Concrete::Bool(true)), + _ => None, + } + } + + pub fn min_concrete(&self) -> Option { + match self { + Builtin::Uint(size) => { + Some(Concrete::Uint(*size, U256::zero())) + } + Builtin::Int(size) => { + Some(Concrete::Int(*size, I256::MIN)) + } + Builtin::Bytes(size) => { + let h = H256::default(); + Some(Concrete::Bytes(*size, h)) + } + Builtin::Address => Some(Concrete::Address(Address::from_slice(&[0x00; 20]))), + Builtin::Bool => Some(Concrete::Bool(false)), + _ => None, + } + } + /// Converts the builtin to a string pub fn as_string(&self, analyzer: &impl GraphBackend) -> Result { use Builtin::*; diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 828c1218..e8d42064 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -103,6 +103,12 @@ pub enum Concrete { Array(Vec), } +// impl From for Concrete { +// fn from(u: usize) -> Self { +// Concrete::Uint(256, U256::from(u)) +// } +// } + impl From for Concrete { fn from(u: U256) -> Self { Concrete::Uint(256, u) @@ -161,6 +167,65 @@ impl> From> for Concrete { } impl Concrete { + pub fn set_indices(&mut self, other: &Self) { + match (self, other) { + (Concrete::DynBytes(s), Concrete::DynBytes(o)) => { + o.iter().enumerate().for_each(|(i, b)| { + s[i] = *b; + }); + } + (Concrete::Array(s), Concrete::Array(o)) => { + o.iter().enumerate().for_each(|(i, b)| { + s[i] = b.clone(); + }); + } + (Concrete::String(s), Concrete::String(o)) => { + o.chars().enumerate().for_each(|(i, b)| { + s.replace_range(i..i+1, &b.to_string()); + }); + } + (Concrete::Bytes(size, s), Concrete::Bytes(cap, o)) => { + let mut bytes = [0u8; 32]; + s.0.into_iter() + .take((*size).into()) + .enumerate() + .for_each(|(i, b)| bytes[i] = b); + o.0.into_iter() + .take((*cap).into()) + .enumerate() + .for_each(|(i, b)| bytes[i] = b); + *s = H256(bytes); + } + _ => {} + } + } + + pub fn get_index(&self, other: &Self) -> Option { + match (self, other) { + (Concrete::DynBytes(s), Concrete::Uint(_, o)) => { + let index = o.as_usize(); + let mut bytes = [0u8; 32]; + bytes[0] = s[index]; + Some(Concrete::Bytes(1, H256(bytes))) + } + (Concrete::Array(s), Concrete::Uint(_, o)) => { + let index = o.as_usize(); + Some(s[index].clone()) + } + (Concrete::String(s), Concrete::Uint(_, o)) => { + let index = o.as_usize(); + Some(Concrete::String(s[index..index+1].to_string())) + } + (Concrete::Bytes(size, s), Concrete::Uint(_, o)) => { + let index = o.as_usize(); + let mut bytes = [0u8; 32]; + bytes[0] = s[index]; + Some(Concrete::Bytes(1, H256(bytes))) + } + _ => None + } + } + /// Returns whether this concrete is a dynamic type pub fn is_dyn(&self) -> bool { matches!( @@ -230,6 +295,12 @@ impl Concrete { Concrete::Bool(false) } } + Concrete::DynBytes(v) => { + let mut bytes = [0u8; 32]; + uint.to_big_endian(&mut bytes); + let new_vec = &bytes.to_vec()[0..v.len()]; + Concrete::DynBytes(new_vec.to_vec()) + } e => todo!("Unsupported: {e:?}"), } } @@ -310,6 +381,20 @@ impl Concrete { } } + pub fn bit_representation(&self) -> Option { + match self { + Concrete::Int(size, val) => { + let mut bytes = [0u8; 32]; + val.to_big_endian(&mut bytes); + Some(Concrete::Uint(*size, U256::from_big_endian(&bytes))) + } + Concrete::Bytes(size, _) => Some(Concrete::Uint(*size as u16 / 8, self.into_u256().unwrap())), + Concrete::Bool(_val) => Some(Concrete::Uint(8, self.into_u256().unwrap())), + Concrete::Address(_val) => Some(Concrete::Uint(20, self.into_u256().unwrap())), + _ => None + } + } + /// Cast the concrete to another type as denoted by a [`Builtin`]. pub fn cast(self, builtin: Builtin) -> Option { match self { @@ -337,7 +422,9 @@ impl Concrete { } } } - Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), + Builtin::Int(size) => { + Some(Concrete::Int(size, I256::from_raw(val))) + }, Builtin::Bytes(size) => { let mask = if size == 32 { U256::MAX @@ -367,13 +454,9 @@ impl Concrete { val.to_big_endian(&mut bytes); Some(Concrete::Address(Address::from_slice(&bytes[12..]))) } - Builtin::Uint(size) => { - let mask = if size == 256 { - U256::MAX - } else { - U256::from(2).pow(size.into()) - 1 - }; - Some(Concrete::Uint(size, val.into_raw() & mask)) + Builtin::Uint(_size) => { + let bit_repr = self.bit_representation().unwrap(); + bit_repr.cast(builtin) } Builtin::Int(size) => { // no op @@ -574,6 +657,9 @@ impl Concrete { } } Concrete::Bytes(_, b) => Some(U256::from_big_endian(b.as_bytes())), + Concrete::DynBytes(v) if v.len() <= 32 => { + self.clone().cast(Builtin::Bytes(v.len() as u8))?.into_u256() + }, Concrete::Address(a) => Some(U256::from_big_endian(a.as_bytes())), Concrete::Bool(b) => { if *b { @@ -761,6 +847,45 @@ impl Concrete { } } + pub fn as_hex_string(&self) -> String { + match self { + Concrete::Uint(_, val) => { + let mut bytes = [0u8; 32]; + val.to_big_endian(&mut bytes); + format!("0x{}", hex::encode(bytes)) + }, + Concrete::Int(_, val) => { + let mut bytes = [0u8; 32]; + val.to_big_endian(&mut bytes); + format!("0x{}", hex::encode(bytes)) + }, + Concrete::Bytes(size, b) => format!( + "0x{}", + b.0.iter() + .take(*size as usize) + .map(|byte| format!("{byte:02x}")) + .collect::>() + .join("") + ), + Concrete::String(s) => hex::encode(s), + Concrete::Bool(_b) => self.bit_representation().unwrap().as_hex_string(), + Concrete::Address(_a) => self.bit_representation().unwrap().as_hex_string(), + Concrete::DynBytes(a) => { + if a.is_empty() { + "0x".to_string() + } else { + hex::encode(a) + } + } + Concrete::Array(arr) => format!( + "0x{}", + arr.iter() + .map(|i| i.as_hex_string()[2..].to_string()) + .collect::>() + .join("") + ), + } + } /// Converts to a string pub fn as_string(&self) -> String { match self { diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index c9bea425..70a1be53 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -116,7 +116,6 @@ impl ContextNode { let as_vec = modifier_set.iter().collect::>(); if as_vec.len() > 2 { - println!("{}", as_vec.iter().map(|i| i.name(analyzer).unwrap()).collect::>().join(", ")); panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") } else if as_vec.len() == 2 { as_vec[0].get_overriding(as_vec[1], analyzer) diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 2f47d450..4378f03c 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,15 +1,15 @@ use crate::SolcRange; +use std::borrow::Cow; use crate::{ as_dot_str, nodes::{ContextNode, ContextVarNode}, - range::{elem::RangeOp, Range, RangeEval}, + range::{Range, elem::RangeOp, RangeEval}, solvers::{ dl::{DLSolver, SolveStatus}, Atomize, SolverAtom, }, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; -use std::borrow::Cow; use shared::NodeIdx; @@ -33,14 +33,7 @@ impl ContextNode { let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { let range = dep.ref_range(analyzer)?.unwrap(); - if range.unsat(analyzer) { - panic!( - "initial range for {} not sat", - dep.display_name(analyzer).unwrap() - ); - } let r: Cow<'_, SolcRange> = range.flattened_range(analyzer)?; - // println!("dep {} range: [{}, {}]", dep.display_name(analyzer).unwrap(), r.min, r.max); ranges.insert(*dep, r.into_owned()); Ok(()) })?; @@ -49,10 +42,8 @@ impl ContextNode { .iter() .filter_map(|(_dep, range)| { if let Some(atom) = range.min.atomize() { - // println!("dep {} atomized min: {:?}", dep.display_name(analyzer).unwrap(), atom); Some(atom) } else { - // println!("dep {} atomized max: {:?}", dep.display_name(analyzer).unwrap(), atom); range.max.atomize() } }) @@ -102,7 +93,6 @@ impl ContextNode { } let underlying = self.underlying_mut(analyzer)?; - underlying.ctx_deps.push(dep); } } diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index a9b340b0..a50d94f7 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -145,11 +145,13 @@ impl ContextVarNode { pub fn as_controllable_name(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ref_range) = self.ref_range(analyzer)? { let mut exclude = vec![]; + let min_name = ref_range .range_min() .simplify_minimize(&mut exclude, analyzer)? .to_range_string(false, analyzer) .s; + exclude = vec![]; let max_name = ref_range .range_max() @@ -206,19 +208,49 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.tmp_of()) } + pub fn array_to_len_var( + &self, + analyzer: &impl GraphBackend, + ) -> Option { + if let Some(len) = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Incoming) + .find(|edge| *edge.weight() == Edge::Context(ContextEdge::AttrAccess("length"))) + .map(|edge| edge.source()) { + Some(len.into()) + } else if let Some(prev) = self.previous_version(analyzer) { + prev.array_to_len_var(analyzer) + } else { + None + } + } + + pub fn index_access_to_array( + &self, + analyzer: &impl GraphBackend, + ) -> Option { + if let Some(arr) = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .find(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) + .map(|edge| edge.target()) { + Some(arr.into()) + } else if let Some(prev) = self.previous_version(analyzer) { + prev.index_access_to_array(analyzer) + } else { + None + } + } + pub fn len_var_to_array( &self, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if self.name(analyzer)?.ends_with(".length") { - if let Some(arr) = analyzer.search_for_ancestor( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::AttrAccess), - ) { - Ok(Some(ContextVarNode::from(arr).latest_version(analyzer))) - } else { - Ok(None) - } + if let Some(arr) = analyzer.search_for_ancestor( + self.0.into(), + &Edge::Context(ContextEdge::AttrAccess("length")), + ) { + Ok(Some(ContextVarNode::from(arr).latest_version(analyzer))) } else { Ok(None) } @@ -228,13 +260,12 @@ impl ContextVarNode { let arr = analyzer .graph() .edges_directed(self.first_version(analyzer).into(), Direction::Outgoing) - .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) - .map(|edge| edge.target()) - .take(1) - .next()?; + .find(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) + .map(|edge| edge.target())?; Some(ContextVarNode::from(arr).latest_version(analyzer)) } + /// Goes from an index access (i.e. `x[idx]`) to the index (i.e. `idx`) pub fn index_access_to_index(&self, analyzer: &impl GraphBackend) -> Option { let index = analyzer.find_child_exclude_via( self.first_version(analyzer).into(), @@ -250,8 +281,7 @@ impl ContextVarNode { .graph() .edges_directed(self.0.into(), Direction::Incoming) .filter(|edge| { - Edge::Context(ContextEdge::IndexAccess) == *edge.weight() - || Edge::Context(ContextEdge::AttrAccess) == *edge.weight() + matches!(*edge.weight(), Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::AttrAccess(_))) }) .map(|edge| ContextVarNode::from(edge.source())) .collect() @@ -309,4 +339,4 @@ impl ContextVarNode { Ok(tree) } -} +} \ No newline at end of file diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 2795a135..7d106dea 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,6 +1,6 @@ use crate::{ nodes::{Concrete, ContextNode, ContextVarNode}, - range::{range_string::ToRangeString, Range}, + range::{range_string::ToRangeString, Range, RangeEval}, AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, }; @@ -149,6 +149,15 @@ impl ContextVarNode { pub fn needs_fallback(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.needs_fallback()) } + + pub fn range_contains_elem(&self, elem: Elem, analyzer: &impl GraphBackend) -> Result { + if let Some(r) = self.ref_range(analyzer)? { + Ok(r.contains_elem(&elem, analyzer)) + } else { + Ok(false) + } + } + // #[tracing::instrument(level = "trace", skip_all)] pub fn set_range_min( &self, @@ -185,7 +194,7 @@ impl ContextVarNode { None }; self.underlying_mut(analyzer)? - .set_range_min(new_min, fallback); + .set_range_min(new_min, fallback)?; } self.cache_range(analyzer)?; Ok(()) @@ -225,7 +234,7 @@ impl ContextVarNode { }; self.underlying_mut(analyzer)? - .set_range_max(new_max, fallback) + .set_range_max(new_max, fallback)?; } self.cache_range(analyzer)?; @@ -237,13 +246,15 @@ impl ContextVarNode { analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result<(), GraphError> { + tracing::trace!("setting range exclusions for {}", self.display_name(analyzer)?); + assert!(*self == self.latest_version(analyzer)); let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? } else { None }; self.underlying_mut(analyzer)? - .set_range_exclusions(new_exclusions, fallback); + .set_range_exclusions(new_exclusions, fallback)?; Ok(()) } @@ -310,6 +321,8 @@ impl ContextVarNode { analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result { + tracing::trace!("setting range exclusions for: {}", self.display_name(analyzer).unwrap()); + assert!(*self == self.latest_version(analyzer)); let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? } else { diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index beeb82a7..cec9ea0b 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,11 +1,14 @@ use crate::{ + range::RangeEval, nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, + elem::{Elem}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; use shared::{Search, StorageLocation}; -use petgraph::Direction; +use ethers_core::types::{I256, U256}; +use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::Loc; impl ContextVarNode { @@ -29,7 +32,7 @@ impl ContextVarNode { Ok(matches!( self.underlying(analyzer)?.storage, Some(StorageLocation::Storage(..)) - )) + ) || self.is_attr_or_index_of_storage(analyzer)) } pub fn is_memory(&self, analyzer: &impl GraphBackend) -> Result { @@ -68,21 +71,65 @@ impl ContextVarNode { let global_first = self.global_first_version(analyzer); let is_independent = self.is_independent(analyzer)?; - Ok((global_first.is_storage(analyzer)? - || global_first.is_calldata_input(analyzer) - || global_first.is_msg(analyzer)? - || global_first.is_block(analyzer)? - || ( - // if its a function input, and we are evaluating the function - // as a standalone (i.e. its internal, but we are treating it like its external) - // it wont be marked as calldata, but for the purposes - // of determining controllability it is to better to assume there is some path that lets us - // control it - global_first.is_func_input(analyzer) - && global_first.maybe_ctx(analyzer).is_some() - && !global_first.ctx(analyzer).has_parent(analyzer)? - )) - && is_independent) + Ok(is_independent + && ( + global_first.is_storage(analyzer)? + || global_first.is_calldata_input(analyzer) + || global_first.is_msg(analyzer)? + || global_first.is_block(analyzer)? + || ( + // if its a function input, and we are evaluating the function + // as a standalone (i.e. its internal, but we are treating it like its external) + // it wont be marked as calldata, but for the purposes + // of determining controllability it is to better to assume there is some path that lets us + // control it + global_first.is_func_input(analyzer) + && global_first.maybe_ctx(analyzer).is_some() + && !global_first.ctx(analyzer).has_parent(analyzer)? + ) + || self.is_attr_or_index_of_fundamental(analyzer) // performed last to try to not have to do this check + ) + ) + } + + pub fn is_attr_or_index_of_fundamental(&self, analyzer: &impl GraphBackend) -> bool { + let direct_is_fundamental = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .any(|edge| { + if matches!(edge.weight(), Edge::Context(ContextEdge::AttrAccess(_)) | Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::Index)) { + ContextVarNode::from(edge.target()).is_fundamental(analyzer).unwrap_or(false) + } else { + false + } + }); + if direct_is_fundamental { + direct_is_fundamental + } else if let Some(prev) = self.previous_global_version(analyzer) { + prev.is_attr_or_index_of_fundamental(analyzer) + } else { + false + } + } + + pub fn is_attr_or_index_of_storage(&self, analyzer: &impl GraphBackend) -> bool { + let direct_is_storage = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .any(|edge| { + if matches!(edge.weight(), Edge::Context(ContextEdge::AttrAccess(_)) | Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::Index)) { + ContextVarNode::from(edge.target()).is_storage(analyzer).unwrap_or(false) + } else { + false + } + }); + if direct_is_storage { + direct_is_storage + } else if let Some(prev) = self.previous_or_inherited_version(analyzer) { + prev.is_attr_or_index_of_storage(analyzer) + } else { + false + } } pub fn is_independent(&self, analyzer: &impl GraphBackend) -> Result { @@ -182,14 +229,13 @@ impl ContextVarNode { }) } - pub fn is_len_var(&self, analyzer: &impl GraphBackend) -> Result { - Ok(self.name(analyzer)?.ends_with(".length") - && analyzer - .search_for_ancestor( - self.first_version(analyzer).into(), - &Edge::Context(ContextEdge::AttrAccess), - ) - .is_some()) + pub fn is_len_var(&self, analyzer: &impl GraphBackend) -> bool { + analyzer + .search_for_ancestor( + self.first_version(analyzer).into(), + &Edge::Context(ContextEdge::AttrAccess("length")), + ) + .is_some() } pub fn is_array_index_access(&self, analyzer: &impl GraphBackend) -> bool { @@ -277,23 +323,29 @@ impl ContextVarNode { to_ty: VarType, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { + let new_underlying = self + .underlying(analyzer)? + .clone(); + let node = analyzer.add_node(Node::ContextVar(new_underlying)); + analyzer.add_edge(node, *self, Edge::Context(ContextEdge::Prev)); + let new_self = ContextVarNode::from(node); + let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { - self.underlying_mut(analyzer)?.ty = new_ty; + new_self.underlying_mut(analyzer)?.ty = new_ty; } - if let (Some(r), Some(r2)) = (self.range(analyzer)?, to_ty.range(analyzer)?) { - let min = r.min.cast(r2.min); - let max = r.max.cast(r2.max); - self.set_range_min(analyzer, min)?; - self.set_range_max(analyzer, max)?; + + if let Some((new_min, new_max)) = self.cast_exprs(&to_ty, analyzer)? { + new_self.set_range_min(analyzer, new_min)?; + new_self.set_range_max(analyzer, new_max)?; } } - if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { + if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (new_self.ty(analyzer)?, to_ty) { // update name let display_name = cnode.underlying(analyzer)?.as_human_string(); - self.underlying_mut(analyzer)?.display_name = display_name; + new_self.underlying_mut(analyzer)?.display_name = display_name; } Ok(()) } @@ -331,4 +383,69 @@ impl ContextVarNode { pub fn is_int(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_int(analyzer) } + + pub fn cast_exprs( + &self, + to_ty: &VarType, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ) -> Result, Elem)>, GraphError> { + if let Some(to_range) = to_ty.range(analyzer)? { + let mut min_expr = (*self) + .range_min(analyzer)?.unwrap() + .cast(to_range.min.clone()) + .min( + (*self) + .range_max(analyzer)?.unwrap() + .cast(to_range.min.clone()) + ); + let mut max_expr = (*self) + .range_min(analyzer)?.unwrap() + .cast(to_range.min.clone()) + .max( + (*self) + .range_max(analyzer)?.unwrap() + .cast(to_range.min) + ); + + if let Some(r) = self.ref_range(analyzer)? { + let zero = Elem::from(Concrete::from(U256::zero())); + if r.contains_elem(&zero, analyzer) { + min_expr = min_expr.min(zero.clone()); + max_expr = max_expr.max(zero); + } + } + + if let (VarType::BuiltIn(from_bn, _), VarType::BuiltIn(to_bn, _)) = (self.ty(analyzer)?, to_ty) { + match (from_bn.underlying(analyzer)?, to_bn.underlying(analyzer)?) { + (Builtin::Uint(_), int @ Builtin::Int(_)) => { + // from ty is uint, to ty is int, check if type(int.min).bit_representation() + // is in range + if let Some(r) = self.ref_range(analyzer)? { + let int_min = int.min_concrete().unwrap(); + let bit_repr = int_min.bit_representation().unwrap(); + let bit_repr = bit_repr.into(); + if r.contains_elem(&bit_repr, analyzer) { + min_expr = min_expr.min(int_min.clone().into()); + max_expr = max_expr.max(int_min.into()); + } + } + } + (Builtin::Int(_), Builtin::Uint(_size)) => { + // from ty is int, to ty is uint + if let Some(r) = self.ref_range(analyzer)? { + let neg1 = Concrete::from(I256::from(-1i32)); + if r.contains_elem(&neg1.clone().into(), analyzer) { + max_expr = max_expr.max(neg1.bit_representation().unwrap().into()); + } + } + } + _ => {} + } + } + + Ok(Some((min_expr, max_expr))) + } else { + Ok(None) + } + } } diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index d8cfda8e..1764710a 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -266,7 +266,7 @@ impl ContextVar { } // #[tracing::instrument(level = "trace", skip_all)] - pub fn set_range_min(&mut self, new_min: Elem, fallback_range: Option) { + pub fn set_range_min(&mut self, new_min: Elem, fallback_range: Option) -> Result<(), GraphError> { // tracing::trace!("Setting range min in underlying: {:?}", self.ty); match &mut self.ty { VarType::User(TypeNode::Contract(_), ref mut maybe_range) @@ -275,14 +275,17 @@ impl ContextVar { | VarType::BuiltIn(_, ref mut maybe_range) => { if let Some(range) = maybe_range { range.set_range_min(new_min); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + Ok(()) + } else if let Some(mut fr) = fallback_range { fr.set_range_min(new_min); *maybe_range = Some(fr); + Ok(()) + } else { + Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) } } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin: {e:?}"), + VarType::Concrete(_) => Ok(()), + e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), } } @@ -299,11 +302,12 @@ impl ContextVar { if let Some(range) = maybe_range { range.set_range_min(new_min); true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + } else if let Some(mut fr) = fallback_range { fr.set_range_min(new_min); *maybe_range = Some(fr); true + } else { + false } } VarType::Concrete(_) => true, @@ -311,7 +315,7 @@ impl ContextVar { } } - pub fn set_range_max(&mut self, new_max: Elem, fallback_range: Option) { + pub fn set_range_max(&mut self, new_max: Elem, fallback_range: Option) -> Result<(), GraphError> { match &mut self.ty { VarType::User(TypeNode::Contract(_), ref mut maybe_range) | VarType::User(TypeNode::Enum(_), ref mut maybe_range) @@ -319,14 +323,17 @@ impl ContextVar { | VarType::BuiltIn(_, ref mut maybe_range) => { if let Some(range) = maybe_range { range.set_range_max(new_max); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + Ok(()) + } else if let Some(mut fr) = fallback_range { fr.set_range_max(new_max); *maybe_range = Some(fr); + Ok(()) + } else { + Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) } } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin or concrete: {e:?}"), + VarType::Concrete(_) => Ok(()), + e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), } } @@ -334,7 +341,7 @@ impl ContextVar { &mut self, new_exclusions: Vec>, fallback_range: Option, - ) { + ) -> Result<(), GraphError> { match &mut self.ty { VarType::User(TypeNode::Contract(_), ref mut maybe_range) | VarType::User(TypeNode::Enum(_), ref mut maybe_range) @@ -342,14 +349,17 @@ impl ContextVar { | VarType::BuiltIn(_, ref mut maybe_range) => { if let Some(range) = maybe_range { range.set_range_exclusions(new_exclusions); - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + Ok(()) + } else if let Some(mut fr) = fallback_range { fr.set_range_exclusions(new_exclusions); *maybe_range = Some(fr); + Ok(()) + } else { + Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) } } - VarType::Concrete(_) => {} - e => panic!("wasnt builtin or concrete: {e:?}"), + VarType::Concrete(_) => Ok(()), + e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), } } @@ -366,11 +376,12 @@ impl ContextVar { if let Some(range) = maybe_range { range.set_range_max(new_max); true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + } else if let Some(mut fr) = fallback_range { fr.set_range_max(new_max); *maybe_range = Some(fr); true + } else { + false } } VarType::Concrete(_) => true, @@ -391,11 +402,12 @@ impl ContextVar { if let Some(range) = maybe_range { range.set_range_exclusions(new_exclusions); true - } else { - let mut fr = fallback_range.expect("No range and no fallback_range"); + } else if let Some(mut fr) = fallback_range { fr.set_range_exclusions(new_exclusions); *maybe_range = Some(fr); true + } else { + false } } VarType::Concrete(_) => true, diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index 483dac22..df8b4bb3 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -192,4 +192,25 @@ impl ContextVarNode { .next() } } + + pub fn previous_global_version(&self, analyzer: &impl GraphBackend) -> Option { + if let Some(prev) = self.previous_version(analyzer) { + Some(prev) + } else if let Some(inherited) = analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() { + Some(inherited) + } else { analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() + } + } } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 92b3a6e1..c7b2d1c0 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,6 +1,6 @@ use crate::{ nodes::{Concrete, ContextVarNode}, - range::elem::{RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference}, + range::elem::{MaybeCollapsed, collapse, RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference}, GraphBackend, GraphError, }; use solang_parser::pt::Loc; @@ -20,7 +20,7 @@ pub enum Elem { /// A range element that is a reference to another node Reference(Reference), /// A concrete range element of type `T`. e.g.: some number like `10` - ConcreteDyn(Box>), + ConcreteDyn(RangeDyn), /// A concrete range element of type `T`. e.g.: some number like `10` Concrete(RangeConcrete), /// A range element that is an expression composed of other range elements @@ -79,13 +79,29 @@ impl Elem { pub fn maybe_range_dyn(&self) -> Option> { match self { - Elem::ConcreteDyn(a) => Some(*a.clone()), + Elem::ConcreteDyn(a) => Some(a.clone()), _ => None, } } + + pub fn is_conc(&self) -> bool { + match self { + Elem::Concrete(_a) => true, + Elem::ConcreteDyn(a) => { + a.len.maybe_concrete().is_some() + && a.val.iter().all(|(key, (val, _))| { + key.is_conc() && val.is_conc() + }) + } + Elem::Expr(expr) => { + expr.lhs.is_conc() && expr.rhs.is_conc() + }, + _ => false, + } + } } -impl Elem { +impl Elem { pub fn contains_node(&self, node_idx: NodeIdx) -> bool { match self { Self::Reference(d) => d.idx == node_idx, @@ -103,14 +119,14 @@ impl Elem { } } - pub fn dyn_map(&self) -> Option<&BTreeMap> { + pub fn dyn_map(&self) -> Option<&BTreeMap> { match self { Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), _ => None, } } - pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { + pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { match self { Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), _ => None, @@ -157,6 +173,36 @@ impl Elem { let expr = RangeExpr::new(self, RangeOp::Exp, other); Elem::Expr(expr) } + + /// Creates a new range element that is a memcopy of another + pub fn memcopy(self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Memcopy, Elem::Null); + Elem::Expr(expr) + } + + /// Creates a new range element that applies a setting of indices of a memory object + pub fn set_indices(self, other: RangeDyn) -> Self { + let expr = RangeExpr::new(self, RangeOp::SetIndices, Elem::ConcreteDyn(other)); + Elem::Expr(expr) + } + + /// Creates a new range element that sets the length of a memory object + pub fn set_length(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::SetLength, other); + Elem::Expr(expr) + } + + /// Gets the length of a memory object + pub fn get_length(self) -> Self { + let expr = RangeExpr::new(self, RangeOp::GetLength, Elem::Null); + Elem::Expr(expr) + } + + /// Gets the length of a memory object + pub fn get_index(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::GetIndex, other); + Elem::Expr(expr) + } } impl From> for Elem { @@ -171,7 +217,7 @@ impl From> for Elem { } } -impl Add for Elem { +impl Add for Elem { type Output = Self; fn add(self, other: Elem) -> Self { @@ -180,7 +226,7 @@ impl Add for Elem { } } -impl Sub for Elem { +impl Sub for Elem { type Output = Self; fn sub(self, other: Elem) -> Self { @@ -189,7 +235,7 @@ impl Sub for Elem { } } -impl Mul for Elem { +impl Mul for Elem { type Output = Self; fn mul(self, other: Elem) -> Self { @@ -198,7 +244,7 @@ impl Mul for Elem { } } -impl Div for Elem { +impl Div for Elem { type Output = Self; fn div(self, other: Elem) -> Self { @@ -207,7 +253,7 @@ impl Div for Elem { } } -impl Shl for Elem { +impl Shl for Elem { type Output = Self; fn shl(self, other: Elem) -> Self { @@ -216,7 +262,7 @@ impl Shl for Elem { } } -impl Shr for Elem { +impl Shr for Elem { type Output = Self; fn shr(self, other: Elem) -> Self { @@ -225,7 +271,7 @@ impl Shr for Elem { } } -impl Rem for Elem { +impl Rem for Elem { type Output = Self; fn rem(self, other: Elem) -> Self { @@ -234,7 +280,7 @@ impl Rem for Elem { } } -impl BitAnd for Elem { +impl BitAnd for Elem { type Output = Self; fn bitand(self, other: Self) -> Self::Output { @@ -243,7 +289,7 @@ impl BitAnd for Elem { } } -impl BitOr for Elem { +impl BitOr for Elem { type Output = Self; fn bitor(self, other: Self) -> Self::Output { @@ -252,7 +298,7 @@ impl BitOr for Elem { } } -impl BitXor for Elem { +impl BitXor for Elem { type Output = Self; fn bitxor(self, other: Self) -> Self::Output { @@ -268,6 +314,103 @@ impl From for Elem { } impl Elem { + pub fn overlaps(&self, other: &Self, eval: bool, analyzer: &impl GraphBackend) -> Result, GraphError> { + match (self, other) { + (Elem::Concrete(s), Elem::Concrete(o)) => { + Ok(Some(o.val == s.val)) + } + (Elem::Reference(s), Elem::Reference(o)) => { + if eval { + let lhs_min = s.minimize(analyzer)?; + let rhs_max = o.maximize(analyzer)?; + + match lhs_min.range_ord(&rhs_max) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = s.maximize(analyzer)?; + let rhs_min = o.minimize(analyzer)?; + Ok(Some(matches!( + lhs_max.range_ord(&rhs_min), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else if s == o { + Ok(Some(true)) + } else { + Ok(None) + } + } + (Elem::Reference(s), c @ Elem::Concrete(_)) => { + if eval { + let lhs_min = s.minimize(analyzer)?; + + match lhs_min.range_ord(c) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = s.maximize(analyzer)?; + Ok(Some(matches!( + lhs_max.range_ord(c), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else { + Ok(None) + } + } + (Elem::Concrete(_), Elem::Reference(_)) => other.overlaps(self, eval, analyzer), + _ => Ok(None) + } + } + pub fn overlaps_dual(&self, rhs_min: &Self, rhs_max: &Self, eval: bool, analyzer: &impl GraphBackend) -> Result, GraphError> { + match self { + Self::Reference(d) => { + if eval { + let lhs_min = d.minimize(analyzer)?; + let rhs_max = rhs_max.maximize(analyzer)?; + + match lhs_min.range_ord(&rhs_max) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = d.maximize(analyzer)?; + let rhs_min = rhs_min.minimize(analyzer)?; + Ok(Some(matches!( + lhs_max.range_ord(&rhs_min), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else if self == rhs_min || self == rhs_max { + Ok(Some(true)) + } else { + Ok(None) + } + }, + Self::Concrete(_) => { + match rhs_min.range_ord(self) { + Some(std::cmp::Ordering::Less) => { + Ok(Some(matches!( + rhs_max.range_ord(self), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + }, + _ => Ok(None), + } + } pub fn is_negative( &self, maximize: bool, @@ -339,7 +482,13 @@ impl std::fmt::Display for Elem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), - Elem::ConcreteDyn(..) => write!(f, "range_elem"), + Elem::ConcreteDyn(d) => { + write!(f, "{{len: {}, values: {{", d.len)?; + d.val.iter().try_for_each(|(key, (val, op))| { + write!(f, " {key}: ({val}, {op}),") + })?; + write!(f, "}}}}") + }, Elem::Concrete(RangeConcrete { val, .. }) => { write!(f, "{}", val.as_string()) } @@ -383,6 +532,9 @@ impl RangeElem for Elem { match (self, other) { (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), (Self::Reference(a), Self::Reference(b)) => a.range_ord(b), + (Elem::Null, Elem::Null) => None, + (_a, Elem::Null) => Some(std::cmp::Ordering::Greater), + (Elem::Null, _a) => Some(std::cmp::Ordering::Less), _ => None, } } @@ -516,7 +668,14 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_maximize(exclude, analyzer), Concrete(inner) => inner.simplify_maximize(exclude, analyzer), ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), - Expr(expr) => expr.simplify_maximize(exclude, analyzer), + Expr(expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(collapsed) => { + collapsed.simplify_maximize(exclude, analyzer) + } + _ => expr.simplify_maximize(exclude, analyzer) + } + } Null => Ok(Elem::Null), } } @@ -531,7 +690,14 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_minimize(exclude, analyzer), Concrete(inner) => inner.simplify_minimize(exclude, analyzer), ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), - Expr(expr) => expr.simplify_minimize(exclude, analyzer), + Expr(expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(collapsed) => { + collapsed.simplify_minimize(exclude, analyzer) + } + _ => expr.simplify_minimize(exclude, analyzer) + } + }, Null => Ok(Elem::Null), } } @@ -542,7 +708,16 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => expr.cache_maximize(analyzer), + Expr(expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_minimize(analyzer)?; + *self = collapsed; + Ok(()) + } + _ => expr.cache_maximize(analyzer) + } + }, Null => Ok(()), } } @@ -553,7 +728,16 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => expr.cache_minimize(analyzer), + Expr(expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_minimize(analyzer)?; + *self = collapsed; + Ok(()) + } + _ => expr.cache_minimize(analyzer) + } + }, Null => Ok(()), } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 9527306c..d557a000 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -8,7 +8,7 @@ use shared::NodeIdx; use std::collections::BTreeMap; -pub trait RangeElem { +pub trait RangeElem { type GraphError; /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables fn flatten( diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 39895636..94121470 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -73,7 +73,7 @@ impl RangeExpr { } } -impl RangeExpr { +impl RangeExpr { /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { RangeExpr { @@ -105,13 +105,10 @@ impl RangeElem for RangeExpr { ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { (true, _, Some(flat)) | (false, Some(flat), _) => { - // println!("flatten cache hit"); return Ok(*flat.clone()); } _ => {} } - // println!("flatten cache miss"); - // println!("flattening expr: {}", Elem::Expr(self.clone())); Ok(Elem::Expr(RangeExpr::new( self.lhs.flatten(maximize, analyzer)?, self.op, @@ -165,6 +162,8 @@ impl RangeElem for RangeExpr { fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { Ok(*cached) + } else if self.op == RangeOp::SetIndices { + self.simplify_exec_op(true, &mut vec![], analyzer) } else { self.exec_op(true, analyzer) } @@ -172,8 +171,10 @@ impl RangeElem for RangeExpr { fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { Ok(*cached) + } else if self.op == RangeOp::SetIndices { + self.simplify_exec_op(false, &mut vec![], analyzer) } else { - self.exec_op(false, analyzer) + self.exec_op(false, analyzer) } } @@ -191,10 +192,22 @@ impl RangeElem for RangeExpr { let collapsed = collapse(l, self.op, r); match collapsed { MaybeCollapsed::Concretes(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) + RangeExpr::new(l, self.op, r).exec_op(true, analyzer) } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, self.op, r))), + MaybeCollapsed::Not(l, r) => { + // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) + match RangeExpr::new(l, self.op, r).simplify_exec_op(true, &mut vec![], analyzer)? { + ref e @ Elem::Expr(ref expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(true, analyzer), + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + _ => Ok(e.clone()) + } + } + other => Ok(other) + } + }, } } fn simplify_minimize( @@ -211,10 +224,22 @@ impl RangeElem for RangeExpr { let collapsed = collapse(l, self.op, r); match collapsed { MaybeCollapsed::Concretes(l, r) => { - RangeExpr::new(l, self.op, r).simplify_exec_op(false, exclude, analyzer) + RangeExpr::new(l, self.op, r).exec_op(false, analyzer) } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, self.op, r))), + MaybeCollapsed::Not(l, r) => { + // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) + match RangeExpr::new(l, self.op, r).simplify_exec_op(false, &mut vec![], analyzer)? { + ref e @ Elem::Expr(ref expr) => { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(false, analyzer), + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + _ => Ok(e.clone()) + } + } + other => Ok(other) + } + }, } } @@ -265,18 +290,21 @@ impl RangeElem for RangeExpr { } } -enum MaybeCollapsed { +pub enum MaybeCollapsed { Concretes(Elem, Elem), Collapsed(Elem), Not(Elem, Elem), } -fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { +pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { let zero = Elem::from(Concrete::from(U256::zero())); let one = Elem::from(Concrete::from(U256::one())); match (l.clone(), r.clone()) { + // (Elem::Null, _) => MaybeCollapsed::Collapsed(r), + // (_, Elem::Null) => MaybeCollapsed::Collapsed(l), (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { + // try to collapse the expression let x = expr.lhs; let y = expr.rhs; let z = d; @@ -321,7 +349,6 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed } // if we have an expression, it fundamentally must have a dynamic in it (Elem::Expr(expr), c @ Elem::Concrete(_)) => { - println!("expr, c"); // potentially collapsible let x = expr.lhs; let y = expr.rhs; @@ -719,6 +746,27 @@ fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(_, _) => unreachable!(), }, + (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => { + match op { + RangeOp::Sub(_) + | RangeOp::Add(_) => { + if matches!(c.range_ord(&zero), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le) + } else { + MaybeCollapsed::Not(l, r) + } + } + RangeOp::Mul(_) + | RangeOp::Div(_) => { + if matches!(c.range_ord(&one), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le) + } else { + MaybeCollapsed::Not(l, r) + } + } + _ => MaybeCollapsed::Not(l, r) + } + } _ => MaybeCollapsed::Not(l, r), } } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index f0d1a21c..673b2c96 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -20,29 +20,79 @@ pub struct RangeDyn { pub flattened_min: Option>>, pub flattened_max: Option>>, /// Length of the dynamic variable - pub len: Elem, + pub len: Box>, /// Values of the dynamic variable - pub val: BTreeMap, Elem>, + pub val: BTreeMap, (Elem, usize)>, + /// An operations log + pub op_num: usize, + /// For recursion, sets whether to filter nulls + // pub filter_null: bool, /// Sourcecode location pub loc: Loc, } -impl RangeDyn { +impl RangeDyn { + pub fn new_w_op_nums(len: Elem, val: BTreeMap, (Elem, usize)>, loc: Loc) -> Self { + let op_num = val.iter().fold(0, |mut acc, (_k, (_v, i))| { + if i > &acc { + acc = *i; + acc + } else { + acc + } + }); + Self { + minimized: None, + maximized: None, + flattened_min: None, + flattened_max: None, + len: Box::new(len), + val, + op_num, + loc, + } + } pub fn new(len: Elem, val: BTreeMap, Elem>, loc: Loc) -> Self { + let mut op_num = 0; + let val = val.into_iter().map(|(k, v)| { + let res = (k, (v, op_num)); + op_num += 1; + res + }).collect(); Self { minimized: None, maximized: None, flattened_min: None, flattened_max: None, - len, + len: Box::new(len), val, + op_num, + loc, + } + } + + pub fn new_for_indices(vals: Vec<(Elem, Elem)>, loc: Loc) -> Self { + let mut op_num = 0; + let val = vals.into_iter().map(|(k, v)| { + let res = (k, (v, op_num)); + op_num += 1; + res + }).collect(); + Self { + minimized: None, + maximized: None, + flattened_min: None, + flattened_max: None, + len: Box::new(Elem::Null), + val, + op_num, loc, } } /// Set the length pub fn set_len(&mut self, new_len: Elem) { - self.len = new_len; + self.len = Box::new(new_len); } /// Check if the node contains a reference to a node index @@ -52,6 +102,10 @@ impl RangeDyn { } } +impl RangeDyn { + +} + impl RangeElem for RangeDyn { type GraphError = GraphError; @@ -59,8 +113,35 @@ impl RangeElem for RangeDyn { false } - fn range_ord(&self, _other: &Self) -> Option { - None + fn range_ord(&self, other: &Self) -> Option { + match self.len.range_ord(&other.len) { + Some(std::cmp::Ordering::Equal) => { + let mut eq = 0; + let mut self_lt = 0; + let mut self_gt = 0; + self.val.iter().zip(other.val.iter()).for_each(|((self_key, self_val), (other_key, other_val))| { + if let Some(std::cmp::Ordering::Equal) = self_key.clone().range_ord(other_key) { + match self_val.0.clone().range_ord(&other_val.0) { + Some(std::cmp::Ordering::Equal) => eq += 1, + Some(std::cmp::Ordering::Less) => self_lt += 1, + Some(std::cmp::Ordering::Greater) => self_gt += 1, + _ => {} + } + } + }); + + if self_lt == self.val.len() { + Some(std::cmp::Ordering::Less) + } else if eq == self.val.len() { + Some(std::cmp::Ordering::Equal) + } else if self_gt == self.val.len() { + Some(std::cmp::Ordering::Greater) + } else { + None + } + } + other => other + } } fn dependent_on(&self) -> Vec { @@ -68,7 +149,7 @@ impl RangeElem for RangeDyn { deps.extend( self.val .iter() - .flat_map(|(_, val)| val.dependent_on()) + .flat_map(|(_, val)| val.0.dependent_on()) .collect::>(), ); deps @@ -82,7 +163,7 @@ impl RangeElem for RangeDyn { deps.extend( self.val .values() - .map(|val| val.recursive_dependent_on(analyzer)) + .map(|val| val.0.recursive_dependent_on(analyzer)) .collect::>, _>>()? .iter() .flatten() @@ -108,7 +189,7 @@ impl RangeElem for RangeDyn { let mut has_cycle = false; has_cycle = has_cycle || self.len.has_cycle(seen, analyzer)?; self.val.iter().try_for_each(|(_, val)| { - has_cycle = has_cycle || val.has_cycle(seen, analyzer)?; + has_cycle = has_cycle || val.0.has_cycle(seen, analyzer)?; Ok(()) })?; Ok(has_cycle) @@ -123,25 +204,25 @@ impl RangeElem for RangeDyn { (true, _, Some(flat)) | (false, Some(flat), _) => return Ok(*flat.clone()), _ => {} } - // println!("flattening range dyn"); - Ok(Elem::ConcreteDyn(Box::new(Self { + Ok(Elem::ConcreteDyn(Self { minimized: None, maximized: None, flattened_min: None, flattened_max: None, - len: self.len.flatten(maximize, analyzer)?, + len: Box::new(self.len.flatten(maximize, analyzer)?), val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert( idx.flatten(maximize, analyzer)?, - val.flatten(maximize, analyzer)?, + (val.0.flatten(maximize, analyzer)?, val.1) ); } map }, + op_num: self.op_num, loc: self.loc, - }))) + })) } fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { @@ -166,7 +247,7 @@ impl RangeElem for RangeDyn { self.len.update_deps(mapping); self.val .iter_mut() - .for_each(|(_, val)| val.update_deps(mapping)); + .for_each(|(_, val)| val.0.update_deps(mapping)); } fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { @@ -177,7 +258,7 @@ impl RangeElem for RangeDyn { .into_iter() .map(|(mut k, mut v)| { k.filter_recursion(node_idx, new_idx); - v.filter_recursion(node_idx, new_idx); + v.0.filter_recursion(node_idx, new_idx); (k, v) }) .collect(); @@ -188,17 +269,24 @@ impl RangeElem for RangeDyn { return Ok(*cached); } - Ok(Elem::ConcreteDyn(Box::new(Self::new( + Ok(Elem::ConcreteDyn(Self::new_w_op_nums( self.len.maximize(analyzer)?, { - let mut map = BTreeMap::default(); + let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.maximize(analyzer)?); + // We dont maximize the key so that any subsequent + // `get_index` can find potential values + let maximized = val.0.maximize(analyzer)?; + map.insert(idx.simplify_maximize(&mut vec![], analyzer)?, (maximized, val.1)); } + + // map.into_iter().filter(|(k, (v, op))| { + // *v != Elem::Null + // }).collect() map }, self.loc, - )))) + ))) } fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { @@ -206,17 +294,24 @@ impl RangeElem for RangeDyn { return Ok(*cached); } - Ok(Elem::ConcreteDyn(Box::new(Self::new( + Ok(Elem::ConcreteDyn(Self::new_w_op_nums( self.len.minimize(analyzer)?, { - let mut map = BTreeMap::default(); + let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.minimize(analyzer)?); + // We dont minimize the key so that any subsequent + // `get_index` can find potential values + let minimized = val.0.minimize(analyzer)?; + map.insert(idx.simplify_minimize(&mut vec![], analyzer)?, (minimized, val.1)); } + + // map.into_iter().filter(|(k, (v, op))| { + // *v != Elem::Null + // }).collect() map }, self.loc, - )))) + ))) } fn simplify_maximize( @@ -227,17 +322,21 @@ impl RangeElem for RangeDyn { if let Some(max) = &self.flattened_max { return Ok(*max.clone()); } - Ok(Elem::ConcreteDyn(Box::new(Self::new( + Ok(Elem::ConcreteDyn(Self::new_w_op_nums( self.len.simplify_maximize(exclude, analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_maximize(exclude, analyzer)?); + // We dont minimize the key so that any subsequent + // `get_index` can find potential values + let simplified = val.0.simplify_maximize(exclude, analyzer)?; + map.insert(idx, (simplified, val.1)); } map }, self.loc, - )))) + ))) + } fn simplify_minimize( &self, @@ -247,17 +346,21 @@ impl RangeElem for RangeDyn { if let Some(min) = &self.flattened_min { return Ok(*min.clone()); } - Ok(Elem::ConcreteDyn(Box::new(Self::new( + + Ok(Elem::ConcreteDyn(Self::new_w_op_nums( self.len.simplify_minimize(exclude, analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { - map.insert(idx, val.simplify_minimize(exclude, analyzer)?); + // We dont minimize the key so that any subsequent + // `get_index` can find potential values + let simplified = val.0.simplify_minimize(exclude, analyzer)?; + map.insert(idx, (simplified, val.1)); } map }, self.loc, - )))) + ))) } fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { @@ -277,8 +380,8 @@ impl RangeElem for RangeDyn { fn uncache(&mut self) { self.minimized = None; self.maximized = None; - self.flattened_min = None; - self.flattened_max = None; + // self.flattened_min = None; + // self.flattened_max = None; } fn contains_op_set( diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index 1fe3a99d..e63fc538 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -73,6 +73,16 @@ pub enum RangeOp { Exp, /// Concatenation Concat, + /// Memcopy + Memcopy, + /// Set memory indices of a memory object + SetIndices, + /// Gets an index of a memory object + GetIndex, + /// Set length of a memory object + SetLength, + /// Get Length of a memory object + GetLength, } impl RangeOp { @@ -157,6 +167,11 @@ impl ToString for RangeOp { BitXor => "^".to_string(), BitNot => "~".to_string(), Concat => "concat".to_string(), + Memcopy => "memcopy".to_string(), + SetIndices => "set_indices".to_string(), + GetIndex => "get_index".to_string(), + GetLength => "get_length".to_string(), + SetLength => "set_length".to_string(), } } } diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 8c13a9b5..71c239eb 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -102,15 +102,12 @@ impl RangeElem for Reference { ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { (true, _, Some(flat)) | (false, Some(flat), _) => { - // println!("flatten cache hit: {}", self.idx.index()); return Ok(*flat.clone()); } _ => {} } - // println!("flatten cache miss: {}", self.idx.index()); let cvar = ContextVarNode::from(self.idx); - // println!("flattening reference: {} (idx_{})", cvar.display_name(analyzer)?, self.idx.index()); if cvar.is_fundamental(analyzer)? { return Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), diff --git a/crates/graph/src/range/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs index 97010932..d78dde75 100644 --- a/crates/graph/src/range/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -45,6 +45,7 @@ impl RangeBitwise for RangeConcrete { } fn range_bit_or(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { let size = if s > s2 { s } else { s2 }; diff --git a/crates/graph/src/range/exec/cast.rs b/crates/graph/src/range/exec/cast.rs index 41ab5ed4..bc20b6de 100644 --- a/crates/graph/src/range/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -13,21 +13,21 @@ impl RangeCast for RangeConcrete { } } -impl RangeCast>> for RangeConcrete { - fn range_cast(&self, other: &Box>) -> Option> { +impl RangeCast> for RangeConcrete { + fn range_cast(&self, other: &RangeDyn) -> Option> { match (self.val.clone(), other.val.iter().take(1).next()) { ( Concrete::Bytes(size, val), Some(( _, - Elem::Concrete(Self { + (Elem::Concrete(Self { val: Concrete::Bytes(..), .. - }), + }), _), )), ) | (Concrete::Bytes(size, val), None) => { - let mut existing = other.val.clone(); + // let mut existing = other.val.clone(); let new = val .0 .iter() @@ -40,25 +40,25 @@ impl RangeCast>> for RangeConcrete { (idx, v) }) .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + // existing.extend(new); + Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(size))), - existing, + new, other.loc, - )))) + ))) } ( Concrete::DynBytes(val), Some(( _, - Elem::Concrete(Self { + (Elem::Concrete(Self { val: Concrete::Bytes(..), .. - }), + }), _), )), ) | (Concrete::DynBytes(val), None) => { - let mut existing = other.val.clone(); + // let mut existing = other.val.clone(); let new = val .iter() .enumerate() @@ -70,25 +70,25 @@ impl RangeCast>> for RangeConcrete { (idx, v) }) .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + // existing.extend(new); + Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(val.len()))), - existing, + new, other.loc, - )))) + ))) } ( Concrete::String(val), Some(( _, - Elem::Concrete(Self { + (Elem::Concrete(Self { val: Concrete::String(..), .. - }), + }), _), )), ) | (Concrete::String(val), None) => { - let mut existing = other.val.clone(); + // let mut existing = other.val.clone(); let new = val .chars() .enumerate() @@ -100,12 +100,12 @@ impl RangeCast>> for RangeConcrete { (idx, v) }) .collect::>(); - existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + // existing.extend(new); + Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(val.len()))), - existing, + new, other.loc, - )))) + ))) } _e => None, } @@ -114,90 +114,90 @@ impl RangeCast>> for RangeConcrete { impl RangeCast> for RangeDyn { fn range_cast(&self, other: &Self) -> Option> { - let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); - let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); + let val: Option<(_, &(Elem, usize))> = self.val.iter().take(1).next(); + let o_val: Option<(_, &(Elem, usize))> = other.val.iter().take(1).next(); match (val, o_val) { ( Some(( _, - &Elem::Concrete(RangeConcrete { + &(Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), Some(( _, - &Elem::Concrete(RangeConcrete { + &(Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), ) | ( Some(( _, - &Elem::Concrete(RangeConcrete { + &(Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + ) => Some(Elem::ConcreteDyn(self.clone())), ( Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Uint(..), .. - }), + }), _), )), Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Uint(..), .. - }), + }), _), )), ) | ( Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Uint(..), .. - }), + }), _), )), None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + ) => Some(Elem::ConcreteDyn(self.clone())), ( Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Int(..), .. - }), + }), _), )), Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Int(..), .. - }), + }), _), )), ) | ( Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Int(..), .. - }), + }), _), )), None, - ) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), - (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + ) => Some(Elem::ConcreteDyn(self.clone())), + (Some((_, (l @ Elem::Reference(_), _))), None) => Some(l.clone()), + (None, Some((_, (r @ Elem::Reference(_), _)))) => Some(r.clone()), + (None, None) => Some(Elem::ConcreteDyn(self.clone())), _e => None, } } @@ -205,9 +205,8 @@ impl RangeCast> for RangeDyn { impl RangeCast> for RangeDyn { fn range_cast(&self, other: &RangeConcrete) -> Option> { - let (_k, val): (_, &Elem) = self.val.iter().take(1).next()?; + let (_k, (val, _op)): (_, &(Elem, _)) = self.val.iter().take(1).next()?; let o_val = &other.val; - // println!("HERE {:?} {:?} {:?}", k, val, o_val); match (val, o_val) { ( &Elem::Concrete(RangeConcrete { @@ -219,10 +218,10 @@ impl RangeCast> for RangeDyn { let mut h = H256::default(); for (i, (_, val)) in self.val.iter().take(*size as usize).enumerate() { match val { - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Bytes(1, v), .. - }) => { + }), _) => { // consume as many as we can h.0[i] = v.0[0]; } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 51afbd33..adecbb60 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -1,3 +1,4 @@ +use crate::nodes::ContextVarNode; use crate::{ nodes::Concrete, range::{elem::*, exec_traits::*}, @@ -11,6 +12,15 @@ use solang_parser::pt::Loc; impl ExecOp for RangeExpr { type GraphError = GraphError; + + fn exec_op( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError> { + self.exec(self.spread(analyzer)?, maximize, analyzer) + } + fn cache_exec_op( &mut self, maximize: bool, @@ -41,8 +51,8 @@ impl ExecOp for RangeExpr { analyzer: &impl GraphBackend, ) -> Result, GraphError> { let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(exclude, analyzer)?; - let lhs_is_conc = lhs_min.maybe_concrete().is_some() && lhs_max.maybe_concrete().is_some(); - let rhs_is_conc = rhs_min.maybe_concrete().is_some() && rhs_max.maybe_concrete().is_some(); + let lhs_is_conc = lhs_min.is_conc() && lhs_max.is_conc(); + let rhs_is_conc = rhs_min.is_conc() && rhs_max.is_conc(); if self.op == RangeOp::Cast { // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete if lhs_is_conc { @@ -57,10 +67,87 @@ impl ExecOp for RangeExpr { return Ok(*self.lhs.clone()); } } + } else if matches!(self.op, RangeOp::Concat | RangeOp::Memcopy) { + // we can always execute a concat or memcopy + return self.exec_op(maximize, analyzer); + } else if matches!(self.op, RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex ) { + match self.op { + RangeOp::GetLength => { + return if maximize { + Ok(lhs_max.range_get_length() + .unwrap_or_else(|| Elem::Expr(self.clone()))) + } else { + Ok(lhs_min.range_get_length() + .unwrap_or_else(|| Elem::Expr(self.clone()))) + }; + } + RangeOp::SetLength => { + return if maximize { + Ok(lhs_max.range_set_length(&rhs_max) + .unwrap_or_else(|| Elem::Expr(self.clone()))) + } else { + Ok(lhs_min.range_set_length(&rhs_min) + .unwrap_or_else(|| Elem::Expr(self.clone()))) + }; + }, + RangeOp::GetIndex => { + if maximize { + let res = match lhs_max { + Elem::ConcreteDyn(RangeDyn { val, ..}) => { + val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { + if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { + if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Greater)) { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } + } else { + Ok(acc) + } + })?.unwrap_or_else(|| Elem::Null) + } + _ => Elem::Expr(self.clone()) + }; + return Ok(res); + } else { + let res = match lhs_max { + Elem::ConcreteDyn(RangeDyn { val, ..}) => { + val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { + if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { + if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Less)) { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } + } else { + Ok(acc) + } + })?.unwrap_or_else(|| Elem::Null) + } + _ => Elem::Expr(self.clone()) + }; + return Ok(res); + } + }, + RangeOp::SetIndices => { + return if maximize { + Ok(lhs_max.range_set_indices(&rhs_max) + .unwrap_or_else(|| Elem::Expr(self.clone()))) + } else { + Ok(lhs_min.range_set_indices(&rhs_min) + .unwrap_or_else(|| Elem::Expr(self.clone()))) + }; + }, + _ => unreachable!() + } } + + let parts = (lhs_min, lhs_max, rhs_min, rhs_max); match (lhs_is_conc, rhs_is_conc) { - (true, true) => self.exec(parts, maximize), + (true, true) => self.exec(parts, maximize, analyzer), _ => Ok(Elem::Expr(self.clone())), } } @@ -113,6 +200,7 @@ impl ExecOp for RangeExpr { Elem, ), maximize: bool, + analyzer: &impl GraphBackend, ) -> Result, GraphError> { tracing::trace!( "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", @@ -141,28 +229,135 @@ impl ExecOp for RangeExpr { rhs: Elem, consts: (bool, bool), ) -> Elem { - // println!("fallback exec: {} {} {}", this.lhs, this.op.to_string(), this.rhs); match consts { (true, true) => { - // println!("true true: {} {} {}", lhs, this.op.to_string(), rhs); Elem::Expr(RangeExpr::new(lhs, this.op, rhs)) } (false, true) => { - // println!("false true: {} {} {}", this.lhs, this.op.to_string(), rhs); Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)) } (true, false) => { - // println!("true false: {} {} {}", lhs, this.op.to_string(), this.rhs); Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())) } (false, false) => { - // println!("false false: {} {} {}", this.lhs, this.op.to_string(), this.rhs); Elem::Expr(this.clone()) } } } let res = match self.op { + RangeOp::GetLength => { + if maximize { + let mut new = lhs_max.clone(); + new.uncache(); + let new_max = new.simplify_minimize(&mut vec![], analyzer)?; + let res = new_max.range_get_length(); + res + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + let new_min = lhs_min.simplify_minimize(&mut vec![], analyzer)?; + let res = new_min.range_get_length(); + res + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + } + RangeOp::SetLength => { + if maximize { + lhs_max.range_set_length(&rhs_max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } else { + lhs_min.range_set_length(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + } + }, + RangeOp::GetIndex => { + if maximize { + fn match_ty_max(lhs_max: Elem, rhs_min: Elem, rhs_max: Elem, analyzer: &impl GraphBackend) -> Result, GraphError> { + match lhs_max { + Elem::ConcreteDyn(RangeDyn { val, ..}) => { + Ok(val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { + if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { + if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Greater)) { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } + } else { + Ok(acc) + } + })?.unwrap_or_else(|| Elem::Null)) + } + Elem::Reference(_) => { + let new_max = lhs_max.simplify_maximize(&mut vec![], analyzer)?; + if new_max == lhs_max { + Ok(Elem::Null) + } else { + match_ty_max(new_max, rhs_min, rhs_max, analyzer) + } + } + _ => Ok(Elem::Null) + } + } + match_ty_max(lhs_max.clone(), rhs_min, rhs_max.clone(), analyzer) + .unwrap_or_else(|_| fallback(self, lhs_max, rhs_max, consts)) + } else { + fn match_ty_min(lhs_min: Elem, rhs_min: Elem, rhs_max: Elem, analyzer: &impl GraphBackend) -> Result, GraphError> { + match lhs_min { + Elem::ConcreteDyn(RangeDyn { val, ..}) => { + Ok(val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { + if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { + if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Less)) { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } + } else { + Ok(acc) + } + })?.unwrap_or_else(|| Elem::Null)) + } + Elem::Reference(ref _r) => { + let new_min = lhs_min.simplify_minimize(&mut vec![], analyzer)?; + if new_min == lhs_min { + Ok(Elem::Null) + } else { + match_ty_min(new_min, rhs_min, rhs_max, analyzer) + } + } + _ => Ok(Elem::Null) + } + } + match_ty_min(lhs_min.clone(), rhs_min.clone(), rhs_max, analyzer) + .unwrap_or_else(|_| fallback(self, lhs_min, rhs_min, consts)) + } + }, + RangeOp::SetIndices => { + if maximize { + let max = self.rhs.simplify_maximize(&mut vec![], analyzer)?; + + lhs_max.range_set_indices(&rhs_max) + .unwrap_or_else(|| { + lhs_max.range_set_indices(&max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + }) + } else { + let min = self.rhs.simplify_minimize(&mut vec![], analyzer)?; + lhs_min.range_set_indices(&rhs_min) + .unwrap_or_else(|| { + lhs_min.range_set_indices(&min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + }) + } + }, + RangeOp::Memcopy => { + if maximize { + lhs_max.clone() + } else { + lhs_min.clone() + } + } RangeOp::Add(unchecked) => { if unchecked { let mut candidates = vec![ @@ -205,11 +400,13 @@ impl ExecOp for RangeExpr { } } RangeOp::Sub(unchecked) => { + // quick check if rhs is const and zero, if so return min or max if unchecked { let mut candidates = vec![]; // check if rhs contains zero, if so add lhs_min and max as candidates - let zero = Elem::from(Concrete::from(U256::from(0))); + let one = Elem::from(Concrete::from(U256::from(1))); + let zero = Elem::from(Concrete::from(U256::from(0))); let rhs_min_contains_zero = matches!( rhs_min.range_ord(&zero), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) @@ -337,13 +534,70 @@ impl ExecOp for RangeExpr { } RangeOp::Mul(unchecked) => { if unchecked { - let candidates = vec![ + let mut candidates: Vec>> = vec![]; + let zero = Elem::from(Concrete::from(U256::from(0))); + let one = Elem::from(Concrete::from(U256::from(1))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + // check if rhs contains 1 + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (rhs_min.range_ord(&one), rhs_max.range_ord(&one)) { + candidates.push(Some(lhs_max.clone())); + candidates.push(Some(lhs_min.clone())); + } + + // check if lhs contains 1 + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (lhs_min.range_ord(&one), lhs_max.range_ord(&one)) { + candidates.push(Some(rhs_max.clone())); + candidates.push(Some(rhs_min.clone())); + } + + // check if rhs contains -1 + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (rhs_min.range_ord(&negative_one), rhs_max.range_ord(&negative_one)) { + candidates.push(lhs_max.range_mul(&negative_one)); + candidates.push(lhs_min.range_mul(&negative_one)); + } + + // check if lhs contains -1 + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (lhs_min.range_ord(&negative_one), lhs_max.range_ord(&negative_one)) { + candidates.push(rhs_max.range_mul(&negative_one)); + candidates.push(rhs_min.range_mul(&negative_one)); + } + + // check if rhs contains zero + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (rhs_min.range_ord(&zero), rhs_max.range_ord(&zero)) { + candidates.push(Some(zero.clone())); + } + // check if lhs contains zero + if let ( + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ) = (lhs_min.range_ord(&zero), lhs_max.range_ord(&zero)) { + candidates.push(Some(zero.clone())); + } + candidates.extend(vec![ lhs_min.range_wrapping_mul(&rhs_min), lhs_min.range_wrapping_mul(&rhs_max), lhs_max.range_wrapping_mul(&rhs_min), lhs_max.range_wrapping_mul(&rhs_max), - ]; + ]); let mut candidates = candidates.into_iter().flatten().collect::>(); + + candidates.sort_by(|a, b| match a.range_ord(b) { Some(r) => r, _ => std::cmp::Ordering::Less, diff --git a/crates/graph/src/range/exec/max.rs b/crates/graph/src/range/exec/max.rs index c32eb45e..1fa32da9 100644 --- a/crates/graph/src/range/exec/max.rs +++ b/crates/graph/src/range/exec/max.rs @@ -37,6 +37,17 @@ impl RangeMax for Elem { fn range_max(&self, other: &Self) -> Option> { match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_max(b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { + if a.op_num > b.op_num { + Some(self.clone()) + } else if a.op_num < b.op_num { + Some(other.clone()) + } else { + None + } + }, + (_, Elem::Null) => Some(self.clone()), + (Elem::Null, _) => Some(other.clone()), _ => None, } } diff --git a/crates/graph/src/range/exec/concat.rs b/crates/graph/src/range/exec/mem_ops/concat.rs similarity index 73% rename from crates/graph/src/range/exec/concat.rs rename to crates/graph/src/range/exec/mem_ops/concat.rs index dfc768d9..47681d9c 100644 --- a/crates/graph/src/range/exec/concat.rs +++ b/crates/graph/src/range/exec/mem_ops/concat.rs @@ -1,3 +1,4 @@ + use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; @@ -20,10 +21,10 @@ impl RangeConcat> for RangeDyn { Concrete::DynBytes(val), Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), ) | (Concrete::DynBytes(val), None) => { @@ -34,28 +35,28 @@ impl RangeConcat> for RangeDyn { .enumerate() .map(|(i, v)| { let idx = Elem::from(Concrete::from(U256::from(i))); - let idx = last.clone() + idx; + let idx = *last.clone() + idx; let mut bytes = [0x00; 32]; bytes[0] = *v; let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) + (idx, (v, self.op_num + i)) }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( Elem::from(Concrete::from(U256::from(val.len()))), existing, other.loc, - )))) + ))) } ( Concrete::String(val), Some(( _, - Elem::Concrete(RangeConcrete { + (Elem::Concrete(RangeConcrete { val: Concrete::String(..), .. - }), + }), _), )), ) | (Concrete::String(val), None) => { @@ -66,19 +67,19 @@ impl RangeConcat> for RangeDyn { .enumerate() .map(|(i, v)| { let idx = Elem::from(Concrete::from(U256::from(i))); - let idx = last.clone() + idx; + let idx = *last.clone() + idx; let mut bytes = [0x00; 32]; v.encode_utf8(&mut bytes[..]); let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, v) + (idx, (v, self.op_num + i)) }) .collect::>(); existing.extend(new); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( Elem::from(Concrete::from(U256::from(val.len()))), existing, other.loc, - )))) + ))) } _e => None, } @@ -87,23 +88,23 @@ impl RangeConcat> for RangeDyn { impl RangeConcat> for RangeDyn { fn range_concat(&self, other: &Self) -> Option> { - let val: Option<(_, &Elem)> = self.val.iter().take(1).next(); - let o_val: Option<(_, &Elem)> = other.val.iter().take(1).next(); + let val: Option<(_, &(Elem, _))> = self.val.iter().take(1).next(); + let o_val: Option<(_, &(Elem, _))> = other.val.iter().take(1).next(); match (val, o_val) { ( Some(( _, - &Elem::Concrete(RangeConcrete { + &(Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), Some(( _, - &Elem::Concrete(RangeConcrete { + &(Elem::Concrete(RangeConcrete { val: Concrete::Bytes(..), .. - }), + }), _), )), ) => { let last = self.len.clone(); @@ -112,32 +113,35 @@ impl RangeConcat> for RangeDyn { .val .clone() .into_iter() - .map(|(i, v)| (i + last.clone(), v)) + .enumerate() + .map(|(i, (key, (v, _op)))| (key + *last.clone(), (v, self.op_num + i))) .collect::>(); existing.extend(other_vals); - Some(Elem::ConcreteDyn(Box::new(RangeDyn::new( - self.len.clone() + other.len.clone(), + + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( + *self.len.clone() + *other.len.clone().max(Box::new(Elem::from(Concrete::from(U256::from(1))))), existing, other.loc, - )))) + ))) } - (Some((_, l @ Elem::Reference(_))), None) => Some(l.clone()), - (None, Some((_, r @ Elem::Reference(_)))) => Some(r.clone()), - (None, None) => Some(Elem::ConcreteDyn(Box::new(self.clone()))), + (Some((_, (l @ Elem::Reference(_), _))), None) => Some(l.clone()), + (None, Some((_, (r @ Elem::Reference(_), _)))) => Some(r.clone()), + (None, None) => Some(Elem::ConcreteDyn(self.clone())), _e => None, } } } + impl RangeConcat for Elem { fn range_concat(&self, other: &Self) -> Option> { match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_concat(b), - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_concat(&**b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_concat(b), (Elem::Concrete(c), Elem::ConcreteDyn(d)) | (Elem::ConcreteDyn(d), Elem::Concrete(c)) => d.range_concat(c), _e => None, } } -} +} \ No newline at end of file diff --git a/crates/graph/src/range/exec/mem_ops/mem_set.rs b/crates/graph/src/range/exec/mem_ops/mem_set.rs new file mode 100644 index 00000000..40c0e443 --- /dev/null +++ b/crates/graph/src/range/exec/mem_ops/mem_set.rs @@ -0,0 +1,219 @@ +use crate::{ + nodes::Concrete, + range::{elem::*, exec_traits::*} +}; + +use ethers_core::types::{H256, U256}; + +use std::collections::BTreeMap; + +impl RangeMemSet for RangeDyn { + fn range_set_indices(&self, range: &Self) -> Option> { + let mut new_val = self.val.clone(); + let mut op_num = self.op_num; + range.val.iter().for_each(|(k, (v, _))| { + op_num += 1; + new_val.insert(k.clone(), (v.clone(), op_num)); + }); + + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( + *self.len.clone(), + new_val, + range.loc, + ))) + } + + fn range_get_index(&self, _index: &Self) -> Option> { + unreachable!() + } + + fn range_set_length(&self, _other: &Self) -> Option> { + unreachable!() + } + + fn range_get_length(&self) -> Option> { + unreachable!() + } +} + +impl RangeMemSet> for RangeDyn { + fn range_set_indices(&self, range: &RangeConcrete) -> Option> { + match (range.val.clone(), self.val.iter().take(1).next()) { + ( + Concrete::DynBytes(val), + Some(( + _, + (Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), _), + )), + ) + | (Concrete::DynBytes(val), None) => { + let mut existing = self.val.clone(); + let new = val + .iter() + .enumerate() + .map(|(i, v)| { + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (Elem::from(Concrete::from(U256::from(i))), (v, self.op_num + i)) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( + *self.len.clone(), + existing, + range.loc, + ))) + } + ( + Concrete::String(val), + Some(( + _, + (Elem::Concrete(RangeConcrete { + val: Concrete::String(..), + .. + }), _), + )), + ) + | (Concrete::String(val), None) => { + let mut existing = self.val.clone(); + let new = val + .chars() + .enumerate() + .map(|(i, v)| { + let mut bytes = [0x00; 32]; + v.encode_utf8(&mut bytes[..]); + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (Elem::from(Concrete::from(U256::from(i))), (v, i + self.op_num)) + }) + .collect::>(); + existing.extend(new); + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( + *self.len.clone(), + existing, + range.loc, + ))) + } + _e => None, + } + } + + fn range_get_index(&self, _index: &RangeConcrete) -> Option> { + unreachable!() + } + + fn range_set_length(&self, _other: &RangeConcrete) -> Option> { + unreachable!() + } + + fn range_get_length(&self) -> Option> { + unreachable!() + } +} + +impl RangeMemSet for RangeConcrete { + fn range_set_indices(&self, range: &Self) -> Option> { + let mut new_val = self.val.clone(); + new_val.set_indices(&range.val); + Some(Elem::Concrete(RangeConcrete { + val: new_val, + loc: range.loc, + })) + } + + fn range_get_index(&self, index: &Self) -> Option> { + self.val.get_index(&index.val).map(Elem::from) + } + + + fn range_set_length(&self, _other: &Self) -> Option> { + unreachable!() + } + + fn range_get_length(&self) -> Option> { + unreachable!() + } +} + +impl RangeMemSet> for RangeConcrete { + fn range_set_indices(&self, _range: &RangeDyn) -> Option> { + todo!() + } + + fn range_get_index(&self, _range: &RangeDyn) -> Option> { + unreachable!() + } + + + fn range_set_length(&self, _other: &RangeDyn) -> Option> { + unreachable!() + } + + fn range_get_length(&self) -> Option> { + unreachable!() + } +} + +impl RangeMemSet for Elem { + fn range_set_indices(&self, other: &Elem) -> Option> { + println!("setting indices: {self}, {other}"); + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_set_indices(b), + (Elem::ConcreteDyn(a), Elem::Concrete(b)) => a.range_set_indices(b), + (Elem::Concrete(a), Elem::ConcreteDyn(b)) => a.range_set_indices(b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_set_indices(b), + _e => None, + } + } + + fn range_set_length(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { + let mut a = a.clone(); + a.len = b.len.clone(); + Some(Elem::ConcreteDyn(a.clone())) + }, + (a @ Elem::Concrete(_), _b @ Elem::Concrete(_)) => { + Some(a.clone()) + }, + (Elem::ConcreteDyn(a), _) => { + let mut a = a.clone(); + a.len = Box::new(other.clone()); + Some(Elem::ConcreteDyn(a.clone())) + }, + _e => None, + } + } + + fn range_get_length(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(Elem::from(Concrete::from(a.val.maybe_array_size()?))), + Elem::ConcreteDyn(a) => Some(*a.len.clone()), + _e => None, + } + } + + fn range_get_index(&self, index: &Elem) -> Option> { + match (self, index) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_get_index(b), + (Elem::ConcreteDyn(a), idx @ Elem::Concrete(_)) => { + if let Some((val, _)) = a.val.get(idx).cloned() { + Some(val) + } else { + None + } + }, + (Elem::ConcreteDyn(a), idx @ Elem::Reference(_)) => { + if let Some((val, _)) = a.val.get(idx).cloned() { + Some(val) + } else { + None + } + } + _e => None, + } + } +} diff --git a/crates/graph/src/range/exec/mem_ops/mod.rs b/crates/graph/src/range/exec/mem_ops/mod.rs new file mode 100644 index 00000000..e06ff543 --- /dev/null +++ b/crates/graph/src/range/exec/mem_ops/mod.rs @@ -0,0 +1,19 @@ +mod concat; +mod mem_set; + +use crate::nodes::Concrete; +use crate::elem::Elem; +use crate::exec_traits::RangeMemOps; +pub use concat::*; +pub use mem_set::*; + + +impl RangeMemOps for Elem { + fn range_memcopy(&self) -> Option> { + match self { + Elem::Concrete(_a) => Some(self.clone()), + Elem::ConcreteDyn(_a) => Some(self.clone()), + _e => None, + } + } +} diff --git a/crates/graph/src/range/exec/min.rs b/crates/graph/src/range/exec/min.rs index 338ed35a..73f00537 100644 --- a/crates/graph/src/range/exec/min.rs +++ b/crates/graph/src/range/exec/min.rs @@ -37,6 +37,25 @@ impl RangeMin for Elem { fn range_min(&self, other: &Self) -> Option> { match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_min(b), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { + if a.op_num > b.op_num { + Some(self.clone()) + } else if a.op_num < b.op_num { + Some(other.clone()) + } else { + None + } + }, + (c @ Elem::Concrete(_), Elem::ConcreteDyn(b)) + | (Elem::ConcreteDyn(b), c @ Elem::Concrete(_)) => { + if b.op_num == 0 { + Some(c.clone()) + } else { + None + } + }, + (_, Elem::Null) => Some(self.clone()), + (Elem::Null, _) => Some(other.clone()), _ => None, } } diff --git a/crates/graph/src/range/exec/mod.rs b/crates/graph/src/range/exec/mod.rs index 4946baed..99fbcdae 100644 --- a/crates/graph/src/range/exec/mod.rs +++ b/crates/graph/src/range/exec/mod.rs @@ -1,7 +1,6 @@ mod add; mod bitwise; mod cast; -mod concat; mod div; mod exec_op; mod exp; @@ -13,3 +12,4 @@ mod mul; mod ord; mod shift; mod sub; +mod mem_ops; diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index b7bd827b..88858fb1 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,4 +1,4 @@ -use crate::{range::elem::Elem, GraphBackend}; +use crate::{range::elem::{RangeDyn, Elem}, GraphBackend}; use shared::NodeIdx; /// For execution of operations to be performed on range expressions @@ -10,14 +10,13 @@ pub trait ExecOp { &self, maximize: bool, analyzer: &impl GraphBackend, - ) -> Result, Self::GraphError> { - self.exec(self.spread(analyzer)?, maximize) - } + ) -> Result, Self::GraphError>; fn exec( &self, parts: (Elem, Elem, Elem, Elem), maximize: bool, + analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Cache execution fn cache_exec_op( @@ -51,8 +50,9 @@ pub trait ExecOp { &self, parts: (Elem, Elem, Elem, Elem), maximize: bool, + analyzer: &impl GraphBackend, ) -> Result, Self::GraphError> { - self.exec(parts, maximize) + self.exec(parts, maximize, analyzer) } } @@ -114,11 +114,6 @@ pub trait RangeCast { fn range_cast(&self, other: &Rhs) -> Option>; } -pub trait RangeConcat { - /// Perform a cast on an element to the type of the right hand side - fn range_concat(&self, other: &Rhs) -> Option>; -} - pub trait RangeUnary { /// Perform a logical NOT fn range_not(&self) -> Option>; @@ -152,3 +147,23 @@ pub trait RangeOrd { /// Perform a logical less than or equal test fn range_lte(&self, other: &Rhs) -> Option>; } + +pub trait RangeMemOps: RangeMemSet + RangeConcat + Sized { + /// Perform a memory copy + fn range_memcopy(&self) -> Option>; +} + +pub trait RangeConcat { + /// Perform a cast on an element to the type of the right hand side + fn range_concat(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMemSet { + /// Applies a transformation of indices + fn range_set_indices(&self, other: &Rhs) -> Option>; + /// Gets an index + fn range_get_index(&self, other: &Rhs) -> Option>; + /// Applies a transformation of length + fn range_set_length(&self, other: &Rhs) -> Option>; + fn range_get_length(&self) -> Option>; +} \ No newline at end of file diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index b50444f9..13a21d81 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -64,7 +64,7 @@ impl ToRangeString for Elem { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), Elem::Reference(Reference { idx, .. }) => { let as_var = ContextVarNode::from(*idx); - let name = as_var.display_name(analyzer).unwrap(); + let name = as_var.as_controllable_name(analyzer).unwrap(); RangeElemString::new(name, as_var.loc(analyzer).unwrap()) } Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), @@ -80,12 +80,12 @@ impl ToRangeString for RangeDyn { .val .iter() .take(20) - .map(|(key, val)| (key.minimize(analyzer).unwrap(), val)) + .map(|(key, val)| (key, val)) .collect::>(); let val_str = displayed_vals .iter() - .map(|(key, val)| { + .map(|(key, (val, _))| { format!( "{}: {}", key.def_string(analyzer).s, @@ -111,12 +111,9 @@ impl ToRangeString for RangeDyn { .val .iter() .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } + .filter(|(key, (val, op))| *val != Elem::Null) + .map(|(key, (val, op))| { + (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) }) .collect::>(); @@ -125,8 +122,8 @@ impl ToRangeString for RangeDyn { .map(|(key, val)| { format!( "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s + key, + val ) }) .collect::>() @@ -137,12 +134,10 @@ impl ToRangeString for RangeDyn { .iter() .rev() .take(5) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } + .filter(|(key, (val, op))| *val != Elem::Null) + .map(|(key, (val, op))| { + // (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) + (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) }) .collect::>(); @@ -151,8 +146,8 @@ impl ToRangeString for RangeDyn { .map(|(key, val)| { format!( "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s + key, + val ) }) .collect::>() @@ -163,12 +158,9 @@ impl ToRangeString for RangeDyn { .val .iter() .take(10) - .map(|(key, val)| { - if maximize { - (key.maximize(analyzer).unwrap(), val) - } else { - (key.minimize(analyzer).unwrap(), val) - } + .filter(|(key, (val, op))| *val != Elem::Null) + .map(|(key, (val, op))| { + (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) }) .collect::>(); @@ -177,8 +169,8 @@ impl ToRangeString for RangeDyn { .map(|(key, val)| { format!( "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s + key, + val, ) }) .collect::>() @@ -202,6 +194,9 @@ impl ToRangeString for RangeExpr { } fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { + if let MaybeCollapsed::Collapsed(collapsed) = collapse(*self.lhs.clone(), self.op, *self.rhs.clone()) { + return collapsed.to_range_string(maximize, analyzer) + } let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); let lhs_str = match *self.lhs { Elem::Expr(_) => { @@ -226,7 +221,7 @@ impl ToRangeString for RangeExpr { format!("{}{{{}, {}}}", self.op.to_string(), lhs_str.s, rhs_str.s), lhs_str.loc, ) - } else if matches!(self.op, RangeOp::Cast | RangeOp::Concat) { + } else if matches!(self.op, RangeOp::Cast) { let rhs = if maximize { self.rhs.maximize(analyzer).unwrap() } else { @@ -258,6 +253,14 @@ impl ToRangeString for RangeExpr { Elem::Concrete(_c) => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), } + } else if matches!(self.op, RangeOp::SetIndices) { + RangeElemString::new(format!("set_indicies({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) + } else if matches!(self.op, RangeOp::GetLength) { + RangeElemString::new(format!("get_length({})", lhs_str.s), lhs_str.loc) + } else if matches!(self.op, RangeOp::SetLength) { + RangeElemString::new(format!("set_length({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) + } else if matches!(self.op, RangeOp::Concat) { + RangeElemString::new(format!("concat({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) } else { RangeElemString::new( format!("{} {} {}", lhs_str.s, self.op.to_string(), rhs_str.s), diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index e6c65a62..20f68779 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -2,7 +2,7 @@ use crate::{range::elem::RangeElem, GraphBackend}; use shared::NodeIdx; use std::borrow::Cow; -pub trait Range { +pub trait Range { type GraphError; type ElemTy: RangeElem + Clone; /// Evaluate both the minimum and the maximum - cache along the way @@ -76,7 +76,7 @@ pub trait Range { Self: Sized + Clone; } -pub trait RangeEval>: Range { +pub trait RangeEval>: Range { fn sat(&self, analyzer: &impl GraphBackend) -> bool; fn unsat(&self, analyzer: &impl GraphBackend) -> bool { !self.sat(analyzer) diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index c63ee8e5..d4560156 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -97,14 +97,11 @@ impl SolcRange { // let dep_depends_on_node = dep_depends_on_node.contains(&node) || dep_depends_on_node.contains(&); if latest == node { if let Some(prev) = latest.previous_version(analyzer) { - println!("replacing: {} with {}", dep.0, prev.0); (dep, prev) } else { - println!("replacing: {} with {}", dep.0, dep.0); (dep, dep) } } else { - println!("replacing: {} with {}", dep.0, latest.0); (dep, latest) } }) @@ -186,11 +183,11 @@ impl SolcRange { (idx, v) }) .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn::new( + let r = Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(s.len()))), val, Loc::Implicit, - ))); + )); Some(SolcRange::new(r.clone(), r, vec![])) } Concrete::DynBytes(b) => { @@ -205,11 +202,11 @@ impl SolcRange { (idx, v) }) .collect::>(); - let r = Elem::ConcreteDyn(Box::new(RangeDyn::new( + let r = Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(b.len()))), val, Loc::Implicit, - ))); + )); Some(SolcRange::new(r.clone(), r, vec![])) } _e => None, @@ -317,29 +314,29 @@ impl SolcRange { | Builtin::String | Builtin::Array(_) | Builtin::Mapping(_, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::zero())), Default::default(), Loc::Implicit, - ))), - Elem::ConcreteDyn(Box::new(RangeDyn::new( + )), + Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::MAX)), Default::default(), Loc::Implicit, - ))), + )), vec![], )), Builtin::SizedArray(s, _) => Some(SolcRange::new( - Elem::ConcreteDyn(Box::new(RangeDyn::new( + Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(*s)), Default::default(), Loc::Implicit, - ))), - Elem::ConcreteDyn(Box::new(RangeDyn::new( + )), + Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(*s)), Default::default(), Loc::Implicit, - ))), + )), vec![], )), _ => None, @@ -604,18 +601,18 @@ impl Range for SolcRange { } fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { - if self.min_cached.is_none() { - let min = self.range_min_mut(); - min.cache_minimize(analyzer)?; - min.cache_flatten(analyzer)?; - self.min_cached = Some(self.range_min().minimize(analyzer)?); - } if self.max_cached.is_none() { let max = self.range_max_mut(); - max.cache_maximize(analyzer)?; max.cache_flatten(analyzer)?; + max.cache_maximize(analyzer)?; self.max_cached = Some(self.range_max().maximize(analyzer)?); } + if self.min_cached.is_none() { + let min = self.range_min_mut(); + min.cache_flatten(analyzer)?; + min.cache_minimize(analyzer)?; + self.min_cached = Some(self.range_min().minimize(analyzer)?); + } Ok(()) } @@ -659,10 +656,12 @@ impl Range for SolcRange { } fn set_range_min(&mut self, new: Self::ElemTy) { self.min_cached = None; + self.flattened = None; self.min = new; } fn set_range_max(&mut self, new: Self::ElemTy) { self.max_cached = None; + self.flattened = None; self.max = new; } @@ -689,13 +688,7 @@ impl Range for SolcRange { Ok(()) } /// Produce a flattened range or use the cached flattened range - fn flattened_range<'a>( - &'a self, - analyzer: &impl GraphBackend, - ) -> Result, Self::GraphError> - where - Self: Sized + Clone, - { + fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone { if let Some(flat) = &self.flattened { Ok(Cow::Borrowed(flat)) } else { diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index c91259bf..eb449f6c 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -297,7 +297,7 @@ impl Atomize for Elem { todo!("here4"); } (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => { - todo!("Should have simplified? {l} {r}") + todo!("Should have simplified? {l} {} {r}", expr.op.to_string()) } (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), @@ -324,9 +324,9 @@ impl Atomize for Elem { use Elem::*; match self { - Reference(_) => None, //{ println!("was dyn"); None}, - Null => None, //{ println!("was null"); None}, - Concrete(_c) => None, //{ println!("was conc: {}", c.val.as_human_string()); None }, + Reference(_) => None, //{ println!("was dyn"); None}, + Null => None, //{ println!("was null"); None}, + Concrete(_c) => None, //{ println!("was conc: {}", _c.val.as_human_string()); None }, ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, Expr(_) => { // println!("atomized: was expr"); diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index f4b34b32..97de610d 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -106,13 +106,13 @@ impl BruteBinSearchSolver { // Sometimes a storage variable will be split due to a context fork. We recombine them here atomic_idxs.sort(); atomic_idxs.dedup(); - atomic_idxs.iter().for_each(|dep| { - println!( - "atomic dep: {} - {}", - dep.display_name(analyzer).unwrap(), - dep.0 - ) - }); + // atomic_idxs.iter().for_each(|dep| { + // println!( + // "atomic dep: {} - {}", + // dep.display_name(analyzer).unwrap(), + // dep.0 + // ) + // }); // let atomics = atomic_idxs; let mut storage_atomics: BTreeMap> = BTreeMap::default(); let mut calldata_atomics = vec![]; diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index dcbc1b61..c91974f9 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -482,139 +482,139 @@ impl VarType { })) } - pub fn try_match_index_dynamic_ty( - &self, - index: ContextVarNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result, GraphError> { - match self { - Self::BuiltIn(_node, None) => Ok(None), - Self::BuiltIn(node, Some(r)) => { - if let Builtin::Bytes(size) = node.underlying(analyzer)? { - if r.is_const(analyzer)? && index.is_const(analyzer)? { - let Some(min) = r.evaled_range_min(analyzer)?.maybe_concrete() else { - return Ok(None); - }; - let Concrete::Bytes(_, val) = min.val else { - return Ok(None); - }; - let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() - else { - return Ok(None); - }; - let Concrete::Uint(_, idx) = idx.val else { - return Ok(None); - }; - if idx.low_u32() < (*size as u32) { - let mut h = H256::default(); - h.0[0] = val.0[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Ok(None) - } else { - // check if the index exists as a key - let min = r.range_min(); - if let Some(map) = min.dyn_map() { - let name = index.name(analyzer)?; - let is_const = index.is_const(analyzer)?; - if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { - Elem::Reference(Reference { idx, .. }) => match analyzer.node(*idx) { - Node::ContextVar(_) => { - let cvar = ContextVarNode::from(*idx); - cvar.name(analyzer).unwrap() == name - } - _ => false, - }, - c @ Elem::Concrete(..) if is_const => { - let index_val = index.evaled_range_min(analyzer).unwrap().unwrap(); - index_val.range_eq(c) - } - _ => false, - }) { - if let Some(idx) = val.node_idx() { - return Ok(idx.into()); - } else if let Some(c) = val.concrete() { - let cnode = analyzer.add_node(Node::Concrete(c)); - return Ok(cnode.into()); - } - } - } - Ok(None) - } - } - Self::Concrete(node) => { - if index.is_const(analyzer)? { - let idx = index - .evaled_range_min(analyzer) - .unwrap() - .unwrap() - .concrete() - .unwrap() - .uint_val() - .unwrap(); - match node.underlying(analyzer)? { - Concrete::Bytes(size, val) => { - if idx.low_u32() < (*size as u32) { - let mut h = H256::default(); - h.0[0] = val.0[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::DynBytes(elems) => { - if idx.low_u32() < (elems.len() as u32) { - let mut h = H256::default(); - h.0[0] = elems[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::String(st) => { - if idx.low_u32() < (st.len() as u32) { - let mut h = H256::default(); - h.0[0] = st.as_bytes()[idx.low_u32() as usize]; - let ret_val = Concrete::Bytes(1, h); - let node = analyzer.add_node(Node::Concrete(ret_val)); - return Ok(Some(node)); - } - } - Concrete::Array(elems) => { - if idx.low_u32() < (elems.len() as u32) { - let elem = &elems[idx.low_u32() as usize]; - let node = analyzer.add_node(Node::Concrete(elem.clone())); - return Ok(Some(node)); - } - } - _ => {} - } - } - Ok(None) - } - _ => Ok(None), - } - } + // pub fn try_match_index_dynamic_ty( + // &self, + // index: ContextVarNode, + // analyzer: &mut (impl GraphBackend + AnalyzerBackend), + // ) -> Result, GraphError> { + // match self { + // Self::BuiltIn(_node, None) => Ok(None), + // Self::BuiltIn(node, Some(r)) => { + // if let Builtin::Bytes(size) = node.underlying(analyzer)? { + // if r.is_const(analyzer)? && index.is_const(analyzer)? { + // let Some(min) = r.evaled_range_min(analyzer)?.maybe_concrete() else { + // return Ok(None); + // }; + // let Concrete::Bytes(_, val) = min.val else { + // return Ok(None); + // }; + // let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() + // else { + // return Ok(None); + // }; + // let Concrete::Uint(_, idx) = idx.val else { + // return Ok(None); + // }; + // if idx.low_u32() < (*size as u32) { + // let mut h = H256::default(); + // h.0[0] = val.0[idx.low_u32() as usize]; + // let ret_val = Concrete::Bytes(1, h); + // let node = analyzer.add_node(Node::Concrete(ret_val)); + // return Ok(Some(node)); + // } + // } + // Ok(None) + // } else { + // // check if the index exists as a key + // let min = r.range_min(); + // if let Some(map) = min.dyn_map() { + // let name = index.name(analyzer)?; + // let is_const = index.is_const(analyzer)?; + // if let Some((_k, val)) = map.iter().find(|(k, _v)| match k { + // Elem::Reference(Reference { idx, .. }) => match analyzer.node(*idx) { + // Node::ContextVar(_) => { + // let cvar = ContextVarNode::from(*idx); + // cvar.name(analyzer).unwrap() == name + // } + // _ => false, + // }, + // c @ Elem::Concrete(..) if is_const => { + // let index_val = index.evaled_range_min(analyzer).unwrap().unwrap(); + // index_val.range_eq(c) + // } + // _ => false, + // }) { + // if let Some(idx) = val.0.node_idx() { + // return Ok(idx.into()); + // } else if let Some(c) = val.0.concrete() { + // let cnode = analyzer.add_node(Node::Concrete(c)); + // return Ok(cnode.into()); + // } + // } + // } + // Ok(None) + // } + // } + // Self::Concrete(node) => { + // if index.is_const(analyzer)? { + // let idx = index + // .evaled_range_min(analyzer) + // .unwrap() + // .unwrap() + // .concrete() + // .unwrap() + // .uint_val() + // .unwrap(); + // match node.underlying(analyzer)? { + // Concrete::Bytes(size, val) => { + // if idx.low_u32() < (*size as u32) { + // let mut h = H256::default(); + // h.0[0] = val.0[idx.low_u32() as usize]; + // let ret_val = Concrete::Bytes(1, h); + // let node = analyzer.add_node(Node::Concrete(ret_val)); + // return Ok(Some(node)); + // } + // } + // Concrete::DynBytes(elems) => { + // if idx.low_u32() < (elems.len() as u32) { + // let mut h = H256::default(); + // h.0[0] = elems[idx.low_u32() as usize]; + // let ret_val = Concrete::Bytes(1, h); + // let node = analyzer.add_node(Node::Concrete(ret_val)); + // return Ok(Some(node)); + // } + // } + // Concrete::String(st) => { + // if idx.low_u32() < (st.len() as u32) { + // let mut h = H256::default(); + // h.0[0] = st.as_bytes()[idx.low_u32() as usize]; + // let ret_val = Concrete::Bytes(1, h); + // let node = analyzer.add_node(Node::Concrete(ret_val)); + // return Ok(Some(node)); + // } + // } + // Concrete::Array(elems) => { + // if idx.low_u32() < (elems.len() as u32) { + // let elem = &elems[idx.low_u32() as usize]; + // let node = analyzer.add_node(Node::Concrete(elem.clone())); + // return Ok(Some(node)); + // } + // } + // _ => {} + // } + // } + // Ok(None) + // } + // _ => Ok(None), + // } + // } pub fn get_index_dynamic_ty( &self, index: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { - if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { - Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) - } else { - match self { - Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), - Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin but it was: {e:?}" - ))), - } + // if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { + // Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) + // } else { + match self { + Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), + Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Builtin but it was: {e:?}" + ))), } + // } } pub fn dynamic_underlying_ty( diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index e842d82b..af191d6c 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -236,10 +236,11 @@ impl GraphDot for Analyzer { let from = petgraph::graph::GraphIndex::index(from); let to = petgraph::graph::GraphIndex::index(to); let edge_idx = idx.index(); + let edge_str = format!("{edge:?}").replace('"', "\'"); if as_mermaid { - format!("{indent}{from:} -->|\"{edge:?}\"| {to:}\n{indent}class {to} linkSource{edge_idx}\n{indent}class {from} linkTarget{edge_idx}") + format!("{indent}{from:} -->|\"{edge_str}\"| {to:}\n{indent}class {to} linkSource{edge_idx}\n{indent}class {from} linkTarget{edge_idx}") } else { - format!("{indent}{from:} -> {to:} [label = \"{edge:?}\"]",) + format!("{indent}{from:} -> {to:} [label = \"{edge_str}\"]",) } }) .collect::>() @@ -368,8 +369,8 @@ impl GraphDot for Analyzer { let from = from.index(); let to = to.index(); Some(format!( - " {from:} -> {to:} [label = \"{:?}\"]", - self.graph().edge_weight(edge).unwrap() + " {from:} -> {to:} [label = \"{}\"]", + format!("{:?}", self.graph().edge_weight(edge).unwrap()).replace('"', "\'") )) } else { None @@ -419,8 +420,8 @@ impl GraphDot for Analyzer { ], &|_graph, edge_ref| { match edge_ref.weight() { - Edge::Context(edge) => format!("label = \"{edge:?}\""), - e => format!("label = \"{e:?}\""), + Edge::Context(edge) => format!("label = \"{}\"", format!("{edge:?}").replace('"', "\'")), + e => format!("label = \"{}\"", format!("{e:?}").replace('"', "\'")), } }, &|_graph, (idx, node_ref)| { @@ -548,8 +549,8 @@ flowchart BT let to = to.index(); let edge_idx = edge.index(); Some(format!( - " {from:} -->|\"{:?}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", - self.graph().edge_weight(edge).unwrap() + " {from:} -->|\"{}\"| {to:}\n class {to} linkSource{edge_idx}\n class {from} linkTarget{edge_idx}", + format!("{:?}", self.graph().edge_weight(edge).unwrap()).replace('"', "\'") )) } else { None diff --git a/crates/pyrometer/tests/test_data/cast.sol b/crates/pyrometer/tests/test_data/cast.sol index 78465c4e..d2cd7041 100644 --- a/crates/pyrometer/tests/test_data/cast.sol +++ b/crates/pyrometer/tests/test_data/cast.sol @@ -251,12 +251,17 @@ contract Cast { require(b == x); } - function int_uint_int() internal { + function int_uint_int_conc() internal { int256 a = -100; uint256 b = uint(a); int256 c = int(b); require(-100 == c); } + + function int_uint_int(int a) internal { + uint256 b = uint(a); + int256 c = int(b); + } } diff --git a/crates/pyrometer/tests/test_data/dyn_types.sol b/crates/pyrometer/tests/test_data/dyn_types.sol index 566550d6..139c1e9f 100644 --- a/crates/pyrometer/tests/test_data/dyn_types.sol +++ b/crates/pyrometer/tests/test_data/dyn_types.sol @@ -9,25 +9,35 @@ contract DynTypes { } function array_dyn(uint256[] calldata x) public { - uint256[] memory y = x; + x[0] = 5; require(x.length < 10); + uint256[] memory y = x; y[8] = 100; require(y.length == 9); } - function nested_bytes_dyn(bytes[] calldata x) public { + function nested_bytes_dyn(bytes[] calldata x, uint y) public returns (bytes1) { bytes memory a = hex"1337"; x[0] = a; require(x[0][0] == hex"13"); - require(x.length == 1); + // return x[0][0]; + + x[y] = hex"1122"; + uint256 z = y - 1; + require(x[z + 1][0] == hex"11"); } function array_push(uint256 x) public { - require(x > 5); + // require(x > 5); + storeVar.push(x); + storeVar.push(x); storeVar.push(x); // TODO: handle this better require(storeVar[0] == x); - uint256 y = storeVar.pop(); + storeVar.push(x); + require(storeVar[1] == x); + uint256 y = storeVar[storeVar.length - 1]; + storeVar.pop(); require(y == x); } diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index efaa8712..d43550ad 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -623,4 +623,16 @@ contract Unchecked { a += (type(uint256).max - 99); require(a == type(uint256).max); } + + function symbUncheckedMul(int256 a, int b) public { + unchecked { + a = a * b; + } + } + + function asmSymbUncheckedMul(int256 a, int b) public { + assembly { + a := mul(a, b) + } + } } \ No newline at end of file diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 26f9480a..dda2dd80 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,12 +1,14 @@ +use graph::elem::RangeElem; use crate::{ require::Require, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; use graph::{ - elem::RangeOp, - nodes::{Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, Node, VarType, + elem::{Elem, RangeOp, RangeDyn}, + range_string::ToRangeString, + nodes::{TmpConstruction, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, Range, }; use solang_parser::{ @@ -137,57 +139,251 @@ pub trait Array: AnalyzerBackend + Sized { (ExprRet::Single(parent), ExprRet::Single(index)) | (ExprRet::Single(parent), ExprRet::SingleLiteral(index)) => { let index = ContextVarNode::from(index).latest_version(self); let parent = ContextVarNode::from(parent).latest_version(self); - let idx = self.advance_var_in_ctx(index, loc, ctx)?; - if !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { - let len_var = self.tmp_length(parent, ctx, loc).latest_version(self); - self.handle_require_inner( - ctx, - loc, - &ExprRet::Single(len_var.latest_version(self).into()), - &ExprRet::Single(idx.latest_version(self).into()), - RangeOp::Gt, - RangeOp::Lt, - (RangeOp::Lte, RangeOp::Gte), - )?; - } + let _ = self.index_into_array_raw(ctx, loc, index, parent, true, false)?; + Ok(()) + } + e => Err(ExprErr::ArrayIndex(loc, format!("Expected single expr evaluation of index expression, but was: {e:?}. This is a bug. Please report it at github.com/nascentxyz/pyrometer."))), + } + } + + fn index_into_array_raw( + &mut self, + ctx: ContextNode, + loc: Loc, + index: ContextVarNode, + parent: ContextVarNode, + length_requirement: bool, + return_var: bool, + ) -> Result, ExprErr> { + println!("access array: {}, parent: {}", index.display_name(self).unwrap(), parent.display_name(self).unwrap()); + let idx = self.advance_var_in_ctx(index, loc, ctx)?; + if length_requirement && !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { + let len_var = self.get_length(ctx, loc, parent, true)?.unwrap().latest_version(self); + self.require( + len_var.latest_version(self), + idx.latest_version(self), + ctx, + loc, + RangeOp::Gt, + RangeOp::Lt, + (RangeOp::Lte, RangeOp::Gte), + )?; + } - let name = format!("{}[{}]", parent.name(self).into_expr_err(loc)?, index.name(self).into_expr_err(loc)?); + let name = format!("{}[{}]", parent.name(self).into_expr_err(loc)?, index.name(self).into_expr_err(loc)?); + if let Some(index_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { + let index_var = index_var.latest_version(self); + let index_var = self.advance_var_in_ctx(index_var, loc, ctx)?; + if !return_var { + ctx.push_expr(ExprRet::Single(index_var.into()), self).into_expr_err(loc)?; + Ok(None) + } else { + Ok(Some(index_var)) + } + } else { + let ty = parent.ty(self).into_expr_err(loc)?.clone(); + let ty = ty.get_index_dynamic_ty(index, self).into_expr_err(loc)?; + // println!("index access ty: {:?#") + let index_access_var = ContextVar { + loc: Some(loc), + name: name.clone(), + display_name: format!( + "{}[{}]", + parent.display_name(self).into_expr_err(loc)?, + index.display_name(self).into_expr_err(loc)? + ), + storage: *parent.storage(self).into_expr_err(loc)?, + is_tmp: false, + tmp_of: Some(TmpConstruction::new(parent, RangeOp::SetIndices, Some(index))), + is_symbolic: true, + is_return: false, + ty, + }; - if let Some(index_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - let index_var = index_var.latest_version(self); - let index_var = self.advance_var_in_ctx(index_var, loc, ctx)?; - ctx.push_expr(ExprRet::Single(index_var.into()), self).into_expr_err(loc)?; - Ok(()) - } else { - let ty = parent.ty(self).into_expr_err(loc)?.clone(); - let ty = ty.get_index_dynamic_ty(index, self).into_expr_err(loc)?; - let index_var = ContextVar { - loc: Some(loc), - name: name.clone(), - display_name: format!( - "{}[{}]", - parent.display_name(self).into_expr_err(loc)?, - index.display_name(self).into_expr_err(loc)? - ), - storage: *parent.storage(self).into_expr_err(loc)?, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty, - }; - - let idx_node = self.add_node(Node::ContextVar(index_var)); - self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); - self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; - self.add_edge(index, idx_node, Edge::Context(ContextEdge::Index)); - - ctx.push_expr(ExprRet::Single(idx_node), self).into_expr_err(loc)?; - Ok(()) + let idx_access_node = self.add_node(Node::ContextVar(index_access_var)); + self.add_edge(idx_access_node, parent, Edge::Context(ContextEdge::IndexAccess)); + self.add_edge(idx_access_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(idx_access_node.into(), self).into_expr_err(loc)?; + self.add_edge(index, idx_access_node, Edge::Context(ContextEdge::Index)); + + let min = Elem::from(parent).get_index(index.into()).max(ContextVarNode::from(idx_access_node).into()); //.range_min(self).unwrap().unwrap()); + let max = Elem::from(parent).get_index(index.into()).min(ContextVarNode::from(idx_access_node).into()); //.range_max(self).unwrap().unwrap()); + + let idx_access_cvar = self.advance_var_in_ctx_forcible(ContextVarNode::from(idx_access_node), loc, ctx, true)?; + idx_access_cvar.set_range_min(self, min).into_expr_err(loc)?; + idx_access_cvar.set_range_max(self, max).into_expr_err(loc)?; + + if idx_access_cvar + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + // if the index access is also an array, produce a length variable + // we specify to return the variable because we dont want it on the stack + let _ = self.get_length(ctx, loc, idx_access_node.into(), true)?; + + } + + if !return_var { + ctx.push_expr(ExprRet::Single(idx_access_cvar.latest_version(self).into()), self).into_expr_err(loc)?; + Ok(None) + } else { + Ok(Some(idx_access_cvar.latest_version(self))) + } + } + } + + fn update_array_if_index_access( + &mut self, + ctx: ContextNode, + loc: Loc, + maybe_index_access: ContextVarNode, + new_value: ContextVarNode + ) -> Result<(), ExprErr> { + // println!("checking if array access: {} (idx {})", maybe_index_access.display_name(self).unwrap(), maybe_index_access.0); + if let Some(arr) = maybe_index_access.index_access_to_array(self) { + // Was indeed an indexed value + // println!("updating index to array: {}, index: {}", arr.display_name(self).unwrap(), maybe_index_access.display_name(self).unwrap()); + if let Some(index) = maybe_index_access.index_access_to_index(self) { + // Found the associated index + let next_arr = self.advance_var_in_ctx(arr.latest_version(self), loc, ctx)?; + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + // update the range + let min = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), new_value.into())], loc)); + let max = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), new_value.into())], loc)); + next_arr + .set_range_min(self, min) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, max) + .into_expr_err(loc)?; } + + // handle nested arrays, i.e. if: + // uint256[][] memory z; + // z[x][y] = 5; + // first pass sets z[x][y] = 5, second pass needs to set z[x] = x + self.update_array_if_index_access(ctx, loc, next_arr.latest_version(self), next_arr.latest_version(self))?; } - e => Err(ExprErr::ArrayIndex(loc, format!("Expected single expr evaluation of index expression, but was: {e:?}. This is a bug. Please report it at github.com/nascentxyz/pyrometer."))), } + Ok(()) + } + + fn update_array_if_length_var( + &mut self, + ctx: ContextNode, + loc: Loc, + maybe_length: ContextVarNode, + ) -> Result<(), ExprErr> { + if let Some(backing_arr) = maybe_length.len_var_to_array(self).into_expr_err(loc)? { + let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; + let new_len = Elem::from(backing_arr).set_length(maybe_length.into()); + next_arr + .set_range_min(self, new_len.clone()) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, new_len) + .into_expr_err(loc)?; + } + Ok(()) + } + + fn set_var_as_length( + &mut self, + ctx: ContextNode, + loc: Loc, + new_length: ContextVarNode, + backing_arr: ContextVarNode + ) -> Result<(), ExprErr> { + let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; + let new_len = Elem::from(backing_arr).get_length().max(new_length.into()); + let min = Elem::from(backing_arr).set_length(new_len); + next_arr + .set_range_min(self, min) + .into_expr_err(loc)?; + let new_len = Elem::from(backing_arr).get_length().min(new_length.into()); + let max = Elem::from(backing_arr).set_length(new_len); + next_arr + .set_range_max(self, max) + .into_expr_err(loc)?; + self.add_edge(new_length, next_arr, Edge::Context(ContextEdge::AttrAccess("length"))); + Ok(()) + } + + fn update_array_from_index_access( + &mut self, + ctx: ContextNode, + loc: Loc, + index: ContextVarNode, + access: ContextVarNode, + backing_arr: ContextVarNode + ) -> Result<(), ExprErr> { + let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; + if next_arr + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + // update the range + let min = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), access.into())], loc)); + let max = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), access.into())], loc)); + next_arr + .set_range_min(self, min) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, max) + .into_expr_err(loc)?; + } + + // handle nested arrays + if let (Some(backing_arr), Some(parent_nested_index)) = (next_arr.index_access_to_array(self), next_arr.index_access_to_index(self)) { + self.update_array_from_index_access(ctx, loc, parent_nested_index, next_arr, backing_arr.latest_version(self)) + } else { + Ok(()) + } + } + + fn update_array_min_if_length( + &mut self, + ctx: ContextNode, + loc: Loc, + maybe_length: ContextVarNode, + ) -> Result<(), ExprErr> { + if let Some(backing_arr) = maybe_length.len_var_to_array(self).into_expr_err(loc)? { + let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; + let new_len = Elem::from(backing_arr).get_length().max(maybe_length.into()); + let min = Elem::from(backing_arr).set_length(new_len); + next_arr + .set_range_min(self, min) + .into_expr_err(loc)?; + } + Ok(()) + } + + fn update_array_max_if_length( + &mut self, + ctx: ContextNode, + loc: Loc, + maybe_length: ContextVarNode, + ) -> Result<(), ExprErr> { + if let Some(backing_arr) = maybe_length.len_var_to_array(self).into_expr_err(loc)? { + let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; + let new_len = Elem::from(backing_arr).get_length().min(maybe_length.into()); + let max = Elem::from(backing_arr).set_length(new_len); + next_arr + .set_range_max(self, max) + .into_expr_err(loc)?; + } + Ok(()) } } diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index a103a503..02e38252 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -1,9 +1,9 @@ -use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::{ListAccess, array::Array, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ elem::Elem, - nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, GraphError, Range, + nodes::{ContextNode, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, GraphError, }; use solang_parser::pt::{Expression, Loc}; @@ -123,7 +123,7 @@ pub trait Assign: AnalyzerBackend + Sized lhs_cvar.display_name(self).unwrap(), ); - let (new_lower_bound, new_upper_bound): (Elem, Elem) = ( + let (new_lower_bound, new_upper_bound) = ( Elem::from(rhs_cvar.latest_version(self)), Elem::from(rhs_cvar.latest_version(self)), ); @@ -200,40 +200,18 @@ pub trait Assign: AnalyzerBackend + Sized let _ = self.add_if_err(res); } - if let Some(arr) = lhs_cvar.index_to_array(self) { - if let Some(index) = lhs_cvar.index_access_to_index(self) { - let next_arr = self.advance_var_in_ctx(arr, loc, ctx)?; - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(rhs_cvar)); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - } + if rhs_cvar.is_indexable(self).into_expr_err(loc)? { + // rhs is indexable. get the length attribute, create a new length for the lhs, + // and perform assign + let rhs_len_cvar = self.get_length(ctx, loc, rhs_cvar, true)?.unwrap(); + let lhs_len_cvar = self.get_length(ctx, loc, lhs_cvar, true)?.unwrap(); + self.assign(loc, lhs_len_cvar, rhs_len_cvar, ctx)?; + // update the range + self.update_array_if_length_var(ctx, loc, lhs_len_cvar.latest_version(self))?; } + self.update_array_if_index_access(ctx, loc, lhs_cvar, rhs_cvar)?; + // advance the rhs variable to avoid recursion issues self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; Ok(ExprRet::Single(new_lhs.into())) diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 86ff6d67..df1d280c 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -209,7 +209,9 @@ pub trait BinOp: AnalyzerBackend + Sized { Elem::from(Reference::new(rhs_cvar.latest_version(self).into())), )); - // TODO: change to only hit this path if !uncheck + + // to prevent some recursive referencing, forcibly increase lhs_cvar + self.advance_var_in_ctx_forcible(lhs_cvar.latest_version(self), loc, ctx, true)?; // TODO: If one of lhs_cvar OR rhs_cvar are not symbolic, // apply the requirement on the symbolic expression side instead of @@ -653,6 +655,9 @@ pub trait BinOp: AnalyzerBackend + Sized { } _ => {} } + } else { + + // self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; } // let lhs_range = if let Some(lhs_range) = new_lhs.range(self).into_expr_err(loc)? { @@ -697,7 +702,7 @@ pub trait BinOp: AnalyzerBackend + Sized { } } } - Ok(ExprRet::Single(new_lhs.into())) + Ok(ExprRet::Single(new_lhs.latest_version(self).into())) } #[tracing::instrument(level = "trace", skip_all)] diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index ed67222d..18e209e0 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -187,19 +187,6 @@ pub trait Cmp: AnalyzerBackend + Sized { .range_exclusions(); SolcRange::new(elem.clone(), elem, exclusions) }; - // println!("{:?}", range.evaled_range_max(self)); - // println!("{:?}", range.evaled_range_min(self)); - - // println!( - // "cmp: {} {} {}, [{}, {}], [{}, {}] ", - // lhs_cvar.name(self).into_expr_err(loc)?, - // op.to_string(), - // rhs_cvar.name(self).into_expr_err(loc)?, - // lhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, - // lhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s, - // rhs_cvar.evaled_range_min(self).into_expr_err(loc)?.unwrap().to_range_string(false, self).s, - // rhs_cvar.evaled_range_max(self).into_expr_err(loc)?.unwrap().to_range_string(true, self).s - // ); let out_var = ContextVar { loc: Some(loc), diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index c053b4e3..e721c059 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -115,7 +115,7 @@ pub trait InternalFuncCaller: .expect("Invalid struct field"); let fc_node = self.add_node(Node::ContextVar(field_cvar)); - self.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess("field"))); self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(fc_node.into(), self).into_expr_err(*loc)?; let field_as_ret = ExprRet::Single(fc_node); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 059b0fcd..9066f4aa 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,12 +1,12 @@ use crate::{ - array::Array, assign::Assign, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, + array::Array, bin_op::BinOp, assign::Assign, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; use graph::{ elem::*, - nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, + nodes::{Concrete, ContextVar, ContextNode, ContextVarNode, ExprRet}, + AnalyzerBackend, Node, Edge, ContextEdge, }; use ethers_core::types::U256; @@ -31,27 +31,53 @@ pub trait ArrayCaller: AnalyzerBackend + S // empty element onto the expr ret stack self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( + return Err(ExprErr::NoRhs( loc, - "array[].push(..) was not an array to push to".to_string(), + "array[].push(..) was not given an element to push".to_string(), )); }; + if matches!(array, ExprRet::CtxKilled(_)) { + ctx.push_expr(array, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + // get length let arr = array.expect_single().into_expr_err(loc)?; let arr = ContextVarNode::from(arr).latest_version(analyzer); + // get length - let len = analyzer.tmp_length(arr, ctx, loc); + let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); - let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; - // set length as index - analyzer.index_into_array_inner( - ctx, + // get the index access and add it to the stack + let _ = analyzer.index_into_array_raw(ctx, loc, len, arr, false, false)?; + + // create a temporary 1 variable + let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + let tmp_one = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) + .into_expr_err(loc)?, + ); + let one = ContextVarNode::from(analyzer.add_node(tmp_one)); + + // add 1 to the length + let tmp_len = analyzer.op( loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + len, + one, + ctx, + RangeOp::Add(false), + false )?; + + let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); + tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; + + analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; + Ok(()) }) } else if input_exprs.len() == 2 { @@ -84,30 +110,56 @@ pub trait ArrayCaller: AnalyzerBackend + S ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; return Ok(()); } + let pushed_value = ContextVarNode::from(new_elem.expect_single().unwrap()); + // get length let arr = array.expect_single().into_expr_err(loc)?; let arr = ContextVarNode::from(arr).latest_version(analyzer); + // get length - let len = analyzer.tmp_length(arr, ctx, loc); + let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); - let len_as_idx = len.as_tmp(loc, ctx, analyzer).into_expr_err(loc)?; - // set length as index - analyzer.index_into_array_inner( - ctx, + // get the index access for the *previous* length + let index_access = analyzer.index_into_array_raw(ctx, loc, len, arr, false, true)?.unwrap(); + // create a temporary 1 variable + let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + let tmp_one = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) + .into_expr_err(loc)?, + ); + let one = ContextVarNode::from(analyzer.add_node(tmp_one)); + + // add 1 to the length + let tmp_len = analyzer.op( loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(len_as_idx.latest_version(analyzer).into()), + len, + one, + ctx, + RangeOp::Add(false), + false )?; - let index = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap(); - if matches!(index, ExprRet::CtxKilled(_)) { - ctx.push_expr(index, analyzer).into_expr_err(loc)?; - return Ok(()); - } - // assign index to new_elem - analyzer.match_assign_sides(ctx, loc, &index, &new_elem) + + let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); + tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; + + + // set the new length + analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; + + + // update the index access's range + let elem = Elem::from(pushed_value); + index_access.set_range_min(analyzer, elem.clone()).into_expr_err(loc)?; + index_access.set_range_max(analyzer, elem.clone()).into_expr_err(loc)?; + + // update the array using the index access + analyzer.update_array_from_index_access( + ctx, + loc, + len, + index_access.latest_version(analyzer), + arr.latest_version(analyzer) + ) }) }) } else { @@ -132,51 +184,120 @@ pub trait ArrayCaller: AnalyzerBackend + S } self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( + let Some(array) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( loc, - "array[].pop() was not an array to pop from".to_string(), + "array[].pop() was not given an array".to_string(), )); }; + if matches!(array, ExprRet::CtxKilled(_)) { ctx.push_expr(array, analyzer).into_expr_err(loc)?; return Ok(()); } - // get the array + // get length let arr = array.expect_single().into_expr_err(loc)?; let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length - analyzer.match_length(ctx, loc, array, false)?; - let Some(len) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "array[].pop() was not an array to pop from".to_string(), - )); - }; - let len = len.expect_single().into_expr_err(loc)?; - let next_len = analyzer.advance_var_in_ctx(len.into(), loc, ctx)?; - next_len - .set_range_min( - analyzer, - Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), - ) - .into_expr_err(loc)?; - next_len - .set_range_max( - analyzer, - Elem::from(len) - Elem::from(Concrete::from(U256::from(1))), - ) - .into_expr_err(loc)?; - - // set length as index - analyzer.index_into_array_inner( + let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); + + // create a temporary 1 variable + let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + let tmp_one = Node::ContextVar( + ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) + .into_expr_err(loc)?, + ); + let one = ContextVarNode::from(analyzer.add_node(tmp_one)); + + // subtract 1 from the length + let tmp_len = analyzer.op( + loc, + len, + one, + ctx, + RangeOp::Sub(false), + false + )?; + + let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); + tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; + + // get the index access + let index_access = analyzer.index_into_array_raw(ctx, loc, tmp_len, arr, false, true)?.unwrap(); + + analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; + index_access.set_range_min(analyzer, Elem::Null).into_expr_err(loc)?; + index_access.set_range_max(analyzer, Elem::Null).into_expr_err(loc)?; + + analyzer.update_array_from_index_access( ctx, loc, - ExprRet::Single(arr.latest_version(analyzer).into()), - ExprRet::Single(next_len.latest_version(analyzer).into()), + tmp_len, + index_access.latest_version(analyzer), + arr.latest_version(analyzer) ) + // let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + // return Err(ExprErr::NoLhs( + // loc, + // "array[].pop() was not an array to pop from".to_string(), + // )); + // }; + // if matches!(array, ExprRet::CtxKilled(_)) { + // ctx.push_expr(array, analyzer).into_expr_err(loc)?; + // return Ok(()); + // } + + // let arr = array.expect_single().into_expr_err(loc)?; + // let arr = ContextVarNode::from(arr).latest_version(analyzer); + // // get length + // let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); + + // // Subtract one from it + // let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + // let tmp_one = Node::ContextVar( + // ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) + // .into_expr_err(loc)?, + // ); + // let one = ContextVarNode::from(analyzer.add_node(tmp_one.clone())); + // let new_len_expr = analyzer.op( + // loc, + // len, + // one, + // ctx, + // RangeOp::Sub(false), + // false, + // )?; + + // if matches!(new_len_expr, ExprRet::CtxKilled(_)) { + // ctx.push_expr(new_len_expr, analyzer).into_expr_err(loc)?; + // return Ok(()); + // } + + // // connect the new length + // let new_len = ContextVarNode::from(new_len_expr.expect_single().unwrap()).latest_version(analyzer); + // let next_arr = analyzer.advance_var_in_ctx(arr.latest_version(analyzer), loc, ctx)?; + // analyzer.add_edge(new_len.latest_version(analyzer), next_arr, Edge::Context(ContextEdge::AttrAccess("length"))); + + // let min = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(new_len.into(), Elem::Null)], loc)); //.set_length(new_len.into()); + // let max = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(new_len.into(), Elem::Null)], loc)); //.set_length(new_len.into()); + + // let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::zero()))); + // let tmp_zero = Node::ContextVar( + // ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) + // .into_expr_err(loc)?, + // ); + // let zero = ContextVarNode::from(analyzer.add_node(tmp_one)); + // analyzer.add_edge(zero, next_arr.latest_version(analyzer), Edge::Context(ContextEdge::StorageWrite)); + // next_arr + // .set_range_min(analyzer, min) + // .into_expr_err(loc)?; + // next_arr + // .set_range_max(analyzer, max) + // .into_expr_err(loc) }) } _ => Err(ExprErr::FunctionNotFound( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index a6f4717a..25da2e29 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -79,7 +79,7 @@ pub trait ConstructorCaller: ctx.add_var(arr, analyzer).into_expr_err(loc)?; analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess)); + analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess("length"))); // update the length if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { @@ -87,14 +87,14 @@ pub trait ConstructorCaller: let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + rd.len = Box::new(Elem::from(len_cvar)); + arr.set_range_min(analyzer, Elem::ConcreteDyn(rd)) .into_expr_err(loc)?; } if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_cvar); - arr.set_range_min(analyzer, Elem::ConcreteDyn(Box::new(rd))) + rd.len = Box::new(Elem::from(len_cvar)); + arr.set_range_min(analyzer, Elem::ConcreteDyn(rd)) .into_expr_err(loc)?; } } @@ -195,7 +195,7 @@ pub trait ConstructorCaller: .expect("Invalid struct field"); let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); - analyzer.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess)); + analyzer.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess("field"))); analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; let field_as_ret = ExprRet::Single(fc_node); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index ef7a610e..5a8c67c8 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,8 +1,9 @@ -use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::{variable::Variable, ListAccess, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ + elem::RangeElem, ContextEdge, Edge, nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, Node, SolcRange, VarType, + AnalyzerBackend, Node, SolcRange, VarType, range_string::ToRangeString, }; use solang_parser::pt::{Expression, Loc}; @@ -67,9 +68,9 @@ pub trait DynBuiltinCaller: AnalyzerBackend 1 { - analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], None) + analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], false) } else { - analyzer.match_concat(ctx, loc, start.clone(), &[], None) + analyzer.match_concat(ctx, loc, start.clone(), &[], false) } } }) @@ -82,24 +83,40 @@ pub trait DynBuiltinCaller: AnalyzerBackend, + has_accum_node: bool, ) -> Result<(), ExprErr> { - if let Some(accum_node) = accum_node { + if has_accum_node { match curr.flatten() { ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - self.concat_inner(loc, accum_node, ContextVarNode::from(var))?; + // pop the accumulation node off the stack + let accum_node = ctx + .pop_expr_latest(loc, self) + .into_expr_err(loc)? + .unwrap() + .expect_single() + .unwrap(); + + let accum_node = self.advance_var_in_ctx(accum_node.into(), loc, ctx)?; + let name = accum_node.display_name(self).into_expr_err(loc)?; + let next_var = ContextVarNode::from(var); + let next_name = next_var.display_name(self).into_expr_err(loc)?; + accum_node.underlying_mut(self).into_expr_err(loc)?.display_name = format!("concat({name}, {next_name})"); + + // concat into it + self.concat_inner(loc, accum_node, next_var)?; + + // add it back to the stack ctx.push_expr(ExprRet::Single(accum_node.into()), self) .into_expr_err(loc)?; + Ok(()) } ExprRet::Null => { - ctx.push_expr(ExprRet::Single(accum_node.into()), self) - .into_expr_err(loc)?; Ok(()) } ExprRet::Multi(inner) => inner .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, Some(accum_node))), + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, true)), ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), } } else { @@ -108,12 +125,20 @@ pub trait DynBuiltinCaller: AnalyzerBackend, ExprErr>>()?; - ctx.push_expr(ExprRet::Single(acc.into()), self) - .into_expr_err(loc)?; + + // create the length variable + let _ = self.tmp_length(acc.latest_version(self), ctx, loc); + Ok(()) } ExprRet::Null => Err(ExprErr::NoRhs( @@ -122,7 +147,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend inner .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, None)), + .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, false)), ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), } } @@ -207,9 +232,8 @@ pub trait DynBuiltinCaller: AnalyzerBackend { - // TODO: improve length calculation here - let min = r.min.clone().concat(r2.min.clone()); - let max = r.max.clone().concat(r2.max.clone()); + let min = r.min.clone().concat(r2.min.clone()).simplify_minimize(&mut vec![], self).into_expr_err(loc)?; + let max = r.max.clone().concat(r2.max.clone()).simplify_maximize(&mut vec![], self).into_expr_err(loc)?; accum.set_range_min(self, min).into_expr_err(loc)?; accum.set_range_max(self, max).into_expr_err(loc)?; Ok(()) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index a0379fbc..1c244c58 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -144,57 +144,18 @@ pub trait TypesCaller: AnalyzerBackend + S ExprRet::CtxKilled(kind) => ctx.kill(analyzer, loc, kind).into_expr_err(loc), ExprRet::Null => Ok(()), ExprRet::Single(cvar) | ExprRet::SingleLiteral(cvar) => { - let new_var = ContextVarNode::from(cvar) + let cvar = ContextVarNode::from(cvar); + let new_var = cvar .as_cast_tmp(loc, ctx, ty.clone(), analyzer) .into_expr_err(loc)?; - new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = - VarType::try_from_idx(analyzer, func_idx).expect(""); - // cast the ranges - if let Some(r) = ContextVarNode::from(cvar) - .range(analyzer) - .into_expr_err(loc)? - { - let curr_range = SolcRange::try_from_builtin(ty).expect("No default range"); - let mut min = r - .range_min() - .into_owned() - .cast(curr_range.range_min().into_owned()); - - min.cache_minimize(analyzer).into_expr_err(loc)?; - let mut max = r - .range_max() - .into_owned() - .cast(curr_range.range_max().into_owned()); - - max.cache_maximize(analyzer).into_expr_err(loc)?; - - let existing_max = r.evaled_range_max(analyzer).into_expr_err(loc)?; - // Check if the max value has changed once the cast is applied. - // If it hasnt, then the cast had no effect and we should adjust the naming - // to not muddle the CLI - if let Some(std::cmp::Ordering::Equal) = max - .maximize(analyzer) - .into_expr_err(loc)? - .range_ord(&existing_max) - { - // its a noop, reflect that in the naming - new_var.underlying_mut(analyzer).unwrap().display_name = - ContextVarNode::from(cvar) - .display_name(analyzer) - .into_expr_err(loc)?; - } - - new_var.set_range_min(analyzer, min).into_expr_err(loc)?; - new_var.set_range_max(analyzer, max).into_expr_err(loc)?; - // cast the range exclusions - TODO: verify this is correct - let mut exclusions = r.range_exclusions(); - exclusions.iter_mut().for_each(|range| { - *range = range.clone().cast(curr_range.range_min().into_owned()); - }); - new_var - .set_range_exclusions(analyzer, exclusions) - .into_expr_err(loc)?; + let v_ty = VarType::try_from_idx(analyzer, func_idx).expect(""); + let maybe_new_range = cvar.cast_exprs(&v_ty, analyzer).into_expr_err(loc)?; + new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = v_ty; + + if let Some((new_min, new_max)) = maybe_new_range { + new_var.set_range_min(analyzer, new_min).into_expr_err(loc)?; + new_var.set_range_max(analyzer, new_max).into_expr_err(loc)?; } ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 354f971c..baae63a6 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -5,116 +5,132 @@ use graph::{ nodes::{BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, VarType, }; -use shared::NodeIdx; -use solang_parser::pt::{Expression, Identifier, Loc}; +use ethers_core::types::U256; +use solang_parser::pt::{Expression, Loc}; impl ListAccess for T where T: AnalyzerBackend + Sized {} /// Handles list/array member access (indices, length, etc) pub trait ListAccess: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] - /// Access an index of a list/array - fn index_access( + /// Get the length member of an array/list + fn length( &mut self, loc: Loc, - parent: NodeIdx, - dyn_builtin: BuiltInNode, - ident: &Identifier, + input_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.variable(ident, ctx, None)?; + self.parse_ctx_expr(input_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(index_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs(loc, "No index in index access".to_string())); + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Attempted to perform member access without a left-hand side".to_string(), + )); }; - - if matches!(index_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(index_paths, analyzer).into_expr_err(loc)?; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_index_access(&index_paths, loc, parent.into(), dyn_builtin, ctx) + analyzer.match_length(ctx, loc, ret, true) }) } #[tracing::instrument(level = "trace", skip_all)] - /// Match on the [`ExprRet`] of a index access expression - fn match_index_access( + /// Get the length member of an array/list + fn match_length( &mut self, - index_paths: &ExprRet, - loc: Loc, - parent: ContextVarNode, - dyn_builtin: BuiltInNode, ctx: ContextNode, + loc: Loc, + elem_path: ExprRet, + update_len_bound: bool, ) -> Result<(), ExprErr> { - match index_paths { - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, *kind).into_expr_err(loc), - ExprRet::Single(idx) => { - let parent = parent.first_version(self); - let parent_name = parent.name(self).into_expr_err(loc)?; - let parent_display_name = parent.display_name(self).unwrap(); - - tracing::trace!( - "Index access: {}[{}]", - parent_display_name, - ContextVarNode::from(*idx) - .display_name(self) - .into_expr_err(loc)? - ); - let parent_ty = dyn_builtin; - let parent_stor = parent - .storage(self) - .into_expr_err(loc)? - .as_ref() - .expect("parent didnt have a storage location?"); - let indexed_var = ContextVar::new_from_index( - self, - loc, - parent_name, - parent_display_name, - *parent_stor, - &parent_ty, - ContextVarNode::from(*idx), - ) - .into_expr_err(loc)?; - - let idx_node = self.add_node(Node::ContextVar(indexed_var)); - self.add_edge(idx_node, parent, Edge::Context(ContextEdge::IndexAccess)); - self.add_edge(idx_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_node.into(), self).into_expr_err(loc)?; - self.add_edge(*idx, idx_node, Edge::Context(ContextEdge::Index)); - ctx.push_expr(ExprRet::Single(idx_node), self) - .into_expr_err(loc)?; + match elem_path { + ExprRet::Null => { + ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; Ok(()) } - e => Err(ExprErr::UnhandledExprRet( - loc, - format!("Unhandled expression return in index access: {e:?}"), - )), + ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), + ExprRet::Single(arr) => { + self.get_length(ctx, loc, arr.into(), false)?; + Ok(()) + } + e => todo!("here: {e:?}"), } } - #[tracing::instrument(level = "trace", skip_all)] - /// Get the length member of an array/list - fn length( + fn get_length( &mut self, - loc: Loc, - input_expr: &Expression, ctx: ContextNode, - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(input_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Attempted to perform member access without a left-hand side".to_string(), - )); + loc: Loc, + array: ContextVarNode, + return_var: bool + ) -> Result, ExprErr> { + let next_arr = self.advance_var_in_ctx( + array.latest_version(self), + loc, + ctx, + )?; + // search for latest length + if let Some(len_var) = next_arr.array_to_len_var(self) { + let len_node = self.advance_var_in_ctx(len_var.latest_version(self), loc, ctx)?; + if !return_var { + ctx.push_expr(ExprRet::Single(len_node.into()), self) + .into_expr_err(loc)?; + Ok(None) + } else { + Ok(Some(len_node)) + } + } else { + // no length variable, create one + let name = format!("{}.length", array.name(self).into_expr_err(loc)?); + + // Create the range from the current length or default to [0, uint256.max] + + let len_min = Elem::from(next_arr).get_length().max(Elem::from(Concrete::from(U256::zero()))); + let len_max = Elem::from(next_arr).get_length().min(Elem::from(Concrete::from(U256::MAX))); + let range = SolcRange::new(len_min, len_max, vec![]); + + let len_var = ContextVar { + loc: Some(loc), + name, + display_name: array.display_name(self).into_expr_err(loc)? + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + Some(range), + ), }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); + let len_node = ContextVarNode::from(self.add_node(Node::ContextVar(len_var))); + self.add_edge(len_node, array, Edge::Context(ContextEdge::AttrAccess("length"))); + self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_node, self).into_expr_err(loc)?; + + // we have to force here to avoid length <-> array recursion + let next_next_arr = self.advance_var_in_ctx_forcible( + array.latest_version(self), + loc, + ctx, + true + )?; + let update_array_len = Elem::from(next_arr.latest_version(self)).set_length(len_node.into()); + + // Update the array + next_next_arr.set_range_min(self, update_array_len.clone()).into_expr_err(loc)?; + next_next_arr.set_range_max(self, update_array_len.clone()).into_expr_err(loc)?; + + if !return_var { + ctx.push_expr(ExprRet::Single(len_node.into()), self) + .into_expr_err(loc)?; + Ok(None) + } else { + Ok(Some(len_node)) } - analyzer.match_length(ctx, loc, ret, true) - }) + } } #[tracing::instrument(level = "trace", skip_all)] @@ -164,156 +180,32 @@ pub trait ListAccess: AnalyzerBackend + Si .unwrap() { if let Some(r) = next_arr.ref_range(self).unwrap() { - let min = r.evaled_range_min(self).unwrap(); - let max = r.evaled_range_max(self).unwrap(); - + let min = r.simplified_range_min(&mut vec![], self).unwrap(); + let max = r.simplified_range_max(&mut vec![], self).unwrap(); if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); + ContextVarNode::from(len_node).set_range_min(self, *rd.len.clone()).unwrap(); + rd.len = Box::new(Elem::from(len_node)); let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) + .set_range_min(self, Elem::ConcreteDyn(rd)) .into_expr_err(loc); let _ = self.add_if_err(res); } if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); + ContextVarNode::from(len_node).set_range_max(self, *rd.len.clone()).unwrap(); + rd.len = Box::new(Elem::from(len_node)); let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) + .set_range_max(self, Elem::ConcreteDyn(rd)) .into_expr_err(loc); let _ = self.add_if_err(res); } } } - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); + self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess("length"))); self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); array_ctx.add_var(len_node.into(), self).unwrap(); len_node.into() } } - - #[tracing::instrument(level = "trace", skip_all)] - /// Get the length member of an array/list - fn match_length( - &mut self, - ctx: ContextNode, - loc: Loc, - elem_path: ExprRet, - update_len_bound: bool, - ) -> Result<(), ExprErr> { - match elem_path { - ExprRet::Null => { - ctx.push_expr(ExprRet::Null, self).into_expr_err(loc)?; - Ok(()) - } - ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), - ExprRet::Single(arr) => { - let next_arr = self.advance_var_in_ctx( - ContextVarNode::from(arr).latest_version(self), - loc, - ctx, - )?; - let arr = ContextVarNode::from(arr).first_version(self); - let name = format!("{}.length", arr.name(self).into_expr_err(loc)?); - tracing::trace!("Length access: {}", name); - if let Some(len_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { - let len_var = len_var.latest_version(self); - let new_len = self.advance_var_in_ctx(len_var, loc, ctx)?; - if update_len_bound - && next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_len); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - ctx.push_expr(ExprRet::Single(new_len.into()), self) - .into_expr_err(loc)?; - Ok(()) - } else { - let range = if let Ok(Some(size)) = - arr.ty(self).into_expr_err(loc)?.maybe_array_size(self) - { - SolcRange::from(Concrete::from(size)) - } else { - SolcRange::try_from_builtin(&Builtin::Uint(256)) - }; - - let len_var = ContextVar { - loc: Some(loc), - name, - display_name: arr.display_name(self).into_expr_err(loc)? + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - range, - ), - }; - let len_node = self.add_node(Node::ContextVar(len_var)); - - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(len_node); - let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc); - let _ = self.add_if_err(res); - } - } - } - - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess)); - self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_node.into(), self).into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(len_node), self) - .into_expr_err(loc)?; - Ok(()) - } - } - e => todo!("here: {e:?}"), - } - } } diff --git a/crates/solc-expressions/src/member_access/struct_access.rs b/crates/solc-expressions/src/member_access/struct_access.rs index 41d252a5..84b7bfb8 100644 --- a/crates/solc-expressions/src/member_access/struct_access.rs +++ b/crates/solc-expressions/src/member_access/struct_access.rs @@ -50,7 +50,7 @@ pub trait StructAccess: self.add_edge( fc_node, ContextVarNode::from(member_idx).first_version(self), - Edge::Context(ContextEdge::AttrAccess), + Edge::Context(ContextEdge::AttrAccess("field")), ); ctx.add_var(fc_node.into(), self).into_expr_err(loc)?; self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index f37318bb..8f5bbe5d 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,4 +1,4 @@ -use crate::{BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; +use crate::{array::Array, BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; use graph::{ elem::*, @@ -10,7 +10,7 @@ use graph::{ AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; -use ethers_core::types::I256; +use ethers_core::types::{U256, I256}; use solang_parser::{ helpers::CodeLocation, pt::{Expression, Loc}, @@ -707,9 +707,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { if let Some(lhs_range) = new_lhs .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .ty .range(self) .into_expr_err(loc)? { @@ -732,7 +729,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_range_fn = SolcRange::dyn_fn_from_op(rhs_op); new_var_range = rhs_range_fn(rhs_range.clone(), new_lhs); if self - .update_nonconst_from_const(loc, rhs_op, new_lhs, new_rhs, rhs_range)? + .update_nonconst_from_const(ctx, loc, rhs_op, new_lhs, new_rhs, rhs_range)? { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; @@ -740,7 +737,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } } (false, true) => { - if self.update_nonconst_from_const(loc, op, new_rhs, new_lhs, lhs_range)? { + if self.update_nonconst_from_const(ctx, loc, op, new_rhs, new_lhs, lhs_range)? { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); @@ -748,7 +745,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } (false, false) => { if self.update_nonconst_from_nonconst( - loc, op, new_lhs, new_rhs, lhs_range, rhs_range, + ctx, loc, op, new_lhs, new_rhs, lhs_range, rhs_range, )? { tracing::trace!("nonconst killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; @@ -768,78 +765,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { new_rhs = new_rhs.latest_version(self); new_lhs = new_lhs.latest_version(self); - if let Some(backing_arr) = new_lhs.len_var_to_array(self).into_expr_err(loc)? { - if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { - let min = r.range_min().into_owned(); - let max = r.range_max().into_owned(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } else if let Some(arr) = new_lhs.index_to_array(self) { - if let Some(index) = new_lhs.index_access_to_index(self) { - let next_arr = self.advance_var_in_ctx(arr.latest_version(self), loc, ctx)?; - if next_arr - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - if let Some(r) = next_arr.ref_range(self).into_expr_err(loc)? { - let min = r.evaled_range_min(self).into_expr_err(loc)?; - let max = r.evaled_range_max(self).into_expr_err(loc)?; - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(new_rhs)); - next_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.val.insert(Elem::from(index), Elem::from(new_rhs)); - next_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } - } - } - - if let Some(backing_arr) = new_rhs.len_var_to_array(self).into_expr_err(loc)? { - if let Some(r) = backing_arr.ref_range(self).into_expr_err(loc)? { - let min = r.range_min().into_owned(); - let max = r.range_max().into_owned(); - - if let Some(mut rd) = min.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_min(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - - if let Some(mut rd) = max.maybe_range_dyn() { - rd.len = Elem::from(new_lhs); - backing_arr - .set_range_max(self, Elem::ConcreteDyn(Box::new(rd))) - .into_expr_err(loc)?; - } - } - } - + // self.update_array_if_index_access(ctx, loc, new_lhs, new_rhs)?; + // self.update_array_if_index_access(ctx, loc, new_rhs, new_lhs)?; + // self.update_array_if_length_var(ctx, loc, new_lhs)?; + // self.update_array_if_length_var(ctx, loc, new_rhs)?; + let rhs_display_name = new_rhs.display_name(self).into_expr_err(loc)?; let display_name = if rhs_display_name == "true" { (new_lhs.display_name(self).into_expr_err(loc)?).to_string() @@ -1022,6 +952,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { #[tracing::instrument(level = "trace", skip_all)] fn update_nonconst_from_const( &mut self, + ctx: ContextNode, loc: Loc, op: RangeOp, const_var: ContextVarNode, @@ -1046,6 +977,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .set_range_min(self, elem.clone()) .into_expr_err(loc)?; nonconst_var.set_range_max(self, elem).into_expr_err(loc)?; + // self.update_array_min_if_length(ctx, loc, nonconst_var)?; + // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Neq => { @@ -1066,6 +999,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); let min = nonconst_range.range_min().into_owned() + Elem::from(one); nonconst_var.set_range_min(self, min).into_expr_err(loc)?; + self.update_array_min_if_length(ctx, loc, nonconst_var)?; } else if let Some(std::cmp::Ordering::Equal) = nonconst_range .evaled_range_max(self) .into_expr_err(loc)? @@ -1080,6 +1014,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); let max = nonconst_range.range_max().into_owned() - Elem::from(one); nonconst_var.set_range_max(self, max).into_expr_err(loc)?; + // self.update_array_max_if_length(ctx, loc, nonconst_var)?; } else { // just add as an exclusion nonconst_range.add_range_exclusion(elem); @@ -1104,7 +1039,14 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add one to the element because its strict > let Some(max_conc) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!( + "Expected {} to have a concrete range by now. This is likely a bug. Max: {}, expr: {} {} {}", + nonconst_var.display_name(self).unwrap(), + nonconst_range.max, + nonconst_var.display_name(self).unwrap(), + op.to_string(), + const_var.display_name(self).unwrap(), + ))); }; let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); nonconst_var @@ -1113,6 +1055,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (elem + one.into()).max(nonconst_range.range_min().into_owned()), ) .into_expr_err(loc)?; + // self.update_array_min_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Gte => { @@ -1132,6 +1075,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var .set_range_min(self, elem.max(nonconst_range.range_min().into_owned())) .into_expr_err(loc)?; + self.update_array_min_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Lt => { @@ -1149,7 +1093,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add one to the element because its strict > let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected {} to have a concrete range by now. This is likely a bug. Min: {}", nonconst_var.display_name(self).unwrap(), nonconst_range.min))); }; let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); @@ -1159,6 +1103,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (elem - one.into()).min(nonconst_range.range_max().into_owned()), ) .into_expr_err(loc)?; + // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Lte => { @@ -1176,6 +1121,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var .set_range_max(self, elem.min(nonconst_range.range_max().into_owned())) .into_expr_err(loc)?; + // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } e => todo!("Non-comparator in require, {e:?}"), @@ -1185,6 +1131,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Given a const var and a nonconst range, update the range based on the op. Returns whether its impossible fn update_nonconst_from_nonconst( &mut self, + ctx: ContextNode, loc: Loc, op: RangeOp, new_lhs: ContextVarNode, @@ -1246,6 +1193,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } } + // self.update_array_min_if_length(ctx, loc, new_rhs)?; + // self.update_array_min_if_length(ctx, loc, new_lhs)?; + // self.update_array_max_if_length(ctx, loc, new_rhs)?; + // self.update_array_max_if_length(ctx, loc, new_lhs)?; + Ok(false) } RangeOp::Neq => { @@ -1302,6 +1254,9 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (lhs_elem - one.into()).min(rhs_range.range_max().into_owned()), ) .into_expr_err(loc)?; + + // self.update_array_min_if_length(ctx, loc, new_rhs)?; + // self.update_array_min_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Gte => { @@ -1338,9 +1293,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { new_new_rhs .set_range_max(self, new_max) .into_expr_err(loc)?; - // new_rhs - // .set_range_max(self, Elem::Expr(RangeExpr::new(new_rhs.previous_version(self).unwrap().into(), RangeOp::Min, lhs_elem))) - // .into_expr_err(loc)?; + // self.update_array_min_if_length(ctx, loc, new_rhs)?; + // self.update_array_min_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Lt => { @@ -1380,6 +1334,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), ) .into_expr_err(loc)?; + // self.update_array_max_if_length(ctx, loc, new_rhs)?; + // self.update_array_max_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Lte => { @@ -1403,6 +1359,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) .into_expr_err(loc)?; + // self.update_array_max_if_length(ctx, loc, new_rhs.latest_version(self))?; + // self.update_array_max_if_length(ctx, loc, new_lhs.latest_version(self))?; Ok(false) } e => todo!("Non-comparator in require, {e:?}"), diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index c725e930..95dbeacb 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -183,6 +183,7 @@ pub trait YulFuncCaller: lhs_paths .cast_from_ty(cast_ty.clone(), analyzer) .into_expr_err(loc)?; + let rhs_paths = ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); rhs_paths @@ -192,8 +193,8 @@ pub trait YulFuncCaller: analyzer.op_match( ctx, loc, - &ExprRet::Single(lhs_paths.into()), - &ExprRet::Single(rhs_paths.into()), + &ExprRet::Single(lhs_paths.latest_version(analyzer).into()), + &ExprRet::Single(rhs_paths.latest_version(analyzer).into()), op, false, ) @@ -262,7 +263,7 @@ pub trait YulFuncCaller: let expr = Elem::Expr(RangeExpr::new( Elem::from(res), RangeOp::Cast, - Elem::from(Concrete::Uint(1, U256::zero())), + Elem::from(Concrete::Uint(256, U256::zero())), )); next.set_range_min(analyzer, expr.clone()) From eebc10d9d5bee4be579bc9506b8cd5371d98b485 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 10:43:22 -0800 Subject: [PATCH 44/71] works but needs perf improvement --- crates/analyzers/src/bounds.rs | 6 +- crates/cli/src/main.rs | 6 + crates/graph/src/nodes/context/var/node.rs | 29 +++- crates/graph/src/nodes/context/var/ranging.rs | 7 +- crates/graph/src/range/elem/concrete.rs | 4 +- crates/graph/src/range/elem/elem_enum.rs | 39 +++-- crates/graph/src/range/elem/elem_trait.rs | 4 +- crates/graph/src/range/elem/expr.rs | 24 ++-- crates/graph/src/range/elem/map_or_array.rs | 20 +-- crates/graph/src/range/elem/reference.rs | 12 +- crates/graph/src/range/exec/exec_op.rs | 43 ++++-- .../graph/src/range/exec/mem_ops/mem_set.rs | 1 - crates/graph/src/range/exec_traits.rs | 9 +- crates/graph/src/range/range_trait.rs | 2 - crates/graph/src/range/solc_range.rs | 10 +- crates/graph/src/solvers/brute.rs | 4 +- crates/graph/src/var_type.rs | 18 --- crates/pyrometer/src/analyzer.rs | 3 + crates/pyrometer/src/analyzer_backend.rs | 5 + .../pyrometer/tests/test_data/dyn_types.sol | 132 +++++++++++------ crates/pyrometer/tests/test_data/math.sol | 6 + crates/shared/src/analyzer_like.rs | 47 +----- crates/shared/src/graph_like.rs | 8 +- crates/solc-expressions/src/array.rs | 47 +++--- crates/solc-expressions/src/bin_op.rs | 136 +++++++++--------- .../solc-expressions/src/func_call/helper.rs | 12 +- .../func_call/intrinsic_call/dyn_builtin.rs | 4 +- .../src/member_access/list_access.rs | 4 +- crates/solc-expressions/src/require.rs | 26 ---- 29 files changed, 360 insertions(+), 308 deletions(-) diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index 1cbf8ab6..c3b968e6 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -265,9 +265,8 @@ pub fn range_parts( .to_range_string(false, analyzer) .s } else if report_config.simplify_bounds { - let mut exclude = vec![]; range - .simplified_range_min(&mut exclude, analyzer) + .simplified_range_min(analyzer) .unwrap() .to_range_string(false, analyzer) .s @@ -281,9 +280,8 @@ pub fn range_parts( .to_range_string(true, analyzer) .s } else if report_config.simplify_bounds { - let mut exclude = vec![]; range - .simplified_range_max(&mut exclude, analyzer) + .simplified_range_max(analyzer) .unwrap() .to_range_string(true, analyzer) .s diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 5053dc3f..9dc55b6c 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -90,6 +90,10 @@ struct Args { #[clap(long)] pub debug: bool, + /// Forces a panic on first error encountered + #[clap(long)] + pub debug_panic: bool, + /// Max stack depth to evaluate to #[clap(long, default_value = "200")] pub max_stack_depth: usize, @@ -207,6 +211,8 @@ fn main() { let mut analyzer = Analyzer::default(); analyzer.max_depth = args.max_stack_depth; analyzer.root = Root::RemappingsDirectory(env::current_dir().unwrap()); + println!("debug panic: {}", args.debug_panic); + analyzer.debug_panic = args.debug_panic; let (current_path, sol) = if args.path.ends_with(".sol") { let sol = fs::read_to_string(args.path.clone()).expect("Could not find file"); diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index a50d94f7..f6dd7b3b 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -144,18 +144,15 @@ impl ContextVarNode { pub fn as_controllable_name(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ref_range) = self.ref_range(analyzer)? { - let mut exclude = vec![]; - let min_name = ref_range .range_min() - .simplify_minimize(&mut exclude, analyzer)? + .simplify_minimize(&mut Default::default(), analyzer)? .to_range_string(false, analyzer) .s; - exclude = vec![]; let max_name = ref_range .range_max() - .simplify_maximize(&mut exclude, analyzer)? + .simplify_maximize(&mut Default::default(), analyzer)? .to_range_string(true, analyzer) .s; if max_name == min_name { @@ -291,12 +288,30 @@ impl ContextVarNode { &self, analyzer: &impl GraphBackend, return_self: bool, + ) -> Result, GraphError> { + self.dependent_on_no_recursion(analyzer, &mut vec![*self], return_self) + } + + fn dependent_on_no_recursion( + &self, + analyzer: &impl GraphBackend, + seen: &mut Vec, + return_self: bool, ) -> Result, GraphError> { let underlying = self.underlying(analyzer)?; if let Some(tmp) = underlying.tmp_of() { - let mut nodes = tmp.lhs.dependent_on(analyzer, true)?; + let mut nodes = if !seen.contains(&tmp.lhs) { + seen.push(tmp.lhs); + tmp.lhs.dependent_on(analyzer, true)? + } else { + vec![] + }; + if let Some(rhs) = tmp.rhs { - nodes.extend(rhs.dependent_on(analyzer, true)?); + if !seen.contains(&rhs) { + seen.push(rhs); + nodes.extend(rhs.dependent_on(analyzer, true)?); + } } Ok(nodes) } else if return_self { diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 7d106dea..dd2e3102 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -112,14 +112,15 @@ impl ContextVarNode { pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if let Some(mut range) = self.range(analyzer)? { - range.cache_eval(analyzer)?; range.cache_flatten(analyzer)?; + range.cache_eval(analyzer)?; self.set_range(analyzer, range)?; } - // self.cache_flattened_range(analyzer)?; Ok(()) } + + // pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { // if let Some(mut range) = self.range(analyzer)? { // range.cache_flatten(analyzer)?; @@ -214,7 +215,7 @@ impl ContextVarNode { } tracing::trace!( - "setting range maximum: {:?}, {}, current: {}, new: {:#?}", + "setting range maximum: {:?}, {}, current: {}, new: {}", self, self.display_name(analyzer)?, self.ref_range(analyzer)?.unwrap().range_max(), // .unwrap() diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index a1116e48..f3d0d814 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -139,14 +139,14 @@ impl RangeElem for RangeConcrete { fn simplify_maximize( &self, - _exclude: &mut Vec, + _seen_ops: &mut BTreeMap, Elem>, _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_minimize( &self, - _exclude: &mut Vec, + _seen_ops: &mut BTreeMap, Elem>, _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index c7b2d1c0..90cd40e1 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -660,20 +660,24 @@ impl RangeElem for Elem { fn simplify_maximize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(res) = seen_ops.get(&self) { + return Ok(res.clone()) + } + use Elem::*; match self { - Reference(dy) => dy.simplify_maximize(exclude, analyzer), - Concrete(inner) => inner.simplify_maximize(exclude, analyzer), - ConcreteDyn(inner) => inner.simplify_maximize(exclude, analyzer), + Reference(dy) => dy.simplify_maximize(seen_ops, analyzer), + Concrete(inner) => inner.simplify_maximize(seen_ops, analyzer), + ConcreteDyn(inner) => inner.simplify_maximize(seen_ops, analyzer), Expr(expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_maximize(exclude, analyzer) + collapsed.simplify_maximize(seen_ops, analyzer) } - _ => expr.simplify_maximize(exclude, analyzer) + _ => expr.simplify_maximize(seen_ops, analyzer) } } Null => Ok(Elem::Null), @@ -682,24 +686,31 @@ impl RangeElem for Elem { fn simplify_minimize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if let Some(res) = seen_ops.get(&self) { + return Ok(res.clone()) + } + use Elem::*; - match self { - Reference(dy) => dy.simplify_minimize(exclude, analyzer), - Concrete(inner) => inner.simplify_minimize(exclude, analyzer), - ConcreteDyn(inner) => inner.simplify_minimize(exclude, analyzer), + let res = match self { + Reference(dy) => dy.simplify_minimize(seen_ops, analyzer), + Concrete(inner) => inner.simplify_minimize(seen_ops, analyzer), + ConcreteDyn(inner) => inner.simplify_minimize(seen_ops, analyzer), Expr(expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_minimize(exclude, analyzer) + collapsed.simplify_minimize(seen_ops, analyzer) } - _ => expr.simplify_minimize(exclude, analyzer) + _ => expr.simplify_minimize(seen_ops, analyzer) } }, Null => Ok(Elem::Null), - } + }?; + + seen_ops.insert(self.clone(), res.clone()); + Ok(res) } fn cache_maximize(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index d557a000..14577171 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -33,13 +33,13 @@ pub trait RangeElem { /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) fn simplify_maximize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) fn simplify_minimize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Checks if two range elements are equal diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 94121470..c0234c13 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -163,7 +163,7 @@ impl RangeElem for RangeExpr { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { Ok(*cached) } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(true, &mut vec![], analyzer) + self.simplify_exec_op(true, &mut Default::default(), analyzer) } else { self.exec_op(true, analyzer) } @@ -172,7 +172,7 @@ impl RangeElem for RangeExpr { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { Ok(*cached) } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(false, &mut vec![], analyzer) + self.simplify_exec_op(false, &mut Default::default(), analyzer) } else { self.exec_op(false, analyzer) } @@ -180,15 +180,15 @@ impl RangeElem for RangeExpr { fn simplify_maximize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_max) = &self.flattened_max { return Ok(*simp_max.clone()); } - let l = self.lhs.simplify_maximize(exclude, analyzer)?; - let r = self.rhs.simplify_maximize(exclude, analyzer)?; + let l = self.lhs.simplify_maximize(seen_ops, analyzer)?; + let r = self.rhs.simplify_maximize(seen_ops, analyzer)?; let collapsed = collapse(l, self.op, r); match collapsed { MaybeCollapsed::Concretes(l, r) => { @@ -197,7 +197,7 @@ impl RangeElem for RangeExpr { MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(l, r) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - match RangeExpr::new(l, self.op, r).simplify_exec_op(true, &mut vec![], analyzer)? { + match RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(true, analyzer), @@ -212,15 +212,15 @@ impl RangeElem for RangeExpr { } fn simplify_minimize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_min) = &self.flattened_min { return Ok(*simp_min.clone()); } - let l = self.lhs.simplify_minimize(exclude, analyzer)?; - let r = self.rhs.simplify_minimize(exclude, analyzer)?; + let l = self.lhs.simplify_minimize(seen_ops, analyzer)?; + let r = self.rhs.simplify_minimize(seen_ops, analyzer)?; let collapsed = collapse(l, self.op, r); match collapsed { MaybeCollapsed::Concretes(l, r) => { @@ -229,7 +229,7 @@ impl RangeElem for RangeExpr { MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(l, r) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - match RangeExpr::new(l, self.op, r).simplify_exec_op(false, &mut vec![], analyzer)? { + match RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(false, analyzer), @@ -246,12 +246,12 @@ impl RangeElem for RangeExpr { fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 673b2c96..dc0c788b 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -228,12 +228,12 @@ impl RangeElem for RangeDyn { fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) @@ -277,7 +277,7 @@ impl RangeElem for RangeDyn { // We dont maximize the key so that any subsequent // `get_index` can find potential values let maximized = val.0.maximize(analyzer)?; - map.insert(idx.simplify_maximize(&mut vec![], analyzer)?, (maximized, val.1)); + map.insert(idx.simplify_maximize(&mut Default::default(), analyzer)?, (maximized, val.1)); } // map.into_iter().filter(|(k, (v, op))| { @@ -302,7 +302,7 @@ impl RangeElem for RangeDyn { // We dont minimize the key so that any subsequent // `get_index` can find potential values let minimized = val.0.minimize(analyzer)?; - map.insert(idx.simplify_minimize(&mut vec![], analyzer)?, (minimized, val.1)); + map.insert(idx.simplify_minimize(&mut Default::default(), analyzer)?, (minimized, val.1)); } // map.into_iter().filter(|(k, (v, op))| { @@ -316,20 +316,20 @@ impl RangeElem for RangeDyn { fn simplify_maximize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(max) = &self.flattened_max { return Ok(*max.clone()); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_maximize(exclude, analyzer)?, + self.len.simplify_maximize(seen_ops, analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_maximize(exclude, analyzer)?; + let simplified = val.0.simplify_maximize(seen_ops, analyzer)?; map.insert(idx, (simplified, val.1)); } map @@ -340,7 +340,7 @@ impl RangeElem for RangeDyn { } fn simplify_minimize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(min) = &self.flattened_min { @@ -348,13 +348,13 @@ impl RangeElem for RangeDyn { } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_minimize(exclude, analyzer)?, + self.len.simplify_minimize(seen_ops, analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_minimize(exclude, analyzer)?; + let simplified = val.0.simplify_minimize(seen_ops, analyzer)?; map.insert(idx, (simplified, val.1)); } map diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 71c239eb..acb97fa0 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -133,12 +133,12 @@ impl RangeElem for Reference { fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut vec![], g)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut vec![], g)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) @@ -198,7 +198,7 @@ impl RangeElem for Reference { fn simplify_maximize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_max) = &self.flattened_max { @@ -214,13 +214,13 @@ impl RangeElem for Reference { ))) } else { self.flatten(true, analyzer)? - .simplify_maximize(exclude, analyzer) + .simplify_maximize(seen_ops, analyzer) } } fn simplify_minimize( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_min) = &self.flattened_min { @@ -234,7 +234,7 @@ impl RangeElem for Reference { ))) } else { self.flatten(false, analyzer)? - .simplify_minimize(exclude, analyzer) + .simplify_minimize(seen_ops, analyzer) } } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index adecbb60..a25a8a54 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -1,4 +1,3 @@ -use crate::nodes::ContextVarNode; use crate::{ nodes::Concrete, range::{elem::*, exec_traits::*}, @@ -10,6 +9,8 @@ use shared::NodeIdx; use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; +use std::collections::BTreeMap; + impl ExecOp for RangeExpr { type GraphError = GraphError; @@ -47,10 +48,24 @@ impl ExecOp for RangeExpr { fn simplify_exec_op( &self, maximize: bool, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(exclude, analyzer)?; + if let Some(res) = seen_ops.get(&Elem::Expr(self.clone())) { + return Ok(res.clone()); + } + + let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(seen_ops, analyzer)?; + tracing::trace!( + "simplifying op: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", + self.lhs, + self.op.to_string(), + self.rhs, + lhs_min, + lhs_max, + rhs_min, + rhs_max + ); let lhs_is_conc = lhs_min.is_conc() && lhs_max.is_conc(); let rhs_is_conc = rhs_min.is_conc() && rhs_max.is_conc(); if self.op == RangeOp::Cast { @@ -173,7 +188,7 @@ impl ExecOp for RangeExpr { fn simplify_spread( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result< ( @@ -184,10 +199,10 @@ impl ExecOp for RangeExpr { ), GraphError, > { - let lhs_min = self.lhs.simplify_minimize(exclude, analyzer)?; - let lhs_max = self.lhs.simplify_maximize(exclude, analyzer)?; - let rhs_min = self.rhs.simplify_minimize(exclude, analyzer)?; - let rhs_max = self.rhs.simplify_maximize(exclude, analyzer)?; + let lhs_min = self.lhs.simplify_minimize(seen_ops, analyzer)?; + let lhs_max = self.lhs.simplify_maximize(seen_ops, analyzer)?; + let rhs_min = self.rhs.simplify_minimize(seen_ops, analyzer)?; + let rhs_max = self.rhs.simplify_maximize(seen_ops, analyzer)?; Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } @@ -250,12 +265,12 @@ impl ExecOp for RangeExpr { if maximize { let mut new = lhs_max.clone(); new.uncache(); - let new_max = new.simplify_minimize(&mut vec![], analyzer)?; + let new_max = new.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_max.range_get_length(); res .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { - let new_min = lhs_min.simplify_minimize(&mut vec![], analyzer)?; + let new_min = lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_min.range_get_length(); res .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) @@ -289,7 +304,7 @@ impl ExecOp for RangeExpr { })?.unwrap_or_else(|| Elem::Null)) } Elem::Reference(_) => { - let new_max = lhs_max.simplify_maximize(&mut vec![], analyzer)?; + let new_max = lhs_max.simplify_maximize(&mut Default::default(), analyzer)?; if new_max == lhs_max { Ok(Elem::Null) } else { @@ -319,7 +334,7 @@ impl ExecOp for RangeExpr { })?.unwrap_or_else(|| Elem::Null)) } Elem::Reference(ref _r) => { - let new_min = lhs_min.simplify_minimize(&mut vec![], analyzer)?; + let new_min = lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; if new_min == lhs_min { Ok(Elem::Null) } else { @@ -335,7 +350,7 @@ impl ExecOp for RangeExpr { }, RangeOp::SetIndices => { if maximize { - let max = self.rhs.simplify_maximize(&mut vec![], analyzer)?; + let max = self.rhs.simplify_maximize(&mut Default::default(), analyzer)?; lhs_max.range_set_indices(&rhs_max) .unwrap_or_else(|| { @@ -343,7 +358,7 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) }) } else { - let min = self.rhs.simplify_minimize(&mut vec![], analyzer)?; + let min = self.rhs.simplify_minimize(&mut Default::default(), analyzer)?; lhs_min.range_set_indices(&rhs_min) .unwrap_or_else(|| { lhs_min.range_set_indices(&min) diff --git a/crates/graph/src/range/exec/mem_ops/mem_set.rs b/crates/graph/src/range/exec/mem_ops/mem_set.rs index 40c0e443..16e010e8 100644 --- a/crates/graph/src/range/exec/mem_ops/mem_set.rs +++ b/crates/graph/src/range/exec/mem_ops/mem_set.rs @@ -159,7 +159,6 @@ impl RangeMemSet> for RangeConcrete { impl RangeMemSet for Elem { fn range_set_indices(&self, other: &Elem) -> Option> { - println!("setting indices: {self}, {other}"); match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_set_indices(b), (Elem::ConcreteDyn(a), Elem::Concrete(b)) => a.range_set_indices(b), diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index 88858fb1..d0671dd7 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,5 +1,6 @@ -use crate::{range::elem::{RangeDyn, Elem}, GraphBackend}; -use shared::NodeIdx; +use crate::{range::elem::{Elem}, GraphBackend}; +use std::collections::BTreeMap; + /// For execution of operations to be performed on range expressions pub trait ExecOp { @@ -32,7 +33,7 @@ pub trait ExecOp { fn simplify_spread( &self, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; @@ -41,7 +42,7 @@ pub trait ExecOp { fn simplify_exec_op( &self, maximize: bool, - exclude: &mut Vec, + seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index 20f68779..23163d88 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -20,13 +20,11 @@ pub trait Range { /// Simplify the minimum, leaving references in place fn simplified_range_min( &self, - exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result; /// Simplify the maximum, leaving references in place fn simplified_range_max( &self, - exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result; /// Return the range minimum diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index d4560156..18025607 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -569,13 +569,13 @@ impl SolcRange { let flattened_min = self.range_min().flatten(false, analyzer)?; let simp_min = if !self.range_min().is_flatten_cached() { - flattened_min.simplify_minimize(&mut vec![], analyzer)? + flattened_min.simplify_minimize(&mut Default::default(), analyzer)? } else { flattened_min }; let flattened_max = self.range_max().flatten(true, analyzer)?; let simp_max = if !self.range_max().is_flatten_cached() { - flattened_max.simplify_maximize(&mut vec![], analyzer)? + flattened_max.simplify_maximize(&mut Default::default(), analyzer)? } else { flattened_max }; @@ -634,21 +634,19 @@ impl Range for SolcRange { fn simplified_range_min( &self, - exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result { self.range_min() .flatten(false, analyzer)? - .simplify_minimize(exclude, analyzer) + .simplify_minimize(&mut Default::default(), analyzer) } fn simplified_range_max( &self, - exclude: &mut Vec, analyzer: &impl GraphBackend, ) -> Result { self.range_max() .flatten(true, analyzer)? - .simplify_maximize(exclude, analyzer) + .simplify_maximize(&mut Default::default(), analyzer) } fn range_exclusions(&self) -> Vec { diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 97de610d..d72138ed 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -605,7 +605,7 @@ impl SolcSolver for BruteBinSearchSolver { .filter_map(|(_, range)| { if let Some(atom) = range .min - .simplify_minimize(&mut vec![], analyzer) + .simplify_minimize(&mut Default::default(), analyzer) .unwrap() .atomize() { @@ -613,7 +613,7 @@ impl SolcSolver for BruteBinSearchSolver { } else { range .max - .simplify_maximize(&mut vec![], analyzer) + .simplify_maximize(&mut Default::default(), analyzer) .unwrap() .atomize() } diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index c91974f9..924b4a64 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -599,24 +599,6 @@ impl VarType { // } // } - pub fn get_index_dynamic_ty( - &self, - index: ContextVarNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { - // if let Some(var_ty) = self.try_match_index_dynamic_ty(index, analyzer)? { - // Ok(VarType::try_from_idx(analyzer, var_ty).unwrap()) - // } else { - match self { - Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), - Self::Concrete(node) => node.dynamic_underlying_ty(analyzer), - e => Err(GraphError::NodeConfusion(format!( - "Node type confusion: expected node to be Builtin but it was: {e:?}" - ))), - } - // } - } - pub fn dynamic_underlying_ty( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 6a3cb304..ae0ba5fc 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -123,6 +123,8 @@ pub struct Analyzer { pub max_width: usize, /// Dummy function used during parsing to attach contexts to for more complex first-pass parsing (i.e. before `final_pass`) pub parse_fn: FunctionNode, + /// Whether to force a panic on first error encountered + pub debug_panic: bool, } impl Default for Analyzer { @@ -146,6 +148,7 @@ impl Default for Analyzer { max_depth: 200, max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), + debug_panic: false, }; a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 3c7fcf4f..4c0a8dde 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -45,6 +45,9 @@ impl AnalyzerLike for Analyzer { } fn add_expr_err(&mut self, err: ExprErr) { + if self.debug_panic() { + panic!("Encountered an error: {err:?}"); + } if !self.expr_errs.contains(&err) { self.expr_errs.push(err); } @@ -223,4 +226,6 @@ impl AnalyzerLike for Analyzer { None } } + + fn debug_panic(&self) -> bool { self.debug_panic } } diff --git a/crates/pyrometer/tests/test_data/dyn_types.sol b/crates/pyrometer/tests/test_data/dyn_types.sol index 139c1e9f..c6a3f878 100644 --- a/crates/pyrometer/tests/test_data/dyn_types.sol +++ b/crates/pyrometer/tests/test_data/dyn_types.sol @@ -1,51 +1,103 @@ contract DynTypes { - uint256[] storeVar; + // uint256[] storeVar; - function bytes_dyn(bytes calldata x) public { - bytes memory y = x; - require(x.length < 10); - y[8] = 0xff; - require(y.length == 9); - } + // struct Strukt { + // uint256 a; + // uint256 b; + // } - function array_dyn(uint256[] calldata x) public { - x[0] = 5; - require(x.length < 10); - uint256[] memory y = x; - y[8] = 100; - require(y.length == 9); - } + // mapping (address => Strukt) public someMapping; - function nested_bytes_dyn(bytes[] calldata x, uint y) public returns (bytes1) { - bytes memory a = hex"1337"; - x[0] = a; - require(x[0][0] == hex"13"); - // return x[0][0]; + // function bytes_dyn(bytes calldata x) public { + // bytes memory y = x; + // require(x.length < 10); + // y[8] = 0xff; + // require(y.length == 9); + // } - x[y] = hex"1122"; - uint256 z = y - 1; - require(x[z + 1][0] == hex"11"); - } + // function array_dyn(uint256[] calldata x) public { + // x[0] = 5; + // require(x.length < 10); + // uint256[] memory y = x; + // y[8] = 100; + // require(y.length == 9); + // } - function array_push(uint256 x) public { - // require(x > 5); - storeVar.push(x); - storeVar.push(x); - storeVar.push(x); - // TODO: handle this better - require(storeVar[0] == x); - storeVar.push(x); - require(storeVar[1] == x); - uint256 y = storeVar[storeVar.length - 1]; - storeVar.pop(); - require(y == x); - } + // function nested_bytes_dyn(bytes[] calldata x, uint y) public returns (bytes1) { + // bytes memory a = hex"1337"; + // x[0] = a; + // require(x[0][0] == hex"13"); + // // return x[0][0]; + + // x[y] = hex"1122"; + // uint256 z = y - 1; + // require(x[z + 1][0] == hex"11"); + // } + + // function array_push(uint256 x) public { + // // require(x > 5); + // storeVar.push(x); + // storeVar.push(x); + // storeVar.push(x); + // // TODO: handle this better + // require(storeVar[0] == x); + // storeVar.push(x); + // require(storeVar[1] == x); + // uint256 y = storeVar[storeVar.length - 1]; + // storeVar.pop(); + // require(y == x); + // } + + // function indexInto() public returns (uint256) { + // return storeVar[basicFunc()]; + // } - function indexInto() public returns (uint256) { - return storeVar[basicFunc()]; + // function basicFunc() public returns (uint256) { + // return 1; + // } + + // function indexIntoMapping(address who) public { + // // TODO: this should panic + // Strukt storage a = someMapping[who]; + // a.a = 100; + // a.b = 100; + // require(someMapping[who].a == 300); + // } + + // function a(address a, address b) internal { + + // } + + address[] t; + + // function inLoop(address holder) public { + // inLoop(holder, t); + // } + + function inLoop(address holder, address[] memory tokens) public { + address[] memory h = new address[](1); + h[0] = holder; + inLoop(h, tokens); } + + function inLoop(address[] memory holders, address[] memory tokens) public { - function basicFunc() public returns (uint256) { - return 1; + // for (uint i = 0; i < tokens.length; i++) { + // address token = tokens[i]; + for (uint j = 0; j < holders.length; j++) { + address holder = holders[j]; + // a(token, holders[j]); + } + // if (suppliers == true) { + // updateCompSupplyIndex(address(cToken)); + // for (uint j = 0; j < holders.length; j++) { + // distributeSupplierComp(address(cToken), holders[j]); + // } + // } + // } + // for (uint j = 0; j < holders.length; j++) { + // compAccrued[holders[j]] = grantCompInternal(holders[j], compAccrued[holders[j]]); + // } } + } diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index d43550ad..c566b970 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -627,7 +627,13 @@ contract Unchecked { function symbUncheckedMul(int256 a, int b) public { unchecked { a = a * b; + int c = a * a / a; + int d = a * c * b; } + + a = a * b; + int c = a * a / a; + int d = a * c * b; } function asmSymbUncheckedMul(int256 a, int b) public { diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 9d323e7e..61a1db42 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -46,52 +46,13 @@ pub trait AnalyzerLike: GraphLike { ) -> &HashMap, Vec)>; fn builtins(&self) -> &HashMap; fn builtins_mut(&mut self) -> &mut HashMap; - fn builtin_or_add(&mut self, builtin: Self::Builtin) -> NodeIdx; - // { - // if let Some(idx) = self.builtins().get(&builtin) { - // *idx - // } else { - // let idx = self.add_node(Node::Builtin(builtin.clone())); - // self.builtins_mut().insert(builtin, idx); - // idx - // } - // } fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option where Self: std::marker::Sized; - // { - // if let Some(idx) = self.builtin_fn_nodes().get(builtin_name) { - // Some(*idx) - // } else if let Some(func) = self.builtin_fns().get(builtin_name) { - // let (inputs, outputs) = self - // .builtin_fn_inputs() - // .get(builtin_name) - // .expect("builtin func but no inputs") - // .clone(); - // let func_node = self.add_node(Node::Function(func.clone())); - // let mut params_strs = vec![]; - // inputs.into_iter().for_each(|input| { - // let input_node = self.add_node(input); - // params_strs.push(FunctionParamNode::from(input_node).ty_str(self).unwrap()); - // self.add_edge(input_node, func_node, Edge::FunctionParam); - // }); - // outputs.into_iter().for_each(|output| { - // let output_node = self.add_node(output); - // self.add_edge(output_node, func_node, Edge::FunctionReturn); - // }); - - // self.add_edge(func_node, self.entry(), Edge::Func); - - // self.builtin_fn_nodes_mut() - // .insert(builtin_name.to_string(), func_node); - // Some(func_node) - // } else { - // None - // } - // } - - fn add_if_err(&mut self, err: Result) -> Option { + + fn debug_panic(&self) -> bool; + fn add_if_err(&mut self, err: Result) -> Option where Self::ExprErr: std::fmt::Debug { match err { Ok(t) => Some(t), Err(e) => { @@ -100,4 +61,6 @@ pub trait AnalyzerLike: GraphLike { } } } + + } diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 792bfe80..761fdcf7 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -23,7 +23,13 @@ pub trait GraphLike { fn graph(&self) -> &Graph; /// Add a node to the graph fn add_node(&mut self, node: impl Into) -> NodeIdx { - self.graph_mut().add_node(node.into()) + let res = self.graph_mut().add_node(node.into()); + // if res == 81.into() { + // panic!("here"); + // } else { + // res + // } + res } /// Get a reference to a node in the graph fn node(&self, node: impl Into) -> &Self::Node { diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index dda2dd80..4c09a61c 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -155,7 +155,6 @@ pub trait Array: AnalyzerBackend + Sized { length_requirement: bool, return_var: bool, ) -> Result, ExprErr> { - println!("access array: {}, parent: {}", index.display_name(self).unwrap(), parent.display_name(self).unwrap()); let idx = self.advance_var_in_ctx(index, loc, ctx)?; if length_requirement && !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { let len_var = self.get_length(ctx, loc, parent, true)?.unwrap().latest_version(self); @@ -182,8 +181,9 @@ pub trait Array: AnalyzerBackend + Sized { } } else { let ty = parent.ty(self).into_expr_err(loc)?.clone(); - let ty = ty.get_index_dynamic_ty(index, self).into_expr_err(loc)?; - // println!("index access ty: {:?#") + + let ty = ty.dynamic_underlying_ty(self).into_expr_err(loc)?; + let has_range = ty.ref_range(self).into_expr_err(loc)?.is_some(); let index_access_var = ContextVar { loc: Some(loc), name: name.clone(), @@ -206,25 +206,30 @@ pub trait Array: AnalyzerBackend + Sized { ctx.add_var(idx_access_node.into(), self).into_expr_err(loc)?; self.add_edge(index, idx_access_node, Edge::Context(ContextEdge::Index)); - let min = Elem::from(parent).get_index(index.into()).max(ContextVarNode::from(idx_access_node).into()); //.range_min(self).unwrap().unwrap()); - let max = Elem::from(parent).get_index(index.into()).min(ContextVarNode::from(idx_access_node).into()); //.range_max(self).unwrap().unwrap()); - - let idx_access_cvar = self.advance_var_in_ctx_forcible(ContextVarNode::from(idx_access_node), loc, ctx, true)?; - idx_access_cvar.set_range_min(self, min).into_expr_err(loc)?; - idx_access_cvar.set_range_max(self, max).into_expr_err(loc)?; + let idx_access_cvar = if has_range { + let min = Elem::from(parent).get_index(index.into()).max(ContextVarNode::from(idx_access_node).into()); //.range_min(self).unwrap().unwrap()); + let max = Elem::from(parent).get_index(index.into()).min(ContextVarNode::from(idx_access_node).into()); //.range_max(self).unwrap().unwrap()); + + let idx_access_cvar = self.advance_var_in_ctx(ContextVarNode::from(idx_access_node), loc, ctx)?; + idx_access_cvar.set_range_min(self, min).into_expr_err(loc)?; + idx_access_cvar.set_range_max(self, max).into_expr_err(loc)?; - if idx_access_cvar - .underlying(self) - .into_expr_err(loc)? - .ty - .is_dyn_builtin(self) - .into_expr_err(loc)? - { - // if the index access is also an array, produce a length variable - // we specify to return the variable because we dont want it on the stack - let _ = self.get_length(ctx, loc, idx_access_node.into(), true)?; + if idx_access_cvar + .underlying(self) + .into_expr_err(loc)? + .ty + .is_dyn_builtin(self) + .into_expr_err(loc)? + { + // if the index access is also an array, produce a length variable + // we specify to return the variable because we dont want it on the stack + let _ = self.get_length(ctx, loc, idx_access_node.into(), true)?; - } + } + idx_access_cvar + } else { + ContextVarNode::from(idx_access_node) + }; if !return_var { ctx.push_expr(ExprRet::Single(idx_access_cvar.latest_version(self).into()), self).into_expr_err(loc)?; @@ -242,10 +247,8 @@ pub trait Array: AnalyzerBackend + Sized { maybe_index_access: ContextVarNode, new_value: ContextVarNode ) -> Result<(), ExprErr> { - // println!("checking if array access: {} (idx {})", maybe_index_access.display_name(self).unwrap(), maybe_index_access.0); if let Some(arr) = maybe_index_access.index_access_to_array(self) { // Was indeed an indexed value - // println!("updating index to array: {}, index: {}", arr.display_name(self).unwrap(), maybe_index_access.display_name(self).unwrap()); if let Some(index) = maybe_index_access.index_access_to_index(self) { // Found the associated index let next_arr = self.advance_var_in_ctx(arr.latest_version(self), loc, ctx)?; diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index df1d280c..60db9c9c 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -221,7 +221,10 @@ pub trait BinOp: AnalyzerBackend + Sized { if !unchecked { match op { RangeOp::Div(..) | RangeOp::Mod => { + // x / y + if new_rhs.is_const(self).into_expr_err(loc)? { + // y is constant, do a check if it is 0 if new_rhs .evaled_range_min(self) .into_expr_err(loc)? @@ -234,6 +237,7 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { + // y is symbolic, add let tmp_rhs = self.advance_var_in_ctx(new_rhs, loc, ctx)?; let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); let var = ContextVar::new_from_concrete( @@ -259,68 +263,70 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} != 0)", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} != 0)", - tmp_rhs.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - new_lhs, - RangeOp::Gt, - Some(zero_node.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - - let range = tmp_rhs - .ref_range(self) - .into_expr_err(loc)? - .expect("No range?"); - if range.min_is_negative(self).into_expr_err(loc)? { - let mut range_excls = range.range_exclusions(); - let excl = Elem::from(Concrete::from(I256::zero())); - if !range_excls.contains(&excl) { - range_excls.push(excl); - } - tmp_rhs - .set_range_exclusions(self, range_excls) - .into_expr_err(loc)?; - } else { - // the new min is max(1, rhs.min) - let min = Elem::max( - Elem::from(Reference::new(new_rhs.into())), - // tmp_rhs - // .range_min(self) - // .into_expr_err(loc)? - // .unwrap_or_else(|| { - // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) - // }), - Elem::from(Concrete::from(U256::from(1))).cast( - Elem::from(Reference::new(tmp_rhs.into())), // .range_min(self) - // .into_expr_err(loc)? - // .expect("No range minimum?"), - ), - ); - - tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; - new_rhs = tmp_rhs; - } + // let tmp_rhs = tmp_rhs.latest_version(self); + + // let tmp_var = ContextVar { + // loc: Some(loc), + // name: format!( + // "tmp{}({} != 0)", + // ctx.new_tmp(self).into_expr_err(loc)?, + // tmp_rhs.name(self).into_expr_err(loc)?, + // ), + // display_name: format!( + // "({} != 0)", + // tmp_rhs.display_name(self).into_expr_err(loc)?, + // ), + // storage: None, + // is_tmp: true, + // tmp_of: Some(TmpConstruction::new( + // new_lhs, + // RangeOp::Neq, + // Some(zero_node.into()), + // )), + // is_symbolic: true, + // is_return: false, + // ty: VarType::BuiltIn( + // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + // SolcRange::from(Concrete::Bool(true)), + // ), + // }; + + // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + + // let range = tmp_rhs + // .ref_range(self) + // .into_expr_err(loc)? + // .expect("No range?"); + // if range.min_is_negative(self).into_expr_err(loc)? { + // let mut range_excls = range.range_exclusions(); + // let excl = Elem::from(Concrete::from(I256::zero())); + // if !range_excls.contains(&excl) { + // range_excls.push(excl); + // } + // tmp_rhs + // .set_range_exclusions(self, range_excls) + // .into_expr_err(loc)?; + // } else { + // // the new min is max(1, rhs.min) + // let min = Elem::max( + // Elem::from(Reference::new(new_rhs.into())), + // // tmp_rhs + // // .range_min(self) + // // .into_expr_err(loc)? + // // .unwrap_or_else(|| { + // // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) + // // }), + // Elem::from(Concrete::from(U256::from(1))).cast( + // Elem::from(Reference::new(tmp_rhs.into())), // .range_min(self) + // // .into_expr_err(loc)? + // // .expect("No range minimum?"), + // ), + // ); + + // tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; + // new_rhs = tmp_rhs; + // } } } RangeOp::Sub(..) => { @@ -429,7 +435,7 @@ pub trait BinOp: AnalyzerBackend + Sized { max_node.into(), new_rhs, ctx, - RangeOp::Sub(false), + RangeOp::Sub(true), false, )?; @@ -516,7 +522,7 @@ pub trait BinOp: AnalyzerBackend + Sized { let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); let tmp_rhs = - self.op(loc, max_node.into(), new_rhs, ctx, RangeOp::Div(true), true)?; + self.op(loc, max_node.into(), new_rhs, ctx, RangeOp::Div(true), false)?; if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { return Ok(tmp_rhs); @@ -539,6 +545,8 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } + let tmp_rhs = ContextVarNode::from(tmp_rhs).latest_version(self); + let tmp_var = ContextVar { loc: Some(loc), name: format!( diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 62446fd3..66a282e0 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -1,5 +1,5 @@ //! Helper traits & blanket implementations that help facilitate performing function calls. -use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, member_access::ListAccess}; use graph::{ nodes::{ @@ -43,7 +43,7 @@ pub trait CallerHelper: AnalyzerBackend + let mut new_cvar = self.add_if_err(res)?; new_cvar.loc = Some(param.loc(self).unwrap()); new_cvar.name = name.clone(); - new_cvar.display_name = name; + new_cvar.display_name = name.clone(); new_cvar.is_tmp = false; new_cvar.storage = if let Some(StorageLocation::Storage(_)) = param.underlying(self).unwrap().storage @@ -70,6 +70,14 @@ pub trait CallerHelper: AnalyzerBackend + Edge::Context(ContextEdge::InputVariable), ); + + + if let Some(_len_var) = input.array_to_len_var(self) { + // bring the length variable along as well + self.get_length(callee_ctx, loc, node, false).unwrap(); + } + let node = node.latest_version(self); + if let (Some(r), Some(r2)) = (node.range(self).unwrap(), param.range(self).unwrap()) { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index 5a8c67c8..bf3b65e1 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -232,8 +232,8 @@ pub trait DynBuiltinCaller: AnalyzerBackend { - let min = r.min.clone().concat(r2.min.clone()).simplify_minimize(&mut vec![], self).into_expr_err(loc)?; - let max = r.max.clone().concat(r2.max.clone()).simplify_maximize(&mut vec![], self).into_expr_err(loc)?; + let min = r.min.clone().concat(r2.min.clone()).simplify_minimize(&mut Default::default(), self).into_expr_err(loc)?; + let max = r.max.clone().concat(r2.max.clone()).simplify_maximize(&mut Default::default(), self).into_expr_err(loc)?; accum.set_range_min(self, min).into_expr_err(loc)?; accum.set_range_max(self, max).into_expr_err(loc)?; Ok(()) diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index baae63a6..e1d85d22 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -180,8 +180,8 @@ pub trait ListAccess: AnalyzerBackend + Si .unwrap() { if let Some(r) = next_arr.ref_range(self).unwrap() { - let min = r.simplified_range_min(&mut vec![], self).unwrap(); - let max = r.simplified_range_max(&mut vec![], self).unwrap(); + let min = r.simplified_range_min(self).unwrap(); + let max = r.simplified_range_max(self).unwrap(); if let Some(mut rd) = min.maybe_range_dyn() { ContextVarNode::from(len_node).set_range_min(self, *rd.len.clone()).unwrap(); rd.len = Box::new(Elem::from(len_node)); diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 8f5bbe5d..aa96d0ef 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -764,11 +764,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } new_rhs = new_rhs.latest_version(self); new_lhs = new_lhs.latest_version(self); - - // self.update_array_if_index_access(ctx, loc, new_lhs, new_rhs)?; - // self.update_array_if_index_access(ctx, loc, new_rhs, new_lhs)?; - // self.update_array_if_length_var(ctx, loc, new_lhs)?; - // self.update_array_if_length_var(ctx, loc, new_rhs)?; let rhs_display_name = new_rhs.display_name(self).into_expr_err(loc)?; let display_name = if rhs_display_name == "true" { @@ -977,8 +972,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .set_range_min(self, elem.clone()) .into_expr_err(loc)?; nonconst_var.set_range_max(self, elem).into_expr_err(loc)?; - // self.update_array_min_if_length(ctx, loc, nonconst_var)?; - // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Neq => { @@ -999,7 +992,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); let min = nonconst_range.range_min().into_owned() + Elem::from(one); nonconst_var.set_range_min(self, min).into_expr_err(loc)?; - self.update_array_min_if_length(ctx, loc, nonconst_var)?; } else if let Some(std::cmp::Ordering::Equal) = nonconst_range .evaled_range_max(self) .into_expr_err(loc)? @@ -1014,7 +1006,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); let max = nonconst_range.range_max().into_owned() - Elem::from(one); nonconst_var.set_range_max(self, max).into_expr_err(loc)?; - // self.update_array_max_if_length(ctx, loc, nonconst_var)?; } else { // just add as an exclusion nonconst_range.add_range_exclusion(elem); @@ -1055,7 +1046,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (elem + one.into()).max(nonconst_range.range_min().into_owned()), ) .into_expr_err(loc)?; - // self.update_array_min_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Gte => { @@ -1075,7 +1065,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var .set_range_min(self, elem.max(nonconst_range.range_min().into_owned())) .into_expr_err(loc)?; - self.update_array_min_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Lt => { @@ -1103,7 +1092,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (elem - one.into()).min(nonconst_range.range_max().into_owned()), ) .into_expr_err(loc)?; - // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } RangeOp::Lte => { @@ -1121,7 +1109,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var .set_range_max(self, elem.min(nonconst_range.range_max().into_owned())) .into_expr_err(loc)?; - // self.update_array_max_if_length(ctx, loc, nonconst_var)?; Ok(false) } e => todo!("Non-comparator in require, {e:?}"), @@ -1193,11 +1180,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } } - // self.update_array_min_if_length(ctx, loc, new_rhs)?; - // self.update_array_min_if_length(ctx, loc, new_lhs)?; - // self.update_array_max_if_length(ctx, loc, new_rhs)?; - // self.update_array_max_if_length(ctx, loc, new_lhs)?; - Ok(false) } RangeOp::Neq => { @@ -1255,8 +1237,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ) .into_expr_err(loc)?; - // self.update_array_min_if_length(ctx, loc, new_rhs)?; - // self.update_array_min_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Gte => { @@ -1293,8 +1273,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { new_new_rhs .set_range_max(self, new_max) .into_expr_err(loc)?; - // self.update_array_min_if_length(ctx, loc, new_rhs)?; - // self.update_array_min_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Lt => { @@ -1334,8 +1312,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), ) .into_expr_err(loc)?; - // self.update_array_max_if_length(ctx, loc, new_rhs)?; - // self.update_array_max_if_length(ctx, loc, new_lhs)?; Ok(false) } RangeOp::Lte => { @@ -1359,8 +1335,6 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) .into_expr_err(loc)?; - // self.update_array_max_if_length(ctx, loc, new_rhs.latest_version(self))?; - // self.update_array_max_if_length(ctx, loc, new_lhs.latest_version(self))?; Ok(false) } e => todo!("Non-comparator in require, {e:?}"), From 24ddaee7159b79b8557bf819ac8f11322d265334 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 10:44:06 -0800 Subject: [PATCH 45/71] lint --- crates/analyzers/src/bounds.rs | 2 +- crates/analyzers/src/func_analyzer/mod.rs | 4 +- .../src/var_analyzer/report_display.rs | 2 +- crates/cli/src/main.rs | 25 +- crates/graph/src/nodes/builtin.rs | 16 +- crates/graph/src/nodes/concrete.rs | 29 +- crates/graph/src/nodes/context/solving.rs | 4 +- crates/graph/src/nodes/context/var/node.rs | 32 +- crates/graph/src/nodes/context/var/ranging.rs | 18 +- crates/graph/src/nodes/context/var/typing.rs | 95 +++--- .../graph/src/nodes/context/var/underlying.rs | 39 ++- .../graph/src/nodes/context/var/versioning.rs | 18 +- crates/graph/src/range/elem/elem_enum.rs | 131 ++++---- crates/graph/src/range/elem/expr.rs | 56 ++-- crates/graph/src/range/elem/map_or_array.rs | 67 ++-- crates/graph/src/range/exec/bitwise.rs | 1 - crates/graph/src/range/exec/cast.rs | 143 +++++--- crates/graph/src/range/exec/exec_op.rs | 315 +++++++++++------- crates/graph/src/range/exec/max.rs | 2 +- crates/graph/src/range/exec/mem_ops/concat.rs | 54 +-- .../graph/src/range/exec/mem_ops/mem_set.rs | 46 +-- crates/graph/src/range/exec/mem_ops/mod.rs | 11 +- crates/graph/src/range/exec/min.rs | 4 +- crates/graph/src/range/exec/mod.rs | 2 +- crates/graph/src/range/exec_traits.rs | 5 +- crates/graph/src/range/range_string.rs | 74 ++-- crates/graph/src/range/solc_range.rs | 8 +- crates/graph/src/solvers/atoms.rs | 6 +- crates/graph/src/var_type.rs | 8 +- crates/pyrometer/src/analyzer_backend.rs | 4 +- crates/pyrometer/src/graph_backend.rs | 4 +- crates/shared/src/analyzer_like.rs | 9 +- crates/solc-expressions/src/array.rs | 171 ++++++---- crates/solc-expressions/src/assign.rs | 5 +- crates/solc-expressions/src/bin_op.rs | 19 +- .../solc-expressions/src/func_call/helper.rs | 7 +- .../src/func_call/internal_call.rs | 6 +- .../src/func_call/intrinsic_call/array.rs | 129 ++++--- .../func_call/intrinsic_call/constructors.rs | 12 +- .../func_call/intrinsic_call/dyn_builtin.rs | 35 +- .../src/func_call/intrinsic_call/types.rs | 12 +- .../src/member_access/list_access.rs | 57 ++-- crates/solc-expressions/src/require.rs | 20 +- 43 files changed, 1007 insertions(+), 700 deletions(-) diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index c3b968e6..a3877649 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -82,7 +82,7 @@ impl OrderedAnalysis { ba.bound_changes .iter() .enumerate() - .for_each(|(i, bound_change)| { + .for_each(|(_i, bound_change)| { let (parts, unsat) = range_parts(analyzer, &ba.report_config, &bound_change.1); let item = StrippedAnalysisItem { init: false, diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index 85ad1231..bef2a700 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -5,8 +5,6 @@ use crate::{ use graph::{ nodes::{ContextNode, KilledKind}, - range_string::ToRangeString, - solvers::{Atomize, SolverAtom}, AnalyzerBackend, GraphBackend, }; use shared::Search; @@ -83,7 +81,7 @@ impl<'a> FunctionVarsBoundAnalysis { let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); let ret = parts.into_iter().fold( format!("{}. {name}", i + 1), - |mut acc, part| { + |mut acc, _part| { acc = acc.to_string(); acc }, diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index 2507b26f..3f876c7d 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -33,7 +33,7 @@ impl ReportDisplay for VarBoundAnalysis { self.bound_changes .iter() .enumerate() - .map(|(i, bound_change)| { + .map(|(_i, bound_change)| { let (parts, unsat) = range_parts(analyzer, &self.report_config, &bound_change.1); AnalysisItem { diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 9dc55b6c..006b409a 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,9 +1,8 @@ use analyzers::{FunctionVarsBoundAnalyzer, ReportConfig, ReportDisplay}; use graph::{ - elem::{Elem, RangeElem}, - nodes::{Concrete, ContractNode, FunctionNode}, + nodes::{ContractNode, FunctionNode}, solvers::{AtomicSolveStatus, BruteBinSearchSolver, SolcSolver}, - Edge, Range, + Edge, }; use pyrometer::{Analyzer, Root, SourcePath}; use shared::GraphDot; @@ -11,7 +10,7 @@ use shared::Search; use ariadne::sources; use clap::{ArgAction, Parser, ValueHint}; -use ethers_core::types::I256; + use tracing_subscriber::prelude::*; use std::{ @@ -350,15 +349,21 @@ fn main() { let mut all_edges = ctx.all_edges(&analyzer).unwrap(); all_edges.push(ctx); all_edges.iter().for_each(|c| { - let rets = c.return_nodes(&analyzer).unwrap(); + let _rets = c.return_nodes(&analyzer).unwrap(); // if c.path(&analyzer).starts_with(r#"step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64)"#) // && rets.iter().take(1).any(|ret| { // let range = ret.1.ref_range(&analyzer).unwrap().unwrap(); // range.evaled_range_min(&analyzer).unwrap().range_eq(&Elem::from(Concrete::from(I256::from(-1)))) // }) - { // step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64).fork{ false }.fork{ true }.fork{ true }.fork{ false }"#.to_string()) { + { + // step(uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64).fork{ false }.fork{ true }.fork{ true }.fork{ false }"#.to_string()) { // println!("{:#?}", c.ctx_deps_as_controllables_str(&analyzer).unwrap()); - if let Some(mut solver) = BruteBinSearchSolver::maybe_new(c.ctx_deps(&analyzer).unwrap(), &analyzer).unwrap() { + if let Some(mut solver) = BruteBinSearchSolver::maybe_new( + c.ctx_deps(&analyzer).unwrap(), + &analyzer, + ) + .unwrap() + { println!("created solver"); match solver.solve(&analyzer).unwrap() { AtomicSolveStatus::Unsat => { @@ -368,7 +373,11 @@ fn main() { println!("-----------------------"); println!("sat for: {}", c.path(&analyzer)); ranges.iter().for_each(|(atomic, conc)| { - println!("{}: {}", atomic.idxs[0].display_name(&analyzer).unwrap(), conc.as_human_string()); + println!( + "{}: {}", + atomic.idxs[0].display_name(&analyzer).unwrap(), + conc.as_human_string() + ); }); } AtomicSolveStatus::Indeterminate => { diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index f657d59d..a2491f8b 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -392,12 +392,8 @@ impl Builtin { pub fn zero_concrete(&self) -> Option { match self { - Builtin::Uint(size) => { - Some(Concrete::Uint(*size, U256::zero())) - } - Builtin::Int(size) => { - Some(Concrete::Int(*size, I256::from_raw(U256::zero()))) - } + Builtin::Uint(size) => Some(Concrete::Uint(*size, U256::zero())), + Builtin::Int(size) => Some(Concrete::Int(*size, I256::from_raw(U256::zero()))), Builtin::Bytes(size) => { let h = H256::default(); Some(Concrete::Bytes(*size, h)) @@ -443,12 +439,8 @@ impl Builtin { pub fn min_concrete(&self) -> Option { match self { - Builtin::Uint(size) => { - Some(Concrete::Uint(*size, U256::zero())) - } - Builtin::Int(size) => { - Some(Concrete::Int(*size, I256::MIN)) - } + Builtin::Uint(size) => Some(Concrete::Uint(*size, U256::zero())), + Builtin::Int(size) => Some(Concrete::Int(*size, I256::MIN)), Builtin::Bytes(size) => { let h = H256::default(); Some(Concrete::Bytes(*size, h)) diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index e8d42064..3b033650 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -181,7 +181,7 @@ impl Concrete { } (Concrete::String(s), Concrete::String(o)) => { o.chars().enumerate().for_each(|(i, b)| { - s.replace_range(i..i+1, &b.to_string()); + s.replace_range(i..i + 1, &b.to_string()); }); } (Concrete::Bytes(size, s), Concrete::Bytes(cap, o)) => { @@ -214,15 +214,15 @@ impl Concrete { } (Concrete::String(s), Concrete::Uint(_, o)) => { let index = o.as_usize(); - Some(Concrete::String(s[index..index+1].to_string())) + Some(Concrete::String(s[index..index + 1].to_string())) } - (Concrete::Bytes(size, s), Concrete::Uint(_, o)) => { + (Concrete::Bytes(_size, s), Concrete::Uint(_, o)) => { let index = o.as_usize(); let mut bytes = [0u8; 32]; bytes[0] = s[index]; Some(Concrete::Bytes(1, H256(bytes))) } - _ => None + _ => None, } } @@ -388,10 +388,12 @@ impl Concrete { val.to_big_endian(&mut bytes); Some(Concrete::Uint(*size, U256::from_big_endian(&bytes))) } - Concrete::Bytes(size, _) => Some(Concrete::Uint(*size as u16 / 8, self.into_u256().unwrap())), + Concrete::Bytes(size, _) => { + Some(Concrete::Uint(*size as u16 / 8, self.into_u256().unwrap())) + } Concrete::Bool(_val) => Some(Concrete::Uint(8, self.into_u256().unwrap())), Concrete::Address(_val) => Some(Concrete::Uint(20, self.into_u256().unwrap())), - _ => None + _ => None, } } @@ -422,9 +424,7 @@ impl Concrete { } } } - Builtin::Int(size) => { - Some(Concrete::Int(size, I256::from_raw(val))) - }, + Builtin::Int(size) => Some(Concrete::Int(size, I256::from_raw(val))), Builtin::Bytes(size) => { let mask = if size == 32 { U256::MAX @@ -657,9 +657,10 @@ impl Concrete { } } Concrete::Bytes(_, b) => Some(U256::from_big_endian(b.as_bytes())), - Concrete::DynBytes(v) if v.len() <= 32 => { - self.clone().cast(Builtin::Bytes(v.len() as u8))?.into_u256() - }, + Concrete::DynBytes(v) if v.len() <= 32 => self + .clone() + .cast(Builtin::Bytes(v.len() as u8))? + .into_u256(), Concrete::Address(a) => Some(U256::from_big_endian(a.as_bytes())), Concrete::Bool(b) => { if *b { @@ -853,12 +854,12 @@ impl Concrete { let mut bytes = [0u8; 32]; val.to_big_endian(&mut bytes); format!("0x{}", hex::encode(bytes)) - }, + } Concrete::Int(_, val) => { let mut bytes = [0u8; 32]; val.to_big_endian(&mut bytes); format!("0x{}", hex::encode(bytes)) - }, + } Concrete::Bytes(size, b) => format!( "0x{}", b.0.iter() diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 4378f03c..1e266974 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,15 +1,15 @@ use crate::SolcRange; -use std::borrow::Cow; use crate::{ as_dot_str, nodes::{ContextNode, ContextVarNode}, - range::{Range, elem::RangeOp, RangeEval}, + range::{elem::RangeOp, Range, RangeEval}, solvers::{ dl::{DLSolver, SolveStatus}, Atomize, SolverAtom, }, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; +use std::borrow::Cow; use shared::NodeIdx; diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index f6dd7b3b..c7e5f8ee 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -205,16 +205,14 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.tmp_of()) } - pub fn array_to_len_var( - &self, - analyzer: &impl GraphBackend, - ) -> Option { + pub fn array_to_len_var(&self, analyzer: &impl GraphBackend) -> Option { if let Some(len) = analyzer .graph() .edges_directed(self.0.into(), Direction::Incoming) .find(|edge| *edge.weight() == Edge::Context(ContextEdge::AttrAccess("length"))) - .map(|edge| edge.source()) { - Some(len.into()) + .map(|edge| edge.source()) + { + Some(len.into()) } else if let Some(prev) = self.previous_version(analyzer) { prev.array_to_len_var(analyzer) } else { @@ -222,16 +220,14 @@ impl ContextVarNode { } } - pub fn index_access_to_array( - &self, - analyzer: &impl GraphBackend, - ) -> Option { + pub fn index_access_to_array(&self, analyzer: &impl GraphBackend) -> Option { if let Some(arr) = analyzer .graph() .edges_directed(self.0.into(), Direction::Outgoing) .find(|edge| *edge.weight() == Edge::Context(ContextEdge::IndexAccess)) - .map(|edge| edge.target()) { - Some(arr.into()) + .map(|edge| edge.target()) + { + Some(arr.into()) } else if let Some(prev) = self.previous_version(analyzer) { prev.index_access_to_array(analyzer) } else { @@ -278,7 +274,11 @@ impl ContextVarNode { .graph() .edges_directed(self.0.into(), Direction::Incoming) .filter(|edge| { - matches!(*edge.weight(), Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::AttrAccess(_))) + matches!( + *edge.weight(), + Edge::Context(ContextEdge::IndexAccess) + | Edge::Context(ContextEdge::AttrAccess(_)) + ) }) .map(|edge| ContextVarNode::from(edge.source())) .collect() @@ -306,11 +306,11 @@ impl ContextVarNode { } else { vec![] }; - + if let Some(rhs) = tmp.rhs { if !seen.contains(&rhs) { seen.push(rhs); - nodes.extend(rhs.dependent_on(analyzer, true)?); + nodes.extend(rhs.dependent_on(analyzer, true)?); } } Ok(nodes) @@ -354,4 +354,4 @@ impl ContextVarNode { Ok(tree) } -} \ No newline at end of file +} diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index dd2e3102..8242ec1b 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -119,8 +119,6 @@ impl ContextVarNode { Ok(()) } - - // pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { // if let Some(mut range) = self.range(analyzer)? { // range.cache_flatten(analyzer)?; @@ -151,7 +149,11 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.needs_fallback()) } - pub fn range_contains_elem(&self, elem: Elem, analyzer: &impl GraphBackend) -> Result { + pub fn range_contains_elem( + &self, + elem: Elem, + analyzer: &impl GraphBackend, + ) -> Result { if let Some(r) = self.ref_range(analyzer)? { Ok(r.contains_elem(&elem, analyzer)) } else { @@ -247,7 +249,10 @@ impl ContextVarNode { analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result<(), GraphError> { - tracing::trace!("setting range exclusions for {}", self.display_name(analyzer)?); + tracing::trace!( + "setting range exclusions for {}", + self.display_name(analyzer)? + ); assert!(*self == self.latest_version(analyzer)); let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? @@ -322,7 +327,10 @@ impl ContextVarNode { analyzer: &mut impl GraphBackend, new_exclusions: Vec>, ) -> Result { - tracing::trace!("setting range exclusions for: {}", self.display_name(analyzer).unwrap()); + tracing::trace!( + "setting range exclusions for: {}", + self.display_name(analyzer).unwrap() + ); assert!(*self == self.latest_version(analyzer)); let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index cec9ea0b..b029b07c 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,7 +1,7 @@ use crate::{ - range::RangeEval, + elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, - elem::{Elem}, + range::RangeEval, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; @@ -74,22 +74,22 @@ impl ContextVarNode { Ok(is_independent && ( global_first.is_storage(analyzer)? - || global_first.is_calldata_input(analyzer) - || global_first.is_msg(analyzer)? - || global_first.is_block(analyzer)? - || ( - // if its a function input, and we are evaluating the function - // as a standalone (i.e. its internal, but we are treating it like its external) - // it wont be marked as calldata, but for the purposes - // of determining controllability it is to better to assume there is some path that lets us - // control it - global_first.is_func_input(analyzer) - && global_first.maybe_ctx(analyzer).is_some() - && !global_first.ctx(analyzer).has_parent(analyzer)? + || global_first.is_calldata_input(analyzer) + || global_first.is_msg(analyzer)? + || global_first.is_block(analyzer)? + || ( + // if its a function input, and we are evaluating the function + // as a standalone (i.e. its internal, but we are treating it like its external) + // it wont be marked as calldata, but for the purposes + // of determining controllability it is to better to assume there is some path that lets us + // control it + global_first.is_func_input(analyzer) + && global_first.maybe_ctx(analyzer).is_some() + && !global_first.ctx(analyzer).has_parent(analyzer)? ) - || self.is_attr_or_index_of_fundamental(analyzer) // performed last to try to not have to do this check - ) - ) + || self.is_attr_or_index_of_fundamental(analyzer) + // performed last to try to not have to do this check + )) } pub fn is_attr_or_index_of_fundamental(&self, analyzer: &impl GraphBackend) -> bool { @@ -97,8 +97,15 @@ impl ContextVarNode { .graph() .edges_directed(self.0.into(), Direction::Outgoing) .any(|edge| { - if matches!(edge.weight(), Edge::Context(ContextEdge::AttrAccess(_)) | Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::Index)) { - ContextVarNode::from(edge.target()).is_fundamental(analyzer).unwrap_or(false) + if matches!( + edge.weight(), + Edge::Context(ContextEdge::AttrAccess(_)) + | Edge::Context(ContextEdge::IndexAccess) + | Edge::Context(ContextEdge::Index) + ) { + ContextVarNode::from(edge.target()) + .is_fundamental(analyzer) + .unwrap_or(false) } else { false } @@ -117,8 +124,15 @@ impl ContextVarNode { .graph() .edges_directed(self.0.into(), Direction::Outgoing) .any(|edge| { - if matches!(edge.weight(), Edge::Context(ContextEdge::AttrAccess(_)) | Edge::Context(ContextEdge::IndexAccess) | Edge::Context(ContextEdge::Index)) { - ContextVarNode::from(edge.target()).is_storage(analyzer).unwrap_or(false) + if matches!( + edge.weight(), + Edge::Context(ContextEdge::AttrAccess(_)) + | Edge::Context(ContextEdge::IndexAccess) + | Edge::Context(ContextEdge::Index) + ) { + ContextVarNode::from(edge.target()) + .is_storage(analyzer) + .unwrap_or(false) } else { false } @@ -323,9 +337,7 @@ impl ContextVarNode { to_ty: VarType, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { - let new_underlying = self - .underlying(analyzer)? - .clone(); + let new_underlying = self.underlying(analyzer)?.clone(); let node = analyzer.add_node(Node::ContextVar(new_underlying)); analyzer.add_edge(node, *self, Edge::Context(ContextEdge::Prev)); let new_self = ContextVarNode::from(node); @@ -335,7 +347,7 @@ impl ContextVarNode { if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { new_self.underlying_mut(analyzer)?.ty = new_ty; } - + if let Some((new_min, new_max)) = self.cast_exprs(&to_ty, analyzer)? { new_self.set_range_min(analyzer, new_min)?; new_self.set_range_max(analyzer, new_max)?; @@ -391,31 +403,32 @@ impl ContextVarNode { ) -> Result, Elem)>, GraphError> { if let Some(to_range) = to_ty.range(analyzer)? { let mut min_expr = (*self) - .range_min(analyzer)?.unwrap() - .cast(to_range.min.clone()) - .min( - (*self) - .range_max(analyzer)?.unwrap() - .cast(to_range.min.clone()) - ); + .range_min(analyzer)? + .unwrap() + .cast(to_range.min.clone()) + .min( + (*self) + .range_max(analyzer)? + .unwrap() + .cast(to_range.min.clone()), + ); let mut max_expr = (*self) - .range_min(analyzer)?.unwrap() - .cast(to_range.min.clone()) - .max( - (*self) - .range_max(analyzer)?.unwrap() - .cast(to_range.min) - ); + .range_min(analyzer)? + .unwrap() + .cast(to_range.min.clone()) + .max((*self).range_max(analyzer)?.unwrap().cast(to_range.min)); if let Some(r) = self.ref_range(analyzer)? { let zero = Elem::from(Concrete::from(U256::zero())); if r.contains_elem(&zero, analyzer) { min_expr = min_expr.min(zero.clone()); max_expr = max_expr.max(zero); - } + } } - if let (VarType::BuiltIn(from_bn, _), VarType::BuiltIn(to_bn, _)) = (self.ty(analyzer)?, to_ty) { + if let (VarType::BuiltIn(from_bn, _), VarType::BuiltIn(to_bn, _)) = + (self.ty(analyzer)?, to_ty) + { match (from_bn.underlying(analyzer)?, to_bn.underlying(analyzer)?) { (Builtin::Uint(_), int @ Builtin::Int(_)) => { // from ty is uint, to ty is int, check if type(int.min).bit_representation() diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 1764710a..b46daddf 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -266,7 +266,11 @@ impl ContextVar { } // #[tracing::instrument(level = "trace", skip_all)] - pub fn set_range_min(&mut self, new_min: Elem, fallback_range: Option) -> Result<(), GraphError> { + pub fn set_range_min( + &mut self, + new_min: Elem, + fallback_range: Option, + ) -> Result<(), GraphError> { // tracing::trace!("Setting range min in underlying: {:?}", self.ty); match &mut self.ty { VarType::User(TypeNode::Contract(_), ref mut maybe_range) @@ -281,11 +285,16 @@ impl ContextVar { *maybe_range = Some(fr); Ok(()) } else { - Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) + Err(GraphError::NodeConfusion(format!( + "No range and no fallback range for type: {:?}", + self.ty + ))) } } VarType::Concrete(_) => Ok(()), - e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), + e => Err(GraphError::NodeConfusion(format!( + "Expected a type that has a range, but was type: {e:?} that had no range" + ))), } } @@ -315,7 +324,11 @@ impl ContextVar { } } - pub fn set_range_max(&mut self, new_max: Elem, fallback_range: Option) -> Result<(), GraphError> { + pub fn set_range_max( + &mut self, + new_max: Elem, + fallback_range: Option, + ) -> Result<(), GraphError> { match &mut self.ty { VarType::User(TypeNode::Contract(_), ref mut maybe_range) | VarType::User(TypeNode::Enum(_), ref mut maybe_range) @@ -329,11 +342,16 @@ impl ContextVar { *maybe_range = Some(fr); Ok(()) } else { - Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) + Err(GraphError::NodeConfusion(format!( + "No range and no fallback range for type: {:?}", + self.ty + ))) } } VarType::Concrete(_) => Ok(()), - e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), + e => Err(GraphError::NodeConfusion(format!( + "Expected a type that has a range, but was type: {e:?} that had no range" + ))), } } @@ -355,11 +373,16 @@ impl ContextVar { *maybe_range = Some(fr); Ok(()) } else { - Err(GraphError::NodeConfusion(format!("No range and no fallback range for type: {:?}", self.ty))) + Err(GraphError::NodeConfusion(format!( + "No range and no fallback range for type: {:?}", + self.ty + ))) } } VarType::Concrete(_) => Ok(()), - e => Err(GraphError::NodeConfusion(format!("Expected a type that has a range, but was type: {e:?} that had no range"))), + e => Err(GraphError::NodeConfusion(format!( + "Expected a type that has a range, but was type: {e:?} that had no range" + ))), } } diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index df8b4bb3..c1c6ba93 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -202,15 +202,17 @@ impl ContextVarNode { .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) .map(|edge| ContextVarNode::from(edge.target())) .take(1) - .next() { - Some(inherited) - } else { analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) .next() + { + Some(inherited) + } else { + analyzer + .graph() + .edges_directed(self.0.into(), Direction::Outgoing) + .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() } } } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 90cd40e1..1a19eea6 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,6 +1,8 @@ use crate::{ nodes::{Concrete, ContextVarNode}, - range::elem::{MaybeCollapsed, collapse, RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference}, + range::elem::{ + collapse, MaybeCollapsed, RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference, + }, GraphBackend, GraphError, }; use solang_parser::pt::Loc; @@ -89,13 +91,11 @@ impl Elem { Elem::Concrete(_a) => true, Elem::ConcreteDyn(a) => { a.len.maybe_concrete().is_some() - && a.val.iter().all(|(key, (val, _))| { - key.is_conc() && val.is_conc() - }) + && a.val + .iter() + .all(|(key, (val, _))| key.is_conc() && val.is_conc()) } - Elem::Expr(expr) => { - expr.lhs.is_conc() && expr.rhs.is_conc() - }, + Elem::Expr(expr) => expr.lhs.is_conc() && expr.rhs.is_conc(), _ => false, } } @@ -314,11 +314,14 @@ impl From for Elem { } impl Elem { - pub fn overlaps(&self, other: &Self, eval: bool, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn overlaps( + &self, + other: &Self, + eval: bool, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match (self, other) { - (Elem::Concrete(s), Elem::Concrete(o)) => { - Ok(Some(o.val == s.val)) - } + (Elem::Concrete(s), Elem::Concrete(o)) => Ok(Some(o.val == s.val)), (Elem::Reference(s), Elem::Reference(o)) => { if eval { let lhs_min = s.minimize(analyzer)?; @@ -341,13 +344,13 @@ impl Elem { } else if s == o { Ok(Some(true)) } else { - Ok(None) + Ok(None) } } (Elem::Reference(s), c @ Elem::Concrete(_)) => { if eval { let lhs_min = s.minimize(analyzer)?; - + match lhs_min.range_ord(c) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max @@ -366,13 +369,19 @@ impl Elem { } } (Elem::Concrete(_), Elem::Reference(_)) => other.overlaps(self, eval, analyzer), - _ => Ok(None) + _ => Ok(None), } } - pub fn overlaps_dual(&self, rhs_min: &Self, rhs_max: &Self, eval: bool, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn overlaps_dual( + &self, + rhs_min: &Self, + rhs_max: &Self, + eval: bool, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match self { Self::Reference(d) => { - if eval { + if eval { let lhs_min = d.minimize(analyzer)?; let rhs_max = rhs_max.maximize(analyzer)?; @@ -393,20 +402,16 @@ impl Elem { } else if self == rhs_min || self == rhs_max { Ok(Some(true)) } else { - Ok(None) - } - }, - Self::Concrete(_) => { - match rhs_min.range_ord(self) { - Some(std::cmp::Ordering::Less) => { - Ok(Some(matches!( - rhs_max.range_ord(self), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ))) - } - Some(std::cmp::Ordering::Equal) => Ok(Some(true)), - _ => Ok(Some(false)), + Ok(None) } + } + Self::Concrete(_) => match rhs_min.range_ord(self) { + Some(std::cmp::Ordering::Less) => Ok(Some(matches!( + rhs_max.range_ord(self), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))), + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), }, _ => Ok(None), } @@ -484,11 +489,11 @@ impl std::fmt::Display for Elem { Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), Elem::ConcreteDyn(d) => { write!(f, "{{len: {}, values: {{", d.len)?; - d.val.iter().try_for_each(|(key, (val, op))| { - write!(f, " {key}: ({val}, {op}),") - })?; + d.val + .iter() + .try_for_each(|(key, (val, op))| write!(f, " {key}: ({val}, {op}),"))?; write!(f, "}}}}") - }, + } Elem::Concrete(RangeConcrete { val, .. }) => { write!(f, "{}", val.as_string()) } @@ -663,8 +668,8 @@ impl RangeElem for Elem { seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if let Some(res) = seen_ops.get(&self) { - return Ok(res.clone()) + if let Some(res) = seen_ops.get(self) { + return Ok(res.clone()); } use Elem::*; @@ -672,14 +677,12 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_maximize(seen_ops, analyzer), Concrete(inner) => inner.simplify_maximize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_maximize(seen_ops, analyzer), - Expr(expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_maximize(seen_ops, analyzer) - } - _ => expr.simplify_maximize(seen_ops, analyzer) + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(collapsed) => { + collapsed.simplify_maximize(seen_ops, analyzer) } - } + _ => expr.simplify_maximize(seen_ops, analyzer), + }, Null => Ok(Elem::Null), } } @@ -689,8 +692,8 @@ impl RangeElem for Elem { seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if let Some(res) = seen_ops.get(&self) { - return Ok(res.clone()) + if let Some(res) = seen_ops.get(self) { + return Ok(res.clone()); } use Elem::*; @@ -698,13 +701,11 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_minimize(seen_ops, analyzer), Concrete(inner) => inner.simplify_minimize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_minimize(seen_ops, analyzer), - Expr(expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_minimize(seen_ops, analyzer) - } - _ => expr.simplify_minimize(seen_ops, analyzer) - } + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(collapsed) => { + collapsed.simplify_minimize(seen_ops, analyzer) + } + _ => expr.simplify_minimize(seen_ops, analyzer), }, Null => Ok(Elem::Null), }?; @@ -719,15 +720,13 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Collapsed(mut collapsed) => { - collapsed.cache_minimize(analyzer)?; - *self = collapsed; - Ok(()) - } - _ => expr.cache_maximize(analyzer) + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_minimize(analyzer)?; + *self = collapsed; + Ok(()) } + _ => expr.cache_maximize(analyzer), }, Null => Ok(()), } @@ -739,15 +738,13 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Collapsed(mut collapsed) => { - collapsed.cache_minimize(analyzer)?; - *self = collapsed; - Ok(()) - } - _ => expr.cache_minimize(analyzer) + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_minimize(analyzer)?; + *self = collapsed; + Ok(()) } + _ => expr.cache_minimize(analyzer), }, Null => Ok(()), } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index c0234c13..32a5a254 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -174,7 +174,7 @@ impl RangeElem for RangeExpr { } else if self.op == RangeOp::SetIndices { self.simplify_exec_op(false, &mut Default::default(), analyzer) } else { - self.exec_op(false, analyzer) + self.exec_op(false, analyzer) } } @@ -200,14 +200,16 @@ impl RangeElem for RangeExpr { match RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(true, analyzer), + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, expr.op, r).exec_op(true, analyzer) + } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - _ => Ok(e.clone()) + _ => Ok(e.clone()), } } - other => Ok(other) + other => Ok(other), } - }, + } } } fn simplify_minimize( @@ -232,14 +234,16 @@ impl RangeElem for RangeExpr { match RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { - MaybeCollapsed::Concretes(l, r) => RangeExpr::new(l, expr.op, r).exec_op(false, analyzer), + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, expr.op, r).exec_op(false, analyzer) + } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - _ => Ok(e.clone()) + _ => Ok(e.clone()), } } - other => Ok(other) + other => Ok(other), } - }, + } } } @@ -301,7 +305,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla let one = Elem::from(Concrete::from(U256::one())); match (l.clone(), r.clone()) { // (Elem::Null, _) => MaybeCollapsed::Collapsed(r), - // (_, Elem::Null) => MaybeCollapsed::Collapsed(l), + // (_, Elem::Null) => MaybeCollapsed::Collapsed(l), (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { // try to collapse the expression @@ -746,27 +750,23 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(_, _) => unreachable!(), }, - (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => { - match op { - RangeOp::Sub(_) - | RangeOp::Add(_) => { - if matches!(c.range_ord(&zero), Some(std::cmp::Ordering::Equal)) { - MaybeCollapsed::Collapsed(le) - } else { - MaybeCollapsed::Not(l, r) - } + (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => match op { + RangeOp::Sub(_) | RangeOp::Add(_) => { + if matches!(c.range_ord(&zero), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le) + } else { + MaybeCollapsed::Not(l, r) } - RangeOp::Mul(_) - | RangeOp::Div(_) => { - if matches!(c.range_ord(&one), Some(std::cmp::Ordering::Equal)) { - MaybeCollapsed::Collapsed(le) - } else { - MaybeCollapsed::Not(l, r) - } + } + RangeOp::Mul(_) | RangeOp::Div(_) => { + if matches!(c.range_ord(&one), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le) + } else { + MaybeCollapsed::Not(l, r) } - _ => MaybeCollapsed::Not(l, r) } - } + _ => MaybeCollapsed::Not(l, r), + }, _ => MaybeCollapsed::Not(l, r), } } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index dc0c788b..cffbdc1c 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -54,11 +54,14 @@ impl RangeDyn { } pub fn new(len: Elem, val: BTreeMap, Elem>, loc: Loc) -> Self { let mut op_num = 0; - let val = val.into_iter().map(|(k, v)| { - let res = (k, (v, op_num)); - op_num += 1; - res - }).collect(); + let val = val + .into_iter() + .map(|(k, v)| { + let res = (k, (v, op_num)); + op_num += 1; + res + }) + .collect(); Self { minimized: None, maximized: None, @@ -73,11 +76,14 @@ impl RangeDyn { pub fn new_for_indices(vals: Vec<(Elem, Elem)>, loc: Loc) -> Self { let mut op_num = 0; - let val = vals.into_iter().map(|(k, v)| { - let res = (k, (v, op_num)); - op_num += 1; - res - }).collect(); + let val = vals + .into_iter() + .map(|(k, v)| { + let res = (k, (v, op_num)); + op_num += 1; + res + }) + .collect(); Self { minimized: None, maximized: None, @@ -102,9 +108,7 @@ impl RangeDyn { } } -impl RangeDyn { - -} +impl RangeDyn {} impl RangeElem for RangeDyn { type GraphError = GraphError; @@ -119,16 +123,20 @@ impl RangeElem for RangeDyn { let mut eq = 0; let mut self_lt = 0; let mut self_gt = 0; - self.val.iter().zip(other.val.iter()).for_each(|((self_key, self_val), (other_key, other_val))| { - if let Some(std::cmp::Ordering::Equal) = self_key.clone().range_ord(other_key) { - match self_val.0.clone().range_ord(&other_val.0) { - Some(std::cmp::Ordering::Equal) => eq += 1, - Some(std::cmp::Ordering::Less) => self_lt += 1, - Some(std::cmp::Ordering::Greater) => self_gt += 1, - _ => {} + self.val.iter().zip(other.val.iter()).for_each( + |((self_key, self_val), (other_key, other_val))| { + if let Some(std::cmp::Ordering::Equal) = + self_key.clone().range_ord(other_key) + { + match self_val.0.clone().range_ord(&other_val.0) { + Some(std::cmp::Ordering::Equal) => eq += 1, + Some(std::cmp::Ordering::Less) => self_lt += 1, + Some(std::cmp::Ordering::Greater) => self_gt += 1, + _ => {} + } } - } - }); + }, + ); if self_lt == self.val.len() { Some(std::cmp::Ordering::Less) @@ -140,7 +148,7 @@ impl RangeElem for RangeDyn { None } } - other => other + other => other, } } @@ -215,7 +223,7 @@ impl RangeElem for RangeDyn { for (idx, val) in self.val.clone().into_iter() { map.insert( idx.flatten(maximize, analyzer)?, - (val.0.flatten(maximize, analyzer)?, val.1) + (val.0.flatten(maximize, analyzer)?, val.1), ); } map @@ -277,7 +285,10 @@ impl RangeElem for RangeDyn { // We dont maximize the key so that any subsequent // `get_index` can find potential values let maximized = val.0.maximize(analyzer)?; - map.insert(idx.simplify_maximize(&mut Default::default(), analyzer)?, (maximized, val.1)); + map.insert( + idx.simplify_maximize(&mut Default::default(), analyzer)?, + (maximized, val.1), + ); } // map.into_iter().filter(|(k, (v, op))| { @@ -302,7 +313,10 @@ impl RangeElem for RangeDyn { // We dont minimize the key so that any subsequent // `get_index` can find potential values let minimized = val.0.minimize(analyzer)?; - map.insert(idx.simplify_minimize(&mut Default::default(), analyzer)?, (minimized, val.1)); + map.insert( + idx.simplify_minimize(&mut Default::default(), analyzer)?, + (minimized, val.1), + ); } // map.into_iter().filter(|(k, (v, op))| { @@ -336,7 +350,6 @@ impl RangeElem for RangeDyn { }, self.loc, ))) - } fn simplify_minimize( &self, diff --git a/crates/graph/src/range/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs index d78dde75..97010932 100644 --- a/crates/graph/src/range/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -45,7 +45,6 @@ impl RangeBitwise for RangeConcrete { } fn range_bit_or(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { let size = if s > s2 { s } else { s2 }; diff --git a/crates/graph/src/range/exec/cast.rs b/crates/graph/src/range/exec/cast.rs index bc20b6de..cf3033cb 100644 --- a/crates/graph/src/range/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -20,10 +20,13 @@ impl RangeCast> for RangeConcrete { Concrete::Bytes(size, val), Some(( _, - (Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), _), + ( + Elem::Concrete(Self { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) | (Concrete::Bytes(size, val), None) => { @@ -51,10 +54,13 @@ impl RangeCast> for RangeConcrete { Concrete::DynBytes(val), Some(( _, - (Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), _), + ( + Elem::Concrete(Self { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) | (Concrete::DynBytes(val), None) => { @@ -81,10 +87,13 @@ impl RangeCast> for RangeConcrete { Concrete::String(val), Some(( _, - (Elem::Concrete(Self { - val: Concrete::String(..), - .. - }), _), + ( + Elem::Concrete(Self { + val: Concrete::String(..), + .. + }), + _, + ), )), ) | (Concrete::String(val), None) => { @@ -120,78 +129,105 @@ impl RangeCast> for RangeDyn { ( Some(( _, - &(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + &( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), Some(( _, - &(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + &( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) | ( Some(( _, - &(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + &( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), None, ) => Some(Elem::ConcreteDyn(self.clone())), ( Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + _, + ), )), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + _, + ), )), ) | ( Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }), + _, + ), )), None, ) => Some(Elem::ConcreteDyn(self.clone())), ( Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + _, + ), )), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + _, + ), )), ) | ( Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }), + _, + ), )), None, ) => Some(Elem::ConcreteDyn(self.clone())), @@ -218,10 +254,13 @@ impl RangeCast> for RangeDyn { let mut h = H256::default(); for (i, (_, val)) in self.val.iter().take(*size as usize).enumerate() { match val { - (Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(1, v), - .. - }), _) => { + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(1, v), + .. + }), + _, + ) => { // consume as many as we can h.0[i] = v.0[0]; } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index a25a8a54..62c58d6c 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -4,8 +4,6 @@ use crate::{ GraphBackend, GraphError, }; -use shared::NodeIdx; - use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; @@ -85,81 +83,113 @@ impl ExecOp for RangeExpr { } else if matches!(self.op, RangeOp::Concat | RangeOp::Memcopy) { // we can always execute a concat or memcopy return self.exec_op(maximize, analyzer); - } else if matches!(self.op, RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex ) { + } else if matches!( + self.op, + RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex + ) { match self.op { RangeOp::GetLength => { return if maximize { - Ok(lhs_max.range_get_length() + Ok(lhs_max + .range_get_length() .unwrap_or_else(|| Elem::Expr(self.clone()))) } else { - Ok(lhs_min.range_get_length() + Ok(lhs_min + .range_get_length() .unwrap_or_else(|| Elem::Expr(self.clone()))) }; } RangeOp::SetLength => { return if maximize { - Ok(lhs_max.range_set_length(&rhs_max) + Ok(lhs_max + .range_set_length(&rhs_max) .unwrap_or_else(|| Elem::Expr(self.clone()))) } else { - Ok(lhs_min.range_set_length(&rhs_min) + Ok(lhs_min + .range_set_length(&rhs_min) .unwrap_or_else(|| Elem::Expr(self.clone()))) }; - }, + } RangeOp::GetIndex => { if maximize { let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, ..}) => { - val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { - if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { - if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Greater)) { - acc = Some(val.clone()); - Ok(acc) + Elem::ConcreteDyn(RangeDyn { val, .. }) => val + .iter() + .try_fold( + None, + |mut acc: Option>, (key, (val, _))| { + if matches!( + key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + Some(true) + ) { + if acc.is_none() + || matches!( + acc.clone().unwrap().range_ord(val), + Some(std::cmp::Ordering::Greater) + ) + { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } } else { Ok(acc) } - } else { - Ok(acc) - } - })?.unwrap_or_else(|| Elem::Null) - } - _ => Elem::Expr(self.clone()) + }, + )? + .unwrap_or_else(|| Elem::Null), + _ => Elem::Expr(self.clone()), }; return Ok(res); } else { let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, ..}) => { - val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { - if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { - if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Less)) { - acc = Some(val.clone()); - Ok(acc) + Elem::ConcreteDyn(RangeDyn { val, .. }) => val + .iter() + .try_fold( + None, + |mut acc: Option>, (key, (val, _))| { + if matches!( + key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + Some(true) + ) { + if acc.is_none() + || matches!( + acc.clone().unwrap().range_ord(val), + Some(std::cmp::Ordering::Less) + ) + { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } } else { Ok(acc) } - } else { - Ok(acc) - } - })?.unwrap_or_else(|| Elem::Null) - } - _ => Elem::Expr(self.clone()) + }, + )? + .unwrap_or_else(|| Elem::Null), + _ => Elem::Expr(self.clone()), }; return Ok(res); } - }, + } RangeOp::SetIndices => { return if maximize { - Ok(lhs_max.range_set_indices(&rhs_max) + Ok(lhs_max + .range_set_indices(&rhs_max) .unwrap_or_else(|| Elem::Expr(self.clone()))) } else { - Ok(lhs_min.range_set_indices(&rhs_min) + Ok(lhs_min + .range_set_indices(&rhs_min) .unwrap_or_else(|| Elem::Expr(self.clone()))) }; - }, - _ => unreachable!() + } + _ => unreachable!(), } } - let parts = (lhs_min, lhs_max, rhs_min, rhs_max); match (lhs_is_conc, rhs_is_conc) { (true, true) => self.exec(parts, maximize, analyzer), @@ -245,18 +275,10 @@ impl ExecOp for RangeExpr { consts: (bool, bool), ) -> Elem { match consts { - (true, true) => { - Elem::Expr(RangeExpr::new(lhs, this.op, rhs)) - } - (false, true) => { - Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)) - } - (true, false) => { - Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())) - } - (false, false) => { - Elem::Expr(this.clone()) - } + (true, true) => Elem::Expr(RangeExpr::new(lhs, this.op, rhs)), + (false, true) => Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)), + (true, false) => Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())), + (false, false) => Elem::Expr(this.clone()), } } @@ -267,105 +289,145 @@ impl ExecOp for RangeExpr { new.uncache(); let new_max = new.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_max.range_get_length(); - res - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { let new_min = lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_min.range_get_length(); - res - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } } RangeOp::SetLength => { if maximize { - lhs_max.range_set_length(&rhs_max) + lhs_max + .range_set_length(&rhs_max) .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { - lhs_min.range_set_length(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + lhs_min + .range_set_length(&rhs_min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } - }, + } RangeOp::GetIndex => { if maximize { - fn match_ty_max(lhs_max: Elem, rhs_min: Elem, rhs_max: Elem, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn match_ty_max( + lhs_max: Elem, + rhs_min: Elem, + rhs_max: Elem, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, ..}) => { - Ok(val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { - if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { - if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Greater)) { - acc = Some(val.clone()); - Ok(acc) + Elem::ConcreteDyn(RangeDyn { val, .. }) => Ok(val + .iter() + .try_fold( + None, + |mut acc: Option>, (key, (val, _))| { + if matches!( + key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + Some(true) + ) { + if acc.is_none() + || matches!( + acc.clone().unwrap().range_ord(val), + Some(std::cmp::Ordering::Greater) + ) + { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } } else { Ok(acc) } - } else { - Ok(acc) - } - })?.unwrap_or_else(|| Elem::Null)) - } + }, + )? + .unwrap_or_else(|| Elem::Null)), Elem::Reference(_) => { - let new_max = lhs_max.simplify_maximize(&mut Default::default(), analyzer)?; + let new_max = + lhs_max.simplify_maximize(&mut Default::default(), analyzer)?; if new_max == lhs_max { Ok(Elem::Null) } else { match_ty_max(new_max, rhs_min, rhs_max, analyzer) } } - _ => Ok(Elem::Null) + _ => Ok(Elem::Null), } } match_ty_max(lhs_max.clone(), rhs_min, rhs_max.clone(), analyzer) .unwrap_or_else(|_| fallback(self, lhs_max, rhs_max, consts)) } else { - fn match_ty_min(lhs_min: Elem, rhs_min: Elem, rhs_max: Elem, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn match_ty_min( + lhs_min: Elem, + rhs_min: Elem, + rhs_max: Elem, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match lhs_min { - Elem::ConcreteDyn(RangeDyn { val, ..}) => { - Ok(val.iter().try_fold(None, |mut acc: Option>, (key, (val, _))| { - if matches!(key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, Some(true)) { - if acc.is_none() || matches!(acc.clone().unwrap().range_ord(val), Some(std::cmp::Ordering::Less)) { - acc = Some(val.clone()); - Ok(acc) + Elem::ConcreteDyn(RangeDyn { val, .. }) => Ok(val + .iter() + .try_fold( + None, + |mut acc: Option>, (key, (val, _))| { + if matches!( + key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + Some(true) + ) { + if acc.is_none() + || matches!( + acc.clone().unwrap().range_ord(val), + Some(std::cmp::Ordering::Less) + ) + { + acc = Some(val.clone()); + Ok(acc) + } else { + Ok(acc) + } } else { Ok(acc) } - } else { - Ok(acc) - } - })?.unwrap_or_else(|| Elem::Null)) - } + }, + )? + .unwrap_or_else(|| Elem::Null)), Elem::Reference(ref _r) => { - let new_min = lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; + let new_min = + lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; if new_min == lhs_min { Ok(Elem::Null) } else { - match_ty_min(new_min, rhs_min, rhs_max, analyzer) + match_ty_min(new_min, rhs_min, rhs_max, analyzer) } } - _ => Ok(Elem::Null) + _ => Ok(Elem::Null), } } match_ty_min(lhs_min.clone(), rhs_min.clone(), rhs_max, analyzer) .unwrap_or_else(|_| fallback(self, lhs_min, rhs_min, consts)) } - }, + } RangeOp::SetIndices => { if maximize { - let max = self.rhs.simplify_maximize(&mut Default::default(), analyzer)?; - - lhs_max.range_set_indices(&rhs_max) - .unwrap_or_else(|| { - lhs_max.range_set_indices(&max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - }) + let max = self + .rhs + .simplify_maximize(&mut Default::default(), analyzer)?; + + lhs_max.range_set_indices(&rhs_max).unwrap_or_else(|| { + lhs_max + .range_set_indices(&max) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + }) } else { - let min = self.rhs.simplify_minimize(&mut Default::default(), analyzer)?; - lhs_min.range_set_indices(&rhs_min) - .unwrap_or_else(|| { - lhs_min.range_set_indices(&min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - }) + let min = self + .rhs + .simplify_minimize(&mut Default::default(), analyzer)?; + lhs_min.range_set_indices(&rhs_min).unwrap_or_else(|| { + lhs_min + .range_set_indices(&min) + .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) + }) } - }, + } RangeOp::Memcopy => { if maximize { lhs_max.clone() @@ -419,7 +481,7 @@ impl ExecOp for RangeExpr { if unchecked { let mut candidates = vec![]; // check if rhs contains zero, if so add lhs_min and max as candidates - + let one = Elem::from(Concrete::from(U256::from(1))); let zero = Elem::from(Concrete::from(U256::from(0))); let rhs_min_contains_zero = matches!( @@ -556,52 +618,62 @@ impl ExecOp for RangeExpr { // check if rhs contains 1 if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (rhs_min.range_ord(&one), rhs_max.range_ord(&one)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = (rhs_min.range_ord(&one), rhs_max.range_ord(&one)) + { candidates.push(Some(lhs_max.clone())); candidates.push(Some(lhs_min.clone())); } // check if lhs contains 1 if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (lhs_min.range_ord(&one), lhs_max.range_ord(&one)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = (lhs_min.range_ord(&one), lhs_max.range_ord(&one)) + { candidates.push(Some(rhs_max.clone())); candidates.push(Some(rhs_min.clone())); } // check if rhs contains -1 if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (rhs_min.range_ord(&negative_one), rhs_max.range_ord(&negative_one)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = ( + rhs_min.range_ord(&negative_one), + rhs_max.range_ord(&negative_one), + ) { candidates.push(lhs_max.range_mul(&negative_one)); candidates.push(lhs_min.range_mul(&negative_one)); } // check if lhs contains -1 if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (lhs_min.range_ord(&negative_one), lhs_max.range_ord(&negative_one)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = ( + lhs_min.range_ord(&negative_one), + lhs_max.range_ord(&negative_one), + ) { candidates.push(rhs_max.range_mul(&negative_one)); candidates.push(rhs_min.range_mul(&negative_one)); } // check if rhs contains zero if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (rhs_min.range_ord(&zero), rhs_max.range_ord(&zero)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = (rhs_min.range_ord(&zero), rhs_max.range_ord(&zero)) + { candidates.push(Some(zero.clone())); } // check if lhs contains zero if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ) = (lhs_min.range_ord(&zero), lhs_max.range_ord(&zero)) { + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), + ) = (lhs_min.range_ord(&zero), lhs_max.range_ord(&zero)) + { candidates.push(Some(zero.clone())); } candidates.extend(vec![ @@ -612,7 +684,6 @@ impl ExecOp for RangeExpr { ]); let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { Some(r) => r, _ => std::cmp::Ordering::Less, diff --git a/crates/graph/src/range/exec/max.rs b/crates/graph/src/range/exec/max.rs index 1fa32da9..74f1d62c 100644 --- a/crates/graph/src/range/exec/max.rs +++ b/crates/graph/src/range/exec/max.rs @@ -45,7 +45,7 @@ impl RangeMax for Elem { } else { None } - }, + } (_, Elem::Null) => Some(self.clone()), (Elem::Null, _) => Some(other.clone()), _ => None, diff --git a/crates/graph/src/range/exec/mem_ops/concat.rs b/crates/graph/src/range/exec/mem_ops/concat.rs index 47681d9c..e28dd4f3 100644 --- a/crates/graph/src/range/exec/mem_ops/concat.rs +++ b/crates/graph/src/range/exec/mem_ops/concat.rs @@ -1,4 +1,3 @@ - use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; @@ -21,10 +20,13 @@ impl RangeConcat> for RangeDyn { Concrete::DynBytes(val), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) | (Concrete::DynBytes(val), None) => { @@ -53,10 +55,13 @@ impl RangeConcat> for RangeDyn { Concrete::String(val), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::String(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::String(..), + .. + }), + _, + ), )), ) | (Concrete::String(val), None) => { @@ -94,17 +99,23 @@ impl RangeConcat> for RangeDyn { ( Some(( _, - &(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + &( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), Some(( _, - &(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + &( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) => { let last = self.len.clone(); @@ -120,7 +131,11 @@ impl RangeConcat> for RangeDyn { existing.extend(other_vals); Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( - *self.len.clone() + *other.len.clone().max(Box::new(Elem::from(Concrete::from(U256::from(1))))), + *self.len.clone() + + *other + .len + .clone() + .max(Box::new(Elem::from(Concrete::from(U256::from(1))))), existing, other.loc, ))) @@ -133,7 +148,6 @@ impl RangeConcat> for RangeDyn { } } - impl RangeConcat for Elem { fn range_concat(&self, other: &Self) -> Option> { match (self, other) { @@ -144,4 +158,4 @@ impl RangeConcat for Elem { _e => None, } } -} \ No newline at end of file +} diff --git a/crates/graph/src/range/exec/mem_ops/mem_set.rs b/crates/graph/src/range/exec/mem_ops/mem_set.rs index 16e010e8..74f3b9d1 100644 --- a/crates/graph/src/range/exec/mem_ops/mem_set.rs +++ b/crates/graph/src/range/exec/mem_ops/mem_set.rs @@ -1,6 +1,6 @@ use crate::{ nodes::Concrete, - range::{elem::*, exec_traits::*} + range::{elem::*, exec_traits::*}, }; use ethers_core::types::{H256, U256}; @@ -43,10 +43,13 @@ impl RangeMemSet> for RangeDyn { Concrete::DynBytes(val), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }), + _, + ), )), ) | (Concrete::DynBytes(val), None) => { @@ -58,7 +61,10 @@ impl RangeMemSet> for RangeDyn { let mut bytes = [0x00; 32]; bytes[0] = *v; let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (Elem::from(Concrete::from(U256::from(i))), (v, self.op_num + i)) + ( + Elem::from(Concrete::from(U256::from(i))), + (v, self.op_num + i), + ) }) .collect::>(); existing.extend(new); @@ -72,10 +78,13 @@ impl RangeMemSet> for RangeDyn { Concrete::String(val), Some(( _, - (Elem::Concrete(RangeConcrete { - val: Concrete::String(..), - .. - }), _), + ( + Elem::Concrete(RangeConcrete { + val: Concrete::String(..), + .. + }), + _, + ), )), ) | (Concrete::String(val), None) => { @@ -87,7 +96,10 @@ impl RangeMemSet> for RangeDyn { let mut bytes = [0x00; 32]; v.encode_utf8(&mut bytes[..]); let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (Elem::from(Concrete::from(U256::from(i))), (v, i + self.op_num)) + ( + Elem::from(Concrete::from(U256::from(i))), + (v, i + self.op_num), + ) }) .collect::>(); existing.extend(new); @@ -128,7 +140,6 @@ impl RangeMemSet for RangeConcrete { self.val.get_index(&index.val).map(Elem::from) } - fn range_set_length(&self, _other: &Self) -> Option> { unreachable!() } @@ -147,7 +158,6 @@ impl RangeMemSet> for RangeConcrete { unreachable!() } - fn range_set_length(&self, _other: &RangeDyn) -> Option> { unreachable!() } @@ -174,15 +184,13 @@ impl RangeMemSet for Elem { let mut a = a.clone(); a.len = b.len.clone(); Some(Elem::ConcreteDyn(a.clone())) - }, - (a @ Elem::Concrete(_), _b @ Elem::Concrete(_)) => { - Some(a.clone()) - }, + } + (a @ Elem::Concrete(_), _b @ Elem::Concrete(_)) => Some(a.clone()), (Elem::ConcreteDyn(a), _) => { let mut a = a.clone(); a.len = Box::new(other.clone()); Some(Elem::ConcreteDyn(a.clone())) - }, + } _e => None, } } @@ -204,7 +212,7 @@ impl RangeMemSet for Elem { } else { None } - }, + } (Elem::ConcreteDyn(a), idx @ Elem::Reference(_)) => { if let Some((val, _)) = a.val.get(idx).cloned() { Some(val) diff --git a/crates/graph/src/range/exec/mem_ops/mod.rs b/crates/graph/src/range/exec/mem_ops/mod.rs index e06ff543..4bbd3e2c 100644 --- a/crates/graph/src/range/exec/mem_ops/mod.rs +++ b/crates/graph/src/range/exec/mem_ops/mod.rs @@ -1,19 +1,16 @@ mod concat; mod mem_set; -use crate::nodes::Concrete; use crate::elem::Elem; use crate::exec_traits::RangeMemOps; -pub use concat::*; -pub use mem_set::*; - +use crate::nodes::Concrete; impl RangeMemOps for Elem { - fn range_memcopy(&self) -> Option> { - match self { + fn range_memcopy(&self) -> Option> { + match self { Elem::Concrete(_a) => Some(self.clone()), Elem::ConcreteDyn(_a) => Some(self.clone()), _e => None, } - } + } } diff --git a/crates/graph/src/range/exec/min.rs b/crates/graph/src/range/exec/min.rs index 73f00537..823d8a26 100644 --- a/crates/graph/src/range/exec/min.rs +++ b/crates/graph/src/range/exec/min.rs @@ -45,7 +45,7 @@ impl RangeMin for Elem { } else { None } - }, + } (c @ Elem::Concrete(_), Elem::ConcreteDyn(b)) | (Elem::ConcreteDyn(b), c @ Elem::Concrete(_)) => { if b.op_num == 0 { @@ -53,7 +53,7 @@ impl RangeMin for Elem { } else { None } - }, + } (_, Elem::Null) => Some(self.clone()), (Elem::Null, _) => Some(other.clone()), _ => None, diff --git a/crates/graph/src/range/exec/mod.rs b/crates/graph/src/range/exec/mod.rs index 99fbcdae..f7aed5af 100644 --- a/crates/graph/src/range/exec/mod.rs +++ b/crates/graph/src/range/exec/mod.rs @@ -6,10 +6,10 @@ mod exec_op; mod exp; mod logical; mod max; +mod mem_ops; mod min; mod modulo; mod mul; mod ord; mod shift; mod sub; -mod mem_ops; diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index d0671dd7..9b2c160e 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,7 +1,6 @@ -use crate::{range::elem::{Elem}, GraphBackend}; +use crate::{range::elem::Elem, GraphBackend}; use std::collections::BTreeMap; - /// For execution of operations to be performed on range expressions pub trait ExecOp { type GraphError; @@ -167,4 +166,4 @@ pub trait RangeMemSet { /// Applies a transformation of length fn range_set_length(&self, other: &Rhs) -> Option>; fn range_get_length(&self) -> Option>; -} \ No newline at end of file +} diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 13a21d81..4fa9129d 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -76,12 +76,7 @@ impl ToRangeString for Elem { impl ToRangeString for RangeDyn { fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { - let displayed_vals = self - .val - .iter() - .take(20) - .map(|(key, val)| (key, val)) - .collect::>(); + let displayed_vals = self.val.iter().take(20).collect::>(); let val_str = displayed_vals .iter() @@ -111,21 +106,18 @@ impl ToRangeString for RangeDyn { .val .iter() .take(5) - .filter(|(key, (val, op))| *val != Elem::Null) - .map(|(key, (val, op))| { - (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) + .filter(|(_key, (val, _op))| *val != Elem::Null) + .map(|(key, (val, _op))| { + ( + key.to_range_string(maximize, analyzer).s, + val.to_range_string(maximize, analyzer).s, + ) }) .collect::>(); let val_str_head = displayed_vals .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key, - val - ) - }) + .map(|(key, val)| format!("{}: {}", key, val)) .collect::>() .join(", "); @@ -134,22 +126,19 @@ impl ToRangeString for RangeDyn { .iter() .rev() .take(5) - .filter(|(key, (val, op))| *val != Elem::Null) - .map(|(key, (val, op))| { + .filter(|(_key, (val, _op))| *val != Elem::Null) + .map(|(key, (val, _op))| { // (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) - (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) + ( + key.to_range_string(maximize, analyzer).s, + val.to_range_string(maximize, analyzer).s, + ) }) .collect::>(); let val_str_tail = displayed_vals_tail .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key, - val - ) - }) + .map(|(key, val)| format!("{}: {}", key, val)) .collect::>() .join(", "); format!("{val_str_head} ... {val_str_tail}") @@ -158,21 +147,18 @@ impl ToRangeString for RangeDyn { .val .iter() .take(10) - .filter(|(key, (val, op))| *val != Elem::Null) - .map(|(key, (val, op))| { - (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) + .filter(|(_key, (val, _op))| *val != Elem::Null) + .map(|(key, (val, _op))| { + ( + key.to_range_string(maximize, analyzer).s, + val.to_range_string(maximize, analyzer).s, + ) }) .collect::>(); displayed_vals .iter() - .map(|(key, val)| { - format!( - "{}: {}", - key, - val, - ) - }) + .map(|(key, val)| format!("{}: {}", key, val,)) .collect::>() .join(", ") }; @@ -194,8 +180,10 @@ impl ToRangeString for RangeExpr { } fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { - if let MaybeCollapsed::Collapsed(collapsed) = collapse(*self.lhs.clone(), self.op, *self.rhs.clone()) { - return collapsed.to_range_string(maximize, analyzer) + if let MaybeCollapsed::Collapsed(collapsed) = + collapse(*self.lhs.clone(), self.op, *self.rhs.clone()) + { + return collapsed.to_range_string(maximize, analyzer); } let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); let lhs_str = match *self.lhs { @@ -254,11 +242,17 @@ impl ToRangeString for RangeExpr { _ => RangeElemString::new(format!("~{}", lhs_str.s), lhs_str.loc), } } else if matches!(self.op, RangeOp::SetIndices) { - RangeElemString::new(format!("set_indicies({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) + RangeElemString::new( + format!("set_indicies({}, {})", lhs_str.s, rhs_str.s), + lhs_str.loc, + ) } else if matches!(self.op, RangeOp::GetLength) { RangeElemString::new(format!("get_length({})", lhs_str.s), lhs_str.loc) } else if matches!(self.op, RangeOp::SetLength) { - RangeElemString::new(format!("set_length({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) + RangeElemString::new( + format!("set_length({}, {})", lhs_str.s, rhs_str.s), + lhs_str.loc, + ) } else if matches!(self.op, RangeOp::Concat) { RangeElemString::new(format!("concat({}, {})", lhs_str.s, rhs_str.s), lhs_str.loc) } else { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 18025607..1c225f3a 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -686,7 +686,13 @@ impl Range for SolcRange { Ok(()) } /// Produce a flattened range or use the cached flattened range - fn flattened_range<'a>(&'a self, analyzer: &impl GraphBackend) -> Result, Self::GraphError> where Self: Sized + Clone { + fn flattened_range<'a>( + &'a self, + analyzer: &impl GraphBackend, + ) -> Result, Self::GraphError> + where + Self: Sized + Clone, + { if let Some(flat) = &self.flattened { Ok(Cow::Borrowed(flat)) } else { diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index eb449f6c..0ec14f29 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -324,9 +324,9 @@ impl Atomize for Elem { use Elem::*; match self { - Reference(_) => None, //{ println!("was dyn"); None}, - Null => None, //{ println!("was null"); None}, - Concrete(_c) => None, //{ println!("was conc: {}", _c.val.as_human_string()); None }, + Reference(_) => None, //{ println!("was dyn"); None}, + Null => None, //{ println!("was null"); None}, + Concrete(_c) => None, //{ println!("was conc: {}", _c.val.as_human_string()); None }, ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, Expr(_) => { // println!("atomized: was expr"); diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index 924b4a64..067f5301 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -1,10 +1,10 @@ use crate::{ nodes::{ - BuiltInNode, Builtin, Concrete, ConcreteNode, ContextVarNode, ContractNode, EnumNode, - FunctionNode, StructNode, TyNode, + BuiltInNode, Builtin, Concrete, ConcreteNode, ContractNode, EnumNode, FunctionNode, + StructNode, TyNode, }, range::{ - elem::{Elem, RangeElem, Reference}, + elem::{Elem, RangeElem}, Range, SolcRange, }, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, @@ -12,7 +12,7 @@ use crate::{ use shared::NodeIdx; -use ethers_core::types::{Address, H256, U256}; +use ethers_core::types::{Address, U256}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum VarType { diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 4c0a8dde..5b4c39cf 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -227,5 +227,7 @@ impl AnalyzerLike for Analyzer { } } - fn debug_panic(&self) -> bool { self.debug_panic } + fn debug_panic(&self) -> bool { + self.debug_panic + } } diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index af191d6c..19076a27 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -420,7 +420,9 @@ impl GraphDot for Analyzer { ], &|_graph, edge_ref| { match edge_ref.weight() { - Edge::Context(edge) => format!("label = \"{}\"", format!("{edge:?}").replace('"', "\'")), + Edge::Context(edge) => { + format!("label = \"{}\"", format!("{edge:?}").replace('"', "\'")) + } e => format!("label = \"{}\"", format!("{e:?}").replace('"', "\'")), } }, diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 61a1db42..7955c8cc 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -50,9 +50,12 @@ pub trait AnalyzerLike: GraphLike { fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option where Self: std::marker::Sized; - + fn debug_panic(&self) -> bool; - fn add_if_err(&mut self, err: Result) -> Option where Self::ExprErr: std::fmt::Debug { + fn add_if_err(&mut self, err: Result) -> Option + where + Self::ExprErr: std::fmt::Debug, + { match err { Ok(t) => Some(t), Err(e) => { @@ -61,6 +64,4 @@ pub trait AnalyzerLike: GraphLike { } } } - - } diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index 4c09a61c..a7994193 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -1,14 +1,13 @@ -use graph::elem::RangeElem; use crate::{ require::Require, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; +use graph::elem::RangeElem; use graph::{ - elem::{Elem, RangeOp, RangeDyn}, - range_string::ToRangeString, - nodes::{TmpConstruction, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, Node, VarType, Range, + elem::{Elem, RangeDyn, RangeOp}, + nodes::{Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TmpConstruction}, + AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, }; use solang_parser::{ @@ -156,8 +155,14 @@ pub trait Array: AnalyzerBackend + Sized { return_var: bool, ) -> Result, ExprErr> { let idx = self.advance_var_in_ctx(index, loc, ctx)?; - if length_requirement && !parent.is_mapping(self).into_expr_err(loc)? && parent.is_indexable(self).into_expr_err(loc)? { - let len_var = self.get_length(ctx, loc, parent, true)?.unwrap().latest_version(self); + if length_requirement + && !parent.is_mapping(self).into_expr_err(loc)? + && parent.is_indexable(self).into_expr_err(loc)? + { + let len_var = self + .get_length(ctx, loc, parent, true)? + .unwrap() + .latest_version(self); self.require( len_var.latest_version(self), idx.latest_version(self), @@ -169,12 +174,17 @@ pub trait Array: AnalyzerBackend + Sized { )?; } - let name = format!("{}[{}]", parent.name(self).into_expr_err(loc)?, index.name(self).into_expr_err(loc)?); + let name = format!( + "{}[{}]", + parent.name(self).into_expr_err(loc)?, + index.name(self).into_expr_err(loc)? + ); if let Some(index_var) = ctx.var_by_name_or_recurse(self, &name).into_expr_err(loc)? { let index_var = index_var.latest_version(self); let index_var = self.advance_var_in_ctx(index_var, loc, ctx)?; if !return_var { - ctx.push_expr(ExprRet::Single(index_var.into()), self).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(index_var.into()), self) + .into_expr_err(loc)?; Ok(None) } else { Ok(Some(index_var)) @@ -194,25 +204,43 @@ pub trait Array: AnalyzerBackend + Sized { ), storage: *parent.storage(self).into_expr_err(loc)?, is_tmp: false, - tmp_of: Some(TmpConstruction::new(parent, RangeOp::SetIndices, Some(index))), + tmp_of: Some(TmpConstruction::new( + parent, + RangeOp::SetIndices, + Some(index), + )), is_symbolic: true, is_return: false, ty, }; let idx_access_node = self.add_node(Node::ContextVar(index_access_var)); - self.add_edge(idx_access_node, parent, Edge::Context(ContextEdge::IndexAccess)); + self.add_edge( + idx_access_node, + parent, + Edge::Context(ContextEdge::IndexAccess), + ); self.add_edge(idx_access_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(idx_access_node.into(), self).into_expr_err(loc)?; + ctx.add_var(idx_access_node.into(), self) + .into_expr_err(loc)?; self.add_edge(index, idx_access_node, Edge::Context(ContextEdge::Index)); let idx_access_cvar = if has_range { - let min = Elem::from(parent).get_index(index.into()).max(ContextVarNode::from(idx_access_node).into()); //.range_min(self).unwrap().unwrap()); - let max = Elem::from(parent).get_index(index.into()).min(ContextVarNode::from(idx_access_node).into()); //.range_max(self).unwrap().unwrap()); - - let idx_access_cvar = self.advance_var_in_ctx(ContextVarNode::from(idx_access_node), loc, ctx)?; - idx_access_cvar.set_range_min(self, min).into_expr_err(loc)?; - idx_access_cvar.set_range_max(self, max).into_expr_err(loc)?; + let min = Elem::from(parent) + .get_index(index.into()) + .max(ContextVarNode::from(idx_access_node).into()); //.range_min(self).unwrap().unwrap()); + let max = Elem::from(parent) + .get_index(index.into()) + .min(ContextVarNode::from(idx_access_node).into()); //.range_max(self).unwrap().unwrap()); + + let idx_access_cvar = + self.advance_var_in_ctx(ContextVarNode::from(idx_access_node), loc, ctx)?; + idx_access_cvar + .set_range_min(self, min) + .into_expr_err(loc)?; + idx_access_cvar + .set_range_max(self, max) + .into_expr_err(loc)?; if idx_access_cvar .underlying(self) @@ -224,7 +252,6 @@ pub trait Array: AnalyzerBackend + Sized { // if the index access is also an array, produce a length variable // we specify to return the variable because we dont want it on the stack let _ = self.get_length(ctx, loc, idx_access_node.into(), true)?; - } idx_access_cvar } else { @@ -232,7 +259,11 @@ pub trait Array: AnalyzerBackend + Sized { }; if !return_var { - ctx.push_expr(ExprRet::Single(idx_access_cvar.latest_version(self).into()), self).into_expr_err(loc)?; + ctx.push_expr( + ExprRet::Single(idx_access_cvar.latest_version(self).into()), + self, + ) + .into_expr_err(loc)?; Ok(None) } else { Ok(Some(idx_access_cvar.latest_version(self))) @@ -245,7 +276,7 @@ pub trait Array: AnalyzerBackend + Sized { ctx: ContextNode, loc: Loc, maybe_index_access: ContextVarNode, - new_value: ContextVarNode + new_value: ContextVarNode, ) -> Result<(), ExprErr> { if let Some(arr) = maybe_index_access.index_access_to_array(self) { // Was indeed an indexed value @@ -260,21 +291,28 @@ pub trait Array: AnalyzerBackend + Sized { .into_expr_err(loc)? { // update the range - let min = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), new_value.into())], loc)); - let max = Elem::from(arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), new_value.into())], loc)); - next_arr - .set_range_min(self, min) - .into_expr_err(loc)?; - next_arr - .set_range_max(self, max) - .into_expr_err(loc)?; + let min = Elem::from(arr).set_indices(RangeDyn::new_for_indices( + vec![(index.into(), new_value.into())], + loc, + )); + let max = Elem::from(arr).set_indices(RangeDyn::new_for_indices( + vec![(index.into(), new_value.into())], + loc, + )); + next_arr.set_range_min(self, min).into_expr_err(loc)?; + next_arr.set_range_max(self, max).into_expr_err(loc)?; } // handle nested arrays, i.e. if: // uint256[][] memory z; // z[x][y] = 5; // first pass sets z[x][y] = 5, second pass needs to set z[x] = x - self.update_array_if_index_access(ctx, loc, next_arr.latest_version(self), next_arr.latest_version(self))?; + self.update_array_if_index_access( + ctx, + loc, + next_arr.latest_version(self), + next_arr.latest_version(self), + )?; } } Ok(()) @@ -290,11 +328,9 @@ pub trait Array: AnalyzerBackend + Sized { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; let new_len = Elem::from(backing_arr).set_length(maybe_length.into()); next_arr - .set_range_min(self, new_len.clone()) - .into_expr_err(loc)?; - next_arr - .set_range_max(self, new_len) - .into_expr_err(loc)?; + .set_range_min(self, new_len.clone()) + .into_expr_err(loc)?; + next_arr.set_range_max(self, new_len).into_expr_err(loc)?; } Ok(()) } @@ -304,20 +340,20 @@ pub trait Array: AnalyzerBackend + Sized { ctx: ContextNode, loc: Loc, new_length: ContextVarNode, - backing_arr: ContextVarNode + backing_arr: ContextVarNode, ) -> Result<(), ExprErr> { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; let new_len = Elem::from(backing_arr).get_length().max(new_length.into()); let min = Elem::from(backing_arr).set_length(new_len); - next_arr - .set_range_min(self, min) - .into_expr_err(loc)?; + next_arr.set_range_min(self, min).into_expr_err(loc)?; let new_len = Elem::from(backing_arr).get_length().min(new_length.into()); let max = Elem::from(backing_arr).set_length(new_len); - next_arr - .set_range_max(self, max) - .into_expr_err(loc)?; - self.add_edge(new_length, next_arr, Edge::Context(ContextEdge::AttrAccess("length"))); + next_arr.set_range_max(self, max).into_expr_err(loc)?; + self.add_edge( + new_length, + next_arr, + Edge::Context(ContextEdge::AttrAccess("length")), + ); Ok(()) } @@ -327,7 +363,7 @@ pub trait Array: AnalyzerBackend + Sized { loc: Loc, index: ContextVarNode, access: ContextVarNode, - backing_arr: ContextVarNode + backing_arr: ContextVarNode, ) -> Result<(), ExprErr> { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; if next_arr @@ -338,19 +374,30 @@ pub trait Array: AnalyzerBackend + Sized { .into_expr_err(loc)? { // update the range - let min = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), access.into())], loc)); - let max = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices(vec![(index.into(), access.into())], loc)); - next_arr - .set_range_min(self, min) - .into_expr_err(loc)?; - next_arr - .set_range_max(self, max) - .into_expr_err(loc)?; + let min = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices( + vec![(index.into(), access.into())], + loc, + )); + let max = Elem::from(backing_arr).set_indices(RangeDyn::new_for_indices( + vec![(index.into(), access.into())], + loc, + )); + next_arr.set_range_min(self, min).into_expr_err(loc)?; + next_arr.set_range_max(self, max).into_expr_err(loc)?; } // handle nested arrays - if let (Some(backing_arr), Some(parent_nested_index)) = (next_arr.index_access_to_array(self), next_arr.index_access_to_index(self)) { - self.update_array_from_index_access(ctx, loc, parent_nested_index, next_arr, backing_arr.latest_version(self)) + if let (Some(backing_arr), Some(parent_nested_index)) = ( + next_arr.index_access_to_array(self), + next_arr.index_access_to_index(self), + ) { + self.update_array_from_index_access( + ctx, + loc, + parent_nested_index, + next_arr, + backing_arr.latest_version(self), + ) } else { Ok(()) } @@ -364,11 +411,11 @@ pub trait Array: AnalyzerBackend + Sized { ) -> Result<(), ExprErr> { if let Some(backing_arr) = maybe_length.len_var_to_array(self).into_expr_err(loc)? { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; - let new_len = Elem::from(backing_arr).get_length().max(maybe_length.into()); + let new_len = Elem::from(backing_arr) + .get_length() + .max(maybe_length.into()); let min = Elem::from(backing_arr).set_length(new_len); - next_arr - .set_range_min(self, min) - .into_expr_err(loc)?; + next_arr.set_range_min(self, min).into_expr_err(loc)?; } Ok(()) } @@ -381,11 +428,11 @@ pub trait Array: AnalyzerBackend + Sized { ) -> Result<(), ExprErr> { if let Some(backing_arr) = maybe_length.len_var_to_array(self).into_expr_err(loc)? { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; - let new_len = Elem::from(backing_arr).get_length().min(maybe_length.into()); + let new_len = Elem::from(backing_arr) + .get_length() + .min(maybe_length.into()); let max = Elem::from(backing_arr).set_length(new_len); - next_arr - .set_range_max(self, max) - .into_expr_err(loc)?; + next_arr.set_range_max(self, max).into_expr_err(loc)?; } Ok(()) } diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index 02e38252..8849d516 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -1,4 +1,7 @@ -use crate::{ListAccess, array::Array, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::{ + array::Array, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, + ListAccess, +}; use graph::{ elem::Elem, diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 60db9c9c..5b9c9384 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -11,7 +11,7 @@ use graph::{ AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; -use ethers_core::types::{I256, U256}; +use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; impl BinOp for T where T: AnalyzerBackend + Sized {} @@ -209,7 +209,6 @@ pub trait BinOp: AnalyzerBackend + Sized { Elem::from(Reference::new(rhs_cvar.latest_version(self).into())), )); - // to prevent some recursive referencing, forcibly increase lhs_cvar self.advance_var_in_ctx_forcible(lhs_cvar.latest_version(self), loc, ctx, true)?; @@ -237,7 +236,7 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { - // y is symbolic, add + // y is symbolic, add let tmp_rhs = self.advance_var_in_ctx(new_rhs, loc, ctx)?; let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); let var = ContextVar::new_from_concrete( @@ -521,8 +520,14 @@ pub trait BinOp: AnalyzerBackend + Sized { ); let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); - let tmp_rhs = - self.op(loc, max_node.into(), new_rhs, ctx, RangeOp::Div(true), false)?; + let tmp_rhs = self.op( + loc, + max_node.into(), + new_rhs, + ctx, + RangeOp::Div(true), + false, + )?; if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { return Ok(tmp_rhs); @@ -565,7 +570,7 @@ pub trait BinOp: AnalyzerBackend + Sized { tmp_of: Some(TmpConstruction::new( tmp_lhs, RangeOp::Lte, - Some(tmp_rhs.into()), + Some(tmp_rhs), )), is_symbolic: true, is_return: false, @@ -664,7 +669,7 @@ pub trait BinOp: AnalyzerBackend + Sized { _ => {} } } else { - + // self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; } diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 66a282e0..df936ce3 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -1,5 +1,8 @@ //! Helper traits & blanket implementations that help facilitate performing function calls. -use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, member_access::ListAccess}; +use crate::{ + member_access::ListAccess, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, + IntoExprErr, +}; use graph::{ nodes::{ @@ -70,8 +73,6 @@ pub trait CallerHelper: AnalyzerBackend + Edge::Context(ContextEdge::InputVariable), ); - - if let Some(_len_var) = input.array_to_len_var(self) { // bring the length variable along as well self.get_length(callee_ctx, loc, node, false).unwrap(); diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index e721c059..66f8e64e 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -115,7 +115,11 @@ pub trait InternalFuncCaller: .expect("Invalid struct field"); let fc_node = self.add_node(Node::ContextVar(field_cvar)); - self.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + self.add_edge( + fc_node, + cvar, + Edge::Context(ContextEdge::AttrAccess("field")), + ); self.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(fc_node.into(), self).into_expr_err(*loc)?; let field_as_ret = ExprRet::Single(fc_node); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 9066f4aa..880063c8 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,12 +1,11 @@ use crate::{ - array::Array, bin_op::BinOp, assign::Assign, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, - IntoExprErr, ListAccess, + array::Array, bin_op::BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; use graph::{ elem::*, - nodes::{Concrete, ContextVar, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, Node, Edge, ContextEdge, + nodes::{Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, Node, }; use ethers_core::types::U256; @@ -31,8 +30,7 @@ pub trait ArrayCaller: AnalyzerBackend + S // empty element onto the expr ret stack self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -50,33 +48,41 @@ pub trait ArrayCaller: AnalyzerBackend + S let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length - let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); + let len = analyzer + .get_length(ctx, loc, arr, true)? + .unwrap() + .latest_version(analyzer); // get the index access and add it to the stack let _ = analyzer.index_into_array_raw(ctx, loc, len, arr, false, false)?; // create a temporary 1 variable - let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + let cnode = + analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); let tmp_one = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) - .into_expr_err(loc)?, + ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + cnode.into(), + analyzer, + ) + .into_expr_err(loc)?, ); let one = ContextVarNode::from(analyzer.add_node(tmp_one)); // add 1 to the length - let tmp_len = analyzer.op( - loc, - len, - one, - ctx, - RangeOp::Add(false), - false - )?; + let tmp_len = + analyzer.op(loc, len, one, ctx, RangeOp::Add(false), false)?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; - analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; + analyzer.set_var_as_length( + ctx, + loc, + tmp_len, + arr.latest_version(analyzer), + )?; Ok(()) }) @@ -110,47 +116,60 @@ pub trait ArrayCaller: AnalyzerBackend + S ctx.push_expr(new_elem, analyzer).into_expr_err(loc)?; return Ok(()); } - let pushed_value = ContextVarNode::from(new_elem.expect_single().unwrap()); + let pushed_value = + ContextVarNode::from(new_elem.expect_single().unwrap()); // get length let arr = array.expect_single().into_expr_err(loc)?; let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length - let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); + let len = analyzer + .get_length(ctx, loc, arr, true)? + .unwrap() + .latest_version(analyzer); // get the index access for the *previous* length - let index_access = analyzer.index_into_array_raw(ctx, loc, len, arr, false, true)?.unwrap(); + let index_access = analyzer + .index_into_array_raw(ctx, loc, len, arr, false, true)? + .unwrap(); // create a temporary 1 variable - let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); + let cnode = + analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); let tmp_one = Node::ContextVar( - ContextVar::new_from_concrete(Loc::Implicit, ctx, cnode.into(), analyzer) - .into_expr_err(loc)?, + ContextVar::new_from_concrete( + Loc::Implicit, + ctx, + cnode.into(), + analyzer, + ) + .into_expr_err(loc)?, ); let one = ContextVarNode::from(analyzer.add_node(tmp_one)); // add 1 to the length - let tmp_len = analyzer.op( - loc, - len, - one, - ctx, - RangeOp::Add(false), - false - )?; + let tmp_len = + analyzer.op(loc, len, one, ctx, RangeOp::Add(false), false)?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; - // set the new length - analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; - + analyzer.set_var_as_length( + ctx, + loc, + tmp_len, + arr.latest_version(analyzer), + )?; // update the index access's range let elem = Elem::from(pushed_value); - index_access.set_range_min(analyzer, elem.clone()).into_expr_err(loc)?; - index_access.set_range_max(analyzer, elem.clone()).into_expr_err(loc)?; + index_access + .set_range_min(analyzer, elem.clone()) + .into_expr_err(loc)?; + index_access + .set_range_max(analyzer, elem.clone()) + .into_expr_err(loc)?; // update the array using the index access analyzer.update_array_from_index_access( @@ -158,7 +177,7 @@ pub trait ArrayCaller: AnalyzerBackend + S loc, len, index_access.latest_version(analyzer), - arr.latest_version(analyzer) + arr.latest_version(analyzer), ) }) }) @@ -184,9 +203,7 @@ pub trait ArrayCaller: AnalyzerBackend + S } self.parse_ctx_expr(&input_exprs[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(array) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, "array[].pop() was not given an array".to_string(), @@ -203,7 +220,10 @@ pub trait ArrayCaller: AnalyzerBackend + S let arr = ContextVarNode::from(arr).latest_version(analyzer); // get length - let len = analyzer.get_length(ctx, loc, arr, true)?.unwrap().latest_version(analyzer); + let len = analyzer + .get_length(ctx, loc, arr, true)? + .unwrap() + .latest_version(analyzer); // create a temporary 1 variable let cnode = analyzer.add_node(Node::Concrete(Concrete::from(U256::from(1)))); @@ -214,31 +234,30 @@ pub trait ArrayCaller: AnalyzerBackend + S let one = ContextVarNode::from(analyzer.add_node(tmp_one)); // subtract 1 from the length - let tmp_len = analyzer.op( - loc, - len, - one, - ctx, - RangeOp::Sub(false), - false - )?; + let tmp_len = analyzer.op(loc, len, one, ctx, RangeOp::Sub(false), false)?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; // get the index access - let index_access = analyzer.index_into_array_raw(ctx, loc, tmp_len, arr, false, true)?.unwrap(); + let index_access = analyzer + .index_into_array_raw(ctx, loc, tmp_len, arr, false, true)? + .unwrap(); analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; - index_access.set_range_min(analyzer, Elem::Null).into_expr_err(loc)?; - index_access.set_range_max(analyzer, Elem::Null).into_expr_err(loc)?; + index_access + .set_range_min(analyzer, Elem::Null) + .into_expr_err(loc)?; + index_access + .set_range_max(analyzer, Elem::Null) + .into_expr_err(loc)?; analyzer.update_array_from_index_access( ctx, loc, tmp_len, index_access.latest_version(analyzer), - arr.latest_version(analyzer) + arr.latest_version(analyzer), ) // let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { // return Err(ExprErr::NoLhs( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 25da2e29..8f7d0e67 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -79,7 +79,11 @@ pub trait ConstructorCaller: ctx.add_var(arr, analyzer).into_expr_err(loc)?; analyzer.add_edge(len_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(len_cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(len_cvar, arr, Edge::Context(ContextEdge::AttrAccess("length"))); + analyzer.add_edge( + len_cvar, + arr, + Edge::Context(ContextEdge::AttrAccess("length")), + ); // update the length if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { @@ -195,7 +199,11 @@ pub trait ConstructorCaller: .expect("Invalid struct field"); let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); - analyzer.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + analyzer.add_edge( + fc_node, + cvar, + Edge::Context(ContextEdge::AttrAccess("field")), + ); analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; let field_as_ret = ExprRet::Single(fc_node); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index bf3b65e1..a7325173 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,9 +1,11 @@ -use crate::{variable::Variable, ListAccess, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::{ + variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, +}; use graph::{ - elem::RangeElem, ContextEdge, Edge, + elem::RangeElem, nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, Node, SolcRange, VarType, range_string::ToRangeString, + AnalyzerBackend, ContextEdge, Edge, Node, SolcRange, VarType, }; use solang_parser::pt::{Expression, Loc}; @@ -100,20 +102,21 @@ pub trait DynBuiltinCaller: AnalyzerBackend { + Ok(()) } + ExprRet::Null => Ok(()), ExprRet::Multi(inner) => inner .into_iter() .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, true)), @@ -232,8 +235,18 @@ pub trait DynBuiltinCaller: AnalyzerBackend { - let min = r.min.clone().concat(r2.min.clone()).simplify_minimize(&mut Default::default(), self).into_expr_err(loc)?; - let max = r.max.clone().concat(r2.max.clone()).simplify_maximize(&mut Default::default(), self).into_expr_err(loc)?; + let min = r + .min + .clone() + .concat(r2.min.clone()) + .simplify_minimize(&mut Default::default(), self) + .into_expr_err(loc)?; + let max = r + .max + .clone() + .concat(r2.max.clone()) + .simplify_maximize(&mut Default::default(), self) + .into_expr_err(loc)?; accum.set_range_min(self, min).into_expr_err(loc)?; accum.set_range_max(self, max).into_expr_err(loc)?; Ok(()) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 1c244c58..ed959c19 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -6,7 +6,7 @@ use crate::{ use graph::{ elem::*, nodes::{BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode}, - AnalyzerBackend, GraphBackend, Node, Range, SolcRange, VarType, + AnalyzerBackend, GraphBackend, Node, Range, VarType, }; use shared::NodeIdx; @@ -152,10 +152,14 @@ pub trait TypesCaller: AnalyzerBackend + S let v_ty = VarType::try_from_idx(analyzer, func_idx).expect(""); let maybe_new_range = cvar.cast_exprs(&v_ty, analyzer).into_expr_err(loc)?; new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = v_ty; - + if let Some((new_min, new_max)) = maybe_new_range { - new_var.set_range_min(analyzer, new_min).into_expr_err(loc)?; - new_var.set_range_max(analyzer, new_max).into_expr_err(loc)?; + new_var + .set_range_min(analyzer, new_min) + .into_expr_err(loc)?; + new_var + .set_range_max(analyzer, new_max) + .into_expr_err(loc)?; } ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index e1d85d22..85e9307d 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -43,7 +43,7 @@ pub trait ListAccess: AnalyzerBackend + Si ctx: ContextNode, loc: Loc, elem_path: ExprRet, - update_len_bound: bool, + _update_len_bound: bool, ) -> Result<(), ExprErr> { match elem_path { ExprRet::Null => { @@ -64,13 +64,9 @@ pub trait ListAccess: AnalyzerBackend + Si ctx: ContextNode, loc: Loc, array: ContextVarNode, - return_var: bool + return_var: bool, ) -> Result, ExprErr> { - let next_arr = self.advance_var_in_ctx( - array.latest_version(self), - loc, - ctx, - )?; + let next_arr = self.advance_var_in_ctx(array.latest_version(self), loc, ctx)?; // search for latest length if let Some(len_var) = next_arr.array_to_len_var(self) { let len_node = self.advance_var_in_ctx(len_var.latest_version(self), loc, ctx)?; @@ -87,8 +83,12 @@ pub trait ListAccess: AnalyzerBackend + Si // Create the range from the current length or default to [0, uint256.max] - let len_min = Elem::from(next_arr).get_length().max(Elem::from(Concrete::from(U256::zero()))); - let len_max = Elem::from(next_arr).get_length().min(Elem::from(Concrete::from(U256::MAX))); + let len_min = Elem::from(next_arr) + .get_length() + .max(Elem::from(Concrete::from(U256::zero()))); + let len_max = Elem::from(next_arr) + .get_length() + .min(Elem::from(Concrete::from(U256::MAX))); let range = SolcRange::new(len_min, len_max, vec![]); let len_var = ContextVar { @@ -106,22 +106,27 @@ pub trait ListAccess: AnalyzerBackend + Si ), }; let len_node = ContextVarNode::from(self.add_node(Node::ContextVar(len_var))); - self.add_edge(len_node, array, Edge::Context(ContextEdge::AttrAccess("length"))); + self.add_edge( + len_node, + array, + Edge::Context(ContextEdge::AttrAccess("length")), + ); self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(len_node, self).into_expr_err(loc)?; // we have to force here to avoid length <-> array recursion - let next_next_arr = self.advance_var_in_ctx_forcible( - array.latest_version(self), - loc, - ctx, - true - )?; - let update_array_len = Elem::from(next_arr.latest_version(self)).set_length(len_node.into()); + let next_next_arr = + self.advance_var_in_ctx_forcible(array.latest_version(self), loc, ctx, true)?; + let update_array_len = + Elem::from(next_arr.latest_version(self)).set_length(len_node.into()); // Update the array - next_next_arr.set_range_min(self, update_array_len.clone()).into_expr_err(loc)?; - next_next_arr.set_range_max(self, update_array_len.clone()).into_expr_err(loc)?; + next_next_arr + .set_range_min(self, update_array_len.clone()) + .into_expr_err(loc)?; + next_next_arr + .set_range_max(self, update_array_len.clone()) + .into_expr_err(loc)?; if !return_var { ctx.push_expr(ExprRet::Single(len_node.into()), self) @@ -183,7 +188,9 @@ pub trait ListAccess: AnalyzerBackend + Si let min = r.simplified_range_min(self).unwrap(); let max = r.simplified_range_max(self).unwrap(); if let Some(mut rd) = min.maybe_range_dyn() { - ContextVarNode::from(len_node).set_range_min(self, *rd.len.clone()).unwrap(); + ContextVarNode::from(len_node) + .set_range_min(self, *rd.len.clone()) + .unwrap(); rd.len = Box::new(Elem::from(len_node)); let res = next_arr .set_range_min(self, Elem::ConcreteDyn(rd)) @@ -192,7 +199,9 @@ pub trait ListAccess: AnalyzerBackend + Si } if let Some(mut rd) = max.maybe_range_dyn() { - ContextVarNode::from(len_node).set_range_max(self, *rd.len.clone()).unwrap(); + ContextVarNode::from(len_node) + .set_range_max(self, *rd.len.clone()) + .unwrap(); rd.len = Box::new(Elem::from(len_node)); let res = next_arr .set_range_max(self, Elem::ConcreteDyn(rd)) @@ -202,7 +211,11 @@ pub trait ListAccess: AnalyzerBackend + Si } } - self.add_edge(len_node, arr, Edge::Context(ContextEdge::AttrAccess("length"))); + self.add_edge( + len_node, + arr, + Edge::Context(ContextEdge::AttrAccess("length")), + ); self.add_edge(len_node, array_ctx, Edge::Context(ContextEdge::Variable)); array_ctx.add_var(len_node.into(), self).unwrap(); len_node.into() diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index aa96d0ef..a41489ef 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -1,4 +1,4 @@ -use crate::{array::Array, BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; +use crate::{BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, Variable}; use graph::{ elem::*, @@ -10,7 +10,7 @@ use graph::{ AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; -use ethers_core::types::{U256, I256}; +use ethers_core::types::I256; use solang_parser::{ helpers::CodeLocation, pt::{Expression, Loc}, @@ -728,16 +728,18 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // flip the new range around to be in terms of rhs let rhs_range_fn = SolcRange::dyn_fn_from_op(rhs_op); new_var_range = rhs_range_fn(rhs_range.clone(), new_lhs); - if self - .update_nonconst_from_const(ctx, loc, rhs_op, new_lhs, new_rhs, rhs_range)? - { + if self.update_nonconst_from_const( + ctx, loc, rhs_op, new_lhs, new_rhs, rhs_range, + )? { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); } } (false, true) => { - if self.update_nonconst_from_const(ctx, loc, op, new_rhs, new_lhs, lhs_range)? { + if self + .update_nonconst_from_const(ctx, loc, op, new_rhs, new_lhs, lhs_range)? + { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); @@ -764,7 +766,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } new_rhs = new_rhs.latest_version(self); new_lhs = new_lhs.latest_version(self); - + let rhs_display_name = new_rhs.display_name(self).into_expr_err(loc)?; let display_name = if rhs_display_name == "true" { (new_lhs.display_name(self).into_expr_err(loc)?).to_string() @@ -947,7 +949,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { #[tracing::instrument(level = "trace", skip_all)] fn update_nonconst_from_const( &mut self, - ctx: ContextNode, + _ctx: ContextNode, loc: Loc, op: RangeOp, const_var: ContextVarNode, @@ -1118,7 +1120,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Given a const var and a nonconst range, update the range based on the op. Returns whether its impossible fn update_nonconst_from_nonconst( &mut self, - ctx: ContextNode, + _ctx: ContextNode, loc: Loc, op: RangeOp, new_lhs: ContextVarNode, From 10468a9968d3c08c6a4acf9f379d041b7301f077 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 12:58:02 -0800 Subject: [PATCH 46/71] recursive caching --- crates/cli/src/main.rs | 4 +- crates/graph/src/nodes/context/var/ranging.rs | 35 ++++++++++++---- crates/graph/src/nodes/context/variables.rs | 2 +- crates/graph/src/range/elem/concrete.rs | 6 +-- crates/graph/src/range/elem/elem_enum.rs | 6 +-- crates/graph/src/range/elem/elem_trait.rs | 6 +-- crates/graph/src/range/elem/expr.rs | 14 +++++-- crates/graph/src/range/elem/map_or_array.rs | 42 +++++++++++++++---- crates/graph/src/range/elem/reference.rs | 14 +++++-- crates/graph/src/range/exec/exec_op.rs | 3 +- crates/graph/src/range/exec_traits.rs | 2 +- crates/graph/src/range/range_trait.rs | 2 +- crates/graph/src/range/solc_range.rs | 2 +- crates/graph/src/solvers/brute.rs | 24 +++++------ crates/solc-expressions/src/variable.rs | 2 + 15 files changed, 115 insertions(+), 49 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 006b409a..3dff0931 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -360,12 +360,12 @@ fn main() { // println!("{:#?}", c.ctx_deps_as_controllables_str(&analyzer).unwrap()); if let Some(mut solver) = BruteBinSearchSolver::maybe_new( c.ctx_deps(&analyzer).unwrap(), - &analyzer, + &mut analyzer, ) .unwrap() { println!("created solver"); - match solver.solve(&analyzer).unwrap() { + match solver.solve(&mut analyzer).unwrap() { AtomicSolveStatus::Unsat => { println!("TRUE UNSAT: {}", c.path(&analyzer)); } diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 8242ec1b..1590705f 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -119,13 +119,21 @@ impl ContextVarNode { Ok(()) } - // pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - // if let Some(mut range) = self.range(analyzer)? { - // range.cache_flatten(analyzer)?; - // self.set_range(analyzer, range)?; - // } - // Ok(()) - // } + pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + if let Some(mut range) = self.range(analyzer)? { + range.cache_flatten(analyzer)?; + self.set_range(analyzer, range)?; + } + Ok(()) + } + + pub fn cache_eval_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + if let Some(mut range) = self.range(analyzer)? { + range.cache_eval(analyzer)?; + self.set_range(analyzer, range)?; + } + Ok(()) + } pub fn set_range( &self, @@ -176,6 +184,9 @@ impl ContextVarNode { } } + // new_min.cache_flatten(analyzer)?; + // new_min.cache_minimize(analyzer)?; + tracing::trace!( "setting range minimum: {} (node idx: {}), current:{}, new_min:{}, deps: {:#?}", self.display_name(analyzer)?, @@ -216,6 +227,10 @@ impl ContextVarNode { } } + // new_max.cache_flatten(analyzer)?; + // new_max.cache_maximize(analyzer)?; + + tracing::trace!( "setting range maximum: {:?}, {}, current: {}, new: {}", self, @@ -276,6 +291,9 @@ impl ContextVarNode { } } + new_min.cache_flatten(analyzer)?; + new_min.cache_minimize(analyzer)?; + if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; @@ -305,6 +323,9 @@ impl ContextVarNode { } } + new_max.cache_flatten(analyzer)?; + new_max.cache_maximize(analyzer)?; + if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 6fc5c1d8..6063cca1 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -14,7 +14,7 @@ impl ContextNode { var: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { - var.cache_range(analyzer)?; + // var.cache_range(analyzer)?; let name = var.name(analyzer)?; let vars = &mut self.underlying_mut(analyzer)?.cache.vars; vars.insert(name, var); diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index f3d0d814..17d39b78 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -52,7 +52,7 @@ impl RangeElem for RangeConcrete { true } - fn cache_flatten(&mut self, _: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten(&mut self, _: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } @@ -152,11 +152,11 @@ impl RangeElem for RangeConcrete { Ok(Elem::Concrete(self.clone())) } - fn cache_maximize(&mut self, _g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize(&mut self, _g: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } - fn cache_minimize(&mut self, _g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize(&mut self, _g: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } fn uncache(&mut self) {} diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 1a19eea6..7863a211 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -558,7 +558,7 @@ impl RangeElem for Elem { } } - fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { match self { Self::Reference(d) => d.cache_flatten(analyzer), Self::Concrete(c) => c.cache_flatten(analyzer), @@ -714,7 +714,7 @@ impl RangeElem for Elem { Ok(res) } - fn cache_maximize(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { use Elem::*; match self { Reference(dy) => dy.cache_maximize(analyzer), @@ -732,7 +732,7 @@ impl RangeElem for Elem { } } - fn cache_minimize(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { use Elem::*; match self { Reference(dy) => dy.cache_minimize(analyzer), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 14577171..a72af98a 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -19,15 +19,15 @@ pub trait RangeElem { /// Returns whether `cache_flatten` has been called fn is_flatten_cached(&self) -> bool; /// Flattens an element and caches the result - fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value fn maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Maximizes the element and caches the result for quicker use later - fn cache_maximize(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_maximize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value fn minimize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Minimizes the element and caches the result for quicker use later - fn cache_minimize(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_minimize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Uncaches the minimum and maximum fn uncache(&mut self); /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 32a5a254..d52cddf8 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -247,13 +247,17 @@ impl RangeElem for RangeExpr { } } - fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { + self.lhs.cache_flatten(g)?; + self.rhs.cache_flatten(g)?; let flat_max = self.flatten(true, g)?; let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { + self.lhs.cache_flatten(g)?; + self.rhs.cache_flatten(g)?; let flat_min = self.flatten(false, g)?; let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); @@ -261,15 +265,19 @@ impl RangeElem for RangeExpr { Ok(()) } - fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { + self.lhs.cache_maximize(g)?; + self.rhs.cache_maximize(g)?; self.cache_exec_op(true, g)?; } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { + self.lhs.cache_minimize(g)?; + self.rhs.cache_minimize(g)?; self.cache_exec_op(false, g)?; } Ok(()) diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index cffbdc1c..62f49257 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -233,15 +233,29 @@ impl RangeElem for RangeDyn { })) } - fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { - let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; + self.len.cache_flatten(analyzer)?; + let mapping = std::mem::take(&mut self.val); + self.val = mapping.into_iter().map(|(mut idx, mut val)| { + idx.cache_flatten(analyzer).unwrap(); + val.0.cache_flatten(analyzer).unwrap(); + (idx, val) + }).collect(); + let flat_max = self.flatten(true, analyzer)?; + let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), analyzer)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { - let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; + self.len.cache_flatten(analyzer)?; + let mapping = std::mem::take(&mut self.val); + self.val = mapping.into_iter().map(|(mut idx, mut val)| { + idx.cache_flatten(analyzer).unwrap(); + val.0.cache_flatten(analyzer).unwrap(); + (idx, val) + }).collect(); + let flat_min = self.flatten(false, analyzer)?; + let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), analyzer)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) @@ -376,15 +390,29 @@ impl RangeElem for RangeDyn { ))) } - fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { + self.len.cache_maximize(g)?; + let mapping = std::mem::take(&mut self.val); + self.val = mapping.into_iter().map(|(mut idx, mut val)| { + idx.cache_maximize(g).unwrap(); + val.0.cache_maximize(g).unwrap(); + (idx, val) + }).collect(); self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { + self.len.cache_minimize(g)?; + let mapping = std::mem::take(&mut self.val); + self.val = mapping.into_iter().map(|(mut idx, mut val)| { + idx.cache_minimize(g).unwrap(); + val.0.cache_minimize(g).unwrap(); + (idx, val) + }).collect(); self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); } Ok(()) diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index acb97fa0..72a89a4e 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -130,13 +130,17 @@ impl RangeElem for Reference { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn cache_flatten(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { + let cvar = ContextVarNode::from(self.idx); + cvar.cache_flattened_range(g)?; let flat_max = self.flatten(true, g)?; let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { + let cvar = ContextVarNode::from(self.idx); + cvar.cache_flattened_range(g)?; let flat_min = self.flatten(false, g)?; let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); @@ -238,15 +242,19 @@ impl RangeElem for Reference { } } - fn cache_maximize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { + let cvar = ContextVarNode::from(self.idx); + cvar.cache_eval_range(g)?; self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); } Ok(()) } - fn cache_minimize(&mut self, g: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { + let cvar = ContextVarNode::from(self.idx); + cvar.cache_eval_range(g)?; self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); } Ok(()) diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 62c58d6c..ae6ad591 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -23,7 +23,7 @@ impl ExecOp for RangeExpr { fn cache_exec_op( &mut self, maximize: bool, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result<(), GraphError> { self.lhs.cache_minimize(analyzer)?; self.lhs.cache_maximize(analyzer)?; @@ -286,7 +286,6 @@ impl ExecOp for RangeExpr { RangeOp::GetLength => { if maximize { let mut new = lhs_max.clone(); - new.uncache(); let new_max = new.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_max.range_get_length(); res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index 9b2c160e..6c5a028a 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -22,7 +22,7 @@ pub trait ExecOp { fn cache_exec_op( &mut self, maximize: bool, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result<(), Self::GraphError>; fn spread( diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index 23163d88..623d8a38 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -6,7 +6,7 @@ pub trait Range { type GraphError; type ElemTy: RangeElem + Clone; /// Evaluate both the minimum and the maximum - cache along the way - fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Evaluate the range minimum fn evaled_range_min( &self, diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 1c225f3a..8425574a 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -600,7 +600,7 @@ impl Range for SolcRange { &mut self.max } - fn cache_eval(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { + fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if self.max_cached.is_none() { let max = self.range_max_mut(); max.cache_flatten(analyzer)?; diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index d72138ed..5dbe98bd 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -15,20 +15,20 @@ pub trait SolcSolver { fn simplify(&mut self, analyzer: &(impl GraphBackend + AnalyzerBackend)); fn solve( &mut self, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result; fn recurse_check( &mut self, idx: usize, solved_atomics: &mut Vec, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result; fn check( &mut self, solved_for: usize, lmr: (Elem, Elem, Elem), solved_atomics: &mut Vec, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(bool, Option), GraphError>; } @@ -83,7 +83,7 @@ pub enum HintOrRanges { impl BruteBinSearchSolver { pub fn maybe_new( deps: Vec, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result, GraphError> { let mut atomic_idxs = vec![]; @@ -184,7 +184,7 @@ impl BruteBinSearchSolver { pub fn lmr( &self, atomic: &Atomic, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> (Elem, Elem, Elem) { let range = &self.atomic_ranges[atomic]; let mut min = range.evaled_range_min(analyzer).unwrap(); @@ -197,14 +197,14 @@ impl BruteBinSearchSolver { (min, mid, max) } - pub fn reset_lmrs(&mut self, analyzer: &impl GraphBackend) { + pub fn reset_lmrs(&mut self, analyzer: &mut impl GraphBackend) { self.lmrs = vec![]; (0..self.atomic_ranges.len()).for_each(|i| { self.lmrs.push(self.lmr(&self.atomics[i], analyzer).into()); }); } - pub fn reset_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) { + pub fn reset_lmr(&mut self, i: usize, analyzer: &mut impl GraphBackend) { self.lmrs[i] = self.lmr(&self.atomics[i], analyzer).into(); } @@ -274,7 +274,7 @@ impl SolcSolver for BruteBinSearchSolver { fn solve( &mut self, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { // pick a value for a variable. check if it satisfies all dependendies // if is sat, try to reduce using bin search? Not sure how that will @@ -431,7 +431,7 @@ impl SolcSolver for BruteBinSearchSolver { &mut self, i: usize, solved_atomics: &mut Vec, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { // println!("recurse check for: {}", self.atomics[i].idxs[0].display_name(analyzer).unwrap()); if i >= self.lmrs.len() { @@ -515,7 +515,7 @@ impl SolcSolver for BruteBinSearchSolver { solved_for_idx: usize, (low, mid, high): (Elem, Elem, Elem), solved_atomics: &mut Vec, - analyzer: &(impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(bool, Option), GraphError> { let solved_dep = &self.atomics[solved_for_idx].clone(); @@ -528,7 +528,7 @@ impl SolcSolver for BruteBinSearchSolver { mut mid_done: bool, mut high_done: bool, solved_atomics: &mut Vec, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result<(bool, Option), GraphError> { let res = if !low_done { check_for_lmr( @@ -590,7 +590,7 @@ impl SolcSolver for BruteBinSearchSolver { solved_dep: &Atomic, conc: Elem, solved_atomics: &mut Vec, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result<(bool, Option), GraphError> { // println!("checking: {}, conc: {}, {}", this.atomics[solved_for_idx].idxs[0].display_name(analyzer).unwrap(), conc.maximize(analyzer)?.to_range_string(true, analyzer).s, conc.minimize(analyzer)?.to_range_string(false, analyzer).s); solved_atomics.push(solved_for_idx); diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index fb713c49..8623bc6a 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,3 +1,5 @@ +use graph::elem::RangeElem; +use graph::Range; use crate::{assign::Assign, env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ From 18b8def0225a91d9ee268f8f38fea4033e424a8f Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 17:04:13 -0800 Subject: [PATCH 47/71] refactor function call --- Cargo.lock | 13 +- crates/cli/Cargo.toml | 16 +- crates/graph/src/nodes/concrete.rs | 25 +++ crates/graph/src/nodes/context/expr_ret.rs | 9 ++ crates/graph/src/nodes/contract_ty.rs | 9 ++ crates/graph/src/nodes/func_ty.rs | 38 +++++ crates/graph/src/range/elem/concrete.rs | 6 + crates/graph/src/range/elem/elem_enum.rs | 17 ++ crates/graph/src/range/elem/map_or_array.rs | 25 ++- crates/pyrometer/src/analyzer.rs | 3 + .../pyrometer/tests/test_data/intrinsics.sol | 1 + crates/solc-expressions/Cargo.toml | 2 + .../src/context_builder/expr.rs | 21 ++- .../src/func_call/func_caller.rs | 149 +++++++++++++++++- .../solc-expressions/src/func_call/helper.rs | 53 ++++--- .../src/func_call/internal_call.rs | 40 ++++- .../src/func_call/intrinsic_call/abi.rs | 4 +- .../src/func_call/intrinsic_call/address.rs | 3 +- .../src/func_call/intrinsic_call/array.rs | 11 +- .../src/func_call/intrinsic_call/block.rs | 7 +- .../func_call/intrinsic_call/constructors.rs | 13 +- .../func_call/intrinsic_call/dyn_builtin.rs | 7 +- .../intrinsic_call/intrinsic_caller.rs | 132 +++++++++++++++- .../src/func_call/intrinsic_call/msg.rs | 3 +- .../func_call/intrinsic_call/precompile.rs | 17 +- .../src/func_call/intrinsic_call/solidity.rs | 73 +++++++-- .../src/func_call/intrinsic_call/types.rs | 29 +++- .../src/func_call/namespaced_call.rs | 59 +++---- .../src/member_access/func_access.rs | 0 .../solc-expressions/src/yul/yul_builder.rs | 25 ++- crates/solc-expressions/src/yul/yul_funcs.rs | 74 ++++++--- 31 files changed, 733 insertions(+), 151 deletions(-) create mode 100644 crates/solc-expressions/src/member_access/func_access.rs diff --git a/Cargo.lock b/Cargo.lock index eb2ec0c1..0de06ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,7 +326,7 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "analyzers", "ariadne", @@ -927,6 +927,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types", + "tiny-keccak", +] + [[package]] name = "lalrpop" version = "0.19.12" @@ -1782,6 +1792,7 @@ dependencies = [ "ethers-core", "graph", "hex", + "keccak-hash", "petgraph", "shared", "solang-parser", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 7c14ee7d..98cc05ee 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,7 +1,13 @@ [package] name = "cli" -version = "0.1.0" -edition = "2021" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -21,9 +27,9 @@ ethers-core.workspace = true clap = { version = "4.1.4", features = ["derive"] } -# [[bin]] -# name = "pyrometer" -# path = "src/main.rs" +[[bin]] +name = "pyrometer" +path = "src/main.rs" # [profile.release] diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 3b033650..85356b68 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -920,6 +920,31 @@ impl Concrete { } } + pub fn as_bytes(&self) -> Vec { + match self { + Concrete::Uint(_, val) => { + let mut bytes = [0; 32]; + val.to_big_endian(&mut bytes); + bytes.to_vec() + }, + Concrete::Int(_, val) => { + let mut bytes = [0; 32]; + val.to_big_endian(&mut bytes); + bytes.to_vec() + }, + Concrete::Bytes(_, _) + | Concrete::Address(_) + | Concrete::Bool(_) => { + Concrete::Uint(256, self.into_u256().unwrap()).as_bytes() + } + Concrete::DynBytes(inner) => inner.clone(), + Concrete::String(inner) => inner.as_bytes().to_vec(), + Concrete::Array(inner) => { + inner.iter().flat_map(|i| i.as_bytes()).collect() + }, + } + } + /// Converts to a human readable string. For integers, this means trying to find a /// power of 2 that is close to the value. pub fn as_human_string(&self) -> String { diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index a4fd2e64..b9b6b782 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -267,4 +267,13 @@ impl ExprRet { _ => self, } } + + pub fn len(&self) -> usize { + match self { + ExprRet::Single(_) | ExprRet::SingleLiteral(_) => 1, + ExprRet::Multi(inner) => inner.len(), + ExprRet::CtxKilled(..) => 0, + ExprRet::Null => 0, + } + } } diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 77f6dbca..d10a9cca 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -136,6 +136,15 @@ impl ContractNode { .collect() } + pub fn constructor(&self, analyzer: &(impl GraphBackend + Search)) -> Option { + analyzer + .search_children_depth(self.0.into(), &Edge::Constructor, 1, 0) + .into_iter() + .map(FunctionNode::from) + .take(1) + .next() + } + /// Gets all associated storage vars from the underlying node data for the [`Contract`] pub fn direct_storage_vars(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { analyzer diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index c5d0d8f4..c5ec2d01 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -35,6 +35,14 @@ impl FunctionNode { } } + pub fn ty(&self, analyzer: &impl GraphBackend) -> Result { + Ok(self.underlying(analyzer)?.ty) + } + + pub fn is_constructor(&self, analyzer: &impl GraphBackend) -> Result { + Ok(matches!(self.ty(analyzer)?, FunctionTy::Constructor)) + } + pub fn body_loc(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(body_stmt) = &self.underlying(analyzer)?.body { Ok(Some(body_stmt.loc())) @@ -130,6 +138,21 @@ impl FunctionNode { } } + pub fn prefix_only_name(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + match self.underlying(analyzer)?.ty { + FunctionTy::Function => Ok(Some(self + .underlying(analyzer)? + .name + .clone() + .expect("Unnamed function") + .name + .chars() + .take_while(|&ch| ch != '(') + .collect::())), + _ => Ok(None) + } + } + pub fn loc_specified_name( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), @@ -324,6 +347,21 @@ impl FunctionNode { } } + pub fn ordered_param_names(&self, analyzer: &impl GraphBackend) -> Vec { + let param_nodes = self.params(analyzer); + param_nodes.iter().map(|i| i.name(analyzer).unwrap()).collect() + } + + pub fn maybe_ordered_param_names(&self, analyzer: &impl GraphBackend) -> Option> { + let param_nodes = self.params(analyzer); + let names: Vec = param_nodes.iter().filter_map(|i| i.maybe_name(analyzer).unwrap()).collect(); + if names.len() == param_nodes.len() { + Some(names) + } else { + None + } + } + pub fn set_params_and_ret( &self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 17d39b78..f3cf5dba 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -26,6 +26,12 @@ impl From for RangeConcrete { } } +impl RangeConcrete { + pub fn as_bytes(&self, _analyzer: &impl GraphBackend, _maximize: bool) -> Option> { + Some(self.val.as_bytes()) + } +} + impl RangeElem for RangeConcrete { type GraphError = GraphError; // fn simplify(&self, _analyzer: &impl GraphBackend) -> Elem { diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 7863a211..6b518987 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -314,6 +314,21 @@ impl From for Elem { } impl Elem { + + pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { + let evaled = if maximize { + self.maximize(analyzer).ok()? + } else { + self.minimize(analyzer).ok()? + }; + + match evaled { + Elem::Concrete(c) => c.as_bytes(analyzer, maximize), + Elem::ConcreteDyn(c) => c.as_bytes(analyzer, maximize), + _ => None, + } + } + pub fn overlaps( &self, other: &Self, @@ -529,6 +544,8 @@ impl RangeElem for Elem { fn range_eq(&self, other: &Self) -> bool { match (self, other) { (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), + (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b), + (Self::Reference(a), Self::Reference(b)) => a.idx == b.idx, _ => false, } } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 62f49257..9089f234 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -108,13 +108,32 @@ impl RangeDyn { } } -impl RangeDyn {} +impl RangeDyn { + pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { + let len = if maximize { + self.len.maximize(analyzer).ok()?.concrete()?.into_u256()?.as_usize() + } else { + self.len.minimize(analyzer).ok()?.concrete()?.into_u256()?.as_usize() + }; + + Some( + self.val.values().map(|v| { + v.0.as_bytes(analyzer, maximize) + }) + .collect::>>>()? + .into_iter() + .flatten() + .take(len) + .collect() + ) + } +} impl RangeElem for RangeDyn { type GraphError = GraphError; - fn range_eq(&self, _other: &Self) -> bool { - false + fn range_eq(&self, other: &Self) -> bool { + matches!(self.range_ord(other), Some(std::cmp::Ordering::Equal)) } fn range_ord(&self, other: &Self) -> Option { diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index ae0ba5fc..7461792a 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -99,6 +99,8 @@ pub struct Analyzer { pub file_no: usize, /// The index of the current `msg` node pub msg: MsgNode, + /// The index of the current `msg` node + pub tmp_msg: Option, /// The index of the current `block` node pub block: BlockNode, /// The underlying graph holding all of the elements of the contracts @@ -136,6 +138,7 @@ impl Default for Analyzer { final_pass_items: Default::default(), file_no: 0, msg: MsgNode(0), + tmp_msg: None, block: BlockNode(0), graph: Default::default(), entry: NodeIndex::from(0), diff --git a/crates/pyrometer/tests/test_data/intrinsics.sol b/crates/pyrometer/tests/test_data/intrinsics.sol index f10ebce7..3f984539 100644 --- a/crates/pyrometer/tests/test_data/intrinsics.sol +++ b/crates/pyrometer/tests/test_data/intrinsics.sol @@ -77,6 +77,7 @@ contract Intrinsics { function precompiles() public { bytes memory a = hex"aa"; bytes32 hash = keccak256(a); + require(hash == 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365); bytes32 shaHash = sha256(a); bytes20 ripmdHash = ripemd160(a); address recoveredAddr = ecrecover(hash, 1, 2, 3); diff --git a/crates/solc-expressions/Cargo.toml b/crates/solc-expressions/Cargo.toml index a6ed6cf3..d94fd868 100644 --- a/crates/solc-expressions/Cargo.toml +++ b/crates/solc-expressions/Cargo.toml @@ -21,3 +21,5 @@ ethers-core.workspace = true hex.workspace = true tracing.workspace = true tracing-subscriber.workspace = true + +keccak-hash = "0.10.0" diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index 3a551e69..64b6656a 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -1,3 +1,4 @@ +use crate::func_call::intrinsic_call::IntrinsicFuncCaller; use crate::{ context_builder::ContextBuilder, func_call::func_caller::FuncCaller, variable::Variable, ExprErr, ExprTyParser, IntoExprErr, @@ -282,6 +283,11 @@ pub trait ExpressionParser: let updated_func_expr = match **func_expr { FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { // we dont currently handle the `{value: .. gas: ..}` msg updating + println!("call block: {call_block:#?}"); + + // let mut tmp_msg = Msg { + + // } self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); inner_func_expr.clone() } @@ -291,7 +297,20 @@ pub trait ExpressionParser: self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) } // member - New(_loc, expr) => self.parse_ctx_expr(expr, ctx), + New(_loc, expr) => { + match &**expr { + Expression::FunctionCall(loc, func, inputs) => { + // parse the type + self.new_call( + loc, + func, + inputs, + ctx + ) + }, + _ => panic!("Bad new call") + } + } This(loc) => { let var = ContextVar::new_from_contract( *loc, diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 7418cd60..2d4589d6 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,5 +1,7 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. +use std::rc::Rc; +use std::cell::RefCell; use crate::{ func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, @@ -19,6 +21,143 @@ use solang_parser::pt::{Expression, Loc, NamedArgument}; use std::collections::BTreeMap; + +#[derive(Debug)] +pub enum NamedOrUnnamedArgs<'a> { + Named(&'a [NamedArgument]), + Unnamed(&'a [Expression]) +} + +impl<'a> NamedOrUnnamedArgs<'a> { + pub fn named_args(&self) -> Option<&'a [NamedArgument]> { + match self { + NamedOrUnnamedArgs::Named(inner) => Some(inner), + _ => None + } + } + + pub fn unnamed_args(&self) -> Option<&'a [Expression]> { + match self { + NamedOrUnnamedArgs::Unnamed(inner) => Some(inner), + _ => None + } + } + + pub fn len(&self) -> usize { + match self { + NamedOrUnnamedArgs::Unnamed(inner) => inner.len(), + NamedOrUnnamedArgs::Named(inner) => inner.len(), + } + } + + pub fn is_empty(&self) -> bool { + match self { + NamedOrUnnamedArgs::Unnamed(inner) => inner.len() == 0, + NamedOrUnnamedArgs::Named(inner) => inner.len() == 0, + } + } + + pub fn exprs(&self) -> Vec { + match self { + NamedOrUnnamedArgs::Unnamed(inner) => inner.to_vec(), + NamedOrUnnamedArgs::Named(inner) => inner.iter().map(|i| i.expr.clone()).collect(), + } + } + + pub fn parse(&self, analyzer: &mut (impl AnalyzerBackend + Sized + GraphBackend), ctx: ContextNode, loc: Loc) -> Result<(), ExprErr> { + match self { + NamedOrUnnamedArgs::Unnamed(inner) => analyzer.parse_inputs(ctx, loc, inner), + NamedOrUnnamedArgs::Named(inner) => { + let append = Rc::new(RefCell::new(false)); + inner.iter().try_for_each(|arg| { + analyzer.parse_input(ctx, loc, &arg.expr, &append)?; + Ok(()) + })?; + if !inner.is_empty() { + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + }, + } + } + + pub fn parse_n(&self, n: usize, analyzer: &mut (impl AnalyzerBackend + Sized + GraphBackend), ctx: ContextNode, loc: Loc) -> Result<(), ExprErr> { + let append = Rc::new(RefCell::new(false)); + match self { + NamedOrUnnamedArgs::Unnamed(inner) => { + inner.iter().take(n).try_for_each(|arg| { + analyzer.parse_input(ctx, loc, arg, &append)?; + Ok(()) + })?; + if !inner.is_empty() { + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + }, + NamedOrUnnamedArgs::Named(inner) => { + inner.iter().take(n).try_for_each(|arg| { + analyzer.parse_input(ctx, loc, &arg.expr, &append)?; + Ok(()) + })?; + if !inner.is_empty() { + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + ctx.push_expr(ret, analyzer).into_expr_err(loc) + }) + } else { + Ok(()) + } + }, + } + } + + pub fn order(&self, inputs: ExprRet, ordered_params: Vec) -> ExprRet { + if inputs.len() < 2 { + inputs + } else { + match self { + NamedOrUnnamedArgs::Unnamed(_inner) => inputs, + NamedOrUnnamedArgs::Named(inner) => { + ExprRet::Multi(ordered_params.iter().map(|param| { + let index = inner.iter().enumerate().find(|(_i, arg)| { + &arg.name.name == param + }).unwrap().0; + match &inputs { + ExprRet::Multi(inner) => { + inner[index].clone() + } + _ => panic!("Mismatched ExprRet type") + } + }).collect()) + }, + } + } + } +} + impl FuncCaller for T where T: AnalyzerBackend + Sized + GraphBackend + CallerHelper { @@ -39,7 +178,7 @@ pub trait FuncCaller: use solang_parser::pt::Expression::*; match func_expr { MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_named_func(ctx, loc, member_expr, ident, input_exprs) + self.call_name_spaced_func(ctx, loc, member_expr, ident, NamedOrUnnamedArgs::Named(input_exprs)) } Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), e => Err(ExprErr::IntrinsicNamedArgs( @@ -60,9 +199,9 @@ pub trait FuncCaller: use solang_parser::pt::Expression::*; match func_expr { MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_func(ctx, loc, member_expr, ident, input_exprs) + self.call_name_spaced_func(ctx, loc, member_expr, ident, NamedOrUnnamedArgs::Unnamed(input_exprs)) } - Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, input_exprs), + Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, NamedOrUnnamedArgs::Unnamed(input_exprs)), _ => { self.parse_ctx_expr(func_expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { @@ -76,7 +215,7 @@ pub trait FuncCaller: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(input_exprs), ret) }) } } @@ -87,7 +226,7 @@ pub trait FuncCaller: &mut self, ctx: ContextNode, loc: &Loc, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, ret: ExprRet, ) -> Result<(), ExprErr> { match ret { diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index df936ce3..6d673e6a 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -13,7 +13,7 @@ use graph::{ }; use shared::{NodeIdx, StorageLocation}; -use solang_parser::pt::{Expression, Loc}; +use solang_parser::pt::{Expression, Loc, CodeLocation}; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; @@ -123,26 +123,9 @@ pub trait CallerHelper: AnalyzerBackend + }; inputs.iter().try_for_each(|input| { - self.parse_ctx_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( - loc, - "Inputs did not have left hand sides".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - if *append.borrow() { - ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) - } else { - *append.borrow_mut() = true; - ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) - } - }) + self.parse_input(ctx, loc, input, &append) })?; + if !inputs.is_empty() { self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { @@ -158,6 +141,34 @@ pub trait CallerHelper: AnalyzerBackend + } } + fn parse_input( + &mut self, + ctx: ContextNode, + _loc: Loc, + input: &Expression, + append: &Rc>, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(input, ctx)?; + self.apply_to_edges(ctx, input.loc(), &|analyzer, ctx, loc| { + let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoLhs( + loc, + "Inputs did not have left hand sides".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + if *append.borrow() { + ctx.append_tmp_expr(ret, analyzer).into_expr_err(loc) + } else { + *append.borrow_mut() = true; + ctx.push_tmp_expr(ret, analyzer).into_expr_err(loc) + } + }) + } + /// Creates a new context for a call fn create_call_ctx( &mut self, @@ -311,7 +322,7 @@ pub trait CallerHelper: AnalyzerBackend + .modifier_state .clone(), ) - .unwrap(); + .into_expr_err(loc)?; let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 66f8e64e..13d1dc66 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -1,5 +1,6 @@ //! Traits & blanket implementations that facilitate performing locally scoped function calls. +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ assign::Assign, func_call::func_caller::FuncCaller, helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, @@ -27,7 +28,6 @@ pub trait InternalFuncCaller: ctx: ContextNode, loc: &Loc, ident: &Identifier, - // _func_expr: &Expression, input_args: &[NamedArgument], ) -> Result<(), ExprErr> { // It is a function call, check if we have the ident in scope @@ -192,7 +192,7 @@ pub trait InternalFuncCaller: loc: &Loc, ident: &Identifier, func_expr: &Expression, - input_exprs: &[Expression], + input_exprs: NamedOrUnnamedArgs, ) -> Result<(), ExprErr> { tracing::trace!("function call: {}(..)", ident.name); // It is a function call, check if we have the ident in scope @@ -202,9 +202,28 @@ pub trait InternalFuncCaller: let possible_funcs = funcs .iter() .filter(|func| { - func.name(self) + let named_correctly = func + .name(self) .unwrap() - .starts_with(&format!("{}(", ident.name)) + .starts_with(&format!("{}(", ident.name)); + if !named_correctly { + false + } else { + // filter by params + let params = func.params(self); + if params.len() != input_exprs.len() { + false + } else if matches!(input_exprs, NamedOrUnnamedArgs::Named(_)) { + params.iter().all(|param| { + input_exprs.named_args() + .unwrap() + .iter() + .any(|input| input.name.name == param.name(self).unwrap()) + }) + } else { + true + } + } }) .copied() .collect::>(); @@ -223,17 +242,22 @@ pub trait InternalFuncCaller: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_intrinsic_fallback(ctx, &loc, input_exprs, ret) + analyzer.match_intrinsic_fallback(ctx, &loc, &input_exprs, ret) }) } 1 => { // there is only a single possible function - self.parse_inputs(ctx, *loc, input_exprs)?; + input_exprs.parse(self, ctx, *loc)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let inputs = ctx + let mut inputs = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? .unwrap_or_else(|| ExprRet::Multi(vec![])); + inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + input_exprs.order(inputs, ordered_param_names) + } else { + inputs + }; let inputs = inputs.flatten(); if matches!(inputs, ExprRet::CtxKilled(_)) { ctx.push_expr(inputs, analyzer).into_expr_err(loc)?; @@ -250,7 +274,7 @@ pub trait InternalFuncCaller: } _ => { // this is the annoying case due to function overloading & type inference on number literals - self.parse_inputs(ctx, *loc, input_exprs)?; + input_exprs.parse(self, ctx, *loc)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let inputs = ctx .pop_expr_latest(loc, analyzer) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 84e7befb..2ec3985e 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ @@ -15,7 +16,7 @@ pub trait AbiCaller: AnalyzerBackend + Siz fn abi_call( &mut self, func_name: String, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -74,6 +75,7 @@ pub trait AbiCaller: AnalyzerBackend + Siz )), } } + let input_exprs = input_exprs.unnamed_args().unwrap(); self.parse_ctx_expr(&input_exprs[1], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs index 8303d01d..4542c45c 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ExprErr, IntoExprErr}; use graph::{ @@ -15,7 +16,7 @@ pub trait AddressCaller: AnalyzerBackend + fn address_call( &mut self, func_name: String, - _input_exprs: &[Expression], + _input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 880063c8..0c883067 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ array::Array, bin_op::BinOp, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; @@ -19,7 +20,7 @@ pub trait ArrayCaller: AnalyzerBackend + S fn array_call( &mut self, func_name: String, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -28,7 +29,7 @@ pub trait ArrayCaller: AnalyzerBackend + S if input_exprs.len() == 1 { // array.push() is valid syntax. It pushes a new // empty element onto the expr ret stack - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -88,7 +89,7 @@ pub trait ArrayCaller: AnalyzerBackend + S }) } else if input_exprs.len() == 2 { // array.push(value) - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -101,7 +102,7 @@ pub trait ArrayCaller: AnalyzerBackend + S ctx.push_expr(array, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_expr(&input_exprs[1], ctx)?; + analyzer.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[1], ctx)?; analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(new_elem) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? @@ -201,7 +202,7 @@ pub trait ArrayCaller: AnalyzerBackend + S ), )); } - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index edb12ead..8b2d2951 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -1,4 +1,5 @@ -use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use crate::func_caller::NamedOrUnnamedArgs; +use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ nodes::{Builtin, ContextNode, ContextVar, ExprRet}, @@ -15,13 +16,13 @@ pub trait BlockCaller: AnalyzerBackend + S fn block_call( &mut self, func_name: String, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { "blockhash" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; + input_exprs.parse_n(1, self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 8f7d0e67..9a01ba20 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ assign::Assign, func_call::helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, @@ -25,12 +26,12 @@ pub trait ConstructorCaller: fn construct_array( &mut self, func_idx: NodeIdx, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { // create a new list - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); @@ -113,13 +114,13 @@ pub trait ConstructorCaller: fn construct_contract( &mut self, func_idx: NodeIdx, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { // construct a new contract if !input_exprs.is_empty() { - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; } self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { if !input_exprs.is_empty() { @@ -161,7 +162,7 @@ pub trait ConstructorCaller: fn construct_struct( &mut self, func_idx: NodeIdx, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -172,7 +173,7 @@ pub trait ConstructorCaller: ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index a7325173..438b8020 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; @@ -19,7 +20,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend Result<(), ExprErr> { @@ -40,10 +41,10 @@ pub trait DynBuiltinCaller: AnalyzerBackend Result<(), ExprErr> { - input_exprs[1..].iter().try_for_each(|expr| { + input_exprs.unnamed_args().unwrap()[1..].iter().try_for_each(|expr| { self.parse_ctx_expr(expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let input = ctx diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index a6126edf..68aa4d2d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -1,3 +1,9 @@ +use crate::func_call::func_caller::FuncCaller; +use crate::context_builder::ExpressionParser; +use graph::nodes::ContextVarNode; +use crate::func_caller::NamedOrUnnamedArgs; +use graph::nodes::ContractNode; +use graph::nodes::ContextVar; use crate::{ func_call::helper::CallerHelper, intrinsic_call::{ @@ -55,12 +61,132 @@ impl IntrinsicFuncCaller for T where pub trait IntrinsicFuncCaller: AnalyzerBackend + Sized + CallerParts { + fn new_call( + &mut self, + loc: &Loc, + ty_expr: &Expression, + inputs: &[Expression], + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(ty_expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(ty) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "No type given for call to `new`".to_string(), + )); + }; + let ty_idx = ty.expect_single().into_expr_err(loc)?; + match analyzer.node(ty_idx) { + Node::Builtin(Builtin::Array(_)) => { + // construct a new list + analyzer.construct_array(ty_idx, &NamedOrUnnamedArgs::Unnamed(inputs), loc, ctx) + } + Node::Contract(_c) => { + let cnode = ContractNode::from(ty_idx); + if let Some(constructor) = cnode.constructor(analyzer) { + let params = constructor.params(analyzer); + if params.is_empty() { + // call the constructor + let inputs = ExprRet::Multi(vec![]); + analyzer.func_call( + ctx, + loc, + &inputs, + constructor, + None, + None, + )?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, ty_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(ty_idx) + ), + )) + } + }; + let contract_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + }) + } else { + analyzer.parse_inputs(ctx, loc, inputs)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(input_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No inputs for constructor and expected some".to_string(), + )); + }; + // call the constructor + analyzer.func_call( + ctx, + loc, + &input_paths, + constructor, + None, + None, + )?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, ty_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(ty_idx) + ), + )) + } + }; + let contract_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + }) + }) + } + } else { + let var = match ContextVar::maybe_from_user_ty(analyzer, loc, ty_idx) { + Some(v) => v, + None => { + return Err(ExprErr::VarBadType( + loc, + format!( + "Could not create context variable from user type: {:?}", + analyzer.node(ty_idx) + ), + )) + } + }; + let contract_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); + ctx.push_expr(ExprRet::Single(contract_cvar.into()), analyzer) + .into_expr_err(loc) + } + } + _ => Err(ExprErr::ParseError(loc, "Tried to construct a new element of a type that doesn't support the `new` keyword".to_string())) + } + }) + } + /// Calls an intrinsic/builtin function call (casts, require, etc.) #[tracing::instrument(level = "trace", skip_all)] fn intrinsic_func_call( &mut self, loc: &Loc, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, func_idx: NodeIdx, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -104,7 +230,7 @@ pub trait IntrinsicFuncCaller: } // typing "type" | "wrap" | "unwrap" => { - self.types_call(func_name.name.clone(), input_exprs, *loc, ctx) + self.types_call(func_name.name.clone(), func_idx, input_exprs, *loc, ctx) } e => Err(ExprErr::Todo( *loc, @@ -139,7 +265,7 @@ pub trait IntrinsicFuncCaller: } Node::Unresolved(_) => { // Try to give a nice error - self.parse_inputs(ctx, *loc, input_exprs)?; + input_exprs.parse(self, ctx, *loc)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs index d2b3f1d5..26b1da9d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/msg.rs @@ -1,3 +1,4 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ExprErr, IntoExprErr}; use graph::{ @@ -15,7 +16,7 @@ pub trait MsgCaller: AnalyzerBackend + Siz fn msg_call( &mut self, func_name: String, - _input_exprs: &[Expression], + _input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 9bcb866c..db449ef3 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,3 +1,5 @@ +use graph::nodes::FunctionNode; +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ func_call::helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; @@ -24,13 +26,13 @@ pub trait PrecompileCaller: &mut self, func_name: String, func_idx: NodeIdx, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { "sha256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -55,7 +57,7 @@ pub trait PrecompileCaller: }) } "ripemd160" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -80,8 +82,7 @@ pub trait PrecompileCaller: }) } "ecrecover" => { - self.parse_inputs(ctx, loc, input_exprs)?; - + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let cctx = Context::new_subctx( ctx, @@ -109,6 +110,12 @@ pub trait PrecompileCaller: )); }; + let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + input_exprs.order(input, ordered_param_names) + } else { + input + }; + if matches!(input, ExprRet::CtxKilled(_)) { ctx.push_expr(input, analyzer).into_expr_err(loc)?; return Ok(()); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index 70b5e76d..f26cec46 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -1,13 +1,15 @@ +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ func_call::helper::CallerHelper, require::Require, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; use graph::{ - nodes::{Builtin, ContextNode, ContextVar, ExprRet}, + nodes::{Builtin, ContextNode, ContextVar, ExprRet, Concrete, ConcreteNode, ContextVarNode}, AnalyzerBackend, Node, }; +use ethers_core::types::H256; use solang_parser::pt::{Expression, Loc}; impl SolidityCaller for T where @@ -23,36 +25,75 @@ pub trait SolidityCaller: fn solidity_call( &mut self, func_name: String, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { "keccak256" => { - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(_input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, - "keccak256 call was not given inputs".to_string(), + "No input into keccak256" + .to_string(), )); }; - let var = ContextVar::new_from_builtin( - loc, - analyzer.builtin_or_add(Builtin::Bytes(32)).into(), - analyzer, - ) - .into_expr_err(loc)?; - let cvar = analyzer.add_node(Node::ContextVar(var)); - ctx.push_expr(ExprRet::Single(cvar), analyzer) + + let cvar = if let Ok(var) = input.expect_single() { + ContextVarNode::from(var) + } else { + return Err(ExprErr::NoRhs( + loc, + "No input into keccak256" + .to_string(), + )); + }; + + + if cvar.is_const(analyzer).into_expr_err(loc)? { + let bytes = cvar.evaled_range_min(analyzer) + .unwrap() + .unwrap() + .as_bytes(analyzer, true) + .unwrap(); + let mut out = [0; 32]; + keccak_hash::keccak_256(&bytes, &mut out); + + let hash = Node::Concrete(Concrete::from(H256(out))); + let hash_node = ConcreteNode::from(analyzer.add_node(hash)); + let var = ContextVar::new_from_concrete( + loc, + ctx, + hash_node, + analyzer, + ) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + } else { + println!("not const: [{}]", cvar.range_string(analyzer).unwrap().unwrap()); + let var = ContextVar::new_from_builtin( + loc, + analyzer.builtin_or_add(Builtin::Bytes(32)).into(), + analyzer, + ) .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + } + Ok(()) }) } "addmod" => { // TODO: actually calcuate this if possible - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; @@ -70,7 +111,7 @@ pub trait SolidityCaller: } "mulmod" => { // TODO: actually calcuate this if possible - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; let var = ContextVar::new_from_builtin( @@ -86,7 +127,7 @@ pub trait SolidityCaller: }) } "require" | "assert" => self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(input_exprs, ctx) + analyzer.handle_require(input_exprs.unnamed_args().unwrap(), ctx) }), _ => Err(ExprErr::FunctionNotFound( loc, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index ed959c19..7942f436 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,3 +1,5 @@ +use graph::nodes::FunctionNode; +use crate::func_caller::NamedOrUnnamedArgs; use crate::{ func_call::helper::CallerHelper, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, @@ -20,18 +22,19 @@ pub trait TypesCaller: AnalyzerBackend + S fn types_call( &mut self, func_name: String, - input_exprs: &[Expression], + func_idx: NodeIdx, + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { - "type" => self.parse_ctx_expr(&input_exprs[0], ctx), + "type" => self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx), "wrap" => { if input_exprs.len() != 2 { return Err(ExprErr::InvalidFunctionInput(loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); } - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -39,6 +42,13 @@ pub trait TypesCaller: AnalyzerBackend + S ".wrap(..) did not receive an input".to_string(), )); }; + + let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + input_exprs.order(input, ordered_param_names) + } else { + input + }; + input.expect_length(2).into_expr_err(loc)?; let ret = input.as_vec(); let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; @@ -61,7 +71,7 @@ pub trait TypesCaller: AnalyzerBackend + S }) } "unwrap" => { - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -69,6 +79,13 @@ pub trait TypesCaller: AnalyzerBackend + S ".unwrap(..) did not receive an input".to_string(), )); }; + + let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + input_exprs.order(input, ordered_param_names) + } else { + input + }; + input.expect_length(2).into_expr_err(loc)?; let ret = input.as_vec(); let wrapping_ty = ret[0].expect_single().into_expr_err(loc)?; @@ -127,7 +144,7 @@ pub trait TypesCaller: AnalyzerBackend + S &mut self, ty: Builtin, func_idx: NodeIdx, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -172,7 +189,7 @@ pub trait TypesCaller: AnalyzerBackend + S } } - self.parse_ctx_expr(&input_exprs[0], ctx)?; + self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Cast had no target type".to_string())); diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index b6079862..a33f58e7 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,7 +1,7 @@ //! Traits & blanket implementations that facilitate performing namespaced function calls. use crate::{ - func_call::func_caller::FuncCaller, func_call::helper::CallerHelper, + func_call::func_caller::{NamedOrUnnamedArgs, FuncCaller}, func_call::helper::CallerHelper, intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; @@ -13,7 +13,7 @@ use graph::{ use shared::NodeIdx; -use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; +use solang_parser::pt::{Expression, Identifier, Loc}; impl NameSpaceFuncCaller for T where T: AnalyzerBackend + Sized + GraphBackend + CallerHelper @@ -23,20 +23,6 @@ impl NameSpaceFuncCaller for T where pub trait NameSpaceFuncCaller: AnalyzerBackend + Sized + GraphBackend + CallerHelper { - #[tracing::instrument(level = "trace", skip_all)] - /// TODO: Call a namedspaced named input function, i.e. `MyContract.myFunc({a: 1, b: 2})` - fn call_name_spaced_named_func( - &mut self, - ctx: ContextNode, - _loc: &Loc, - member_expr: &Expression, - _ident: &Identifier, - _input_args: &[NamedArgument], - ) -> Result<(), ExprErr> { - self.parse_ctx_expr(member_expr, ctx)?; - todo!("here"); - } - #[tracing::instrument(level = "trace", skip_all)] /// Call a namedspaced function, i.e. `MyContract.myFunc(...)` fn call_name_spaced_func( @@ -45,7 +31,7 @@ pub trait NameSpaceFuncCaller: loc: &Loc, member_expr: &Expression, ident: &Identifier, - input_exprs: &[Expression], + input_exprs: NamedOrUnnamedArgs, ) -> Result<(), ExprErr> { use solang_parser::pt::Expression::*; tracing::trace!("Calling name spaced function"); @@ -55,7 +41,7 @@ pub trait NameSpaceFuncCaller: let fn_node = self .builtin_fn_or_maybe_add(&func_name) .unwrap_or_else(|| panic!("No builtin function with name {func_name}")); - return self.intrinsic_func_call(loc, input_exprs, fn_node, ctx); + return self.intrinsic_func_call(loc, &input_exprs, fn_node, ctx); } else if name == "super" { if let Some(contract) = ctx.maybe_associated_contract(self).into_expr_err(*loc)? { let supers = contract.super_contracts(self); @@ -76,7 +62,7 @@ pub trait NameSpaceFuncCaller: "Could not find function in super".to_string(), )); } - self.parse_inputs(ctx, *loc, input_exprs)?; + input_exprs.parse(self, ctx, *loc)?; return self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let inputs = if let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? @@ -86,7 +72,11 @@ pub trait NameSpaceFuncCaller: ExprRet::Multi(vec![]) }; if possible_funcs.len() == 1 { - let mut inputs = inputs.as_vec(); + let mut inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + input_exprs.order(inputs, ordered_param_names).as_vec() + } else { + inputs.as_vec() + }; let func = possible_funcs[0]; if func.params(analyzer).len() < inputs.len() { inputs = inputs[1..].to_vec(); @@ -103,6 +93,7 @@ pub trait NameSpaceFuncCaller: let mut lits = vec![false]; lits.extend( input_exprs + .exprs() .iter() .map(|expr| { match expr { @@ -155,7 +146,7 @@ pub trait NameSpaceFuncCaller: return Ok(()); } - analyzer.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) + analyzer.match_namespaced_member(ctx, loc, member_expr, ident, &input_exprs, ret) }) } @@ -166,7 +157,7 @@ pub trait NameSpaceFuncCaller: loc: Loc, member_expr: &Expression, ident: &Identifier, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, ret: ExprRet, ) -> Result<(), ExprErr> { match ret { @@ -192,7 +183,7 @@ pub trait NameSpaceFuncCaller: loc: Loc, member_expr: &Expression, ident: &Identifier, - input_exprs: &[Expression], + input_exprs: &NamedOrUnnamedArgs, member: NodeIdx, ) -> Result<(), ExprErr> { use solang_parser::pt::Expression::*; @@ -217,7 +208,7 @@ pub trait NameSpaceFuncCaller: ctx.push_expr(ExprRet::Single(member), self) .into_expr_err(loc)?; - self.parse_inputs(ctx, loc, input_exprs)?; + input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -329,13 +320,8 @@ pub trait NameSpaceFuncCaller: return Ok(()); } let mut modifier_input_exprs = vec![member_expr.clone()]; - modifier_input_exprs.extend(input_exprs.to_vec()); - analyzer.match_intrinsic_fallback( - ctx, - &loc, - &modifier_input_exprs, - ret, - ) + modifier_input_exprs.extend(input_exprs.exprs()); + analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), ret) }) } else { // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) @@ -374,12 +360,16 @@ pub trait NameSpaceFuncCaller: return Ok(()); } let mut modifier_input_exprs = vec![member_expr.clone()]; - modifier_input_exprs.extend(input_exprs.to_vec()); - analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + modifier_input_exprs.extend(input_exprs.exprs()); + analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), ret) }) } } else if possible_funcs.len() == 1 { - let mut inputs = inputs.as_vec(); + let mut inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + input_exprs.order(inputs, ordered_param_names).as_vec() + } else { + inputs.as_vec() + }; let func = possible_funcs[0]; if func.params(analyzer).len() > inputs.len() { // Add the member back in if its a context variable @@ -406,6 +396,7 @@ pub trait NameSpaceFuncCaller: let mut lits = vec![false]; lits.extend( input_exprs + .exprs() .iter() .map(|expr| { match expr { diff --git a/crates/solc-expressions/src/member_access/func_access.rs b/crates/solc-expressions/src/member_access/func_access.rs new file mode 100644 index 00000000..e69de29b diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index f3f43c53..9ba4193e 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -312,10 +312,27 @@ pub trait YulBuilder: }) } FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), - SuffixAccess(_loc, _yul_member_expr, _ident) => Err(ExprErr::Todo( - expr.loc(), - "Yul member access not yet supported".to_string(), - )), + SuffixAccess(loc, yul_member_expr, ident) => { + self.parse_inputs( + ctx, + *loc, + &[*yul_member_expr.clone()], + )?; + + self.apply_to_edges(ctx, *loc, &|analyzer, _ctx, _loc| { + match &*ident.name { + "slot" => { + Ok(()) + } + _ => { + Err(ExprErr::Todo( + expr.loc(), + format!("Yul member access `{}` not yet supported", ident.name), + )) + } + } + }) + }, } } diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 95dbeacb..253aa2a9 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,5 +1,5 @@ use crate::{ - variable::Variable, yul::YulBuilder, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, + assign::Assign, variable::Variable, yul::YulBuilder, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, }; use graph::{ @@ -461,24 +461,60 @@ pub trait YulFuncCaller: Ok(()) } "sstore" => { - // TODO: improve this. Right now we are extremely pessimistic and just say we know nothing about storage variables anymore. - // We should check if the location is a reference to an existing var and update based on that - let vars = ctx.local_vars(self).clone(); - vars.iter().try_for_each(|(_name, var)| { - // widen to any max range - let latest_var = var.latest_version(self); - if matches!( - latest_var.underlying(self).into_expr_err(*loc)?.storage, - Some(StorageLocation::Storage(_)) - ) { - let res = latest_var.ty(self).into_expr_err(*loc)?; - if let Some(r) = res.default_range(self).unwrap() { - let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); - let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); - let _ = self.add_if_err(res); - let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); - let _ = self.add_if_err(res); - } + if arguments.len() != 2 { + return Err(ExprErr::InvalidFunctionInput( + *loc, + format!( + "Yul function: `{}` expects 2 arguments found: {:?}", + id.name, + arguments.len() + ), + )); + } + + self.parse_inputs(ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Some(mut lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::InvalidFunctionInput( + loc, + "Yul `sload` operation had no inputs".to_string(), + )); + }; + + if lhs_paths.expect_length(2).into_expr_err(loc).is_err() { + return Err(ExprErr::NoRhs( + loc, + "Yul `sload` operation had no rhs".to_string(), + )); + } + let value = lhs_paths.take_one().into_expr_err(loc)?.unwrap(); + let slot = lhs_paths.take_one().into_expr_err(loc)?.unwrap(); + let cvar = ContextVarNode::from(slot.expect_single().unwrap()); + + if cvar.is_storage(analyzer).into_expr_err(loc)? { + analyzer.match_assign_sides(ctx, loc, &slot, &value)?; + } else { + // TODO: improve this. We now handle `slot` but should try to figure out storage layout + let vars = ctx.local_vars(analyzer).clone(); + vars.iter().try_for_each(|(_name, var)| { + // widen to any max range + let latest_var = var.latest_version(analyzer); + if matches!( + latest_var.underlying(analyzer).into_expr_err(loc)?.storage, + Some(StorageLocation::Storage(_)) + ) { + let res = latest_var.ty(analyzer).into_expr_err(loc)?; + if let Some(r) = res.default_range(analyzer).unwrap() { + let new_var = analyzer.advance_var_in_ctx(latest_var, loc, ctx).unwrap(); + let res = new_var.set_range_min(analyzer, r.min).into_expr_err(loc); + let _ = analyzer.add_if_err(res); + let res = new_var.set_range_max(analyzer, r.max).into_expr_err(loc); + let _ = analyzer.add_if_err(res); + } + } + Ok(()) + })?; } Ok(()) })?; From cd3a5392822d32a4cdea98ab7151621b24a461f2 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 17:52:43 -0800 Subject: [PATCH 48/71] fixes --- crates/graph/src/graph_elements.rs | 2 + crates/graph/src/nodes/context/typing.rs | 14 ++++ crates/graph/src/nodes/context/variables.rs | 9 +++ crates/graph/src/nodes/context/versioning.rs | 29 ++++++++ .../src/context_builder/expr.rs | 4 +- .../intrinsic_call/intrinsic_caller.rs | 4 +- .../solc-expressions/src/yul/yul_builder.rs | 69 ++++++++++++++----- 7 files changed, 111 insertions(+), 20 deletions(-) diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 7b760ea5..3a61fc79 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -349,6 +349,8 @@ pub enum ContextEdge { FuncAccess, /// A write to a storage variable, connecting the variable that is written to the variable and the storage variable itself StorageWrite, + /// An access to a storage slot + SlotAccess, // Variable incoming edges /// Unused diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index 49e2612e..ad97d933 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -4,6 +4,20 @@ use crate::{ }; impl ContextNode { + /// Checks if its an anonymous function call (i.e. loop) + pub fn is_anonymous_fn_call(&self, analyzer: &impl GraphBackend) -> Result { + let underlying = self.underlying(analyzer)?; + + Ok(underlying.fn_call.is_none() && underlying.ext_fn_call.is_none() && !underlying.is_fork) + } + + pub fn has_continuation( + &self, + analyzer: &mut impl GraphBackend, + ) -> Result { + Ok(self.underlying(analyzer)?.continuation_of.is_some()) + } + /// Returns whether this context is killed or returned pub fn killed_or_ret(&self, analyzer: &impl GraphBackend) -> Result { let underlying = self.underlying(analyzer)?; diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 6063cca1..d6a1dbe7 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -21,6 +21,15 @@ impl ContextNode { Ok(()) } + /// Returns whether the context's cache contains a variable (by name) + pub fn contains_var( + &self, + var_name: &str, + analyzer: &impl GraphBackend, + ) -> Result { + Ok(self.underlying(analyzer)?.cache.vars.contains_key(var_name)) + } + /// Gets a variable by name in the context pub fn var_by_name(&self, analyzer: &impl GraphBackend, name: &str) -> Option { self.underlying(analyzer) diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index e56bf422..6662ae8d 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,3 +1,5 @@ +use crate::ContextEdge; +use petgraph::graph::Edge; use crate::{ nodes::{CallFork, ContextNode, FunctionNode, KilledKind}, AnalyzerBackend, GraphBackend, GraphError, Node, @@ -11,6 +13,33 @@ impl ContextNode { Ok(self.underlying(analyzer)?.parent_ctx.is_some()) } + /// Sets the continuation context + pub fn set_continuation_ctx( + &self, + analyzer: &mut impl AnalyzerBackend, + continuation_ctx: ContextNode, + ) -> Result<(), GraphError> { + assert!( + self.0 > continuation_ctx.0, + "{} {}", + self.0, + continuation_ctx.0 + ); + if let Some(cont) = self.underlying_mut(analyzer)?.continuation_of { + cont.set_continuation_ctx(analyzer, continuation_ctx) + } else { + analyzer.add_edge( + *self, + continuation_ctx, + Edge::Context(ContextEdge::Continue), + ); + + self.underlying_mut(analyzer)?.continuation_of = Some(continuation_ctx); + self.underlying_mut(analyzer)?.cache.vars = continuation_ctx.underlying(analyzer)?.cache.vars.clone(); + Ok(()) + } + } + /// Gets the first ancestor of this context pub fn first_ancestor( &self, diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index 64b6656a..27e4672d 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -283,12 +283,12 @@ pub trait ExpressionParser: let updated_func_expr = match **func_expr { FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { // we dont currently handle the `{value: .. gas: ..}` msg updating - println!("call block: {call_block:#?}"); + // println!("call block: {call_block:#?}"); // let mut tmp_msg = Msg { // } - self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); + // self.add_expr_err(ExprErr::FunctionCallBlockTodo(call_block.loc(), "Function call block is currently unsupported. Relevant changes on `msg` will not take effect".to_string())); inner_func_expr.clone() } _ => func_expr.clone(), diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index 68aa4d2d..3e7ea5ad 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -80,7 +80,7 @@ pub trait IntrinsicFuncCaller: }; let ty_idx = ty.expect_single().into_expr_err(loc)?; match analyzer.node(ty_idx) { - Node::Builtin(Builtin::Array(_)) => { + Node::Builtin(Builtin::Array(_)) | Node::Builtin(Builtin::DynamicBytes) => { // construct a new list analyzer.construct_array(ty_idx, &NamedOrUnnamedArgs::Unnamed(inputs), loc, ctx) } @@ -176,7 +176,7 @@ pub trait IntrinsicFuncCaller: .into_expr_err(loc) } } - _ => Err(ExprErr::ParseError(loc, "Tried to construct a new element of a type that doesn't support the `new` keyword".to_string())) + e => Err(ExprErr::ParseError(loc, format!("Tried to construct a new element of a type ({e:?}) that doesn't support the `new` keyword"))) } }) } diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 9ba4193e..177c349f 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -5,8 +5,8 @@ use crate::{ }; use graph::{ - nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, Node, VarType, + nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, BuiltInNode}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, SolcRange, }; use solang_parser::{ @@ -313,26 +313,33 @@ pub trait YulBuilder: } FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), SuffixAccess(loc, yul_member_expr, ident) => { - self.parse_inputs( - ctx, - *loc, - &[*yul_member_expr.clone()], - )?; + self.parse_inputs(ctx, *loc, &[*yul_member_expr.clone()])?; - self.apply_to_edges(ctx, *loc, &|analyzer, _ctx, _loc| { + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let Ok(Some(lhs)) = ctx.pop_expr_latest(loc, analyzer) else { + return Err(ExprErr::NoLhs( + loc, + "`.slot` had no left hand side".to_string(), + )); + }; match &*ident.name { "slot" => { + let slot_var = analyzer.slot( + ctx, + loc, + lhs.expect_single().into_expr_err(loc)?.into(), + ); + ctx.push_expr(ExprRet::Single(slot_var.into()), analyzer) + .into_expr_err(loc)?; Ok(()) } - _ => { - Err(ExprErr::Todo( - expr.loc(), - format!("Yul member access `{}` not yet supported", ident.name), - )) - } - } + _ => Err(ExprErr::Todo( + expr.loc(), + format!("Yul member access `{}` not yet supported", ident.name), + )), + } }) - }, + } } } @@ -399,4 +406,34 @@ pub trait YulBuilder: } Ok(()) } + + fn slot(&mut self, ctx: ContextNode, loc: Loc, lhs: ContextVarNode) -> ContextVarNode { + let lhs = lhs.first_version(self); + let name = format!("{}.slot", lhs.name(self).unwrap()); + tracing::trace!("Slot access: {}", name); + if let Some(attr_var) = ctx.var_by_name_or_recurse(self, &name).unwrap() { + attr_var.latest_version(self) + } else { + let slot_var = ContextVar { + loc: Some(loc), + name: lhs.name(self).unwrap() + ".slot", + display_name: lhs.display_name(self).unwrap() + ".slot", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + SolcRange::try_from_builtin(&Builtin::Uint(256)), + ), + }; + let slot_node = self.add_node(Node::ContextVar(slot_var)); + + self.add_edge(slot_node, lhs, Edge::Context(ContextEdge::SlotAccess)); + self.add_edge(slot_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(slot_node.into(), self).unwrap(); + slot_node.into() + } + } } From 6713a02726b83853b27aa784a59b9b119b00aa85 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Dec 2023 22:18:57 -0800 Subject: [PATCH 49/71] higher support, still slow - need to convert ranges to arena style --- crates/analyzers/src/var_analyzer/mod.rs | 35 +- crates/graph/src/graph_elements.rs | 2 + crates/graph/src/nodes/builtin.rs | 1 + crates/graph/src/nodes/concrete.rs | 7 +- crates/graph/src/nodes/context/node.rs | 30 +- crates/graph/src/nodes/context/querying.rs | 2 +- crates/graph/src/nodes/context/underlying.rs | 62 +++- crates/graph/src/nodes/context/var/node.rs | 11 + crates/graph/src/nodes/context/var/ranging.rs | 13 +- crates/graph/src/nodes/context/var/typing.rs | 69 ++-- .../graph/src/nodes/context/var/underlying.rs | 2 +- crates/graph/src/nodes/context/variables.rs | 14 + crates/graph/src/nodes/context/versioning.rs | 2 +- crates/graph/src/nodes/contract_ty.rs | 58 ++- crates/graph/src/nodes/func_ty.rs | 28 +- crates/graph/src/range/elem/map_or_array.rs | 32 +- crates/graph/src/range/exec/bitwise.rs | 12 +- crates/graph/src/range/exec/modulo.rs | 4 +- crates/graph/src/var_type.rs | 48 ++- crates/shared/src/gas.rs | 12 + crates/shared/src/lib.rs | 1 + crates/solc-expressions/src/bin_op.rs | 1 + crates/solc-expressions/src/cond_op.rs | 12 + .../src/context_builder/expr.rs | 10 +- .../src/context_builder/stmt.rs | 10 - crates/solc-expressions/src/env.rs | 3 + .../src/func_call/func_caller.rs | 24 +- .../solc-expressions/src/func_call/helper.rs | 335 +++++++++--------- .../src/func_call/intrinsic_call/abi.rs | 79 ++++- .../func_call/intrinsic_call/precompile.rs | 60 +++- .../src/func_call/modifier.rs | 82 ++--- .../src/func_call/namespaced_call.rs | 269 +++++++++----- crates/solc-expressions/src/literal.rs | 28 +- crates/solc-expressions/src/loops.rs | 6 +- .../src/member_access/contract_access.rs | 59 ++- .../src/member_access/member_trait.rs | 46 ++- crates/solc-expressions/src/require.rs | 19 +- crates/solc-expressions/src/variable.rs | 75 ++-- .../solc-expressions/src/yul/yul_builder.rs | 4 +- crates/solc-expressions/src/yul/yul_funcs.rs | 21 +- 40 files changed, 1064 insertions(+), 524 deletions(-) create mode 100644 crates/shared/src/gas.rs diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 29d3609d..6d424564 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -224,10 +224,43 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { } }; - if let Some(curr_range) = curr.ref_range(self).unwrap() { + let (comparator, needs_curr) = if let Some(inherited) = curr.previous_or_inherited_version(self) { + (inherited, true) + } else { + (curr, false) + }; + + if let Some(curr_range) = comparator.ref_range(self).unwrap() { let mut cr_min = curr_range.evaled_range_min(self).unwrap(); let mut cr_max = curr_range.evaled_range_max(self).unwrap(); let mut cr_excl = curr_range.range_exclusions(); + + if needs_curr { + if let Some(next_range) = curr.ref_range(self).unwrap() { + let nr_min = next_range.evaled_range_min(self).unwrap(); + let nr_max = next_range.evaled_range_max(self).unwrap(); + let nr_excl = &next_range.exclusions; + + // check if there was a bound change + if report_config.show_all_lines + || nr_min != cr_min + || nr_max != cr_max + || nr_excl != &cr_excl + { + cr_min = nr_min; + cr_max = nr_max; + cr_excl = nr_excl.to_vec(); + let new = ( + LocStrSpan::new(file_mapping, curr.loc(self).unwrap()), + next_range.into_owned(), + ); + if !ba.bound_changes.contains(&new) { + ba.bound_changes.push(new); + } + } + } + } + while let Some(next) = curr.next_version(self) { if let Some(next_range) = next.ref_range(self).unwrap() { let nr_min = next_range.evaled_range_min(self).unwrap(); diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 3a61fc79..b3e20b41 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -323,6 +323,8 @@ pub enum ContextEdge { ContextMerge, /// A call to a function, a connection from a context to a `FuncCall` node Call, + /// A loop + Loop, // Context Variables /// A new variable in cotext diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index a2491f8b..d0e63896 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -373,6 +373,7 @@ impl Builtin { (DynamicBytes, DynamicBytes) => true, (String, String) => true, (Uint(from_size), Uint(to_size)) => from_size <= to_size, + (Uint(from_size), Address) => *from_size == 160, (Int(from_size), Int(to_size)) => from_size <= to_size, (Bytes(from_size), Bytes(to_size)) => from_size <= to_size, _ => false, diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 85356b68..7fb60069 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -932,9 +932,10 @@ impl Concrete { val.to_big_endian(&mut bytes); bytes.to_vec() }, - Concrete::Bytes(_, _) - | Concrete::Address(_) - | Concrete::Bool(_) => { + Concrete::Bytes(size, val) => { + val[0..(*size as usize)].to_vec() + } + Concrete::Address(_) | Concrete::Bool(_) => { Concrete::Uint(256, self.into_u256().unwrap()).as_bytes() } Concrete::DynBytes(inner) => inner.clone(), diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 26fc48bc..099a556b 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -28,6 +28,10 @@ impl ContextNode { todo!("Joining not supported yet"); } + pub fn add_gas_cost(&self, analyzer: &mut impl GraphBackend, cost: u64) -> Result<(), GraphError> { + self.associated_fn(analyzer)?.add_gas_cost(analyzer, cost) + } + /// Gets the total context width pub fn total_width( &self, @@ -98,20 +102,7 @@ impl ContextNode { ) -> Result<(), GraphError> { self.underlying_mut(analyzer)? .ret - .push((ret_stmt_loc, Some(ret))); - self.propogate_end(analyzer)?; - Ok(()) - } - - /// Add an empty/placeholder return to the context - pub fn add_empty_return( - &self, - ret_stmt_loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)? - .ret - .push((ret_stmt_loc, None)); + .push((ret_stmt_loc, ret)); self.propogate_end(analyzer)?; Ok(()) } @@ -137,16 +128,7 @@ impl ContextNode { &self, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - let rets = &self.underlying(analyzer)?.ret.clone(); - let all_good = rets.iter().all(|(_, node)| node.is_some()); - if all_good { - Ok(rets - .iter() - .map(|(loc, node)| (*loc, node.unwrap())) - .collect()) - } else { - Ok(vec![]) - } + Ok(self.underlying(analyzer)?.ret.clone()) } /// Returns a string for dot-string things diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 70a1be53..8a4ac064 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -149,7 +149,7 @@ impl ContextNode { return Ok(vis.clone()); } if let Some(contract) = self.maybe_associated_contract(analyzer)? { - let mut mapping = contract.linearized_functions(analyzer); + let mut mapping = contract.linearized_functions(analyzer)?; // extend with free floating functions mapping.extend( analyzer diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index eaaec14f..c3ea9ea2 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -18,6 +18,7 @@ pub struct Context { /// An optional parent context (i.e. this context is a fork or subcontext of another previous context) pub parent_ctx: Option, pub returning_ctx: Option, + pub continuation_of: Option, /// Variables whose bounds are required to be met for this context fork to exist. i.e. a conditional operator /// like an if statement pub ctx_deps: Vec, @@ -39,7 +40,7 @@ pub struct Context { /// The location in source of the context pub loc: Loc, /// The return node and the return location - pub ret: Vec<(Loc, Option)>, + pub ret: Vec<(Loc, ContextVarNode)>, /// Depth tracker pub depth: usize, /// Width tracker @@ -65,6 +66,7 @@ impl Context { parent_fn, parent_ctx: None, returning_ctx: None, + continuation_of: None, path: fn_name, tmp_var_ctr: 0, killed: None, @@ -163,6 +165,7 @@ impl Context { parent_fn, parent_ctx: Some(parent_ctx), returning_ctx, + continuation_of: None, path, is_fork: fork_expr.is_some(), fn_call, @@ -232,6 +235,63 @@ impl Context { }) } + pub fn new_loop_subctx( + parent_ctx: ContextNode, + loc: Loc, + analyzer: &mut impl AnalyzerBackend, + ) -> Result { + let depth = parent_ctx.underlying(analyzer)?.depth + 1; + + if analyzer.max_depth() < depth { + return Err(GraphError::MaxStackDepthReached(format!( + "Stack depth limit reached: {}", + depth - 1 + ))); + } + + let fn_name = "loop"; + + let path = format!("{}.{}", parent_ctx.underlying(analyzer)?.path, fn_name); + + let parent_fn = parent_ctx.associated_fn(analyzer)?; + + parent_ctx.underlying_mut(analyzer)?.number_of_live_edges += 1; + + tracing::trace!("new subcontext path: {path}, depth: {depth}"); + Ok(Context { + parent_fn, + parent_ctx: Some(parent_ctx), + path, + returning_ctx: None, + continuation_of: None, + is_fork: false, + fn_call: None, + ext_fn_call: None, + ctx_deps: parent_ctx.underlying(analyzer)?.ctx_deps.clone(), + killed: None, + child: None, + tmp_var_ctr: parent_ctx.underlying(analyzer)?.tmp_var_ctr, + ret: vec![], + loc, + modifier_state: None, + depth, + width: 0, + expr_ret_stack: parent_ctx.underlying(analyzer)?.expr_ret_stack.clone(), + tmp_expr: parent_ctx.underlying(analyzer)?.tmp_expr.clone(), + unchecked: parent_ctx.underlying(analyzer)?.unchecked, + number_of_live_edges: 0, + cache: ContextCache { + vars: parent_ctx.underlying(analyzer)?.cache.vars.clone(), + visible_funcs: parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone(), + visible_structs: parent_ctx.underlying(analyzer)?.cache.visible_structs.clone(), + first_ancestor: parent_ctx.underlying(analyzer)?.cache.first_ancestor, + associated_source: None, + associated_contract: None, + }, + dl_solver: parent_ctx.underlying(analyzer)?.dl_solver.clone(), + }) + } + /// Set the child context to a fork pub fn set_child_fork(&mut self, world1: ContextNode, world2: ContextNode) -> bool { if self.child.is_some() { diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index c7e5f8ee..2c2a3e42 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -220,6 +220,17 @@ impl ContextVarNode { } } + pub fn slot_to_storage(&self, analyzer: &impl GraphBackend) -> Option { + let slot = analyzer + .graph() + .edges_directed(self.first_version(analyzer).into(), Direction::Outgoing) + .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::SlotAccess)) + .map(|edge| edge.target()) + .take(1) + .next()?; + Some(ContextVarNode::from(slot).latest_version(analyzer)) + } + pub fn index_access_to_array(&self, analyzer: &impl GraphBackend) -> Option { if let Some(arr) = analyzer .graph() diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 1590705f..4b8be862 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -111,7 +111,7 @@ impl ContextVarNode { } pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { + if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { range.cache_flatten(analyzer)?; range.cache_eval(analyzer)?; self.set_range(analyzer, range)?; @@ -120,7 +120,7 @@ impl ContextVarNode { } pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { + if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { range.cache_flatten(analyzer)?; self.set_range(analyzer, range)?; } @@ -128,13 +128,20 @@ impl ContextVarNode { } pub fn cache_eval_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { + if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { range.cache_eval(analyzer)?; self.set_range(analyzer, range)?; } Ok(()) } + pub fn ty_mut<'a>( + &self, + analyzer: &'a mut impl GraphBackend, + ) -> Result<&'a mut VarType, GraphError> { + Ok(&mut self.underlying_mut(analyzer)?.ty) + } + pub fn set_range( &self, analyzer: &mut impl GraphBackend, diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index b029b07c..686c115e 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -16,6 +16,10 @@ impl ContextVarNode { Ok(&self.underlying(analyzer)?.ty) } + pub fn ty_eq_ty(&self, other: &VarType, analyzer: &impl GraphBackend) -> Result { + self.ty(analyzer)?.ty_eq(other, analyzer) + } + pub fn is_mapping(&self, analyzer: &impl GraphBackend) -> Result { self.ty(analyzer)?.is_mapping(analyzer) } @@ -213,11 +217,7 @@ impl ContextVarNode { pub fn is_return_node(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ctx) = self.maybe_ctx(analyzer) { return Ok(ctx.underlying(analyzer)?.ret.iter().any(|(_, node)| { - if let Some(node) = node { - node.name(analyzer).unwrap() == self.name(analyzer).unwrap() - } else { - false - } + node.name(analyzer).unwrap() == self.name(analyzer).unwrap() })); } Ok(false) @@ -234,11 +234,7 @@ impl ContextVarNode { .ret .iter() .any(|(_, node)| { - if let Some(node) = node { - node.name(analyzer).unwrap() == self.name(analyzer).unwrap() - } else { - false - } + node.name(analyzer).unwrap() == self.name(analyzer).unwrap() }) }) } @@ -332,32 +328,57 @@ impl ContextVarNode { Ok(()) } + // pub fn cast_from_ty( + // &self, + // to_ty: VarType, + // analyzer: &mut (impl GraphBackend + AnalyzerBackend), + // ) -> Result<(), GraphError> { + // let new_underlying = self.underlying(analyzer)?.clone(); + // let node = analyzer.add_node(Node::ContextVar(new_underlying)); + // analyzer.add_edge(node, *self, Edge::Context(ContextEdge::Prev)); + // let new_self = ContextVarNode::from(node); + + // let from_ty = self.ty(analyzer)?.clone(); + // if !from_ty.ty_eq(&to_ty, analyzer)? { + // if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { + // new_self.underlying_mut(analyzer)?.ty = new_ty; + // } + + // if let Some((new_min, new_max)) = self.cast_exprs(&to_ty, analyzer)? { + // new_self.set_range_min(analyzer, new_min)?; + // new_self.set_range_max(analyzer, new_max)?; + // } + // } + + // if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (new_self.ty(analyzer)?, to_ty) { + // // update name + // let display_name = cnode.underlying(analyzer)?.as_human_string(); + // new_self.underlying_mut(analyzer)?.display_name = display_name; + // } + // Ok(()) + // } + pub fn cast_from_ty( &self, to_ty: VarType, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { - let new_underlying = self.underlying(analyzer)?.clone(); - let node = analyzer.add_node(Node::ContextVar(new_underlying)); - analyzer.add_edge(node, *self, Edge::Context(ContextEdge::Prev)); - let new_self = ContextVarNode::from(node); - let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { - new_self.underlying_mut(analyzer)?.ty = new_ty; + self.underlying_mut(analyzer)?.ty = new_ty; } - - if let Some((new_min, new_max)) = self.cast_exprs(&to_ty, analyzer)? { - new_self.set_range_min(analyzer, new_min)?; - new_self.set_range_max(analyzer, new_max)?; + if let (Some(mut r), Some(r2)) = (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) { + r.min = r.min.cast(r2.min); + r.max = r.max.cast(r2.max); + self.set_range(analyzer, r)?; } } - if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (new_self.ty(analyzer)?, to_ty) { + if let (VarType::Concrete(_), VarType::Concrete(cnode)) = (self.ty(analyzer)?, to_ty) { // update name - let display_name = cnode.underlying(analyzer)?.as_human_string(); - new_self.underlying_mut(analyzer)?.display_name = display_name; + let display_name = cnode.underlying(analyzer)?.as_string(); + self.underlying_mut(analyzer)?.display_name = display_name; } Ok(()) } diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index b46daddf..840b0a79 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -260,7 +260,7 @@ impl ContextVar { VarType::User(TypeNode::Contract(_), ref maybe_range) | VarType::User(TypeNode::Enum(_), ref maybe_range) | VarType::User(TypeNode::Ty(_), ref maybe_range) - | VarType::BuiltIn(_, ref maybe_range) => maybe_range.is_some(), + | VarType::BuiltIn(_, ref maybe_range) => maybe_range.is_none(), _ => false, } } diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index d6a1dbe7..3416adb2 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -8,6 +8,18 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; impl ContextNode { + /// Debug print the stack + pub fn debug_expr_stack( + &self, + analyzer: &impl GraphBackend, + ) -> Result<(), GraphError> { + let underlying_mut = self.underlying(analyzer)?; + underlying_mut.expr_ret_stack.iter().for_each(|elem| { + println!("{}", elem.debug_str(analyzer)) + }); + Ok(()) + } + /// Add a variable to this context pub fn add_var( &self, @@ -48,6 +60,8 @@ impl ContextNode { ) -> Result, GraphError> { if let Some(var) = self.var_by_name(analyzer, name) { Ok(Some(var)) + } else if let Some(parent) = self.underlying(analyzer)?.continuation_of { + parent.var_by_name_or_recurse(analyzer, name) } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { parent.var_by_name_or_recurse(analyzer, name) } else { diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 6662ae8d..1eba34ec 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,5 +1,5 @@ use crate::ContextEdge; -use petgraph::graph::Edge; +use crate::Edge; use crate::{ nodes::{CallFork, ContextNode, FunctionNode, KilledKind}, AnalyzerBackend, GraphBackend, GraphError, Node, diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index d10a9cca..48f25279 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -46,6 +46,23 @@ impl ContractNode { } } + /// Gets the underlying node data for the [`Contract`] as mutable + pub fn underlying_mut<'a>( + &self, + analyzer: &'a mut impl GraphBackend, + ) -> Result<&'a mut Contract, GraphError> { + match analyzer.node_mut(*self) { + Node::Contract(contract) => Ok(contract), + Node::Unresolved(ident) => Err(GraphError::UnknownVariable(format!( + "Could not find variable: {}", + ident.name + ))), + e => Err(GraphError::NodeConfusion(format!( + "Node type confusion: expected node to be Contract but it was: {e:?}" + ))), + } + } + pub fn super_contracts(&self, analyzer: &impl GraphBackend) -> Vec { analyzer .graph() @@ -181,22 +198,28 @@ impl ContractNode { pub fn linearized_functions( &self, - analyzer: &(impl GraphBackend + Search + AnalyzerBackend), - ) -> BTreeMap { - let mut mapping = self.funcs_mapping(analyzer); - self.direct_inherited_contracts(analyzer) - .iter() - .for_each(|inherited| { - inherited - .linearized_functions(analyzer) - .iter() - .for_each(|(name, func)| { - if !mapping.contains_key(name) { - mapping.insert(name.to_string(), *func); - } - }); - }); - mapping + analyzer: &mut (impl Search + AnalyzerBackend), + ) -> Result, GraphError> { + if let Some(funcs) = &self.underlying(analyzer)?.cached_functions { + Ok(funcs.clone()) + } else { + let mut mapping = self.funcs_mapping(analyzer); + self.direct_inherited_contracts(analyzer) + .iter() + .for_each(|inherited| { + inherited + .linearized_functions(analyzer) + .unwrap() + .iter() + .for_each(|(name, func)| { + if !mapping.contains_key(name) { + mapping.insert(name.to_string(), *func); + } + }); + }); + self.underlying_mut(analyzer)?.cached_functions = Some(mapping.clone()); + Ok(mapping) + } } pub fn structs(&self, analyzer: &(impl GraphBackend + Search)) -> Vec { @@ -270,6 +293,8 @@ pub struct Contract { pub name: Option, /// A list of contracts that this contract inherits (TODO: inheritance linearization) pub inherits: Vec, + /// Cached linearized functions + pub cached_functions: Option>, } impl From for Node { @@ -329,6 +354,7 @@ impl Contract { ty: con.ty, name: con.name, inherits, + cached_functions: None }, unhandled_inherits, ) diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index c5ec2d01..4088e2b3 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -35,6 +35,11 @@ impl FunctionNode { } } + pub fn add_gas_cost(&mut self, analyzer: &mut impl GraphBackend, cost: u64) -> Result<(), GraphError>{ + self.underlying_mut(analyzer)?.add_gas_cost(cost); + Ok(()) + } + pub fn ty(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.ty) } @@ -103,7 +108,7 @@ impl FunctionNode { pub fn underlying_mut<'a>( &self, - analyzer: &'a mut (impl GraphBackend + AnalyzerBackend), + analyzer: &'a mut impl GraphBackend, ) -> Result<&'a mut Function, GraphError> { match analyzer.node_mut(*self) { Node::Function(func) => Ok(func), @@ -175,7 +180,9 @@ impl FunctionNode { .map(|edge| ContextNode::from(edge.source())) .take(1) .next() - .expect("No context for function"); + .unwrap_or_else(|| { + panic!("No context for function: {}", self.name(analyzer).unwrap()) + }); self.underlying_mut(analyzer).unwrap().cache.body_ctx = Some(body_ctx); body_ctx @@ -495,11 +502,12 @@ impl AsDotStr for FunctionNode { .collect::>() .join(" "); format!( - "{} {}({}) {}", + "{} {}({}) {} -- gas: {}", self.underlying(analyzer).unwrap().ty, self.name(analyzer).unwrap().split('(').collect::>()[0], inputs, - attrs + attrs, + self.underlying(analyzer).unwrap().estimated_gas ) } } @@ -528,6 +536,7 @@ pub struct Function { pub returns: ParameterList, pub modifiers_set: bool, pub cache: FunctionCache, + pub estimated_gas: u64, } #[derive(Debug, Clone, Eq, PartialEq, Default)] @@ -554,6 +563,7 @@ impl Default for Function { returns: vec![], modifiers_set: false, cache: Default::default(), + estimated_gas: 0, } } } @@ -568,6 +578,10 @@ impl Function { }) .collect() } + + pub fn add_gas_cost(&mut self, cost: u64) { + self.estimated_gas += cost; + } } impl From for Node { @@ -589,6 +603,7 @@ impl From for Function { returns: func.returns, modifiers_set: false, cache: Default::default(), + estimated_gas: 0, } } } @@ -711,6 +726,7 @@ impl From for Function { returns: vec![ret], modifiers_set: true, cache: Default::default(), + estimated_gas: 0, } } } @@ -893,6 +909,10 @@ impl FunctionReturnNode { pub fn loc(&self, analyzer: &impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.loc) } + + pub fn ty(&self, analyzer: &impl GraphBackend) -> Result { + Ok(self.underlying(analyzer)?.ty) + } } impl From for NodeIdx { diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 9089f234..9146d993 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -111,9 +111,25 @@ impl RangeDyn { impl RangeDyn { pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { let len = if maximize { - self.len.maximize(analyzer).ok()?.concrete()?.into_u256()?.as_usize() + let as_u256 = self.len.maximize(analyzer).ok()?.concrete()?.into_u256()?; + if as_u256 > usize::MAX.into() { + usize::MAX + } else { + as_u256.as_usize() + } } else { - self.len.minimize(analyzer).ok()?.concrete()?.into_u256()?.as_usize() + let mut as_u256 = self.len.minimize(analyzer).ok()?.concrete()?.into_u256()?; + if let Some(max_key) = self.evaled_max_key(analyzer) { + if let Some(max_key) = max_key.into_u256() { + as_u256 = as_u256.max(max_key); + } + } + + if as_u256 > usize::MAX.into() { + usize::MAX + } else { + as_u256.as_usize() + } }; Some( @@ -127,6 +143,18 @@ impl RangeDyn { .collect() ) } + + pub fn evaled_max_key(&self, analyzer: &impl GraphBackend) -> Option { + let mut evaled = self.val.keys().filter_map(|key| { + key.maximize(analyzer).ok() + }) + .collect::>(); + evaled.sort_by(|a, b| { + a.range_ord(b).unwrap_or(std::cmp::Ordering::Less) + }); + + evaled.iter().take(1).next()?.concrete() + } } impl RangeElem for RangeDyn { diff --git a/crates/graph/src/range/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs index 97010932..a980fb7b 100644 --- a/crates/graph/src/range/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -19,17 +19,11 @@ impl RangeBitwise for RangeConcrete { loc: self.loc, })) } - (Concrete::Uint(s, a), Concrete::Int(s2, b)) => { + (Concrete::Uint(s, u), Concrete::Int(s2, i)) + | (Concrete::Int(s, i), Concrete::Uint(s2, u)) => { let size = if s > s2 { s } else { s2 }; Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a & b.into_raw()), - loc: self.loc, - })) - } - (Concrete::Int(s, a), Concrete::Uint(s2, b)) => { - let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, a.into_raw() & *b), + val: Concrete::Uint(*size, *u & i.into_raw()), loc: self.loc, })) } diff --git a/crates/graph/src/range/exec/modulo.rs b/crates/graph/src/range/exec/modulo.rs index 66db9b60..c81039dc 100644 --- a/crates/graph/src/range/exec/modulo.rs +++ b/crates/graph/src/range/exec/modulo.rs @@ -6,7 +6,7 @@ use ethers_core::types::I256; impl RangeMod for RangeConcrete { fn range_mod(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { + (Some(lhs_val), Some(rhs_val)) if rhs_val != 0.into() => Some(Elem::Concrete(RangeConcrete { val: self.val.u256_as_original(lhs_val % rhs_val), loc: self.loc, })), @@ -17,7 +17,7 @@ impl RangeMod for RangeConcrete { loc: self.loc, })) } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) if *val != 0.into() => { Some(Elem::Concrete(RangeConcrete { val: Concrete::Int(*lhs_size, *neg_v % I256::from_raw(*val)), loc: self.loc, diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index 067f5301..9a89f819 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -43,6 +43,16 @@ impl VarType { } } + pub fn take_range(&mut self) -> Option { + match self { + VarType::User(TypeNode::Enum(_), ref mut r) + | VarType::User(TypeNode::Contract(_), ref mut r) + | VarType::User(TypeNode::Ty(_), ref mut r) + | VarType::BuiltIn(_, ref mut r) => r.take(), + _ => None, + } + } + pub fn possible_builtins_from_ty_inf(&self, analyzer: &impl GraphBackend) -> Vec { match self { Self::BuiltIn(bn, _) => bn @@ -65,6 +75,14 @@ impl VarType { } } + pub fn empty_ty(&self) -> VarType { + match self { + Self::User(ty_node, _) => Self::User(*ty_node, None), + Self::BuiltIn(bn, _) => Self::BuiltIn(*bn, None), + Self::Concrete(c) => Self::Concrete(*c), + } + } + pub fn is_dyn_builtin(&self, analyzer: &impl GraphBackend) -> Result { match self { Self::BuiltIn(node, _) => node.is_dyn(analyzer), @@ -93,6 +111,28 @@ impl VarType { } } + pub fn resolve_unresolved(&mut self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { + match self { + VarType::User(TypeNode::Unresolved(n), _) => match analyzer.node(*n) { + Node::Unresolved(ident) => Err(GraphError::NodeConfusion(format!( + "Expected the type \"{}\" to be resolved by now", + ident.name + ))), + _ => { + if let Some(ty) = VarType::try_from_idx(analyzer, *n) { + *self = ty; + Ok(()) + } else { + Err(GraphError::NodeConfusion( + "Tried to type a non-typeable element".to_string(), + )) + } + } + }, + _ => Ok(()), + } + } + pub fn concrete_to_builtin( &mut self, analyzer: &mut (impl GraphBackend + AnalyzerBackend), @@ -336,8 +376,12 @@ impl VarType { (Self::BuiltIn(from_bn, _), Self::BuiltIn(to_bn, _)) => { from_bn.implicitly_castable_to(to_bn, analyzer) } - (Self::Concrete(from_c), Self::BuiltIn(_to_bn, _)) => { - todo!("here, {from_c:?}") + (Self::Concrete(from_c), Self::BuiltIn(to_bn, _)) => { + let to = to_bn.underlying(analyzer)?; + Ok(from_c + .underlying(analyzer)? + .as_builtin() + .implicitly_castable_to(to)) } _ => Ok(false), } diff --git a/crates/shared/src/gas.rs b/crates/shared/src/gas.rs new file mode 100644 index 00000000..62fe1204 --- /dev/null +++ b/crates/shared/src/gas.rs @@ -0,0 +1,12 @@ +// Underestimated gas costs. We underestimate because the optimizer may do some work + +/// Binary operation gas cost +pub const BIN_OP_GAS: u64 = 2; +/// Internal function call gas cost +pub const FUNC_CALL_GAS: u64 = 5; +/// External functionc all gas cost +pub const EXT_FUNC_CALL_GAS: u64 = 100; +/// Read a storage variable gas cost +pub const SLOAD_GAS: u64 = 10; +/// Set a storage variable gas cost +pub const SSTORE_GAS: u64 = 10; \ No newline at end of file diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index bc09b01e..bb8f2765 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -1,6 +1,7 @@ mod analyzer_like; mod graph_like; mod search; +pub mod gas; pub use analyzer_like::*; pub use graph_like::*; diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 5b9c9384..aba5dc4e 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -28,6 +28,7 @@ pub trait BinOp: AnalyzerBackend + Sized { op: RangeOp, assign: bool, ) -> Result<(), ExprErr> { + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(loc)?; self.parse_ctx_expr(rhs_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 999e2489..07d0e0ea 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -36,6 +36,12 @@ pub trait CondOp: AnalyzerBackend + Requir let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; + true_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; + false_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); analyzer.add_edge( @@ -154,6 +160,12 @@ pub trait CondOp: AnalyzerBackend + Requir let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; + true_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; + false_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); analyzer.add_edge( diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index 27e4672d..b9e3807e 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -59,7 +59,7 @@ pub trait ExpressionParser: // ); match expr { // literals - NumberLiteral(loc, int, exp, _unit) => self.number_literal(ctx, *loc, int, exp, false), + NumberLiteral(loc, int, exp, unit) => self.number_literal(ctx, *loc, int, exp, false, unit), AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), StringLiteral(lits) => lits .iter() @@ -71,8 +71,8 @@ pub trait ExpressionParser: self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) } Negate(_loc, expr) => match &**expr { - NumberLiteral(loc, int, exp, _unit) => { - self.number_literal(ctx, *loc, int, exp, true) + NumberLiteral(loc, int, exp, unit) => { + self.number_literal(ctx, *loc, int, exp, true, unit) } HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), e => { @@ -297,9 +297,9 @@ pub trait ExpressionParser: self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) } // member - New(_loc, expr) => { + New(loc, expr) => { match &**expr { - Expression::FunctionCall(loc, func, inputs) => { + Expression::FunctionCall(_loc, func, inputs) => { // parse the type self.new_call( loc, diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs index 50a1d6b6..ade756e1 100644 --- a/crates/solc-expressions/src/context_builder/stmt.rs +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -489,16 +489,6 @@ pub trait StatementParser: ); let _ = self.widen_if_limit_hit(parent.into().into(), res); } - } else if let Some(parent) = parent_ctx { - let res = - self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { - let res = ctx.add_empty_return(loc, analyzer).into_expr_err(loc); - analyzer.add_if_err(res); - Ok(()) - }); - if self.widen_if_limit_hit(parent.into().into(), res) { - return; - } } } Revert(loc, _maybe_err_path, _exprs) => { diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 17c73755..8bee98f6 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -20,11 +20,13 @@ pub trait Env: AnalyzerBackend + Sized { ) -> Result, ExprErr> { match &*ident.name { "msg" | "tx" => { + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(ident.loc)?; ctx.push_expr(ExprRet::Single(self.msg().into()), self) .into_expr_err(ident.loc)?; Ok(Some(())) } "block" => { + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(ident.loc)?; ctx.push_expr(ExprRet::Single(self.block().into()), self) .into_expr_err(ident.loc)?; Ok(Some(())) @@ -38,6 +40,7 @@ pub trait Env: AnalyzerBackend + Sized { .modifier_state .clone() { + ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS).into_expr_err(ident.loc)?; self.resume_from_modifier(ctx, mod_state.clone())?; self.modifier_inherit_return(ctx, mod_state.parent_ctx); Ok(Some(())) diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 2d4589d6..7d33cffc 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -463,7 +463,17 @@ pub trait FuncCaller: }); self.parse_ctx_statement(&body, false, Some(callee_ctx)); - self.ctx_rets(loc, caller_ctx, callee_ctx) + if let Some(mod_state) = &callee_ctx.underlying(self).into_expr_err(loc)?.modifier_state.clone() { + if mod_state.num == 0 { + return self.ctx_rets(loc, mod_state.parent_caller_ctx, callee_ctx) + } + } + + if callee_ctx != caller_ctx { + self.ctx_rets(loc, caller_ctx, callee_ctx) + } else { + Ok(()) + } } else { let ret_ctx = Context::new_subctx( callee_ctx, @@ -481,7 +491,7 @@ pub trait FuncCaller: ) .unwrap(); let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); + ret_subctx.set_continuation_ctx(self, caller_ctx).into_expr_err(loc)?; let res = callee_ctx .set_child_call(ret_subctx, self) @@ -503,6 +513,16 @@ pub trait FuncCaller: format!("{}_{}", func_call, callee_ctx.new_tmp(analyzer).unwrap()); var.display_name = func_call.to_string(); } + + if ctx.contains_var(&var.name, analyzer).into_expr_err(loc)? { + var.name = format!( + "{}_ret{}", + var.name, + ctx.new_tmp(analyzer).into_expr_err(loc)? + ); + var.display_name = var.name.clone(); + } + let node = analyzer.add_node(Node::ContextVar(var)); ctx.add_var(node.into(), analyzer).into_expr_err(loc)?; analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 6d673e6a..4e2d27e9 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -46,7 +46,7 @@ pub trait CallerHelper: AnalyzerBackend + let mut new_cvar = self.add_if_err(res)?; new_cvar.loc = Some(param.loc(self).unwrap()); new_cvar.name = name.clone(); - new_cvar.display_name = name.clone(); + new_cvar.display_name = name; new_cvar.is_tmp = false; new_cvar.storage = if let Some(StorageLocation::Storage(_)) = param.underlying(self).unwrap().storage @@ -56,17 +56,15 @@ pub trait CallerHelper: AnalyzerBackend + None }; + let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { - let ty = new_cvar.ty.clone(); - if !ty.ty_eq(¶m_ty, self).unwrap() { - if let Some(new_ty) = ty.try_cast(¶m_ty, self).unwrap() { - new_cvar.ty = new_ty; - } + if !node.ty_eq_ty(¶m_ty, self).unwrap() { + node.cast_from_ty(param_ty, self).unwrap(); } } - let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); self.add_edge( node, input.latest_version(self), @@ -86,11 +84,11 @@ pub trait CallerHelper: AnalyzerBackend + r.range_min().into_owned().cast(r2.range_min().into_owned()); let new_max = r.range_max().into_owned().cast(r2.range_max().into_owned()); - let res = node.try_set_range_min(self, new_min).into_expr_err(loc); + let res = node.latest_version(self).try_set_range_min(self, new_min).into_expr_err(loc); self.add_if_err(res); - let res = node.try_set_range_max(self, new_max).into_expr_err(loc); + let res = node.latest_version(self).try_set_range_max(self, new_max).into_expr_err(loc); self.add_if_err(res); - let res = node + let res = node.latest_version(self) .try_set_range_exclusions(self, r.exclusions) .into_expr_err(loc); self.add_if_err(res); @@ -178,6 +176,11 @@ pub trait CallerHelper: AnalyzerBackend + modifier_state: Option, ) -> Result { let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; + if fn_ext { + curr_ctx.add_gas_cost(self, shared::gas::EXT_FUNC_CALL_GAS).into_expr_err(loc)?; + } else { + curr_ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS).into_expr_err(loc)?; + } let ctx = Context::new_subctx( curr_ctx, None, @@ -287,6 +290,27 @@ pub trait CallerHelper: AnalyzerBackend + caller_ctx.depth(self), callee_ctx.depth(self), ); + + if callee_ctx + .underlying(self) + .unwrap() + .modifier_state + .is_some() + { + if let Some(ret_ctx) = callee_ctx.underlying(self).into_expr_err(loc)?.parent_ctx { + let ret = ret_ctx.underlying(self).into_expr_err(loc)?.ret.clone(); + ret.iter().try_for_each(|(loc, ret)| { + let cvar = self.advance_var_in_forced_ctx(*ret, *loc, callee_ctx)?; + callee_ctx + .add_return_node(*loc, cvar, self) + .into_expr_err(*loc)?; + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); + + Ok(()) + })?; + } + } + match callee_ctx.underlying(self).into_expr_err(loc)?.child { Some(CallFork::Fork(w1, w2)) => { self.ctx_rets(loc, caller_ctx, w1)?; @@ -302,190 +326,151 @@ pub trait CallerHelper: AnalyzerBackend + Ok(()) } _ => { + if callee_ctx.is_anonymous_fn_call(self).into_expr_err(loc)? { + return Ok(()); + } + if callee_ctx.is_killed(self).into_expr_err(loc)? { return Ok(()); } - let callee_depth = callee_ctx.underlying(self).into_expr_err(loc)?.depth; - let caller_depth = caller_ctx.underlying(self).into_expr_err(loc)?.depth; - if callee_depth != caller_depth { - let ctx = Context::new_subctx( - callee_ctx, - Some(caller_ctx), - loc, - None, - None, - false, - self, - caller_ctx - .underlying(self) - .into_expr_err(loc)? - .modifier_state - .clone(), - ) - .into_expr_err(loc)?; - let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); - self.add_edge(ret_subctx, caller_ctx, Edge::Context(ContextEdge::Continue)); - let res = callee_ctx - .set_child_call(ret_subctx, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); + if callee_ctx + .underlying(self) + .into_expr_err(loc)? + .child + .is_some() + { + return Ok(()); + } - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + let ctx = Context::new_subctx( + callee_ctx, + Some(caller_ctx), + loc, + None, + None, + false, + self, + caller_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone(), + ) + .into_expr_err(loc)?; + let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); + ret_subctx + .set_continuation_ctx(self, caller_ctx) + .into_expr_err(loc)?; - if rets.is_empty() { - let func_rets: Vec = callee_ctx - .associated_fn(self) - .into_expr_err(loc)? - .returns(self) - .collect(); - func_rets - .iter() - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) - .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; + let res = callee_ctx + .set_child_call(ret_subctx, self) + .into_expr_err(loc); + let _ = self.add_if_err(res); - // add unnamed rets - func_rets - .into_iter() - .filter(|ret| ret.maybe_name(self).unwrap().is_none()) - .collect::>() - .iter() - .try_for_each(|ret| { - let ret_loc = ret.loc(self).into_expr_err(loc)?; - let cvar = ContextVar::new_from_func_ret( - callee_ctx, - self, - ret.underlying(self).into_expr_err(loc)?.clone(), - ) + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + + if rets.is_empty() { + let func_rets: Vec = callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .collect(); + func_rets + .iter() + .filter_map(|ret| { + let n: String = ret.maybe_name(self).ok()??; + let ret_loc: Loc = ret.loc(self).ok()?; + Some((n, ret_loc)) + }) + .collect::>() + .into_iter() + .try_for_each(|(name, ret_loc)| { + if let Some(cvar) = callee_ctx + .var_by_name_or_recurse(self, &name) .into_expr_err(loc)? - .unwrap(); - let cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); - callee_ctx.add_var(cvar, self).into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Variable), - ); + { + let cvar = cvar.latest_version(self); + // let ret_loc = ret.loc(self).into_expr_err(loc)?; callee_ctx .add_return_node(ret_loc, cvar, self) .into_expr_err(loc)?; self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } + } + Ok(()) + })?; - let handle_rets = rets.iter().all(|(_, node)| node.is_some()); - if handle_rets { - let ret = rets - .into_iter() - .enumerate() - .map(|(i, (_, node))| { - let tmp_ret = node - .unwrap() - .as_tmp( - callee_ctx.underlying(self).unwrap().loc, - ret_subctx, - self, - ) - .unwrap(); - tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; - tmp_ret - .underlying_mut(self) - .into_expr_err(loc)? - .display_name = format!( - "{}.{}", - callee_ctx.associated_fn_name(self).unwrap(), - i - ); - ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; - self.add_edge( - tmp_ret, - ret_subctx, - Edge::Context(ContextEdge::Variable), - ); - Ok(ExprRet::Single(tmp_ret.into())) - }) - .collect::>()?; - ret_subctx - .push_expr(ExprRet::Multi(ret), self) - .into_expr_err(loc)?; - } - Ok(()) - } else { - let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); + // add unnamed rets + func_rets + .into_iter() + .filter(|ret| ret.maybe_name(self).unwrap().is_none()) + .collect::>() + .iter() + .try_for_each(|ret| { + let ret_loc = ret.loc(self).into_expr_err(loc)?; + let cvar = ContextVar::new_from_func_ret( + callee_ctx, + self, + ret.underlying(self).into_expr_err(loc)?.clone(), + ) + .into_expr_err(loc)? + .unwrap(); + let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); + callee_ctx.add_var(cvar, self).into_expr_err(loc)?; + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); + callee_ctx + .add_return_node(ret_loc, cvar, self) + .into_expr_err(loc)?; + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); + Ok(()) + })?; + rets = callee_ctx.underlying(self).unwrap().ret.clone(); + } - if rets.is_empty() { - callee_ctx + let target_rets = + if let Some(mod_state) = &callee_ctx.underlying(self).unwrap().modifier_state { + mod_state + .parent_ctx .associated_fn(self) .into_expr_err(loc)? .returns(self) - .filter_map(|ret| { - let n: String = ret.maybe_name(self).ok()??; - let ret_loc: Loc = ret.loc(self).ok()?; - Some((n, ret_loc)) - }) .collect::>() - .into_iter() - .try_for_each(|(name, ret_loc)| { - if let Some(cvar) = callee_ctx - .var_by_name_or_recurse(self, &name) - .into_expr_err(loc)? - { - let cvar = cvar.latest_version(self); - // let ret_loc = ret.loc(self).into_expr_err(loc)?; - callee_ctx - .add_return_node(ret_loc, cvar, self) - .into_expr_err(loc)?; - self.add_edge( - cvar, - callee_ctx, - Edge::Context(ContextEdge::Return), - ); - } - Ok(()) - })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); - } - if rets.iter().all(|(_, node)| node.is_some()) { - callee_ctx - .push_expr( - ExprRet::Multi( - rets.iter() - .map(|(_, node)| ExprRet::Single((node.unwrap()).into())) - .collect(), - ), - self, - ) - .into_expr_err(loc) } else { - Ok(()) - } - } + callee_ctx + .associated_fn(self) + .into_expr_err(loc)? + .returns(self) + .collect::>() + }; + + let ret = rets + .into_iter() + .zip(target_rets.iter()) + .enumerate() + .map(|(i, ((_, node), target_ret))| { + let target_ty = target_ret.ty(self).unwrap(); + let target_ty = VarType::try_from_idx(self, target_ty).unwrap(); + + let tmp_ret = node + .as_tmp(callee_ctx.underlying(self).unwrap().loc, ret_subctx, self) + .unwrap(); + tmp_ret.cast_from_ty(target_ty, self).unwrap(); + tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; + tmp_ret + .underlying_mut(self) + .into_expr_err(loc)? + .display_name = + format!("{}.{}", callee_ctx.associated_fn_name(self).unwrap(), i); + ret_subctx.add_var(tmp_ret, self).into_expr_err(loc)?; + self.add_edge(tmp_ret, ret_subctx, Edge::Context(ContextEdge::Variable)); + Ok(ExprRet::Single(tmp_ret.into())) + }) + .collect::>()?; + + ret_subctx + .push_expr(ExprRet::Multi(ret), self) + .into_expr_err(loc)?; + Ok(()) } } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 2ec3985e..4e42561b 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -31,17 +31,22 @@ pub trait AbiCaller: AnalyzerBackend + Siz analyzer: &mut impl AnalyzerBackend, ) -> Result<(), ExprErr> { match ret { - ExprRet::Single(expect_builtin) => match analyzer.node(expect_builtin) { + ExprRet::Single(ty) => match analyzer.node(ty) { Node::Builtin(_) => { let var = ContextVar::new_from_builtin( *loc, - expect_builtin.into(), + ty.into(), analyzer, ) .into_expr_err(*loc)?; let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) @@ -49,30 +54,74 @@ pub trait AbiCaller: AnalyzerBackend + Siz Node::ContextVar(cvar) => { let bn = analyzer .builtin_or_add( - cvar.ty.as_builtin(analyzer).into_expr_err(*loc)?, + cvar.ty + .as_builtin(analyzer) + .into_expr_err(*loc)?, ) .into(); - let var = ContextVar::new_from_builtin(*loc, bn, analyzer) + let var = + ContextVar::new_from_builtin(*loc, bn, analyzer) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; + Ok(()) + } + Node::Struct(_) => { + let var = ContextVar::new_from_struct( + *loc, + ty.into(), + ctx, + analyzer, + ) + .into_expr_err(*loc)?; let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; - analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.push_expr(ExprRet::Single(node), analyzer) + .into_expr_err(*loc)?; + Ok(()) + } + Node::Contract(_) => { + let var = ContextVar::new_from_contract( + *loc, + ty.into(), + analyzer, + ) + .into_expr_err(*loc)?; + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer) + .into_expr_err(*loc)?; + analyzer.add_edge( + node, + ctx, + Edge::Context(ContextEdge::Variable), + ); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) } e => todo!("Unhandled type in abi.decode: {e:?}"), }, - ExprRet::Multi(inner) => inner - .iter() - .try_for_each(|i| match_decode(ctx, loc, i.clone(), analyzer)), + ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { + match_decode(ctx, loc, i.clone(), analyzer) + }), ExprRet::CtxKilled(kind) => { ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) } - e => Err(ExprErr::ParseError( - *loc, - format!("This is invalid solidity: {:?}", e), - )), + e => panic!("This is invalid solidity: {:?}", e), } } let input_exprs = input_exprs.unnamed_args().unwrap(); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index db449ef3..7115d388 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -99,18 +99,34 @@ pub trait PrecompileCaller: ctx.set_child_call(call_ctx.into(), analyzer) .into_expr_err(loc)?; let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); - analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); - analyzer.add_edge(call_ctx, call_node, Edge::Context(ContextEdge::Subcontext)); + analyzer.add_edge( + call_node, + func_idx, + Edge::Context(ContextEdge::Call), + ); + analyzer.add_edge( + call_node, + ctx, + Edge::Context(ContextEdge::Subcontext), + ); + analyzer.add_edge( + call_ctx, + call_node, + Edge::Context(ContextEdge::Subcontext), + ); - let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + let Some(input) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { return Err(ExprErr::NoRhs( loc, "ecrecover did not receive inputs".to_string(), )); }; - let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + let input = if let Some(ordered_param_names) = + FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) + { input_exprs.order(input, ordered_param_names) } else { input @@ -124,12 +140,16 @@ pub trait PrecompileCaller: let mut inner_vals = vec![]; match input { ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - inner_vals - .push(ContextVarNode::from(var).display_name(analyzer).unwrap()); + inner_vals.push( + ContextVarNode::from(var) + .display_name(analyzer) + .unwrap(), + ); } _ => inner_vals.push("".to_string()), } - let inner_name = inner_vals.into_iter().collect::>().join(", "); + let inner_name = + inner_vals.into_iter().collect::>().join(", "); let mut var = ContextVar::new_from_builtin( loc, analyzer.builtin_or_add(Builtin::Address).into(), @@ -141,8 +161,16 @@ pub trait PrecompileCaller: var.is_return = true; let cvar = analyzer.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); - analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + cvar, + call_ctx, + Edge::Context(ContextEdge::Return), + ); ContextNode::from(call_ctx) .add_return_node(loc, cvar.into(), analyzer) .into_expr_err(loc)?; @@ -162,7 +190,11 @@ pub trait PrecompileCaller: ContextNode::from(call_ctx) .set_child_call(ret_ctx.into(), analyzer) .into_expr_err(loc)?; - analyzer.add_edge(ret_ctx, call_ctx, Edge::Context(ContextEdge::Continue)); + + // the return is a continuation of the ctx not the ecrecover ctx + ContextNode::from(ret_ctx) + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; let tmp_ret = ContextVarNode::from(cvar) .as_tmp( @@ -178,7 +210,11 @@ pub trait PrecompileCaller: tmp_ret.underlying_mut(analyzer).unwrap().display_name = format!("ecrecover({}).return", inner_name); ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge( + tmp_ret, + ret_ctx, + Edge::Context(ContextEdge::Variable), + ); ContextNode::from(ret_ctx) .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index 321781ef..0dc65b8a 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -28,7 +28,7 @@ pub trait ModifierCaller: + FuncCaller + CallerHelper { - /// Calls a modifier for a function + /// Calls a modifier for a function #[tracing::instrument(level = "trace", skip_all)] fn call_modifier_for_fn( &mut self, @@ -81,6 +81,7 @@ pub trait ModifierCaller: }) } + /// Resumes the parent function of a modifier #[tracing::instrument(level = "trace", skip_all)] fn resume_from_modifier( @@ -88,6 +89,12 @@ pub trait ModifierCaller: ctx: ContextNode, modifier_state: ModifierState, ) -> Result<(), ExprErr> { + tracing::trace!( + "resuming from modifier: {}", + ctx.associated_fn_name(self) + .into_expr_err(modifier_state.loc)? + ); + let mods = modifier_state.parent_fn.modifiers(self); self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { if modifier_state.num + 1 < mods.len() { @@ -113,11 +120,9 @@ pub trait ModifierCaller: .unwrap(); let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); + new_parent_subctx + .set_continuation_ctx(analyzer, modifier_state.parent_ctx) + .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; @@ -144,12 +149,9 @@ pub trait ModifierCaller: ) .unwrap(); let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - - analyzer.add_edge( - new_parent_subctx, - modifier_state.parent_ctx, - Edge::Context(ContextEdge::Continue), - ); + new_parent_subctx + .set_continuation_ctx(analyzer, modifier_state.parent_ctx) + .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; @@ -161,50 +163,11 @@ pub trait ModifierCaller: modifier_state.parent_fn, &modifier_state.renamed_inputs, None, - )?; - - fn inherit_return_from_call( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - loc: Loc, - ctx: ContextNode, - ) -> Result<(), ExprErr> { - let mctx = - Context::new_subctx(ctx, Some(ctx), loc, None, None, false, analyzer, None) - .unwrap(); - let modifier_after_subctx = - ContextNode::from(analyzer.add_node(Node::Context(mctx))); - - ctx.set_child_call(modifier_after_subctx, analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - modifier_after_subctx, - ctx, - Edge::Context(ContextEdge::Continue), - ); - - let ret = ctx.underlying(analyzer).unwrap().ret.clone(); - modifier_after_subctx.underlying_mut(analyzer).unwrap().ret = ret; - Ok(()) - } - - analyzer.apply_to_edges(new_parent_subctx, loc, &|analyzer, ctx, _loc| { - inherit_return_from_call(analyzer, modifier_state.loc, ctx) - }) - - // if edges.is_empty() { - // inherit_return_from_call(analyzer, modifier_state.loc, new_parent_subctx)?; - // } else { - // edges.iter().try_for_each(|i| { - // inherit_return_from_call(analyzer, modifier_state.loc, *i)?; - // Ok(()) - // })?; - // } - // Ok(()) + ) } }) } - /// Gets the modifiers for a function fn modifiers( &mut self, ctx: ContextNode, @@ -243,16 +206,11 @@ pub trait ModifierCaller: self.parse_ctx_expr(expr, callee_ctx)?; let f: Vec = self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { - if let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - { - Ok(ret.try_as_func_input_str(analyzer)) - } else { - Err(ExprErr::ParseError( - loc, - "Bad modifier parse".to_string(), - )) - } + let ret = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap(); + Ok(ret.try_as_func_input_str(analyzer)) })?; ctx.delete_child(self).into_expr_err(expr.loc())?; diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index a33f58e7..8ea97c15 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,5 +1,10 @@ //! Traits & blanket implementations that facilitate performing namespaced function calls. +use crate::assign::Assign; +use graph::VarType; +use graph::ContextEdge; +use graph::nodes::ContextVar; +use graph::Edge; use crate::{ func_call::func_caller::{NamedOrUnnamedArgs, FuncCaller}, func_call::helper::CallerHelper, intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, @@ -7,7 +12,7 @@ use crate::{ }; use graph::{ - nodes::{BuiltInNode, ContextNode, ContextVarNode, ExprRet, FunctionNode}, + nodes::{ContextNode, ContextVarNode, ExprRet, FunctionNode}, AnalyzerBackend, GraphBackend, Node, }; @@ -50,6 +55,7 @@ pub trait NameSpaceFuncCaller: .filter_map(|con_node| { con_node .linearized_functions(self) + .ok()? .into_iter() .find(|(func_name, _func_node)| func_name.starts_with(&ident.name)) .map(|(_, node)| node) @@ -162,7 +168,7 @@ pub trait NameSpaceFuncCaller: ) -> Result<(), ExprErr> { match ret { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { - self.call_name_spaced_func_inner(ctx, loc, member_expr, ident, input_exprs, inner) + self.call_name_spaced_func_inner(ctx, loc, member_expr, ident, input_exprs, inner, true) } ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { self.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) @@ -185,6 +191,7 @@ pub trait NameSpaceFuncCaller: ident: &Identifier, input_exprs: &NamedOrUnnamedArgs, member: NodeIdx, + member_is_lit: bool, ) -> Result<(), ExprErr> { use solang_parser::pt::Expression::*; tracing::trace!( @@ -210,7 +217,7 @@ pub trait NameSpaceFuncCaller: input_exprs.parse(self, ctx, loc)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + let Some(mut inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, "Namespace function call had no inputs".to_string(), @@ -222,6 +229,70 @@ pub trait NameSpaceFuncCaller: return Ok(()); } if possible_funcs.is_empty() { + // check structs + let structs = ctx.visible_structs(analyzer).into_expr_err(loc)?; + let possible_structs = structs + .iter() + .filter(|strukt| { + let named_correctly = strukt + .name(analyzer) + .unwrap() + .starts_with(&ident.name.to_string()); + if !named_correctly { + false + } else { + // filter by params + let fields = strukt.fields(analyzer); + fields.len() == input_exprs.len() + } + }) + .copied() + .collect::>(); + + if possible_structs.len() == 1 { + let strukt = possible_structs[0]; + let var = ContextVar::new_from_struct(loc, strukt, ctx, analyzer) + .into_expr_err(loc)?; + let cvar = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; + analyzer.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + + strukt.fields(analyzer).iter().try_for_each(|field| { + let field_cvar = ContextVar::maybe_new_from_field( + analyzer, + loc, + ContextVarNode::from(cvar) + .underlying(analyzer) + .into_expr_err(loc)?, + field.underlying(analyzer).unwrap().clone(), + ) + .expect("Invalid struct field"); + + let fc_node = analyzer.add_node(Node::ContextVar(field_cvar)); + analyzer.add_edge(fc_node, cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; + let field_as_ret = ExprRet::Single(fc_node); + let Some(assignment) = inputs.take_one().into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "Struct creation failed".to_string())); + }; + + if matches!(assignment, ExprRet::CtxKilled(_)) { + ctx.push_expr(assignment, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_sides(ctx, loc, &field_as_ret, &assignment)?; + let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; + Ok(()) + })?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + ctx.push_expr(ExprRet::Single(cvar), analyzer) + .into_expr_err(loc)?; + Ok(()) + })?; + return Ok(()); + } // TODO: this is extremely ugly. if inputs.has_killed() { return ctx @@ -232,6 +303,13 @@ pub trait NameSpaceFuncCaller: if let Node::ContextVar(_) = analyzer.node(member) { inputs.insert(0, ExprRet::Single(member)) } + if let Node::ContextVar(_) = analyzer.node(member) { + if member_is_lit { + inputs.insert(0, ExprRet::SingleLiteral(member)) + } else { + inputs.insert(0, ExprRet::Single(member)) + } + } let inputs = ExprRet::Multi(inputs); let as_input_str = inputs.try_as_func_input_str(analyzer); @@ -239,103 +317,107 @@ pub trait NameSpaceFuncCaller: let lits = inputs.literals_list().into_expr_err(loc)?; if lits.iter().any(|i| *i) { // try to disambiguate - if lits[0] { - Err(ExprErr::Todo( - loc, - "First element in function call was literal".to_string(), - )) + let ty = if let Node::ContextVar(cvar) = analyzer.node(member) { + cvar.ty.ty_idx() } else { - let ty = if let Node::ContextVar(cvar) = analyzer.node(member) { - cvar.ty.ty_idx() - } else { - member - }; + member + }; - let possible_builtins: Vec<_> = analyzer - .builtin_fn_inputs() - .iter() - .filter_map(|(func_name, (inputs, _))| { - if func_name.starts_with(&ident.name) { - if let Some(input) = inputs.first() { - let Ok(implicitly_castable) = BuiltInNode::from(ty) - .implicitly_castable_to( - &BuiltInNode::from(input.ty), - analyzer, - ) - else { - return None; - }; - if implicitly_castable { - Some(func_name.clone()) - } else { - None - } + let possible_builtins: Vec<_> = analyzer + .builtin_fn_inputs() + .iter() + .filter_map(|(func_name, (inputs, _))| { + if func_name.starts_with(&ident.name) { + if let Some(input) = inputs.first() { + let try_cast = VarType::try_from_idx(analyzer, ty)? + .implicitly_castable_to( + &VarType::try_from_idx(analyzer, input.ty)?, + analyzer, + ); + let Ok(implicitly_castable) = try_cast else { + return None; + }; + if implicitly_castable { + Some(func_name.clone()) } else { None } } else { None } - }) - .collect::>(); - let possible_builtins: Vec<_> = possible_builtins - .into_iter() - .filter_map(|name| { - analyzer - .builtin_fn_or_maybe_add(&name) - .map(FunctionNode::from) - }) - .collect(); - if let Some(func) = analyzer.disambiguate_fn_call( + } else { + None + } + }) + .collect::>(); + let possible_builtins: Vec<_> = possible_builtins + .into_iter() + .filter_map(|name| { + analyzer + .builtin_fn_or_maybe_add(&name) + .map(FunctionNode::from) + }) + .collect(); + + let maybe_func = if possible_builtins.len() == 1 { + Some(possible_builtins[0]) + } else { + analyzer.disambiguate_fn_call( &ident.name, lits, &inputs, &possible_builtins, - ) { - let expr = &MemberAccess( - loc, - Box::new(member_expr.clone()), - Identifier { - loc: ident.loc, - name: func - .name(analyzer) - .into_expr_err(loc)? - .split('(') - .collect::>()[0] - .to_string(), - }, - ); - analyzer.parse_ctx_expr(expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(ret) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "Fallback function parse failure".to_string(), - )); - }; - if matches!(ret, ExprRet::CtxKilled(_)) { - ctx.push_expr(ret, analyzer).into_expr_err(loc)?; - return Ok(()); - } - let mut modifier_input_exprs = vec![member_expr.clone()]; - modifier_input_exprs.extend(input_exprs.exprs()); - analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), ret) - }) - } else { - // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) - Err(ExprErr::FunctionNotFound( - loc, - format!( - "Could not disambiguate function, possible functions: {:#?}", - possible_builtins - .iter() - .map(|i| i.name(analyzer).unwrap()) - .collect::>() - ), - )) - } + ) + }; + if let Some(func) = maybe_func { + let expr = &MemberAccess( + loc, + Box::new(member_expr.clone()), + Identifier { + loc: ident.loc, + name: func + .name(analyzer) + .into_expr_err(loc)? + .split('(') + .collect::>()[0] + .to_string(), + }, + ); + analyzer.parse_ctx_expr(expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + let Some(ret) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Fallback function parse failure".to_string(), + )); + }; + if matches!(ret, ExprRet::CtxKilled(_)) { + ctx.push_expr(ret, analyzer).into_expr_err(loc)?; + return Ok(()); + } + let mut modifier_input_exprs = vec![member_expr.clone()]; + modifier_input_exprs.extend(input_exprs.exprs()); + analyzer.match_intrinsic_fallback( + ctx, + &loc, + &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), + ret, + ) + }) + } else { + // analyzer.match_intrinsic_fallback(ctx, &loc, &modifier_input_exprs, ret) + Err(ExprErr::FunctionNotFound( + loc, + format!( + "Could not disambiguate function, possible functions: {:#?}", + possible_builtins + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect::>() + ), + )) } } else { let expr = &MemberAccess( @@ -361,11 +443,18 @@ pub trait NameSpaceFuncCaller: } let mut modifier_input_exprs = vec![member_expr.clone()]; modifier_input_exprs.extend(input_exprs.exprs()); - analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), ret) + analyzer.match_intrinsic_fallback( + ctx, + &loc, + &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), + ret, + ) }) } } else if possible_funcs.len() == 1 { - let mut inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + let mut inputs = if let Some(ordered_param_names) = + possible_funcs[0].maybe_ordered_param_names(analyzer) + { input_exprs.order(inputs, ordered_param_names).as_vec() } else { inputs.as_vec() diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index de1d0837..f265c11f 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -22,6 +22,7 @@ pub trait Literal: AnalyzerBackend + Sized { integer: &str, exponent: &str, negative: bool, + unit: &Option, ) -> Result<(), ExprErr> { let int = U256::from_dec_str(integer).unwrap(); let val = if !exponent.is_empty() { @@ -31,6 +32,12 @@ pub trait Literal: AnalyzerBackend + Sized { int }; + let val = if let Some(unit) = unit { + val * self.unit_to_uint(unit) + } else { + val + }; + let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; let concrete_node = if negative { let val = if val == U256::from(2).pow(255.into()) { @@ -55,6 +62,18 @@ pub trait Literal: AnalyzerBackend + Sized { Ok(()) } + fn unit_to_uint(&self, unit: &Identifier) -> U256 { + match &*unit.name { + "gwei" => U256::from(10).pow(9.into()), + "ether" => U256::from(10).pow(18.into()), + "minutes" => U256::from(60), + "hours" => U256::from(3600), + "days" => U256::from(86400), + "weeks" => U256::from(604800), + _ => U256::from(1), + } + } + fn rational_number_literal( &mut self, ctx: ContextNode, @@ -62,7 +81,7 @@ pub trait Literal: AnalyzerBackend + Sized { integer: &str, fraction: &str, exponent: &str, - _unit: &Option, + unit: &Option, ) -> Result<(), ExprErr> { let int = U256::from_dec_str(integer).unwrap(); let exp = if !exponent.is_empty() { @@ -79,9 +98,14 @@ pub trait Literal: AnalyzerBackend + Sized { Elem::from(Concrete::from(U256::from(1))), ); let exp_elem = Elem::from(Concrete::from(exp)); - let rational_range = (Elem::from(Concrete::from(fraction)) + let mut rational_range = (Elem::from(Concrete::from(fraction)) + int_elem * Elem::from(Concrete::from(fraction_denom))) * Elem::from(Concrete::from(U256::from(10))).pow(exp_elem); + + if let Some(unit) = unit { + rational_range = rational_range * Elem::from(Concrete::from(self.unit_to_uint(unit))) + } + let cvar = ContextVar::new_from_builtin(loc, self.builtin_or_add(Builtin::Uint(256)).into(), self) .into_expr_err(loc)?; diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index 27bcdd5f..99b11ae7 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -1,3 +1,5 @@ +use graph::Edge; +use graph::ContextEdge; use crate::{variable::Variable, ContextBuilder, ExprErr, IntoExprErr, StatementParser}; use graph::{ @@ -44,10 +46,10 @@ pub trait Looper: /// Resets all variables referenced in the loop because we don't elegantly handle loops fn reset_vars(&mut self, loc: Loc, ctx: ContextNode, body: &Statement) -> Result<(), ExprErr> { let og_ctx = ctx; - let sctx = Context::new_subctx(ctx, None, loc, None, None, false, self, None) - .into_expr_err(loc)?; + let sctx = Context::new_loop_subctx(ctx, loc, self).into_expr_err(loc)?; let subctx = ContextNode::from(self.add_node(Node::Context(sctx))); ctx.set_child_call(subctx, self).into_expr_err(loc)?; + self.add_edge(subctx, ctx, Edge::Context(ContextEdge::Loop)); self.parse_ctx_statement(body, false, Some(subctx)); self.apply_to_edges(subctx, loc, &|analyzer, ctx, loc| { let vars = subctx.local_vars(analyzer).clone(); diff --git a/crates/solc-expressions/src/member_access/contract_access.rs b/crates/solc-expressions/src/member_access/contract_access.rs index 860558a8..081344ca 100644 --- a/crates/solc-expressions/src/member_access/contract_access.rs +++ b/crates/solc-expressions/src/member_access/contract_access.rs @@ -111,19 +111,52 @@ pub trait ContractAccess: AnalyzerBackend return Ok(ExprRet::Single(node)); } _ => { - return Err(ExprErr::ContractFunctionNotFound( - loc, - format!( - "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", - ident.name, - con_node.name(self).unwrap(), - con_node - .funcs(self) - .iter() - .map(|func| func.name(self).unwrap()) - .collect::>() - ), - )) + // try to match just prefix + if let Some(func) = con_node.funcs(self).into_iter().find(|func_node| { + if let Some(prefix) = func_node.prefix_only_name(self).unwrap() { + prefix == ident.name + } else { + false + } + }) { + if let Some(func_cvar) = + ContextVar::maybe_from_user_ty(self, loc, func.0.into()) + { + let fn_node = self.add_node(Node::ContextVar(func_cvar)); + // this prevents attaching a dummy node to the parent which could cause a cycle in the graph + if maybe_parent.is_some() { + self.add_edge( + fn_node, + member_idx, + Edge::Context(ContextEdge::FuncAccess), + ); + } + Ok(ExprRet::Single(fn_node)) + } else { + Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unable to construct the function \"{}\" in contract \"{}\"", + ident.name, + con_node.name(self).into_expr_err(loc)? + ), + )) + } + } else { + return Err(ExprErr::ContractFunctionNotFound( + loc, + format!( + "No function or struct with name {:?} in contract: {:?}. Functions: {:#?}", + ident.name, + con_node.name(self).unwrap(), + con_node + .funcs(self) + .iter() + .map(|func| func.name(self).unwrap()) + .collect::>() + ), + )) + } } } } diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index 893db13d..4ab86604 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -1,3 +1,5 @@ +use graph::nodes::ConcreteNode; +use graph::nodes::Concrete; use crate::{ BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, ExpressionParser, IntoExprErr, ListAccess, StructAccess, @@ -142,9 +144,10 @@ pub trait MemberAccess: let res = match self.node(member_idx) { Node::ContextVar(cvar) => match &cvar.ty { VarType::User(TypeNode::Contract(con_node), _) => { - let mut funcs = con_node.linearized_functions(self); + let cnode = *con_node; + let mut funcs = cnode.linearized_functions(self).into_expr_err(loc)?; self - .possible_library_funcs(ctx, con_node.0.into()) + .possible_library_funcs(ctx, cnode.0.into()) .into_iter() .for_each(|func| { let name = func.name(self).unwrap(); @@ -224,6 +227,9 @@ pub trait MemberAccess: VarType::User(TypeNode::Enum(enum_node), _) => { self.enum_member_access(member_idx, *enum_node, ident, ctx, loc) } + VarType::User(TypeNode::Func(func_node), _) => { + self.func_member_access(*func_node, ident, ctx, loc) + } VarType::User(TypeNode::Ty(ty_node), _) => { self.ty_member_access(member_idx, *ty_node, ident, ctx, loc, Some(cvar)) } @@ -285,4 +291,40 @@ pub trait MemberAccess: )) } } + + /// Access function members + fn func_member_access( + &mut self, + func_node: FunctionNode, + ident: &Identifier, + ctx: ContextNode, + loc: Loc, + ) -> Result { + let prefix_only_name = func_node + .prefix_only_name(self) + .into_expr_err(loc)? + .unwrap(); + let name = format!("{}.{}", prefix_only_name, ident.name); + tracing::trace!("Function member access: {}", name); + match &*ident.name { + "selector" => { + let mut out = [0; 32]; + keccak_hash::keccak_256(prefix_only_name.as_bytes(), &mut out); + let selector: [u8; 4] = [out[0], out[1], out[2], out[3]]; + let selector_conc = Node::Concrete(Concrete::from(selector)); + let selector_node = ConcreteNode::from(self.add_node(selector_conc)); + let var = ContextVar::new_from_concrete(loc, ctx, selector_node, self) + .into_expr_err(loc)?; + let cvar = self.add_node(Node::ContextVar(var)); + Ok(ExprRet::Single(cvar)) + } + _ => Err(ExprErr::MemberAccessNotFound( + loc, + format!( + "Unknown member access \"{}\" on function \"{}\"", + ident.name, prefix_only_name + ), + )), + } + } } diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index a41489ef..a85feef4 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -47,6 +47,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Handles a require expression #[tracing::instrument(level = "trace", skip_all)] fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(inputs[0].loc())?; match inputs.first().expect("No lhs input for require statement") { Expression::Equal(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; @@ -87,7 +88,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &lhs_paths.flatten(), &rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), ) }) @@ -129,7 +130,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &lhs_paths.flatten(), &rhs_paths, RangeOp::Neq, - RangeOp::Eq, + RangeOp::Neq, (RangeOp::Eq, RangeOp::Neq), ) }) @@ -336,7 +337,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &lhs_paths, &rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), ) }) @@ -401,7 +402,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &ExprRet::Single(tmp.lhs.into()), &ExprRet::Single(tmp.rhs.unwrap().into()), op, - inv_op, + op, pair, )?; } @@ -419,7 +420,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &ExprRet::Single(tmp.lhs.into()), &ExprRet::Single(tmp.rhs.unwrap().into()), op, - inv_op, + op, pair, )?; } @@ -431,7 +432,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &lhs_paths, &tmp_rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), )?; @@ -441,7 +442,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &rhs_paths, &tmp_rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), )?; @@ -542,7 +543,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &ExprRet::Single(or_var.into()), &rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), ) }) @@ -576,7 +577,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { &lhs_paths, &rhs_paths, RangeOp::Eq, - RangeOp::Neq, + RangeOp::Eq, (RangeOp::Neq, RangeOp::Eq), ) }) diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 8623bc6a..65caaa2e 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -72,13 +72,11 @@ pub trait Variable: AnalyzerBackend + Size None }; - let mut storage_idx = None; let var = if let Some(con) = const_var { con } else { match self.node(idx) { - Node::Var(_) => { - storage_idx = Some(idx); + Node::Var(_) | Node::Enum(_) => { match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { Some(v) => v, None => { @@ -92,18 +90,6 @@ pub trait Variable: AnalyzerBackend + Size } } } - Node::Enum(_) => match ContextVar::maybe_from_user_ty(self, ident.loc, idx) { - Some(v) => v, - None => { - return Err(ExprErr::VarBadType( - ident.loc, - format!( - "Could not create context variable from user type: {:?}", - self.node(idx) - ), - )) - } - }, _ => { return target_ctx .push_expr(ExprRet::Single(idx), self) @@ -116,14 +102,6 @@ pub trait Variable: AnalyzerBackend + Size ctx.add_var(new_cvarnode.into(), self) .into_expr_err(ident.loc)?; - - if let Some(store_idx) = storage_idx { - self.add_edge( - new_cvarnode, - store_idx, - Edge::Context(ContextEdge::InheritedStorageVariable), - ); - } self.add_edge( new_cvarnode, target_ctx, @@ -368,6 +346,57 @@ pub trait Variable: AnalyzerBackend + Size Ok(ContextVarNode::from(new_cvarnode)) } + fn advance_var_in_forced_ctx( + &mut self, + cvar_node: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result { + let mut new_cvar = cvar_node + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + // get the old context + let new_cvarnode; + + 'a: { + if let Some(old_ctx) = cvar_node.maybe_ctx(self) { + // get the previous version to remove and prevent spurious nodes + if let Some(prev) = cvar_node.latest_version(self).previous_version(self) { + let prev_version = prev.underlying(self).into_expr_err(loc)?; + // check if there was no change between the previous version and the latest version + if prev_version.eq_ignore_loc(&new_cvar) && old_ctx == ctx { + // there was no change in the current context, just give them the current variable + new_cvarnode = cvar_node.into(); + break 'a; + } + } + + new_cvar.loc = Some(loc); + // new_cvar.display_name = format!("{}_{}", new_cvar.name, cvar_node.prev_versions(self)); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + if old_ctx != ctx { + ctx.add_var(new_cvarnode.into(), self).into_expr_err(loc)?; + self.add_edge(new_cvarnode, ctx, Edge::Context(ContextEdge::Variable)); + self.add_edge( + new_cvarnode, + cvar_node.0, + Edge::Context(ContextEdge::InheritedVariable), + ); + } else { + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } else { + new_cvar.loc = Some(loc); + new_cvarnode = self.add_node(Node::ContextVar(new_cvar)); + self.add_edge(new_cvarnode, cvar_node.0, Edge::Context(ContextEdge::Prev)); + } + } + + Ok(ContextVarNode::from(new_cvarnode)) + } + /// Creates a new version of a variable in it's current context fn advance_var_in_curr_ctx( &mut self, diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 177c349f..14003b4a 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -274,8 +274,8 @@ pub trait YulBuilder: use YulExpression::*; match expr { BoolLiteral(loc, b, _) => self.bool_literal(ctx, *loc, *b), - NumberLiteral(loc, int, expr, _unit) => { - self.number_literal(ctx, *loc, int, expr, false) + NumberLiteral(loc, int, expr, unit) => { + self.number_literal(ctx, *loc, int, expr, false, unit) } HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 253aa2a9..f79f781e 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -474,7 +474,8 @@ pub trait YulFuncCaller: self.parse_inputs(ctx, *loc, arguments)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(mut lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + let Some(mut lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::InvalidFunctionInput( loc, @@ -492,8 +493,13 @@ pub trait YulFuncCaller: let slot = lhs_paths.take_one().into_expr_err(loc)?.unwrap(); let cvar = ContextVarNode::from(slot.expect_single().unwrap()); - if cvar.is_storage(analyzer).into_expr_err(loc)? { - analyzer.match_assign_sides(ctx, loc, &slot, &value)?; + if let Some(slot) = cvar.slot_to_storage(analyzer) { + analyzer.match_assign_sides( + ctx, + loc, + &ExprRet::Single(slot.into()), + &value, + )?; } else { // TODO: improve this. We now handle `slot` but should try to figure out storage layout let vars = ctx.local_vars(analyzer).clone(); @@ -506,10 +512,13 @@ pub trait YulFuncCaller: ) { let res = latest_var.ty(analyzer).into_expr_err(loc)?; if let Some(r) = res.default_range(analyzer).unwrap() { - let new_var = analyzer.advance_var_in_ctx(latest_var, loc, ctx).unwrap(); - let res = new_var.set_range_min(analyzer, r.min).into_expr_err(loc); + let new_var = + analyzer.advance_var_in_ctx(latest_var, loc, ctx).unwrap(); + let res = + new_var.set_range_min(analyzer, r.min).into_expr_err(loc); let _ = analyzer.add_if_err(res); - let res = new_var.set_range_max(analyzer, r.max).into_expr_err(loc); + let res = + new_var.set_range_max(analyzer, r.max).into_expr_err(loc); let _ = analyzer.add_if_err(res); } } From c2b1f28d1dfe1aee5bad1ac98ab2682173e319d2 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Wed, 20 Dec 2023 08:38:40 -0800 Subject: [PATCH 50/71] small fix --- .../pyrometer/tests/test_data/dyn_types.sol | 136 ++++++++---------- .../src/func_call/namespaced_call.rs | 5 +- 2 files changed, 60 insertions(+), 81 deletions(-) diff --git a/crates/pyrometer/tests/test_data/dyn_types.sol b/crates/pyrometer/tests/test_data/dyn_types.sol index c6a3f878..5931af92 100644 --- a/crates/pyrometer/tests/test_data/dyn_types.sol +++ b/crates/pyrometer/tests/test_data/dyn_types.sol @@ -1,79 +1,71 @@ contract DynTypes { - // uint256[] storeVar; + uint256[] storeVar; - // struct Strukt { - // uint256 a; - // uint256 b; - // } - - // mapping (address => Strukt) public someMapping; + struct Strukt { + uint256 a; + uint256 b; + } - // function bytes_dyn(bytes calldata x) public { - // bytes memory y = x; - // require(x.length < 10); - // y[8] = 0xff; - // require(y.length == 9); - // } + mapping (address => Strukt) public someMapping; - // function array_dyn(uint256[] calldata x) public { - // x[0] = 5; - // require(x.length < 10); - // uint256[] memory y = x; - // y[8] = 100; - // require(y.length == 9); - // } + function bytes_dyn(bytes calldata x) public { + bytes memory y = x; + require(x.length < 10); + y[8] = 0xff; + require(y.length == 9); + } - // function nested_bytes_dyn(bytes[] calldata x, uint y) public returns (bytes1) { - // bytes memory a = hex"1337"; - // x[0] = a; - // require(x[0][0] == hex"13"); - // // return x[0][0]; + function array_dyn(uint256[] calldata x) public { + x[0] = 5; + require(x.length < 10); + uint256[] memory y = x; + y[8] = 100; + require(y.length == 9); + } - // x[y] = hex"1122"; - // uint256 z = y - 1; - // require(x[z + 1][0] == hex"11"); - // } + function nested_bytes_dyn(bytes[] calldata x, uint y) public returns (bytes1) { + bytes memory a = hex"1337"; + x[0] = a; + require(x[0][0] == hex"13"); + // return x[0][0]; - // function array_push(uint256 x) public { - // // require(x > 5); - // storeVar.push(x); - // storeVar.push(x); - // storeVar.push(x); - // // TODO: handle this better - // require(storeVar[0] == x); - // storeVar.push(x); - // require(storeVar[1] == x); - // uint256 y = storeVar[storeVar.length - 1]; - // storeVar.pop(); - // require(y == x); - // } + x[y] = hex"1122"; + uint256 z = y - 1; + require(x[z + 1][0] == hex"11"); + } - // function indexInto() public returns (uint256) { - // return storeVar[basicFunc()]; - // } + function array_push(uint256 x) public { + // require(x > 5); + storeVar.push(x); + storeVar.push(x); + storeVar.push(x); + // TODO: handle this better + require(storeVar[0] == x); + storeVar.push(x); + require(storeVar[1] == x); + uint256 y = storeVar[storeVar.length - 1]; + storeVar.pop(); + require(y == x); + } - // function basicFunc() public returns (uint256) { - // return 1; - // } + function indexInto() public returns (uint256) { + return storeVar[basicFunc()]; + } - // function indexIntoMapping(address who) public { - // // TODO: this should panic - // Strukt storage a = someMapping[who]; - // a.a = 100; - // a.b = 100; - // require(someMapping[who].a == 300); - // } + function basicFunc() public returns (uint256) { + return 1; + } - // function a(address a, address b) internal { - - // } + function indexIntoMapping(address who) public { + // TODO: this should panic + Strukt storage a = someMapping[who]; + a.a = 100; + a.b = 100; + require(someMapping[who].a == 300); + } address[] t; - // function inLoop(address holder) public { - // inLoop(holder, t); - // } - function inLoop(address holder, address[] memory tokens) public { address[] memory h = new address[](1); h[0] = holder; @@ -81,23 +73,9 @@ contract DynTypes { } function inLoop(address[] memory holders, address[] memory tokens) public { - - // for (uint i = 0; i < tokens.length; i++) { - // address token = tokens[i]; - for (uint j = 0; j < holders.length; j++) { - address holder = holders[j]; - // a(token, holders[j]); - } - // if (suppliers == true) { - // updateCompSupplyIndex(address(cToken)); - // for (uint j = 0; j < holders.length; j++) { - // distributeSupplierComp(address(cToken), holders[j]); - // } - // } - // } - // for (uint j = 0; j < holders.length; j++) { - // compAccrued[holders[j]] = grantCompInternal(holders[j], compAccrued[holders[j]]); - // } + for (uint j = 0; j < holders.length; j++) { + address holder = holders[j]; + } } } diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 8ea97c15..50f8dfc9 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -343,7 +343,8 @@ pub trait NameSpaceFuncCaller: None } } else { - None + // generic builtin function, return it + Some(func_name.clone()) } } else { None @@ -411,7 +412,7 @@ pub trait NameSpaceFuncCaller: Err(ExprErr::FunctionNotFound( loc, format!( - "Could not disambiguate function, possible functions: {:#?}", + "Could not disambiguate builtin function, possible builtin functions: {:#?}", possible_builtins .iter() .map(|i| i.name(analyzer).unwrap()) From 3d3886350ab94bf2a5e833ba62cfe7a57004d4b2 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Wed, 20 Dec 2023 11:15:59 -0800 Subject: [PATCH 51/71] add non-useful arena --- crates/graph/src/graph_elements.rs | 3 +- crates/graph/src/nodes/concrete.rs | 6 + crates/graph/src/nodes/context/solving.rs | 10 +- crates/graph/src/nodes/context/var/ranging.rs | 24 +-- crates/graph/src/range/elem/concrete.rs | 25 +-- crates/graph/src/range/elem/elem_enum.rs | 123 +++++++++----- crates/graph/src/range/elem/elem_trait.rs | 23 ++- crates/graph/src/range/elem/expr.rs | 101 ++++++------ crates/graph/src/range/elem/map_or_array.rs | 68 +++++--- crates/graph/src/range/elem/reference.rs | 22 +-- crates/graph/src/range/exec/exec_op.rs | 150 +++++++++--------- crates/graph/src/range/range_string.rs | 4 +- crates/graph/src/range/range_trait.rs | 4 +- crates/graph/src/range/solc_range.rs | 70 ++------ crates/graph/src/solvers/atoms.rs | 28 ++-- crates/graph/src/solvers/brute.rs | 20 +-- crates/graph/src/solvers/dl.rs | 79 ++++----- crates/graph/src/var_type.rs | 2 +- crates/pyrometer/src/analyzer.rs | 6 + crates/pyrometer/src/graph_backend.rs | 21 ++- crates/shared/src/graph_like.rs | 24 +++ crates/solc-expressions/src/bin_op.rs | 8 +- crates/solc-expressions/src/cmp.rs | 30 ++-- crates/solc-expressions/src/require.rs | 36 ++--- .../solc-expressions/src/yul/yul_cond_op.rs | 12 ++ 25 files changed, 492 insertions(+), 407 deletions(-) diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index b3e20b41..460f8cac 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -1,3 +1,4 @@ +use crate::elem::Elem; use crate::{nodes::*, VarType}; use shared::{AnalyzerLike, GraphLike, Heirarchical, NodeIdx}; @@ -7,7 +8,7 @@ use solang_parser::pt::Identifier; use std::collections::HashMap; -pub trait GraphBackend: GraphLike {} +pub trait GraphBackend: GraphLike> {} pub trait AnalyzerBackend: AnalyzerLike< Builtin = Builtin, diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 7fb60069..b71e65e7 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -103,6 +103,12 @@ pub enum Concrete { Array(Vec), } +impl Default for Concrete { + fn default() -> Self { + Concrete::Uint(0, U256::zero()) + } +} + // impl From for Concrete { // fn from(u: usize) -> Self { // Concrete::Uint(256, U256::from(u)) diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 1e266974..eb7aca86 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -85,11 +85,13 @@ impl ContextNode { let r = range.flattened_range(analyzer)?.into_owned(); // add the atomic constraint if let Some(atom) = r.min.atomize() { - let underlying = self.underlying_mut(analyzer)?; - underlying.dl_solver.add_constraints(vec![atom]); + let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); + solver.add_constraints(vec![atom], analyzer); + self.underlying_mut(analyzer)?.dl_solver = solver; } else if let Some(atom) = r.max.atomize() { - let underlying = self.underlying_mut(analyzer)?; - underlying.dl_solver.add_constraints(vec![atom]); + let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); + solver.add_constraints(vec![atom], analyzer); + self.underlying_mut(analyzer)?.dl_solver = solver; } let underlying = self.underlying_mut(analyzer)?; diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 4b8be862..b834bdf0 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -9,20 +9,6 @@ use crate::range::elem::*; use solang_parser::pt::Loc; impl ContextVarNode { - #[tracing::instrument(level = "trace", skip_all)] - pub fn update_deps( - &mut self, - ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { - if let Some(mut range) = self.range(analyzer)? { - range.update_deps(*self, ctx, analyzer); - self.set_range_min(analyzer, range.min)?; - self.set_range_max(analyzer, range.max)?; - } - Ok(()) - } - pub fn range(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { self.underlying(analyzer)?.ty.range(analyzer) } @@ -185,7 +171,7 @@ impl ContextVarNode { assert!(self.latest_version(analyzer) == *self); if new_min.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into()); + new_min.filter_recursion((*self).into(), prev.into(), analyzer); } else { return Err(GraphError::UnbreakableRecursion(format!("The variable {}'s range is self-referential and we cannot break the recursion.", self.display_name(analyzer)?))); } @@ -230,7 +216,7 @@ impl ContextVarNode { assert!(self.latest_version(analyzer) == *self); if new_max.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into()); + new_max.filter_recursion((*self).into(), prev.into(), analyzer); } } @@ -294,7 +280,7 @@ impl ContextVarNode { assert!(self.latest_version(analyzer) == *self); if new_min.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into()); + new_min.filter_recursion((*self).into(), prev.into(), analyzer); } } @@ -326,7 +312,7 @@ impl ContextVarNode { assert!(self.latest_version(analyzer) == *self); if new_max.recursive_dependent_on(analyzer)?.contains(self) { if let Some(prev) = self.previous_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into()); + new_max.filter_recursion((*self).into(), prev.into(), analyzer); } } @@ -372,7 +358,7 @@ impl ContextVarNode { pub fn range_deps(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { - Ok(range.dependent_on()) + Ok(range.dependent_on(analyzer)) } else { Ok(vec![]) } diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index f3cf5dba..a17bd821 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -11,7 +11,7 @@ use std::collections::BTreeMap; use solang_parser::pt::Loc; /// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RangeConcrete { pub val: T, pub loc: Loc, @@ -34,9 +34,13 @@ impl RangeConcrete { impl RangeElem for RangeConcrete { type GraphError = GraphError; - // fn simplify(&self, _analyzer: &impl GraphBackend) -> Elem { - // Elem::Concrete(self.clone()) - // } + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + let _ = analyzer.range_arena_idx_or_upsert(Elem::Concrete(self.clone())); + } + + fn dearenaize(&self, _analyzer: &impl GraphBackend) -> Elem { + Elem::Concrete(self.clone()) + } fn has_cycle( &self, @@ -54,7 +58,7 @@ impl RangeElem for RangeConcrete { Ok(Elem::Concrete(self.clone())) } - fn is_flatten_cached(&self) -> bool { + fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { true } @@ -62,7 +66,7 @@ impl RangeElem for RangeConcrete { Ok(()) } - fn range_eq(&self, other: &Self) -> bool { + fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => self_val == other_val, _ => match (&self.val, &other.val) { @@ -84,7 +88,7 @@ impl RangeElem for RangeConcrete { loc: other.loc, }; - a.range_eq(&b) + a.range_eq(&b, analyzer) }) } else { false @@ -95,7 +99,7 @@ impl RangeElem for RangeConcrete { } } - fn range_ord(&self, other: &Self) -> Option { + fn range_ord(&self, other: &Self, _analyzer: &impl GraphBackend) -> Option { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), (Some(_), _) => { @@ -129,12 +133,11 @@ impl RangeElem for RangeConcrete { } } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self, _analyzer: &impl GraphBackend) -> Vec { vec![] } - fn update_deps(&mut self, _mapping: &BTreeMap) {} - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &impl GraphBackend) {} fn maximize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 6b518987..138c3317 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -7,7 +7,7 @@ use crate::{ }; use solang_parser::pt::Loc; -use shared::NodeIdx; +use shared::{RangeArenaIdx, NodeIdx}; use ethers_core::types::I256; @@ -17,7 +17,7 @@ use std::{ }; /// A core range element. -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub enum Elem { /// A range element that is a reference to another node Reference(Reference), @@ -27,7 +27,10 @@ pub enum Elem { Concrete(RangeConcrete), /// A range element that is an expression composed of other range elements Expr(RangeExpr), + /// A range element that is a pointer to another expression in an arena + Arena(RangeArenaIdx), /// A null range element useful in range expressions that dont have a rhs + #[default] Null, } @@ -47,7 +50,8 @@ impl Elem { expr.minimized = None; } Elem::ConcreteDyn(_d) => todo!(), - Elem::Null => {} + Elem::Null => {}, + Elem::Arena(_) => todo!() } } @@ -109,6 +113,7 @@ impl Elem { Self::Expr(expr) => expr.contains_node(node_idx), Self::ConcreteDyn(d) => d.contains_node(node_idx), Self::Null => false, + Elem::Arena(_) => todo!() } } @@ -342,14 +347,14 @@ impl Elem { let lhs_min = s.minimize(analyzer)?; let rhs_max = o.maximize(analyzer)?; - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, analyzer) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max // check that the max is greater than or eq their min let lhs_max = s.maximize(analyzer)?; let rhs_min = o.minimize(analyzer)?; Ok(Some(matches!( - lhs_max.range_ord(&rhs_min), + lhs_max.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ))) } @@ -366,13 +371,13 @@ impl Elem { if eval { let lhs_min = s.minimize(analyzer)?; - match lhs_min.range_ord(c) { + match lhs_min.range_ord(c, analyzer) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max // check that the max is greater than or eq their min let lhs_max = s.maximize(analyzer)?; Ok(Some(matches!( - lhs_max.range_ord(c), + lhs_max.range_ord(c, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ))) } @@ -400,14 +405,14 @@ impl Elem { let lhs_min = d.minimize(analyzer)?; let rhs_max = rhs_max.maximize(analyzer)?; - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, analyzer) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max // check that the max is greater than or eq their min let lhs_max = d.maximize(analyzer)?; let rhs_min = rhs_min.minimize(analyzer)?; Ok(Some(matches!( - lhs_max.range_ord(&rhs_min), + lhs_max.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ))) } @@ -420,9 +425,9 @@ impl Elem { Ok(None) } } - Self::Concrete(_) => match rhs_min.range_ord(self) { + Self::Concrete(_) => match rhs_min.range_ord(self, analyzer) { Some(std::cmp::Ordering::Less) => Ok(Some(matches!( - rhs_max.range_ord(self), + rhs_max.range_ord(self, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ))), Some(std::cmp::Ordering::Equal) => Ok(Some(true)), @@ -479,6 +484,7 @@ impl Elem { Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), Self::ConcreteDyn(_d) => None, Self::Null => None, + Self::Arena(_) => todo!(), } } } @@ -541,19 +547,45 @@ impl std::fmt::Display for Elem { impl RangeElem for Elem { type GraphError = GraphError; - fn range_eq(&self, other: &Self) -> bool { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + match self { + Self::Arena(_) => return, + Self::Reference(d) => d.arenaize(analyzer), + Self::ConcreteDyn(d) => d.arenaize(analyzer), + Self::Expr(expr) => { + expr.arenaize(analyzer); + }, + _ => {} + } + + let self_take = std::mem::take(self); + *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(self_take)); + } + + fn dearenaize(&self, analyzer: &impl GraphBackend) -> Self { + match self { + Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone(), + e => e.clone() + } + } + + fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b), - (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b), + (Self::Arena(a), Self::Arena(b)) => { + a == b + }, + (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b, analyzer), + (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b, analyzer), (Self::Reference(a), Self::Reference(b)) => a.idx == b.idx, _ => false, } } - fn range_ord(&self, other: &Self) -> Option { + fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { match (self, other) { - (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b), - (Self::Reference(a), Self::Reference(b)) => a.range_ord(b), + (Self::Arena(_), Self::Arena(_)) => self.dearenaize(analyzer).range_ord(&other.dearenaize(analyzer), analyzer), + (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), + (Self::Reference(a), Self::Reference(b)) => a.range_ord(b, analyzer), (Elem::Null, Elem::Null) => None, (_a, Elem::Null) => Some(std::cmp::Ordering::Greater), (Elem::Null, _a) => Some(std::cmp::Ordering::Less), @@ -572,6 +604,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.flatten(maximize, analyzer), Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), Self::Null => Ok(Elem::Null), + Self::Arena(_) => todo!(), } } @@ -582,26 +615,29 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.cache_flatten(analyzer), Self::ConcreteDyn(d) => d.cache_flatten(analyzer), Self::Null => Ok(()), + Self::Arena(_) => todo!(), } } - fn is_flatten_cached(&self) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend,) -> bool { match self { - Self::Reference(d) => d.is_flatten_cached(), - Self::Concrete(c) => c.is_flatten_cached(), - Self::Expr(expr) => expr.is_flatten_cached(), - Self::ConcreteDyn(d) => d.is_flatten_cached(), + Self::Reference(d) => d.is_flatten_cached(analyzer), + Self::Concrete(c) => c.is_flatten_cached(analyzer), + Self::Expr(expr) => expr.is_flatten_cached(analyzer), + Self::ConcreteDyn(d) => d.is_flatten_cached(analyzer), Self::Null => true, + Self::Arena(_) => self.dearenaize(analyzer).is_flatten_cached(analyzer), } } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { match self { - Self::Reference(d) => d.dependent_on(), + Self::Reference(d) => d.dependent_on(analyzer), Self::Concrete(_) => vec![], - Self::Expr(expr) => expr.dependent_on(), - Self::ConcreteDyn(d) => d.dependent_on(), + Self::Expr(expr) => expr.dependent_on(analyzer), + Self::ConcreteDyn(d) => d.dependent_on(analyzer), Self::Null => vec![], + Self::Arena(_) => self.dearenaize(analyzer).dependent_on(analyzer), } } @@ -615,6 +651,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.recursive_dependent_on(analyzer), Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer), Self::Null => Ok(vec![]), + Self::Arena(_) => self.dearenaize(analyzer).recursive_dependent_on(analyzer), } } @@ -629,20 +666,11 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.has_cycle(seen, analyzer), Self::ConcreteDyn(d) => d.has_cycle(seen, analyzer), Self::Null => Ok(false), + Self::Arena(_) => self.dearenaize(analyzer).has_cycle(seen, analyzer), } } - fn update_deps(&mut self, mapping: &BTreeMap) { - match self { - Self::Reference(d) => d.update_deps(mapping), - Self::Concrete(_) => {} - Self::Expr(expr) => expr.update_deps(mapping), - Self::ConcreteDyn(d) => d.update_deps(mapping), - Self::Null => {} - } - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { match self { Self::Reference(ref mut d) => { if d.idx == node_idx { @@ -650,9 +678,10 @@ impl RangeElem for Elem { } } Self::Concrete(_) => {} - Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx), - Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx), + Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx, analyzer), + Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx, analyzer), Self::Null => {} + Self::Arena(_) => self.dearenaize(analyzer).filter_recursion(node_idx, new_idx, analyzer), } } @@ -664,6 +693,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.maximize(analyzer)?, Expr(expr) => expr.maximize(analyzer)?, Null => Elem::Null, + Arena(_) => todo!(), }; Ok(res) } @@ -676,6 +706,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.minimize(analyzer)?, Expr(expr) => expr.minimize(analyzer)?, Null => Elem::Null, + Arena(_) => todo!(), }; Ok(res) } @@ -694,13 +725,14 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_maximize(seen_ops, analyzer), Concrete(inner) => inner.simplify_maximize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_maximize(seen_ops, analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Collapsed(collapsed) => { collapsed.simplify_maximize(seen_ops, analyzer) } _ => expr.simplify_maximize(seen_ops, analyzer), }, Null => Ok(Elem::Null), + Arena(_) => todo!(), } } @@ -718,13 +750,14 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_minimize(seen_ops, analyzer), Concrete(inner) => inner.simplify_minimize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_minimize(seen_ops, analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Collapsed(collapsed) => { collapsed.simplify_minimize(seen_ops, analyzer) } _ => expr.simplify_minimize(seen_ops, analyzer), }, Null => Ok(Elem::Null), + Arena(_) => todo!(), }?; seen_ops.insert(self.clone(), res.clone()); @@ -737,7 +770,7 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { collapsed.cache_minimize(analyzer)?; *self = collapsed; @@ -746,6 +779,7 @@ impl RangeElem for Elem { _ => expr.cache_maximize(analyzer), }, Null => Ok(()), + Arena(_) => todo!(), } } @@ -755,7 +789,7 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { collapsed.cache_minimize(analyzer)?; *self = collapsed; @@ -764,6 +798,7 @@ impl RangeElem for Elem { _ => expr.cache_minimize(analyzer), }, Null => Ok(()), + Arena(_) => todo!(), } } fn uncache(&mut self) { @@ -774,6 +809,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), Null => {} + Arena(_) => todo!(), } } @@ -790,6 +826,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), Expr(expr) => expr.contains_op_set(max, op_set, analyzer), Null => Ok(false), + Arena(_) => todo!(), } } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index a72af98a..41f208f8 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -17,7 +17,7 @@ pub trait RangeElem { analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Returns whether `cache_flatten` has been called - fn is_flatten_cached(&self) -> bool; + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool; /// Flattens an element and caches the result fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value @@ -43,11 +43,11 @@ pub trait RangeElem { analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Checks if two range elements are equal - fn range_eq(&self, other: &Self) -> bool; + fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; /// Tries to compare the ordering of two range elements - fn range_ord(&self, other: &Self) -> Option; + fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option; /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). - fn range_op(lhs: Elem, rhs: Elem, op: RangeOp) -> Elem + fn range_op(lhs: Elem, rhs: Elem, op: RangeOp, analyzer: &impl GraphBackend) -> Elem where Self: Sized, { @@ -55,7 +55,7 @@ pub trait RangeElem { } /// Traverses the range expression and finds all nodes that are dynamically pointed to /// and returns it in a vector. - fn dependent_on(&self) -> Vec; + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec; fn recursive_dependent_on( &self, @@ -67,14 +67,6 @@ pub trait RangeElem { seen: &mut Vec, analyzer: &impl GraphBackend, ) -> Result; - /// Traverses the range expression and updates stale pointers from older versions - /// of a variable to a newer version. - /// - /// e.g.: `uint256 z = x + 100`, followed by `require(x < 100)`. Initially, - /// without the `require` statement, `z`'s max is `2**256 - 1`, but with - /// the introduction of the `require` statement, we do a little backtracking - /// and can update `z`'s max to be `200`. - fn update_deps(&mut self, mapping: &BTreeMap); /// Attempts to replace range elements that form a cyclic dependency by replacing /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now /// but in theory it can make sense. @@ -82,7 +74,7 @@ pub trait RangeElem { /// e.g.: take the basic expression `x + y`, in normal checked solidity math /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a /// cyclic dependency. - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx); + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); fn contains_op_set( &self, @@ -90,4 +82,7 @@ pub trait RangeElem { op_set: &[RangeOp], analyzer: &impl GraphBackend, ) -> Result; + + fn arenaize(&mut self, analyzer: &mut impl GraphBackend); + fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index d52cddf8..13cd89cd 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -94,7 +94,19 @@ impl RangeExpr { impl RangeElem for RangeExpr { type GraphError = GraphError; - fn range_eq(&self, _other: &Self) -> bool { + + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + self.lhs.arenaize(analyzer); + self.rhs.arenaize(analyzer); + } + + fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { + let lhs = self.lhs.dearenaize(analyzer); + let rhs = self.rhs.dearenaize(analyzer); + Elem::Expr(RangeExpr::new(lhs, self.op, rhs)) + } + + fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { false } @@ -116,17 +128,17 @@ impl RangeElem for RangeExpr { ))) } - fn is_flatten_cached(&self) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn range_ord(&self, _other: &Self) -> Option { + fn range_ord(&self, _other: &Self, analyzer: &impl GraphBackend) -> Option { todo!() } - fn dependent_on(&self) -> Vec { - let mut deps = self.lhs.dependent_on(); - deps.extend(self.rhs.dependent_on()); + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + let mut deps = self.lhs.dependent_on(analyzer); + deps.extend(self.rhs.dependent_on(analyzer)); deps } @@ -149,14 +161,9 @@ impl RangeElem for RangeExpr { Ok(lhs_has_cycle || rhs_has_cycle) } - fn update_deps(&mut self, mapping: &BTreeMap) { - self.lhs.update_deps(mapping); - self.rhs.update_deps(mapping); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.lhs.filter_recursion(node_idx, new_idx); - self.rhs.filter_recursion(node_idx, new_idx); + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + self.lhs.filter_recursion(node_idx, new_idx, analyzer); + self.rhs.filter_recursion(node_idx, new_idx, analyzer); } fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { @@ -189,7 +196,7 @@ impl RangeElem for RangeExpr { let l = self.lhs.simplify_maximize(seen_ops, analyzer)?; let r = self.rhs.simplify_maximize(seen_ops, analyzer)?; - let collapsed = collapse(l, self.op, r); + let collapsed = collapse(l, self.op, r, analyzer); match collapsed { MaybeCollapsed::Concretes(l, r) => { RangeExpr::new(l, self.op, r).exec_op(true, analyzer) @@ -199,7 +206,7 @@ impl RangeElem for RangeExpr { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) match RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Concretes(l, r) => { RangeExpr::new(l, expr.op, r).exec_op(true, analyzer) } @@ -223,7 +230,7 @@ impl RangeElem for RangeExpr { let l = self.lhs.simplify_minimize(seen_ops, analyzer)?; let r = self.rhs.simplify_minimize(seen_ops, analyzer)?; - let collapsed = collapse(l, self.op, r); + let collapsed = collapse(l, self.op, r, analyzer); match collapsed { MaybeCollapsed::Concretes(l, r) => { RangeExpr::new(l, self.op, r).exec_op(false, analyzer) @@ -233,7 +240,7 @@ impl RangeElem for RangeExpr { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) match RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)? { ref e @ Elem::Expr(ref expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone()) { + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { MaybeCollapsed::Concretes(l, r) => { RangeExpr::new(l, expr.op, r).exec_op(false, analyzer) } @@ -308,7 +315,7 @@ pub enum MaybeCollapsed { Not(Elem, Elem), } -pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeCollapsed { +pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &impl GraphBackend) -> MaybeCollapsed { let zero = Elem::from(Concrete::from(U256::zero())); let one = Elem::from(Concrete::from(U256::one())); match (l.clone(), r.clone()) { @@ -321,16 +328,16 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla let y = expr.rhs; let z = d; - let x_ord_z = x.range_ord(&z); + let x_ord_z = x.range_ord(&z, analyzer); let x_eq_z = matches!(x_ord_z, Some(std::cmp::Ordering::Equal)); - let y_ord_z = y.range_ord(&z); + let y_ord_z = y.range_ord(&z, analyzer); let y_eq_z = matches!(y_ord_z, Some(std::cmp::Ordering::Equal)); - let y_eq_zero = matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Equal) | None); - let x_eq_zero = matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Equal) | None); - let y_eq_one = matches!(y.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); - let x_eq_one = matches!(x.range_ord(&one), Some(std::cmp::Ordering::Equal) | None); + let y_eq_zero = matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | None); + let x_eq_zero = matches!(x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | None); + let y_eq_one = matches!(y.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal) | None); + let x_eq_one = matches!(x.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal) | None); match (expr.op, op) { (RangeOp::Sub(_), RangeOp::Eq) | (RangeOp::Div(_), RangeOp::Eq) => { if x_eq_z && !y_eq_zero { @@ -371,10 +378,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla // min{x - y, z} // if x <= z, then x - y will be the minimum if y >= 0 if matches!( - x.range_ord(&z), + x.range_ord(&z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less) ) && matches!( - y.range_ord(&zero), + y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) { MaybeCollapsed::Collapsed(l) @@ -387,16 +394,16 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla // if x >= z, then x + y will be the maximum if y >= 0 // or if y >= z, then x + y will be the maximum if x >= 0 if (matches!( - x.range_ord(&z), + x.range_ord(&z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) && matches!( - y.range_ord(&zero), + y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) )) || (matches!( - y.range_ord(&z), + y.range_ord(&z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) && matches!( - x.range_ord(&zero), + x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) )) { MaybeCollapsed::Collapsed(l) @@ -407,11 +414,11 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla (RangeOp::Eq, RangeOp::Eq) => { // ((x == y) == z) // can skip if x and z eq - if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z) { + if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z, analyzer) { MaybeCollapsed::Collapsed(l) - } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z) { + } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z, analyzer) { MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(true))) { + } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { MaybeCollapsed::Collapsed(l) } else { MaybeCollapsed::Not(l, r) @@ -437,7 +444,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { // ((x + y) - z) => k - y || x + k if l_op == r_op { - match y.range_ord(&z) { + match y.range_ord(&z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { // y and z are concrete && y >= z ==> x + (y - z) let op_fn = if l_op { @@ -476,7 +483,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla None => { // x and z are concrete, if x >= z, just do (x - z) + y // else do (y - (z - x)) - match x.range_ord(&z) { + match x.range_ord(&z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { let op_fn = if l_op { @@ -524,7 +531,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { // ((x - y) + z) => k - y || x + k if l_op == r_op { - match y.range_ord(&z) { + match y.range_ord(&z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { // y and z are concrete && z <= y ==> x - (y - z) let op_fn = if l_op { @@ -651,7 +658,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) if let Some(new) = div_op(&z, &x) { - let new_op = if matches!(x.range_ord(&zero), Some(std::cmp::Ordering::Less)) + let new_op = if matches!(x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() @@ -660,7 +667,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla }; MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, new_op, new))) } else if let Some(new) = div_op(&z, &y) { - let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() @@ -688,7 +695,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla // .. // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) if let Some(new) = mul_op(&z, &y) { - let new_op = if matches!(y.range_ord(&zero), Some(std::cmp::Ordering::Less)) + let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() @@ -711,9 +718,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla } (_, RangeOp::Eq) => { // (x _ y) == z ==> (x _ y if z == true) - if z.range_eq(&Elem::from(Concrete::from(true))) { + if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(false))) { + } else if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { // (!x && !y) match ( x.inverse_if_boolean(), @@ -731,10 +738,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla } (_, RangeOp::Neq) => { // (x _ y) != z ==> (x _ y if z != false) - if z.range_eq(&Elem::from(Concrete::from(false))) { + if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { // != false is == true MaybeCollapsed::Collapsed(l) - } else if z.range_eq(&Elem::from(Concrete::from(true))) { + } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { // != true is == false, to make it == true, inverse everything match ( x.inverse_if_boolean(), @@ -753,21 +760,21 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem) -> MaybeColla _ => MaybeCollapsed::Not(l, r), } } - (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone()) { + (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone(), analyzer) { collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(_, _) => unreachable!(), }, (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => match op { RangeOp::Sub(_) | RangeOp::Add(_) => { - if matches!(c.range_ord(&zero), Some(std::cmp::Ordering::Equal)) { + if matches!(c.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal)) { MaybeCollapsed::Collapsed(le) } else { MaybeCollapsed::Not(l, r) } } RangeOp::Mul(_) | RangeOp::Div(_) => { - if matches!(c.range_ord(&one), Some(std::cmp::Ordering::Equal)) { + if matches!(c.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal)) { MaybeCollapsed::Collapsed(le) } else { MaybeCollapsed::Not(l, r) diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 9146d993..c0eeb750 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -150,7 +150,7 @@ impl RangeDyn { }) .collect::>(); evaled.sort_by(|a, b| { - a.range_ord(b).unwrap_or(std::cmp::Ordering::Less) + a.range_ord(b, analyzer).unwrap_or(std::cmp::Ordering::Less) }); evaled.iter().take(1).next()?.concrete() @@ -160,12 +160,43 @@ impl RangeDyn { impl RangeElem for RangeDyn { type GraphError = GraphError; - fn range_eq(&self, other: &Self) -> bool { - matches!(self.range_ord(other), Some(std::cmp::Ordering::Equal)) + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + self.len.arenaize(analyzer); + self.val = self.val.iter_mut().map(|(k, (v, op))| { + let mut new_k = k.clone(); + let mut new_v = v.clone(); + new_k.arenaize(analyzer); + new_v.arenaize(analyzer); + (new_k, (new_v, *op)) + }).collect(); } - fn range_ord(&self, other: &Self) -> Option { - match self.len.range_ord(&other.len) { + fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { + Elem::ConcreteDyn(Self::new_w_op_nums( + self.len.dearenaize(analyzer), + { + let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); + for (idx, val) in self.val.clone().into_iter() { + // We dont maximize the key so that any subsequent + // `get_index` can find potential values + let dearenaized = val.0.dearenaize(analyzer); + map.insert( + idx.dearenaize(analyzer), + (dearenaized, val.1), + ); + } + map + }, + self.loc, + )) + } + + fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + matches!(self.range_ord(other, analyzer), Some(std::cmp::Ordering::Equal)) + } + + fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { + match self.len.range_ord(&other.len, analyzer) { Some(std::cmp::Ordering::Equal) => { let mut eq = 0; let mut self_lt = 0; @@ -173,9 +204,9 @@ impl RangeElem for RangeDyn { self.val.iter().zip(other.val.iter()).for_each( |((self_key, self_val), (other_key, other_val))| { if let Some(std::cmp::Ordering::Equal) = - self_key.clone().range_ord(other_key) + self_key.clone().range_ord(other_key, analyzer) { - match self_val.0.clone().range_ord(&other_val.0) { + match self_val.0.clone().range_ord(&other_val.0, analyzer) { Some(std::cmp::Ordering::Equal) => eq += 1, Some(std::cmp::Ordering::Less) => self_lt += 1, Some(std::cmp::Ordering::Greater) => self_gt += 1, @@ -199,12 +230,12 @@ impl RangeElem for RangeDyn { } } - fn dependent_on(&self) -> Vec { - let mut deps: Vec = self.len.dependent_on(); + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + let mut deps: Vec = self.len.dependent_on(analyzer); deps.extend( self.val .iter() - .flat_map(|(_, val)| val.0.dependent_on()) + .flat_map(|(_, val)| val.0.dependent_on(analyzer)) .collect::>(), ); deps @@ -308,26 +339,19 @@ impl RangeElem for RangeDyn { Ok(()) } - fn is_flatten_cached(&self) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn update_deps(&mut self, mapping: &BTreeMap) { - self.len.update_deps(mapping); - self.val - .iter_mut() - .for_each(|(_, val)| val.0.update_deps(mapping)); - } - - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx) { - self.len.filter_recursion(node_idx, new_idx); + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + self.len.filter_recursion(node_idx, new_idx, analyzer); self.val = self .val .clone() .into_iter() .map(|(mut k, mut v)| { - k.filter_recursion(node_idx, new_idx); - v.0.filter_recursion(node_idx, new_idx); + k.filter_recursion(node_idx, new_idx, analyzer); + v.0.filter_recursion(node_idx, new_idx, analyzer); (k, v) }) .collect(); diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 72a89a4e..e9210477 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -43,11 +43,17 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn range_eq(&self, _other: &Self) -> bool { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) {} + + fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { + Elem::Reference(self.clone()) + } + + fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { false } - fn range_ord(&self, other: &Self) -> Option { + fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { if self.idx == other.idx { Some(std::cmp::Ordering::Equal) } else { @@ -55,7 +61,7 @@ impl RangeElem for Reference { } } - fn dependent_on(&self) -> Vec { + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { vec![self.idx.into()] } @@ -89,12 +95,6 @@ impl RangeElem for Reference { } } - fn update_deps(&mut self, mapping: &BTreeMap) { - if let Some(new) = mapping.get(&ContextVarNode::from(self.idx)) { - self.idx = new.0.into(); - } - } - fn flatten( &self, maximize: bool, @@ -126,7 +126,7 @@ impl RangeElem for Reference { } } - fn is_flatten_cached(&self) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } @@ -148,7 +148,7 @@ impl RangeElem for Reference { Ok(()) } - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx) {} + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, analyzer: &impl GraphBackend) {} fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index ae6ad591..5bacf429 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -74,7 +74,7 @@ impl ExecOp for RangeExpr { // we can drop the cast if the max of the dynamic lhs is less than the cast let concretized_lhs = self.lhs.maximize(analyzer)?; if matches!( - concretized_lhs.range_ord(&self.rhs), + concretized_lhs.range_ord(&self.rhs, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ) { return Ok(*self.lhs.clone()); @@ -124,7 +124,7 @@ impl ExecOp for RangeExpr { ) { if acc.is_none() || matches!( - acc.clone().unwrap().range_ord(val), + acc.clone().unwrap().range_ord(val, analyzer), Some(std::cmp::Ordering::Greater) ) { @@ -155,7 +155,7 @@ impl ExecOp for RangeExpr { ) { if acc.is_none() || matches!( - acc.clone().unwrap().range_ord(val), + acc.clone().unwrap().range_ord(val, analyzer), Some(std::cmp::Ordering::Less) ) { @@ -264,8 +264,8 @@ impl ExecOp for RangeExpr { let rhs_max_neg = rhs_max.pre_evaled_is_negative(); let consts = ( - matches!(lhs_min.range_ord(&lhs_max), Some(std::cmp::Ordering::Equal)), - matches!(rhs_min.range_ord(&rhs_max), Some(std::cmp::Ordering::Equal)), + matches!(lhs_min.range_ord(&lhs_max, analyzer), Some(std::cmp::Ordering::Equal)), + matches!(rhs_min.range_ord(&rhs_max, analyzer), Some(std::cmp::Ordering::Equal)), ); fn fallback( @@ -326,7 +326,7 @@ impl ExecOp for RangeExpr { ) { if acc.is_none() || matches!( - acc.clone().unwrap().range_ord(val), + acc.clone().unwrap().range_ord(val, analyzer), Some(std::cmp::Ordering::Greater) ) { @@ -374,7 +374,7 @@ impl ExecOp for RangeExpr { ) { if acc.is_none() || matches!( - acc.clone().unwrap().range_ord(val), + acc.clone().unwrap().range_ord(val, analyzer), Some(std::cmp::Ordering::Less) ) { @@ -450,7 +450,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -484,12 +484,12 @@ impl ExecOp for RangeExpr { let one = Elem::from(Concrete::from(U256::from(1))); let zero = Elem::from(Concrete::from(U256::from(0))); let rhs_min_contains_zero = matches!( - rhs_min.range_ord(&zero), + rhs_min.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let rhs_max_contains_zero = matches!( - rhs_max.range_ord(&zero), + rhs_max.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -505,7 +505,7 @@ impl ExecOp for RangeExpr { // zero min max uint256.max // lhs: | - - |----------------------------| - - | // rhs: | - - |--| - - - - - - - - - - - - - - - | - match lhs_max.range_ord(&rhs_min) { + match lhs_max.range_ord(&rhs_min, analyzer) { Some(std::cmp::Ordering::Less) => { // We are going to overflow, zero not possible } @@ -520,7 +520,7 @@ impl ExecOp for RangeExpr { } Some(std::cmp::Ordering::Greater) => { // No guarantees on overflow, check lhs_min - match lhs_min.range_ord(&rhs_min) { + match lhs_min.range_ord(&rhs_min, analyzer) { Some(std::cmp::Ordering::Less) => { // fully contained, add zero and max candidates.push(Some(zero.clone())); @@ -541,7 +541,7 @@ impl ExecOp for RangeExpr { // lhs: | - - |----------------------------| - - | // rhs: | - |----? - - - - - - - - - - - - - - - | // figure out where rhs max is - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, analyzer) { Some(std::cmp::Ordering::Less) => { // zero min // lhs: | - - |---? @@ -582,7 +582,7 @@ impl ExecOp for RangeExpr { lhs_max.range_wrapping_sub(&rhs_max), ]); let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -619,7 +619,7 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (rhs_min.range_ord(&one), rhs_max.range_ord(&one)) + ) = (rhs_min.range_ord(&one, analyzer), rhs_max.range_ord(&one, analyzer)) { candidates.push(Some(lhs_max.clone())); candidates.push(Some(lhs_min.clone())); @@ -629,7 +629,7 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (lhs_min.range_ord(&one), lhs_max.range_ord(&one)) + ) = (lhs_min.range_ord(&one, analyzer), lhs_max.range_ord(&one, analyzer)) { candidates.push(Some(rhs_max.clone())); candidates.push(Some(rhs_min.clone())); @@ -640,8 +640,8 @@ impl ExecOp for RangeExpr { Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), ) = ( - rhs_min.range_ord(&negative_one), - rhs_max.range_ord(&negative_one), + rhs_min.range_ord(&negative_one, analyzer), + rhs_max.range_ord(&negative_one, analyzer), ) { candidates.push(lhs_max.range_mul(&negative_one)); candidates.push(lhs_min.range_mul(&negative_one)); @@ -652,8 +652,8 @@ impl ExecOp for RangeExpr { Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), ) = ( - lhs_min.range_ord(&negative_one), - lhs_max.range_ord(&negative_one), + lhs_min.range_ord(&negative_one, analyzer), + lhs_max.range_ord(&negative_one, analyzer), ) { candidates.push(rhs_max.range_mul(&negative_one)); candidates.push(rhs_min.range_mul(&negative_one)); @@ -663,7 +663,7 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (rhs_min.range_ord(&zero), rhs_max.range_ord(&zero)) + ) = (rhs_min.range_ord(&zero, analyzer), rhs_max.range_ord(&zero, analyzer)) { candidates.push(Some(zero.clone())); } @@ -671,7 +671,7 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (lhs_min.range_ord(&zero), lhs_max.range_ord(&zero)) + ) = (lhs_min.range_ord(&zero, analyzer), lhs_max.range_ord(&zero, analyzer)) { candidates.push(Some(zero.clone())); } @@ -683,7 +683,7 @@ impl ExecOp for RangeExpr { ]); let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -712,7 +712,7 @@ impl ExecOp for RangeExpr { // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { + match min_expr.range_ord(&max_expr, analyzer) { Some(std::cmp::Ordering::Less) => max_expr, Some(std::cmp::Ordering::Greater) => min_expr, _ => max_expr, @@ -767,7 +767,7 @@ impl ExecOp for RangeExpr { // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr) { + match min_expr.range_ord(&max_expr, analyzer) { Some(std::cmp::Ordering::Less) => min_expr, Some(std::cmp::Ordering::Greater) => max_expr, _ => min_expr, @@ -811,12 +811,12 @@ impl ExecOp for RangeExpr { let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); let min_contains = matches!( - rhs_min.range_ord(&one), + rhs_min.range_ord(&one, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&one), + rhs_max.range_ord(&one, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -826,12 +826,12 @@ impl ExecOp for RangeExpr { } let min_contains = matches!( - rhs_min.range_ord(&negative_one), + rhs_min.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&negative_one), + rhs_max.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -841,7 +841,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -972,7 +972,7 @@ impl ExecOp for RangeExpr { lhs_max.range_min(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1029,7 +1029,7 @@ impl ExecOp for RangeExpr { lhs_max.range_max(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1124,10 +1124,10 @@ impl ExecOp for RangeExpr { } RangeOp::Eq => { // prevent trying to eval when we have dependents - if !lhs_min.dependent_on().is_empty() - || !lhs_max.dependent_on().is_empty() - || !rhs_min.dependent_on().is_empty() - || !rhs_max.dependent_on().is_empty() + if !lhs_min.dependent_on(analyzer).is_empty() + || !lhs_max.dependent_on(analyzer).is_empty() + || !rhs_min.dependent_on(analyzer).is_empty() + || !rhs_max.dependent_on(analyzer).is_empty() { return Ok(fallback(self, lhs_min, rhs_min, consts)); } @@ -1146,8 +1146,8 @@ impl ExecOp for RangeExpr { if maximize { // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min, analyzer); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max, analyzer); // if lhs max is less than the rhs min, it has to be false if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { @@ -1180,11 +1180,11 @@ impl ExecOp for RangeExpr { // check if either lhs element is *not* contained by rhs match ( // check if lhs is constant - lhs_min.range_ord(&lhs_max), + lhs_min.range_ord(&lhs_max, analyzer), // check if rhs is constant - rhs_min.range_ord(&rhs_max), + rhs_min.range_ord(&rhs_max, analyzer), // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min), + lhs_min.range_ord(&rhs_min, analyzer), ) { ( Some(std::cmp::Ordering::Equal), @@ -1205,10 +1205,10 @@ impl ExecOp for RangeExpr { } RangeOp::Neq => { // prevent trying to eval when we have dependents - if !lhs_min.dependent_on().is_empty() - || !lhs_max.dependent_on().is_empty() - || !rhs_min.dependent_on().is_empty() - || !rhs_max.dependent_on().is_empty() + if !lhs_min.dependent_on(analyzer).is_empty() + || !lhs_max.dependent_on(analyzer).is_empty() + || !rhs_min.dependent_on(analyzer).is_empty() + || !rhs_max.dependent_on(analyzer).is_empty() { return Ok(fallback(self, lhs_min, rhs_min, consts)); } @@ -1229,7 +1229,7 @@ impl ExecOp for RangeExpr { // true is the maximum is when they are both consts and equal if matches!(consts, (true, true)) { // both are consts, check if they are equal - if matches!(lhs_min.range_ord(&rhs_min), Some(std::cmp::Ordering::Equal)) { + if matches!(lhs_min.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Equal)) { return Ok(Elem::Concrete(RangeConcrete { val: Concrete::Bool(false), loc, @@ -1246,7 +1246,7 @@ impl ExecOp for RangeExpr { if matches!(consts, (true, true)) { // both are consts, check if we are forced to return true if matches!( - lhs_min.range_ord(&rhs_min), + lhs_min.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Less) ) { return Ok(Elem::Concrete(RangeConcrete { @@ -1257,8 +1257,8 @@ impl ExecOp for RangeExpr { } // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max); + let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min, analyzer); + let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max, analyzer); // if lhs max is less than the rhs min, it has to be != (true) if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { @@ -1292,7 +1292,7 @@ impl ExecOp for RangeExpr { lhs_max.range_shl(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1315,7 +1315,7 @@ impl ExecOp for RangeExpr { lhs_max.range_shr(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1338,7 +1338,7 @@ impl ExecOp for RangeExpr { lhs_max.range_and(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1361,7 +1361,7 @@ impl ExecOp for RangeExpr { lhs_max.range_or(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1380,7 +1380,7 @@ impl ExecOp for RangeExpr { assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1405,7 +1405,7 @@ impl ExecOp for RangeExpr { lhs_max.range_cast(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1429,7 +1429,7 @@ impl ExecOp for RangeExpr { lhs_max.range_exp(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1456,12 +1456,12 @@ impl ExecOp for RangeExpr { let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); let min_contains = matches!( - rhs_min.range_ord(&zero), + rhs_min.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&zero), + rhs_max.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1471,12 +1471,12 @@ impl ExecOp for RangeExpr { } let min_contains = matches!( - rhs_min.range_ord(&negative_one), + rhs_min.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&negative_one), + rhs_max.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1486,7 +1486,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1513,12 +1513,12 @@ impl ExecOp for RangeExpr { let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); let min_contains = matches!( - rhs_min.range_ord(&zero), + rhs_min.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&zero), + rhs_max.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1528,12 +1528,12 @@ impl ExecOp for RangeExpr { } let min_contains = matches!( - rhs_min.range_ord(&negative_one), + rhs_min.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&negative_one), + rhs_max.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1543,7 +1543,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1570,12 +1570,12 @@ impl ExecOp for RangeExpr { let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); let min_contains = matches!( - rhs_min.range_ord(&zero), + rhs_min.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&zero), + rhs_max.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1585,12 +1585,12 @@ impl ExecOp for RangeExpr { } let min_contains = matches!( - rhs_min.range_ord(&negative_one), + rhs_min.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - rhs_max.range_ord(&negative_one), + rhs_max.range_ord(&negative_one, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1600,7 +1600,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1621,12 +1621,12 @@ impl ExecOp for RangeExpr { let zero = Elem::from(Concrete::from(U256::from(0))); let min_contains = matches!( - lhs_min.range_ord(&zero), + lhs_min.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - lhs_max.range_ord(&zero), + lhs_max.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -1649,7 +1649,7 @@ impl ExecOp for RangeExpr { } let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); @@ -1673,7 +1673,7 @@ impl ExecOp for RangeExpr { lhs_max.range_concat(&rhs_max), ]; let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b) { + candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { Some(r) => r, _ => std::cmp::Ordering::Less, }); diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 4fa9129d..8a807e53 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -56,6 +56,7 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.def_string(analyzer), Elem::Expr(expr) => expr.def_string(analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + Elem::Arena(_) => todo!(), } } @@ -70,6 +71,7 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), + Elem::Arena(_) => todo!(), } } } @@ -181,7 +183,7 @@ impl ToRangeString for RangeExpr { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { if let MaybeCollapsed::Collapsed(collapsed) = - collapse(*self.lhs.clone(), self.op, *self.rhs.clone()) + collapse(*self.lhs.clone(), self.op, *self.rhs.clone(), analyzer) { return collapsed.to_range_string(maximize, analyzer); } diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index 623d8a38..ad84b24c 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -60,9 +60,9 @@ pub trait Range { where Self: std::marker::Sized; /// Replace a potential recursion causing node index with a new index - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); /// Replace a potential recursion causing node index with a new index - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx); + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); /// Cache the flattened range fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 8425574a..d3714630 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -60,9 +60,9 @@ impl From> for SolcRange { impl SolcRange { /// Get all ContextVarNodes that this range references - pub fn dependent_on(&self) -> Vec { - let mut deps = self.range_min().dependent_on(); - deps.extend(self.range_max().dependent_on()); + pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + let mut deps = self.range_min().dependent_on(analyzer); + deps.extend(self.range_max().dependent_on(analyzer)); deps.dedup(); deps.into_iter().map(ContextVarNode::from).collect() @@ -79,42 +79,6 @@ impl SolcRange { Ok(deps) } - /// Update a particular context variable with the latest version - pub fn update_deps( - &mut self, - node: ContextVarNode, - ctx: ContextNode, - analyzer: &impl GraphBackend, - ) { - assert!(node.latest_version(analyzer) == node); - let deps = self.dependent_on(); - let mapping: BTreeMap = deps - .into_iter() - .filter(|dep| !dep.is_const(analyzer).unwrap()) - .map(|dep| { - let latest = dep.latest_version_in_ctx(ctx, analyzer).unwrap(); - // let dep_depends_on_node = dep.range(analyzer).unwrap().unwrap().recursive_dependent_on(analyzer).unwrap(); - // let dep_depends_on_node = dep_depends_on_node.contains(&node) || dep_depends_on_node.contains(&); - if latest == node { - if let Some(prev) = latest.previous_version(analyzer) { - (dep, prev) - } else { - (dep, dep) - } - } else { - (dep, latest) - } - }) - .collect(); - - let mut min = self.range_min().into_owned(); - let mut max = self.range_max().into_owned(); - min.update_deps(&mapping); - max.update_deps(&mapping); - self.set_range_min(min); - self.set_range_max(max); - } - pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { Self { min, @@ -136,7 +100,7 @@ impl SolcRange { pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { let min = self.evaled_range_min(analyzer)?; let max = self.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max)) + Ok(min.range_eq(&max, analyzer)) } pub fn min_is_negative(&self, analyzer: &impl GraphBackend) -> Result { @@ -568,13 +532,13 @@ impl SolcRange { } let flattened_min = self.range_min().flatten(false, analyzer)?; - let simp_min = if !self.range_min().is_flatten_cached() { + let simp_min = if !self.range_min().is_flatten_cached(analyzer) { flattened_min.simplify_minimize(&mut Default::default(), analyzer)? } else { flattened_min }; let flattened_max = self.range_max().flatten(true, analyzer)?; - let simp_max = if !self.range_max().is_flatten_cached() { + let simp_max = if !self.range_max().is_flatten_cached(analyzer) { flattened_max.simplify_maximize(&mut Default::default(), analyzer)? } else { flattened_max @@ -671,11 +635,11 @@ impl Range for SolcRange { fn set_range_exclusions(&mut self, new: Vec) { self.exclusions = new; } - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { - self.min.filter_recursion(self_idx, new_idx); + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + self.min.filter_recursion(self_idx, new_idx, analyzer); } - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx) { - self.max.filter_recursion(self_idx, new_idx); + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + self.max.filter_recursion(self_idx, new_idx, analyzer); } fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError> { @@ -706,7 +670,7 @@ impl RangeEval> for SolcRange { matches!( self.evaled_range_min(analyzer) .unwrap() - .range_ord(&self.evaled_range_max(analyzer).unwrap()), + .range_ord(&self.evaled_range_max(analyzer).unwrap(), analyzer), None | Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ) } @@ -715,14 +679,14 @@ impl RangeEval> for SolcRange { let min_contains = matches!( self.evaled_range_min(analyzer) .unwrap() - .range_ord(&other.evaled_range_min(analyzer).unwrap()), + .range_ord(&other.evaled_range_min(analyzer).unwrap(), analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( self.evaled_range_max(analyzer) .unwrap() - .range_ord(&other.evaled_range_max(analyzer).unwrap()), + .range_ord(&other.evaled_range_max(analyzer).unwrap(), analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); @@ -733,7 +697,7 @@ impl RangeEval> for SolcRange { let min_contains = match self .evaled_range_min(analyzer) .unwrap() - .range_ord(&other.minimize(analyzer).unwrap()) + .range_ord(&other.minimize(analyzer).unwrap(), analyzer) { Some(std::cmp::Ordering::Less) => true, Some(std::cmp::Ordering::Equal) => return true, @@ -743,7 +707,7 @@ impl RangeEval> for SolcRange { let max_contains = match self .evaled_range_max(analyzer) .unwrap() - .range_ord(&other.maximize(analyzer).unwrap()) + .range_ord(&other.maximize(analyzer).unwrap(), analyzer) { Some(std::cmp::Ordering::Greater) => true, Some(std::cmp::Ordering::Equal) => return true, @@ -757,14 +721,14 @@ impl RangeEval> for SolcRange { let lhs_min = self.evaled_range_min(analyzer).unwrap(); let rhs_max = other.evaled_range_max(analyzer).unwrap(); - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, analyzer) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max // check that the max is greater than or eq their min let lhs_max = self.evaled_range_max(analyzer).unwrap(); let rhs_min = other.evaled_range_min(analyzer).unwrap(); matches!( - lhs_max.range_ord(&rhs_min), + lhs_max.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ) } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 0ec14f29..d1dd5493 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -57,19 +57,11 @@ impl AtomOrPart { } pub fn is_part(&self) -> bool { - if let AtomOrPart::Part(_) = self { - true - } else { - false - } + matches!(self, AtomOrPart::Part(_)) } pub fn is_atom(&self) -> bool { - if let AtomOrPart::Atom(_) = self { - true - } else { - false - } + matches!(self, AtomOrPart::Atom(_)) } pub fn expect_atom(&self) -> SolverAtom { @@ -80,10 +72,10 @@ impl AtomOrPart { } } - pub fn dependent_on(&self) -> Vec { + pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { match self { - AtomOrPart::Part(e) => e.dependent_on(), - AtomOrPart::Atom(a) => a.dependent_on(), + AtomOrPart::Part(e) => e.dependent_on(analyzer), + AtomOrPart::Atom(a) => a.dependent_on(analyzer), } } } @@ -157,9 +149,9 @@ impl SolverAtom { self.ty = self.max_ty(); } - pub fn dependent_on(&self) -> Vec { - let mut deps = self.lhs.dependent_on(); - deps.extend(self.rhs.dependent_on()); + pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + let mut deps = self.lhs.dependent_on(analyzer); + deps.extend(self.rhs.dependent_on(analyzer)); deps } @@ -244,6 +236,7 @@ pub trait Atomize { impl Atomize for Elem { fn atoms_or_part(&self) -> AtomOrPart { match self { + Elem::Arena(_) => todo!(), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), Elem::Expr(expr) => { @@ -251,6 +244,8 @@ impl Atomize for Elem { match (expr.lhs.atoms_or_part(), expr.rhs.atoms_or_part()) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { match (l, r) { + (_, Elem::Arena(_)) => todo!(), + (Elem::Arena(_),_) => todo!(), (Elem::Reference(Reference { .. }), Elem::Concrete(_)) | (Elem::Concrete(_), Elem::Reference(Reference { .. })) => { let ty = OpType::new(expr.op); @@ -336,6 +331,7 @@ impl Atomize for Elem { a.update_max_ty(); Some(a) } + Arena(_) => todo!(), } } } diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 5dbe98bd..701eba66 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -98,7 +98,7 @@ impl BruteBinSearchSolver { ); } let r = range.flattened_range(analyzer)?; - atomic_idxs.extend(r.dependent_on()); + atomic_idxs.extend(r.dependent_on(analyzer)); ranges.insert(*dep, r.into_owned()); Ok(()) })?; @@ -225,7 +225,7 @@ impl BruteBinSearchSolver { let old_mid_conc = self.lmrs[i].mid.maximize(analyzer).unwrap(); if matches!( - new_mid_conc.range_ord(&old_mid_conc), + new_mid_conc.range_ord(&old_mid_conc, analyzer), Some(std::cmp::Ordering::Equal) ) { return false; @@ -254,7 +254,7 @@ impl BruteBinSearchSolver { let old_high_conc = self.lmrs[i].high.minimize(analyzer).unwrap(); if matches!( - new_high_conc.range_ord(&old_high_conc), + new_high_conc.range_ord(&old_high_conc, analyzer), Some(std::cmp::Ordering::Equal) ) { return false; @@ -298,7 +298,7 @@ impl SolcSolver for BruteBinSearchSolver { }) .collect::>(); - let mut dl_solver = DLSolver::new(atoms); + let mut dl_solver = DLSolver::new(atoms, analyzer); let mut atomic_solves: BTreeMap<_, _>; match dl_solver.solve_partial(analyzer)? { @@ -620,7 +620,7 @@ impl SolcSolver for BruteBinSearchSolver { }) .collect::>(); - let mut dl_solver = DLSolver::new(atoms); + let mut dl_solver = DLSolver::new(atoms, analyzer); let mut atomic_solves: BTreeMap<_, _>; match dl_solver.solve_partial(analyzer)? { @@ -736,7 +736,7 @@ impl SolcSolver for BruteBinSearchSolver { // check if the new range is dependent on the solved variable let is_dependent_on_solved = new_range - .dependent_on() + .dependent_on(analyzer) .iter() .any(|dep| solved_dep.idxs.contains(dep)); @@ -779,8 +779,8 @@ impl SolcSolver for BruteBinSearchSolver { if new_range.unsat(analyzer) { // figure out *where* we need to increase or decrease // work on the unreplace range for now - let min_is_dependent = !range.min.dependent_on().is_empty(); - let max_is_dependent = !range.max.dependent_on().is_empty(); + let min_is_dependent = !range.min.dependent_on(analyzer).is_empty(); + let max_is_dependent = !range.max.dependent_on(analyzer).is_empty(); match (min_is_dependent, max_is_dependent) { (true, true) => { @@ -809,10 +809,10 @@ impl SolcSolver for BruteBinSearchSolver { // panic!("here"); let min_change = new_range .evaled_range_min(analyzer)? - .range_ord(&range.evaled_range_min(analyzer)?); + .range_ord(&range.evaled_range_min(analyzer)?, analyzer); let max_change = new_range .evaled_range_max(analyzer)? - .range_ord(&range.evaled_range_max(analyzer)?); + .range_ord(&range.evaled_range_max(analyzer)?, analyzer); match (min_change, max_change) { (Some(std::cmp::Ordering::Less), Some(std::cmp::Ordering::Greater)) => { // panic!("initial range must have been unsat to start"); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index be29164f..856172d9 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -60,7 +60,7 @@ pub struct DLSolveResult { } impl DLSolver { - pub fn new(mut constraints: Vec) -> Self { + pub fn new(mut constraints: Vec, analyzer: &impl GraphBackend) -> Self { constraints.iter_mut().for_each(|c| { c.update_max_ty(); }); @@ -72,7 +72,7 @@ impl DLSolver { root_node, ..Default::default() }; - s.add_constraints(vec![]); + s.add_constraints(vec![], analyzer); s } @@ -97,10 +97,11 @@ impl DLSolver { pub fn add_constraints( &mut self, constraints: Vec, + analyzer: &impl GraphBackend, ) -> BTreeMap>> { let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -121,7 +122,7 @@ impl DLSolver { .collect(); constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -168,7 +169,7 @@ impl DLSolver { .clone() .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); !deps.iter().all(|dep| const_solves.contains_key(dep)) }) .collect(); @@ -180,7 +181,7 @@ impl DLSolver { still_unknown_constraints .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); deps.iter().all(|dep| { dep_to_solve_ty .get(dep) @@ -189,7 +190,7 @@ impl DLSolver { .all(|constraint| constraint.ty == OpType::DL) }) }) - .map(|constraint| (constraint.clone(), Self::dl_atom_normalize(constraint))) + .map(|constraint| (constraint.clone(), Self::dl_atom_normalize(constraint, analyzer))) .collect::>>>() } @@ -203,7 +204,7 @@ impl DLSolver { ) -> Result { let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -222,7 +223,7 @@ impl DLSolver { atoms.iter().any(|atom| { atom.op == RangeOp::Neq && atom.lhs == atom.rhs - && !atom.lhs.dependent_on().is_empty() + && !atom.lhs.dependent_on(analyzer).is_empty() }) }) { return Ok(SolveStatus::Unsat); @@ -261,7 +262,7 @@ impl DLSolver { .clone() .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(); + let deps = constraint.dependent_on(analyzer); !deps.iter().all(|dep| const_solves.contains_key(dep)) }) .collect(); @@ -386,8 +387,8 @@ impl DLSolver { }; let rhs_atom = constraint.rhs.expect_atom(); - let rhs_lhs_deps = rhs_atom.lhs.dependent_on(); - let rhs_rhs_deps = rhs_atom.rhs.dependent_on(); + let rhs_lhs_deps = rhs_atom.lhs.dependent_on(analyzer); + let rhs_rhs_deps = rhs_atom.rhs.dependent_on(analyzer); let ((dyn_elem, dep), const_elem) = match (!rhs_lhs_deps.is_empty(), !rhs_rhs_deps.is_empty()) { (true, true) => { @@ -507,7 +508,7 @@ impl DLSolver { /// Normalizes a DL atom into x <= y - k, where x and y are variables and k is a constant. /// Needed for running negative cycle check. Additionally, if we have an `OR`, we - pub fn dl_atom_normalize(constraint: SolverAtom) -> Vec> { + pub fn dl_atom_normalize(constraint: SolverAtom, analyzer: &impl GraphBackend,) -> Vec> { // println!("normalizing: {}", constraint.into_expr_elem()); let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); let false_part = AtomOrPart::Part(Elem::from(Concrete::from(false))); @@ -527,11 +528,11 @@ impl DLSolver { } (true, false) => { // lhs is just a boolean, drop it - return Self::dl_atom_normalize(constraint.rhs.as_solver_atom()); + return Self::dl_atom_normalize(constraint.rhs.as_solver_atom(), analyzer); } (false, true) => { // rhs is just a boolean, drop it - return Self::dl_atom_normalize(constraint.lhs.as_solver_atom()); + return Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); } _ => {} } @@ -548,7 +549,7 @@ impl DLSolver { op: RangeOp::Sub(true), rhs: Box::new(zero_part.clone()), })), - }); + }, analyzer); assert!(res.len() == 1); res[0].extend( @@ -562,7 +563,7 @@ impl DLSolver { op: RangeOp::Sub(true), rhs: Box::new(zero_part.clone()), })), - }) + }, analyzer) .remove(0), ); res @@ -579,7 +580,7 @@ impl DLSolver { op: RangeOp::Sub(true), rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::from(1))))), })), - }); + }, analyzer); assert!(res.len() == 1); @@ -596,14 +597,14 @@ impl DLSolver { U256::from(1), )))), })), - }) + }, analyzer) .remove(0), ); res } RangeOp::Lt => { - let lhs_symb = !constraint.lhs.dependent_on().is_empty(); - let rhs_symb = !constraint.rhs.dependent_on().is_empty(); + let lhs_symb = !constraint.lhs.dependent_on(analyzer).is_empty(); + let rhs_symb = !constraint.rhs.dependent_on(analyzer).is_empty(); match (lhs_symb, rhs_symb) { (true, true) => { let new_lhs = AtomOrPart::Atom( @@ -621,7 +622,7 @@ impl DLSolver { rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( I256::from(-1), )))), - }) + }, analyzer) } (true, false) => { let new_lhs = AtomOrPart::Atom( @@ -638,7 +639,7 @@ impl DLSolver { lhs: Box::new(new_lhs), op: RangeOp::Lte, rhs: constraint.rhs, - }) + }, analyzer) } (false, true) => { let new_lhs = AtomOrPart::Atom( @@ -652,7 +653,7 @@ impl DLSolver { lhs: Box::new(new_lhs), op: RangeOp::Lte, rhs: constraint.lhs, - }) + }, analyzer) } _ => panic!("here"), } @@ -661,8 +662,8 @@ impl DLSolver { if constraint.lhs.is_atom() { // some form of (x + k <= y) let lhs_atom = constraint.lhs.expect_atom(); - let atom_lhs_is_symb = !lhs_atom.lhs.dependent_on().is_empty(); - let atom_rhs_is_symb = !lhs_atom.rhs.dependent_on().is_empty(); + let atom_lhs_is_symb = !lhs_atom.lhs.dependent_on(analyzer).is_empty(); + let atom_rhs_is_symb = !lhs_atom.rhs.dependent_on(analyzer).is_empty(); match lhs_atom.op { RangeOp::Sub(_) => { @@ -681,7 +682,7 @@ impl DLSolver { op: RangeOp::Sub(true), rhs: Box::new(*lhs_atom.lhs), })), - }) + }, analyzer) } _ => { // (x - k <= y) @@ -696,7 +697,7 @@ impl DLSolver { op: RangeOp::Add(true), rhs: Box::new(*lhs_atom.rhs), })), - }) + }, analyzer) } } } @@ -713,7 +714,7 @@ impl DLSolver { op: RangeOp::Sub(true), rhs: Box::new(*lhs_atom.rhs), })), - }) + }, analyzer) } RangeOp::And => { let mut res = Self::dl_atom_normalize(SolverAtom { @@ -721,14 +722,14 @@ impl DLSolver { lhs: Box::new(*lhs_atom.lhs), op: constraint.op, rhs: constraint.rhs.clone(), - }); + }, analyzer); let mut rhs = Self::dl_atom_normalize(SolverAtom { ty: constraint.ty, lhs: Box::new(*lhs_atom.rhs), op: constraint.op, rhs: constraint.rhs.clone(), - }); + }, analyzer); match (res.len() > 1, rhs.len() > 1) { (true, true) => { res.extend(rhs); @@ -796,7 +797,7 @@ impl DLSolver { lhs: constraint.lhs, op: constraint.op, rhs: Box::new(new_rhs), - }) + }, analyzer) } else { vec![vec![constraint]] } @@ -806,21 +807,21 @@ impl DLSolver { lhs: constraint.rhs, op: RangeOp::Lte, rhs: constraint.lhs, - }), + }, analyzer), RangeOp::Gt => Self::dl_atom_normalize(SolverAtom { ty: OpType::DL, lhs: constraint.rhs, op: RangeOp::Lt, rhs: constraint.lhs, - }), + }, analyzer), RangeOp::Or => { - let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom()); - res.extend(Self::dl_atom_normalize(constraint.rhs.as_solver_atom())); + let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); + res.extend(Self::dl_atom_normalize(constraint.rhs.as_solver_atom(), analyzer)); res } _other => { // println!("other: {}, {}", other.to_string(), constraint.into_expr_elem()); - Self::dl_atom_normalize(constraint) + Self::dl_atom_normalize(constraint, analyzer) } } } @@ -846,7 +847,7 @@ pub fn find_negative_cycle( .maximize(analyzer) .unwrap(); let lt = matches!( - dist.range_ord(&distance[ix(j)]), + dist.range_ord(&distance[ix(j)], analyzer), Some(std::cmp::Ordering::Less) ); if lt { @@ -922,7 +923,7 @@ fn bellman_ford_initialize_relax( .maximize(analyzer) .unwrap(); let lt = matches!( - dist.range_ord(&distance[ix(j)]), + dist.range_ord(&distance[ix(j)], analyzer), Some(std::cmp::Ordering::Less) ); if lt { diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index 9a89f819..9bd42d87 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -499,7 +499,7 @@ impl VarType { if let Some(range) = self.ref_range(analyzer)? { let min = range.evaled_range_min(analyzer)?; let max = range.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max)) + Ok(min.range_eq(&max, analyzer)) } else { Ok(false) } diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 7461792a..3ec223ba 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -1,3 +1,5 @@ +use graph::elem::Elem; +use shared::RangeArena; use crate::builtin_fns; use analyzers::LocStrSpan; @@ -127,6 +129,9 @@ pub struct Analyzer { pub parse_fn: FunctionNode, /// Whether to force a panic on first error encountered pub debug_panic: bool, + + /// An arena of ranges + pub range_arena: RangeArena>, } impl Default for Analyzer { @@ -152,6 +157,7 @@ impl Default for Analyzer { max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), debug_panic: false, + range_arena: RangeArena { ranges: vec![Elem::Null] } }; a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 19076a27..4a9a0df1 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,3 +1,6 @@ +use shared::RangeArena; +use graph::nodes::Concrete; +use graph::elem::Elem; use crate::Analyzer; use graph::{ @@ -16,6 +19,7 @@ use std::{ impl GraphLike for Analyzer { type Node = Node; type Edge = Edge; + type RangeElem = Elem; fn graph_mut(&mut self) -> &mut Graph { &mut self.graph } @@ -23,6 +27,14 @@ impl GraphLike for Analyzer { fn graph(&self) -> &Graph { &self.graph } + + fn range_arena(&self) -> &RangeArena> { + &self.range_arena + } + + fn range_arena_mut(&mut self) -> &mut RangeArena> { + &mut self.range_arena + } } impl GraphBackend for Analyzer {} @@ -573,13 +585,20 @@ struct G<'a> { impl GraphLike for G<'_> { type Node = Node; type Edge = Edge; + type RangeElem = Elem; fn graph_mut(&mut self) -> &mut Graph { - panic!("Should call this") + panic!("Should not call this") } fn graph(&self) -> &Graph { self.graph } + fn range_arena(&self) -> &RangeArena> { + panic!("Should not call this") + } + fn range_arena_mut(&mut self) -> &mut RangeArena> { + panic!("Should not call this") + } } impl GraphBackend for G<'_> {} diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 761fdcf7..0d510e56 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -12,11 +12,18 @@ use std::{ pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; +pub type RangeArenaIdx = usize; + +#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct RangeArena { + pub ranges: Vec, +} /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphLike { type Node; type Edge: Ord + PartialEq + Heirarchical + Copy; + type RangeElem: PartialEq; /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph @@ -53,6 +60,23 @@ pub trait GraphLike { self.graph_mut() .add_edge(from_node.into(), to_node.into(), edge.into()); } + + fn range_arena(&self) -> &RangeArena; + fn range_arena_mut(&mut self) -> &mut RangeArena; + + fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { + self.range_arena().ranges.iter().position(|r| r == elem) + } + + fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { + if let Some(idx) = self.range_arena_idx(&elem) { + idx + } else { + let idx = self.range_arena().ranges.len(); + self.range_arena_mut().ranges.push(elem); + idx + } + } } /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index aba5dc4e..0d85c6f0 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -229,7 +229,7 @@ pub trait BinOp: AnalyzerBackend + Sized { .evaled_range_min(self) .into_expr_err(loc)? .expect("No range?") - .range_eq(&Elem::from(Concrete::from(U256::zero()))) + .range_eq(&Elem::from(Concrete::from(U256::zero())), self) { let res = ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc); let _ = self.add_if_err(res); @@ -255,7 +255,7 @@ pub trait BinOp: AnalyzerBackend + Sized { ctx, loc, RangeOp::Neq, - RangeOp::Eq, + RangeOp::Neq, (RangeOp::Eq, RangeOp::Neq), )? .is_none() @@ -338,7 +338,7 @@ pub trait BinOp: AnalyzerBackend + Sized { rhs_cvar.evaled_range_min(self).into_expr_err(loc)?, ) { if matches!( - lmax.range_ord(&rmin), + lmax.range_ord(&rmin, self), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ) { @@ -592,7 +592,7 @@ pub trait BinOp: AnalyzerBackend + Sized { .evaled_range_min(self) .into_expr_err(loc)? .expect("No range") - .range_ord(&Elem::from(Concrete::from(U256::zero()))), + .range_ord(&Elem::from(Concrete::from(U256::zero())), self), Some(std::cmp::Ordering::Less) ) { ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 18e209e0..6c438999 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -270,7 +270,7 @@ pub trait Cmp: AnalyzerBackend + Sized { let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; // invert - if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?) { + if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?, self) { let val = Elem::Expr(RangeExpr::new( lhs_range.range_min().into_owned(), RangeOp::Not, @@ -313,7 +313,7 @@ pub trait Cmp: AnalyzerBackend + Sized { let lhs_max = lhs_range.evaled_range_max(self)?; let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, self) { return Ok(true.into()); } @@ -321,7 +321,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // false let lhs_min = lhs_range.evaled_range_min(self)?; let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, self) { Some(Ordering::Greater) => { return Ok(false.into()); } @@ -336,7 +336,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // true let lhs_min = lhs_range.evaled_range_min(self)?; let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, self) { return Ok(true.into()); } @@ -344,7 +344,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // false let lhs_max = lhs_range.evaled_range_max(self)?; let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min) { + match lhs_max.range_ord(&rhs_min, self) { Some(Ordering::Less) => { return Ok(false.into()); } @@ -359,7 +359,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // true let lhs_max = lhs_range.evaled_range_max(self)?; let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min) { + match lhs_max.range_ord(&rhs_min, self) { Some(Ordering::Less) => { return Ok(true.into()); } @@ -373,7 +373,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // false let lhs_min = lhs_range.evaled_range_min(self)?; let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max) { + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, self) { return Ok(false.into()); } } @@ -382,7 +382,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // true let lhs_min = lhs_range.evaled_range_min(self)?; let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max) { + match lhs_min.range_ord(&rhs_max, self) { Some(Ordering::Greater) => { return Ok(true.into()); } @@ -396,7 +396,7 @@ pub trait Cmp: AnalyzerBackend + Sized { // false let lhs_max = lhs_range.evaled_range_max(self)?; let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min) { + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, self) { return Ok(false.into()); } } @@ -413,11 +413,11 @@ pub trait Cmp: AnalyzerBackend + Sized { Some(Ordering::Equal), ) = ( // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max), + lhs_min.range_ord(&lhs_max, self), // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min), + lhs_min.range_ord(&rhs_min, self), // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max), + rhs_min.range_ord(&rhs_max, self), ) { return Ok(true.into()); } @@ -435,11 +435,11 @@ pub trait Cmp: AnalyzerBackend + Sized { Some(Ordering::Equal), ) = ( // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max), + lhs_min.range_ord(&lhs_max, self), // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min), + lhs_min.range_ord(&rhs_min, self), // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max), + rhs_min.range_ord(&rhs_max, self), ) { return Ok(false.into()); } diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index a85feef4..c3975a76 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -901,17 +901,17 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { RangeOp::Eq => !lhs_range .evaled_range_min(self) .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap()), + .range_eq(&rhs_range.evaled_range_min(self).unwrap(), self), RangeOp::Neq => lhs_range .evaled_range_min(self) .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap()), + .range_eq(&rhs_range.evaled_range_min(self).unwrap(), self), RangeOp::Gt => { matches!( lhs_range .evaled_range_min(self) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), Some(Ordering::Equal) | Some(Ordering::Less) ) } @@ -920,7 +920,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { lhs_range .evaled_range_min(self) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), Some(Ordering::Less) ) } @@ -929,7 +929,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { lhs_range .evaled_range_min(self) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), Some(Ordering::Equal) | Some(Ordering::Greater) ) } @@ -938,7 +938,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { lhs_range .evaled_range_min(self) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap()), + .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), Some(Ordering::Greater) ) } @@ -985,7 +985,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { if let Some(Ordering::Equal) = nonconst_range .evaled_range_min(self) .into_expr_err(loc)? - .range_ord(&elem) + .range_ord(&elem, self) { // mins are equivalent, add 1 instead of adding an exclusion let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; @@ -998,7 +998,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } else if let Some(std::cmp::Ordering::Equal) = nonconst_range .evaled_range_max(self) .into_expr_err(loc)? - .range_ord(&elem) + .range_ord(&elem, self) { // maxs are equivalent, subtract 1 instead of adding an exclusion let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; @@ -1025,7 +1025,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if nonconst max is <= const, we can't make this true let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; if matches!( - max.range_ord(&elem.minimize(self).into_expr_err(loc)?), + max.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), Some(Ordering::Less) | Some(Ordering::Equal) ) { return Ok(true); @@ -1059,7 +1059,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_range .evaled_range_max(self) .into_expr_err(loc)? - .range_ord(&elem.minimize(self).into_expr_err(loc)?), + .range_ord(&elem.minimize(self).into_expr_err(loc)?, self), Some(Ordering::Less) ) { return Ok(true); @@ -1076,7 +1076,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if nonconst min is >= const, we can't make this true let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?), + min.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), Some(Ordering::Greater) | Some(Ordering::Equal) ) { return Ok(true); @@ -1103,7 +1103,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if nonconst min is > const, we can't make this true let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?), + min.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), Some(Ordering::Greater) ) { return Ok(true); @@ -1141,7 +1141,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { match lhs_range .evaled_range_min(self) .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_min(self).into_expr_err(loc)?) + .range_ord(&rhs_range.evaled_range_min(self).into_expr_err(loc)?, self) { Some(Ordering::Greater) => { // take lhs range min as its tigher @@ -1164,7 +1164,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { match lhs_range .evaled_range_max(self) .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_max(self).into_expr_err(loc)?) + .range_ord(&rhs_range.evaled_range_max(self).into_expr_err(loc)?, self) { Some(Ordering::Less) => { // take lhs range min as its tigher @@ -1212,7 +1212,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if lhs.max is <= rhs.min, we can't make this true let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; if matches!( - max.range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?), + max.range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?, self), Some(Ordering::Less) | Some(Ordering::Equal) ) { return Ok(true); @@ -1252,7 +1252,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if lhs.max is < rhs.min, we can't make this true let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; let min = rhs_elem.minimize(self).into_expr_err(loc)?; - if let Some(Ordering::Less) = max.range_ord(&min) { + if let Some(Ordering::Less) = max.range_ord(&min, self) { return Ok(true); } @@ -1285,7 +1285,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if lhs min is >= rhs.max, we can't make this true let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), + min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?, self), Some(Ordering::Greater) | Some(Ordering::Equal) ) { return Ok(true); @@ -1324,7 +1324,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if nonconst min is > const, we can't make this true let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?), + min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?, self), Some(Ordering::Greater) ) { return Ok(true); diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index f7bc1737..ab15178c 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -42,6 +42,12 @@ pub trait YulCondOp: let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; + true_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; + false_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); analyzer.add_edge( @@ -119,6 +125,12 @@ pub trait YulCondOp: let false_subctx = ContextNode::from(analyzer.add_node(Node::Context(fctx))); ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; + true_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; + false_subctx + .set_continuation_ctx(analyzer, ctx) + .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); analyzer.add_edge( From d6d23a5e28614d0953f4107bed9b313cf324093b Mon Sep 17 00:00:00 2001 From: brock elmore Date: Wed, 20 Dec 2023 11:29:26 -0800 Subject: [PATCH 52/71] init arena --- crates/graph/src/nodes/context/var/ranging.rs | 3 + crates/graph/src/range/elem/concrete.rs | 9 --- crates/graph/src/range/elem/elem_enum.rs | 64 +++++++++++-------- crates/graph/src/range/elem/elem_trait.rs | 7 -- crates/graph/src/range/elem/expr.rs | 14 ---- crates/graph/src/range/elem/map_or_array.rs | 10 --- crates/graph/src/range/elem/reference.rs | 27 -------- crates/graph/src/range/range_string.rs | 4 +- 8 files changed, 41 insertions(+), 97 deletions(-) diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index b834bdf0..41944488 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -177,6 +177,8 @@ impl ContextVarNode { } } + new_min.arenaize(analyzer); + // new_min.cache_flatten(analyzer)?; // new_min.cache_minimize(analyzer)?; @@ -220,6 +222,7 @@ impl ContextVarNode { } } + new_max.arenaize(analyzer); // new_max.cache_flatten(analyzer)?; // new_max.cache_maximize(analyzer)?; diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index a17bd821..63355b3a 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -170,15 +170,6 @@ impl RangeElem for RangeConcrete { } fn uncache(&mut self) {} - fn contains_op_set( - &self, - _: bool, - _op_set: &[RangeOp], - _analyzer: &impl GraphBackend, - ) -> Result { - Ok(false) - } - fn recursive_dependent_on( &self, _: &impl GraphBackend, diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 138c3317..3970c2da 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -539,7 +539,8 @@ impl std::fmt::Display for Elem { } _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), }, - _ => write!(f, ""), + Elem::Arena(idx) => write!(f, "arena_idx_{idx}"), + Elem::Null => write!(f, ""), } } } @@ -583,7 +584,13 @@ impl RangeElem for Elem { fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { match (self, other) { - (Self::Arena(_), Self::Arena(_)) => self.dearenaize(analyzer).range_ord(&other.dearenaize(analyzer), analyzer), + (Self::Arena(a), Self::Arena(b)) => { + if a == b { + Some(std::cmp::Ordering::Equal) + } else { + self.dearenaize(analyzer).range_ord(&other.dearenaize(analyzer), analyzer) + } + }, (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), (Self::Reference(a), Self::Reference(b)) => a.range_ord(b, analyzer), (Elem::Null, Elem::Null) => None, @@ -604,7 +611,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.flatten(maximize, analyzer), Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), Self::Null => Ok(Elem::Null), - Self::Arena(_) => todo!(), + Self::Arena(_) => self.dearenaize(analyzer).flatten(maximize, analyzer), } } @@ -615,7 +622,13 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.cache_flatten(analyzer), Self::ConcreteDyn(d) => d.cache_flatten(analyzer), Self::Null => Ok(()), - Self::Arena(_) => todo!(), + Self::Arena(idx) => { + let idx = *idx; + let mut dearenaized = self.dearenaize(analyzer); + dearenaized.cache_flatten(analyzer)?; + analyzer.range_arena_mut().ranges[idx] = dearenaized; + Ok(()) + }, } } @@ -693,7 +706,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.maximize(analyzer)?, Expr(expr) => expr.maximize(analyzer)?, Null => Elem::Null, - Arena(_) => todo!(), + Arena(_) => self.dearenaize(analyzer).maximize(analyzer)?, }; Ok(res) } @@ -706,7 +719,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.minimize(analyzer)?, Expr(expr) => expr.minimize(analyzer)?, Null => Elem::Null, - Arena(_) => todo!(), + Arena(_) => self.dearenaize(analyzer).minimize(analyzer)?, }; Ok(res) } @@ -732,7 +745,7 @@ impl RangeElem for Elem { _ => expr.simplify_maximize(seen_ops, analyzer), }, Null => Ok(Elem::Null), - Arena(_) => todo!(), + Arena(_) => self.dearenaize(analyzer).simplify_maximize(seen_ops, analyzer), } } @@ -757,7 +770,7 @@ impl RangeElem for Elem { _ => expr.simplify_minimize(seen_ops, analyzer), }, Null => Ok(Elem::Null), - Arena(_) => todo!(), + Arena(_) => self.dearenaize(analyzer).simplify_minimize(seen_ops, analyzer), }?; seen_ops.insert(self.clone(), res.clone()); @@ -779,7 +792,13 @@ impl RangeElem for Elem { _ => expr.cache_maximize(analyzer), }, Null => Ok(()), - Arena(_) => todo!(), + Arena(idx) => { + let idx = *idx; + let mut dearenaized = self.dearenaize(analyzer); + dearenaized.cache_maximize(analyzer)?; + analyzer.range_arena_mut().ranges[idx] = dearenaized; + Ok(()) + }, } } @@ -798,7 +817,13 @@ impl RangeElem for Elem { _ => expr.cache_minimize(analyzer), }, Null => Ok(()), - Arena(_) => todo!(), + Arena(idx) => { + let idx = *idx; + let mut dearenaized = self.dearenaize(analyzer); + dearenaized.cache_minimize(analyzer)?; + analyzer.range_arena_mut().ranges[idx] = dearenaized; + Ok(()) + }, } } fn uncache(&mut self) { @@ -809,24 +834,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), Null => {} - Arena(_) => todo!(), - } - } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphBackend, - ) -> Result { - use Elem::*; - match self { - Reference(dy) => dy.contains_op_set(max, op_set, analyzer), - Concrete(inner) => inner.contains_op_set(max, op_set, analyzer), - ConcreteDyn(inner) => inner.contains_op_set(max, op_set, analyzer), - Expr(expr) => expr.contains_op_set(max, op_set, analyzer), - Null => Ok(false), - Arena(_) => todo!(), + Arena(idx) => {}, } } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 41f208f8..d3285953 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -76,13 +76,6 @@ pub trait RangeElem { /// cyclic dependency. fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphBackend, - ) -> Result; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend); fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 13cd89cd..f60f635e 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -293,20 +293,6 @@ impl RangeElem for RangeExpr { fn uncache(&mut self) { self.uncache_exec(); } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphBackend, - ) -> Result { - if op_set.contains(&self.op) { - Ok(true) - } else { - self.lhs.contains_op_set(max, op_set, analyzer)?; - self.rhs.contains_op_set(max, op_set, analyzer) - } - } } pub enum MaybeCollapsed { diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index c0eeb750..60bf8dea 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -495,14 +495,4 @@ impl RangeElem for RangeDyn { // self.flattened_min = None; // self.flattened_max = None; } - - fn contains_op_set( - &self, - _max: bool, - _op_set: &[RangeOp], - _: &impl GraphBackend, - ) -> Result { - // TODO: reevaluate this - Ok(false) - } } diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index e9210477..1286d86e 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -266,31 +266,4 @@ impl RangeElem for Reference { self.flattened_min = None; self.flattened_max = None; } - - fn contains_op_set( - &self, - max: bool, - op_set: &[RangeOp], - analyzer: &impl GraphBackend, - ) -> Result { - let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; - match &cvar.ty { - VarType::User(TypeNode::Contract(_), maybe_range) - | VarType::User(TypeNode::Enum(_), maybe_range) - | VarType::User(TypeNode::Ty(_), maybe_range) - | VarType::BuiltIn(_, maybe_range) => { - if let Some(range) = maybe_range { - if max { - range.max.contains_op_set(max, op_set, analyzer) - } else { - range.min.contains_op_set(max, op_set, analyzer) - } - } else { - Ok(false) - } - } - VarType::Concrete(_concrete_node) => Ok(false), - _e => Ok(false), - } - } } diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 8a807e53..dd6b3c43 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -56,7 +56,7 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.def_string(analyzer), Elem::Expr(expr) => expr.def_string(analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - Elem::Arena(_) => todo!(), + Elem::Arena(_) => self.dearenaize(analyzer).def_string(analyzer), } } @@ -71,7 +71,7 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - Elem::Arena(_) => todo!(), + Elem::Arena(_) => self.dearenaize(analyzer).to_range_string(maximize, analyzer), } } } From 2e4eeffa1de425678499d2b261636c17d809396c Mon Sep 17 00:00:00 2001 From: brock elmore Date: Wed, 20 Dec 2023 16:54:07 -0800 Subject: [PATCH 53/71] arena works --- crates/cli/src/main.rs | 2 + crates/graph/src/nodes/context/solving.rs | 2 +- crates/graph/src/nodes/context/var/ranging.rs | 23 +- crates/graph/src/nodes/context/var/typing.rs | 5 +- crates/graph/src/range/elem/concrete.rs | 6 +- crates/graph/src/range/elem/elem_enum.rs | 83 +++++-- crates/graph/src/range/elem/elem_trait.rs | 3 +- crates/graph/src/range/elem/expr.rs | 223 ++++++++++-------- crates/graph/src/range/elem/map_or_array.rs | 34 +-- crates/graph/src/range/elem/mod.rs | 2 +- crates/graph/src/range/elem/reference.rs | 26 +- crates/graph/src/range/range_string.rs | 2 +- crates/graph/src/range/range_trait.rs | 4 +- crates/graph/src/range/solc_range.rs | 4 +- crates/pyrometer/src/analyzer.rs | 6 +- crates/pyrometer/src/graph_backend.rs | 6 +- crates/shared/src/graph_like.rs | 14 +- crates/solc-expressions/src/cmp.rs | 4 +- .../src/func_call/intrinsic_call/solidity.rs | 1 - 19 files changed, 261 insertions(+), 189 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 3dff0931..c7d42bb6 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -240,6 +240,8 @@ fn main() { println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); + // println!("Arena: {:#?}", analyzer.range_arena); + // use self.sources to fill a BTreeMap with the file_no and SourcePath.path_to_solidity_file let mut file_mapping: BTreeMap = BTreeMap::new(); let mut src_map: HashMap = HashMap::new(); diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index eb7aca86..ab0ab5a9 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -120,7 +120,7 @@ impl ContextNode { mapping.into_iter().for_each(|(_k, tmp)| { if let Some(rhs) = tmp.rhs { let lhs = if let Some(ver) = contains.keys().find(|other| { - other.range(g).unwrap() == tmp.lhs.range(g).unwrap() + other.ref_range(g).unwrap() == tmp.lhs.ref_range(g).unwrap() && tmp.lhs.display_name(g).unwrap() == other.display_name(g).unwrap() }) { *contains.get(ver).unwrap() diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 41944488..c545162f 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -223,9 +223,6 @@ impl ContextVarNode { } new_max.arenaize(analyzer); - // new_max.cache_flatten(analyzer)?; - // new_max.cache_maximize(analyzer)?; - tracing::trace!( "setting range maximum: {:?}, {}, current: {}, new: {}", @@ -258,7 +255,7 @@ impl ContextVarNode { pub fn set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - new_exclusions: Vec>, + mut new_exclusions: Vec>, ) -> Result<(), GraphError> { tracing::trace!( "setting range exclusions for {}", @@ -270,6 +267,11 @@ impl ContextVarNode { } else { None }; + + new_exclusions.iter_mut().for_each(|excl| { + excl.arenaize(analyzer); + }); + self.underlying_mut(analyzer)? .set_range_exclusions(new_exclusions, fallback)?; Ok(()) @@ -287,8 +289,7 @@ impl ContextVarNode { } } - new_min.cache_flatten(analyzer)?; - new_min.cache_minimize(analyzer)?; + new_min.arenaize(analyzer); if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); @@ -319,8 +320,7 @@ impl ContextVarNode { } } - new_max.cache_flatten(analyzer)?; - new_max.cache_maximize(analyzer)?; + new_max.arenaize(analyzer); if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); @@ -342,7 +342,7 @@ impl ContextVarNode { pub fn try_set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - new_exclusions: Vec>, + mut new_exclusions: Vec>, ) -> Result { tracing::trace!( "setting range exclusions for: {}", @@ -354,6 +354,11 @@ impl ContextVarNode { } else { None }; + + new_exclusions.iter_mut().for_each(|excl| { + excl.arenaize(analyzer); + }); + Ok(self .underlying_mut(analyzer)? .try_set_range_exclusions(new_exclusions, fallback)) diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 686c115e..f7d004c8 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,7 +1,8 @@ + use crate::{ elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, - range::RangeEval, + range::{elem::RangeElem, RangeEval}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; @@ -370,7 +371,9 @@ impl ContextVarNode { } if let (Some(mut r), Some(r2)) = (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) { r.min = r.min.cast(r2.min); + r.min.arenaize(analyzer); r.max = r.max.cast(r2.max); + r.max.arenaize(analyzer); self.set_range(analyzer, r)?; } } diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 63355b3a..356a3b8d 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -38,10 +38,6 @@ impl RangeElem for RangeConcrete { let _ = analyzer.range_arena_idx_or_upsert(Elem::Concrete(self.clone())); } - fn dearenaize(&self, _analyzer: &impl GraphBackend) -> Elem { - Elem::Concrete(self.clone()) - } - fn has_cycle( &self, _seen: &mut Vec, @@ -137,7 +133,7 @@ impl RangeElem for RangeConcrete { vec![] } - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &impl GraphBackend) {} + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &mut impl GraphBackend) {} fn maximize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 3970c2da..0c1e11c4 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,3 +1,5 @@ +use std::hash::Hasher; +use std::hash::Hash; use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{ @@ -17,7 +19,7 @@ use std::{ }; /// A core range element. -#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub enum Elem { /// A range element that is a reference to another node Reference(Reference), @@ -34,6 +36,19 @@ pub enum Elem { Null, } +impl Hash for Elem { + fn hash(&self, state: &mut H) { + match self { + Elem::Reference(r) => r.hash(state), + Elem::Concrete(c) => c.hash(state), + Elem::Expr(expr) => expr.hash(state), + Elem::ConcreteDyn(d) => d.hash(state), + Elem::Null => (-1i32).hash(state), + Elem::Arena(idx) => idx.hash(state), + } + } +} + impl Elem { pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { match self { @@ -319,7 +334,39 @@ impl From for Elem { } impl Elem { + pub fn dearenaize<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a Self { + match self { + Self::Arena(arena_idx) => &analyzer.range_arena().ranges[*arena_idx], + _ => unreachable!() + } + } + + pub fn dearenaize_mut<'a> (&self, analyzer: &'a mut impl GraphBackend) -> &'a mut Self { + match self { + Self::Arena(arena_idx) => &mut analyzer.range_arena_mut().ranges[*arena_idx], + _ => unreachable!() + } + } + pub fn arena_eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Arena(a), Self::Arena(b)) => a == b, + (Self::Concrete(a), Self::Concrete(b)) => a == b, + (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => { + a.len == b.len + && a.val.len() == b.val.len() + && a.val.iter().zip(b.val.iter()).all(|((a, op_a), (b, op_b))| a.arena_eq(b) && op_a == op_b) + }, + (Self::Reference(a), Self::Reference(b)) => a == b, + (Self::Expr(a), Self::Expr(b)) => { + a.lhs.arena_eq(&b.lhs) + && a.rhs.arena_eq(&b.rhs) + && a.op == b.op + }, + (Elem::Null, Elem::Null) => true, + _ => false, + } + } pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { let evaled = if maximize { self.maximize(analyzer).ok()? @@ -563,13 +610,6 @@ impl RangeElem for Elem { *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(self_take)); } - fn dearenaize(&self, analyzer: &impl GraphBackend) -> Self { - match self { - Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone(), - e => e.clone() - } - } - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { match (self, other) { (Self::Arena(a), Self::Arena(b)) => { @@ -588,7 +628,7 @@ impl RangeElem for Elem { if a == b { Some(std::cmp::Ordering::Equal) } else { - self.dearenaize(analyzer).range_ord(&other.dearenaize(analyzer), analyzer) + self.dearenaize(analyzer).range_ord(other.dearenaize(analyzer), analyzer) } }, (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), @@ -624,7 +664,7 @@ impl RangeElem for Elem { Self::Null => Ok(()), Self::Arena(idx) => { let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer); + let mut dearenaized = self.dearenaize(analyzer).clone(); dearenaized.cache_flatten(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) @@ -683,7 +723,7 @@ impl RangeElem for Elem { } } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { match self { Self::Reference(ref mut d) => { if d.idx == node_idx { @@ -694,7 +734,12 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx, analyzer), Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx, analyzer), Self::Null => {} - Self::Arena(_) => self.dearenaize(analyzer).filter_recursion(node_idx, new_idx, analyzer), + Self::Arena(idx) => { + let idx = *idx; + let mut dearenaized = self.dearenaize(analyzer).clone(); + dearenaized.filter_recursion(node_idx, new_idx,analyzer); + analyzer.range_arena_mut().ranges[idx] = dearenaized; + }, } } @@ -738,7 +783,7 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_maximize(seen_ops, analyzer), Concrete(inner) => inner.simplify_maximize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_maximize(seen_ops, analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { + Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { collapsed.simplify_maximize(seen_ops, analyzer) } @@ -763,7 +808,7 @@ impl RangeElem for Elem { Reference(dy) => dy.simplify_minimize(seen_ops, analyzer), Concrete(inner) => inner.simplify_minimize(seen_ops, analyzer), ConcreteDyn(inner) => inner.simplify_minimize(seen_ops, analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { + Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { collapsed.simplify_minimize(seen_ops, analyzer) } @@ -783,7 +828,7 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_maximize(analyzer), Concrete(inner) => inner.cache_maximize(analyzer), ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { + Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { collapsed.cache_minimize(analyzer)?; *self = collapsed; @@ -794,7 +839,7 @@ impl RangeElem for Elem { Null => Ok(()), Arena(idx) => { let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer); + let mut dearenaized = self.dearenaize(analyzer).clone(); dearenaized.cache_maximize(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) @@ -808,7 +853,7 @@ impl RangeElem for Elem { Reference(dy) => dy.cache_minimize(analyzer), Concrete(inner) => inner.cache_minimize(analyzer), ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { + Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { collapsed.cache_minimize(analyzer)?; *self = collapsed; @@ -819,7 +864,7 @@ impl RangeElem for Elem { Null => Ok(()), Arena(idx) => { let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer); + let mut dearenaized = self.dearenaize(analyzer).clone(); dearenaized.cache_minimize(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) @@ -834,7 +879,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), Null => {} - Arena(idx) => {}, + Arena(_idx) => {}, } } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index d3285953..2582aa9d 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -74,8 +74,7 @@ pub trait RangeElem { /// e.g.: take the basic expression `x + y`, in normal checked solidity math /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a /// cyclic dependency. - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); fn arenaize(&mut self, analyzer: &mut impl GraphBackend); - fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index f60f635e..91213ad7 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; +use std::hash::Hasher; use crate::{ nodes::{Concrete, ContextVarNode}, range::{ @@ -35,7 +37,7 @@ pub static EQ_OPS: &[RangeOp] = &[ pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; /// A range expression composed of other range [`Elem`] -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct RangeExpr { pub maximized: Option>, pub minimized: Option>, @@ -46,6 +48,14 @@ pub struct RangeExpr { pub rhs: Box>, } +impl Hash for RangeExpr { + fn hash(&self, state: &mut H) { + (*self.lhs).hash(state); + self.op.hash(state); + (*self.rhs).hash(state); + } +} + impl RangeExpr { pub fn inverse_if_boolean(&self) -> Option { if EQ_OPS.contains(&self.op) { @@ -100,12 +110,6 @@ impl RangeElem for RangeExpr { self.rhs.arenaize(analyzer); } - fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { - let lhs = self.lhs.dearenaize(analyzer); - let rhs = self.rhs.dearenaize(analyzer); - Elem::Expr(RangeExpr::new(lhs, self.op, rhs)) - } - fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { false } @@ -128,11 +132,11 @@ impl RangeElem for RangeExpr { ))) } - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn range_ord(&self, _other: &Self, analyzer: &impl GraphBackend) -> Option { + fn range_ord(&self, _other: &Self, _analyzer: &impl GraphBackend) -> Option { todo!() } @@ -161,7 +165,7 @@ impl RangeElem for RangeExpr { Ok(lhs_has_cycle || rhs_has_cycle) } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { self.lhs.filter_recursion(node_idx, new_idx, analyzer); self.rhs.filter_recursion(node_idx, new_idx, analyzer); } @@ -196,23 +200,25 @@ impl RangeElem for RangeExpr { let l = self.lhs.simplify_maximize(seen_ops, analyzer)?; let r = self.rhs.simplify_maximize(seen_ops, analyzer)?; - let collapsed = collapse(l, self.op, r, analyzer); + let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { - MaybeCollapsed::Concretes(l, r) => { + MaybeCollapsed::Concretes(..) => { RangeExpr::new(l, self.op, r).exec_op(true, analyzer) } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => { + MaybeCollapsed::Not(..) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - match RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)? { - ref e @ Elem::Expr(ref expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { - MaybeCollapsed::Concretes(l, r) => { - RangeExpr::new(l, expr.op, r).exec_op(true, analyzer) + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)?; + match res { + Elem::Expr(expr) => { + match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + MaybeCollapsed::Concretes(..) => { + return expr.exec_op(true, analyzer) } - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - _ => Ok(e.clone()), + MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), + _ => {}, } + Ok(Elem::Expr(expr)) } other => Ok(other), } @@ -230,23 +236,24 @@ impl RangeElem for RangeExpr { let l = self.lhs.simplify_minimize(seen_ops, analyzer)?; let r = self.rhs.simplify_minimize(seen_ops, analyzer)?; - let collapsed = collapse(l, self.op, r, analyzer); + let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { - MaybeCollapsed::Concretes(l, r) => { + MaybeCollapsed::Concretes(..) => { RangeExpr::new(l, self.op, r).exec_op(false, analyzer) } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(l, r) => { - // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - match RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)? { - ref e @ Elem::Expr(ref expr) => { - match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), analyzer) { - MaybeCollapsed::Concretes(l, r) => { - RangeExpr::new(l, expr.op, r).exec_op(false, analyzer) + MaybeCollapsed::Not(..) => { + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)?; + match res { + Elem::Expr(expr) => { + match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + MaybeCollapsed::Concretes(..) => { + return expr.exec_op(false, analyzer) } - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - _ => Ok(e.clone()), + MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), + _ => {}, } + Ok(Elem::Expr(expr)) } other => Ok(other), } @@ -295,29 +302,43 @@ impl RangeElem for RangeExpr { } } -pub enum MaybeCollapsed { - Concretes(Elem, Elem), +pub enum MaybeCollapsed<'a, 'b> { + Concretes(&'a Elem, &'b Elem), Collapsed(Elem), - Not(Elem, Elem), + Not(&'a Elem, &'b Elem), } -pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &impl GraphBackend) -> MaybeCollapsed { +pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b Elem, analyzer: &'c impl GraphBackend) -> MaybeCollapsed<'a, 'b> { let zero = Elem::from(Concrete::from(U256::zero())); let one = Elem::from(Concrete::from(U256::one())); - match (l.clone(), r.clone()) { - // (Elem::Null, _) => MaybeCollapsed::Collapsed(r), - // (_, Elem::Null) => MaybeCollapsed::Collapsed(l), + match (l, r) { + (Elem::Arena(_), r) => { + collapse( + l.dearenaize(analyzer), + op, + r, + analyzer + ) + } + (l, Elem::Arena(_)) => { + collapse( + l, + op, + r.dearenaize(analyzer), + analyzer + ) + } (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { // try to collapse the expression - let x = expr.lhs; - let y = expr.rhs; + let x = &*expr.lhs; + let y = &*expr.rhs; let z = d; - let x_ord_z = x.range_ord(&z, analyzer); + let x_ord_z = x.range_ord(z, analyzer); let x_eq_z = matches!(x_ord_z, Some(std::cmp::Ordering::Equal)); - let y_ord_z = y.range_ord(&z, analyzer); + let y_ord_z = y.range_ord(z, analyzer); let y_eq_z = matches!(y_ord_z, Some(std::cmp::Ordering::Equal)); let y_eq_zero = matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | None); @@ -355,8 +376,8 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // if we have an expression, it fundamentally must have a dynamic in it (Elem::Expr(expr), c @ Elem::Concrete(_)) => { // potentially collapsible - let x = expr.lhs; - let y = expr.rhs; + let x = &*expr.lhs; + let y = &*expr.rhs; let z = c; match (expr.op, op) { @@ -364,13 +385,13 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // min{x - y, z} // if x <= z, then x - y will be the minimum if y >= 0 if matches!( - x.range_ord(&z, analyzer), + x.range_ord(z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less) ) && matches!( y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) { - MaybeCollapsed::Collapsed(l) + MaybeCollapsed::Collapsed(l.clone()) } else { MaybeCollapsed::Not(l, r) } @@ -380,19 +401,19 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // if x >= z, then x + y will be the maximum if y >= 0 // or if y >= z, then x + y will be the maximum if x >= 0 if (matches!( - x.range_ord(&z, analyzer), + x.range_ord(z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) && matches!( y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) )) || (matches!( - y.range_ord(&z, analyzer), + y.range_ord(z, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) ) && matches!( x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) )) { - MaybeCollapsed::Collapsed(l) + MaybeCollapsed::Collapsed(l.clone()) } else { MaybeCollapsed::Not(l, r) } @@ -400,12 +421,12 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im (RangeOp::Eq, RangeOp::Eq) => { // ((x == y) == z) // can skip if x and z eq - if let Some(std::cmp::Ordering::Equal) = x.range_ord(&z, analyzer) { - MaybeCollapsed::Collapsed(l) - } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(&z, analyzer) { - MaybeCollapsed::Collapsed(l) + if let Some(std::cmp::Ordering::Equal) = x.range_ord(z, analyzer) { + MaybeCollapsed::Collapsed(l.clone()) + } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(z, analyzer) { + MaybeCollapsed::Collapsed(l.clone()) } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { - MaybeCollapsed::Collapsed(l) + MaybeCollapsed::Collapsed(l.clone()) } else { MaybeCollapsed::Not(l, r) } @@ -419,10 +440,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeAdd>::range_add }; - if let Some(new) = op_fn(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + if let Some(new) = op_fn(x, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = op_fn(y, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -430,7 +451,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { // ((x + y) - z) => k - y || x + k if l_op == r_op { - match y.range_ord(&z, analyzer) { + match y.range_ord(z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { // y and z are concrete && y >= z ==> x + (y - z) let op_fn = if l_op { @@ -440,8 +461,8 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&y, &z) { - let new_expr = Elem::Expr(RangeExpr::new(*x, expr.op, new)); + if let Some(new) = op_fn(y, z) { + let new_expr = Elem::Expr(RangeExpr::new(x.clone(), expr.op, new)); MaybeCollapsed::Collapsed(new_expr) } else { MaybeCollapsed::Not(l, r) @@ -456,9 +477,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&z, &y) { + if let Some(new) = op_fn(z, y) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, + x.clone(), RangeOp::Sub(l_op), new, ))) @@ -469,7 +490,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im None => { // x and z are concrete, if x >= z, just do (x - z) + y // else do (y - (z - x)) - match x.range_ord(&z, analyzer) { + match x.range_ord(z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { let op_fn = if l_op { @@ -479,9 +500,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&y, &z) { + if let Some(new) = op_fn(y, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, expr.op, new, + x.clone(), expr.op, new, ))) } else { MaybeCollapsed::Not(l, r) @@ -496,9 +517,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&z, &x) { + if let Some(new) = op_fn(z, x) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *y, + y.clone(), RangeOp::Sub(l_op), new, ))) @@ -517,7 +538,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { // ((x - y) + z) => k - y || x + k if l_op == r_op { - match y.range_ord(&z, analyzer) { + match y.range_ord(z, analyzer) { Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { // y and z are concrete && z <= y ==> x - (y - z) let op_fn = if l_op { @@ -527,9 +548,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&y, &z) { + if let Some(new) = op_fn(y, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, expr.op, new, + x.clone(), expr.op, new, ))) } else { MaybeCollapsed::Not(l, r) @@ -544,9 +565,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeSub>::range_sub }; - if let Some(new) = op_fn(&z, &y) { + if let Some(new) = op_fn(z, y) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - *x, + x.clone(), RangeOp::Add(l_op), new, ))) @@ -563,9 +584,9 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeAdd>::range_add }; - if let Some(new) = op_fn(&x, &z) { + if let Some(new) = op_fn(x, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - new, expr.op, *y, + new, expr.op, y.clone(), ))) } else { MaybeCollapsed::Not(l, r) @@ -586,10 +607,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // checked as RangeMul>::range_mul }; - if let Some(new) = op_fn(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_fn(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + if let Some(new) = op_fn(x, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = op_fn(y, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -606,10 +627,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) // .. // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) - if let Some(new) = const_op(&z, &y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = const_op(&z, &x) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + if let Some(new) = const_op(z, y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = const_op(z, x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -627,10 +648,10 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im }; // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) - if let Some(new) = op_x(&x, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) - } else if let Some(new) = op_y(&y, &z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, op, new))) + if let Some(new) = op_x(x, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = op_y(y, z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -643,7 +664,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im }; // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) - if let Some(new) = div_op(&z, &x) { + if let Some(new) = div_op(z, x) { let new_op = if matches!(x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { @@ -651,8 +672,8 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, new_op, new))) - } else if let Some(new) = div_op(&z, &y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), new_op, new))) + } else if let Some(new) = div_op(z, y) { let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { @@ -660,7 +681,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), new_op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -680,7 +701,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) // .. // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) - if let Some(new) = mul_op(&z, &y) { + if let Some(new) = mul_op(z, y) { let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) && FLIP_INEQ_OPS.contains(&op) { @@ -688,13 +709,13 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*x, new_op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), new_op, new))) } else if !FLIP_INEQ_OPS.contains(&op) { - if let Some(new) = div_op(&x, &z) { + if let Some(new) = div_op(x, z) { // y is the dynamic element // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially // but we dont know if y was negative. so we limit to just eq & neq - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(*y, op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) } else { MaybeCollapsed::Not(l, r) } @@ -705,7 +726,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im (_, RangeOp::Eq) => { // (x _ y) == z ==> (x _ y if z == true) if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { - MaybeCollapsed::Collapsed(l) + MaybeCollapsed::Collapsed(l.clone()) } else if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { // (!x && !y) match ( @@ -726,7 +747,7 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im // (x _ y) != z ==> (x _ y if z != false) if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { // != false is == true - MaybeCollapsed::Collapsed(l) + MaybeCollapsed::Collapsed(l.clone()) } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { // != true is == false, to make it == true, inverse everything match ( @@ -746,22 +767,22 @@ pub fn collapse(l: Elem, op: RangeOp, r: Elem, analyzer: &im _ => MaybeCollapsed::Not(l, r), } } - (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r.clone(), op, l.clone(), analyzer) { - collapsed @ MaybeCollapsed::Collapsed(_) => collapsed, + (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r, op, l, analyzer) { + MaybeCollapsed::Collapsed(inner) => MaybeCollapsed::Collapsed(inner.clone()), MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(_, _) => unreachable!(), }, (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => match op { RangeOp::Sub(_) | RangeOp::Add(_) => { if matches!(c.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal)) { - MaybeCollapsed::Collapsed(le) + MaybeCollapsed::Collapsed(le.clone()) } else { MaybeCollapsed::Not(l, r) } } RangeOp::Mul(_) | RangeOp::Div(_) => { if matches!(c.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal)) { - MaybeCollapsed::Collapsed(le) + MaybeCollapsed::Collapsed(le.clone()) } else { MaybeCollapsed::Not(l, r) } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 60bf8dea..20002017 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -1,3 +1,5 @@ +use std::hash::Hasher; +use std::hash::Hash; use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{Elem, MinMaxed, RangeElem, RangeOp}, @@ -11,7 +13,7 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; /// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct RangeDyn { /// Cached minimized value pub minimized: Option>, @@ -31,6 +33,14 @@ pub struct RangeDyn { pub loc: Loc, } +impl Hash for RangeDyn { + fn hash(&self, state: &mut H) { + (*self.len).hash(state); + self.val.hash(state); + self.op_num.hash(state); + } +} + impl RangeDyn { pub fn new_w_op_nums(len: Elem, val: BTreeMap, (Elem, usize)>, loc: Loc) -> Self { let op_num = val.iter().fold(0, |mut acc, (_k, (_v, i))| { @@ -171,26 +181,6 @@ impl RangeElem for RangeDyn { }).collect(); } - fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { - Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.dearenaize(analyzer), - { - let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); - for (idx, val) in self.val.clone().into_iter() { - // We dont maximize the key so that any subsequent - // `get_index` can find potential values - let dearenaized = val.0.dearenaize(analyzer); - map.insert( - idx.dearenaize(analyzer), - (dearenaized, val.1), - ); - } - map - }, - self.loc, - )) - } - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { matches!(self.range_ord(other, analyzer), Some(std::cmp::Ordering::Equal)) } @@ -343,7 +333,7 @@ impl RangeElem for RangeDyn { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { self.len.filter_recursion(node_idx, new_idx, analyzer); self.val = self .val diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index e63fc538..87683672 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -12,7 +12,7 @@ pub use expr::*; pub use map_or_array::*; pub use reference::*; -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub enum MinMaxed { Minimized(Box>), Maximized(Box>), diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 1286d86e..23cd8efa 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; +use std::hash::Hasher; use crate::{ nodes::{Concrete, ContextVarNode}, range::{ @@ -14,7 +16,7 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; /// A dynamic range element value -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] pub struct Reference { /// Index of the node that is referenced pub idx: NodeIdx, @@ -28,6 +30,12 @@ pub struct Reference { pub flattened_max: Option>>, } +impl Hash for Reference { + fn hash(&self, state: &mut H) { + self.idx.hash(state); + } +} + impl Reference { pub fn new(idx: NodeIdx) -> Self { Self { @@ -43,17 +51,13 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) {} - - fn dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { - Elem::Reference(self.clone()) - } + fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) {} - fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { + fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { false } - fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { + fn range_ord(&self, other: &Self, _analyzer: &impl GraphBackend) -> Option { if self.idx == other.idx { Some(std::cmp::Ordering::Equal) } else { @@ -61,7 +65,7 @@ impl RangeElem for Reference { } } - fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + fn dependent_on(&self, _analyzer: &impl GraphBackend) -> Vec { vec![self.idx.into()] } @@ -126,7 +130,7 @@ impl RangeElem for Reference { } } - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } @@ -148,7 +152,7 @@ impl RangeElem for Reference { Ok(()) } - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, analyzer: &impl GraphBackend) {} + fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &mut impl GraphBackend) {} fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index dd6b3c43..2daf2db3 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -183,7 +183,7 @@ impl ToRangeString for RangeExpr { fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { if let MaybeCollapsed::Collapsed(collapsed) = - collapse(*self.lhs.clone(), self.op, *self.rhs.clone(), analyzer) + collapse(&self.lhs, self.op, &self.rhs, analyzer) { return collapsed.to_range_string(maximize, analyzer); } diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index ad84b24c..fe7dd8da 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -60,9 +60,9 @@ pub trait Range { where Self: std::marker::Sized; /// Replace a potential recursion causing node index with a new index - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); /// Replace a potential recursion causing node index with a new index - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend); + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); /// Cache the flattened range fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index d3714630..927a1ee5 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -635,10 +635,10 @@ impl Range for SolcRange { fn set_range_exclusions(&mut self, new: Vec) { self.exclusions = new; } - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { self.min.filter_recursion(self_idx, new_idx, analyzer); } - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &impl GraphBackend) { + fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { self.max.filter_recursion(self_idx, new_idx, analyzer); } diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 3ec223ba..36cebac6 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -157,7 +157,11 @@ impl Default for Analyzer { max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), debug_panic: false, - range_arena: RangeArena { ranges: vec![Elem::Null] } + range_arena: RangeArena { ranges: vec![Elem::Null], map: { + let mut map: HashMap, usize> = Default::default(); + map.insert(Elem::Null, 0); + map + } } }; a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 4a9a0df1..cd3d554b 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -195,7 +195,7 @@ impl GraphDot for Analyzer { // } else { // handled_nodes.lock().unwrap().insert(*child); // } - mermaid_node(g, &indent, *child, true, Some(&curr_cluster_name)) + mermaid_node(self, &indent, *child, true, Some(&curr_cluster_name)) }) .collect::>() .join("\n") @@ -213,7 +213,7 @@ impl GraphDot for Analyzer { handled_nodes.lock().unwrap().insert(*child); } Some(mermaid_node( - g, + self, &indent, *child, true, @@ -266,7 +266,7 @@ impl GraphDot for Analyzer { { handled_nodes.lock().unwrap().insert(node); } - mermaid_node(g, &indent, node, true, Some(&curr_cluster_name)) + mermaid_node(self, &indent, node, true, Some(&curr_cluster_name)) } }; diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 0d510e56..ddd4579a 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,3 +1,5 @@ +use std::hash::Hash; +use std::collections::HashMap; use crate::AnalyzerLike; use crate::Heirarchical; @@ -14,16 +16,17 @@ pub type NodeIdx = NodeIndex; pub type EdgeIdx = EdgeIndex; pub type RangeArenaIdx = usize; -#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct RangeArena { +#[derive(Default, Clone, Debug)] +pub struct RangeArena { pub ranges: Vec, + pub map: HashMap, } /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphLike { type Node; type Edge: Ord + PartialEq + Heirarchical + Copy; - type RangeElem: PartialEq; + type RangeElem: Hash + PartialEq + Eq + PartialOrd + Clone; /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph @@ -65,7 +68,7 @@ pub trait GraphLike { fn range_arena_mut(&mut self) -> &mut RangeArena; fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { - self.range_arena().ranges.iter().position(|r| r == elem) + self.range_arena().map.get(elem).copied() } fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { @@ -73,7 +76,8 @@ pub trait GraphLike { idx } else { let idx = self.range_arena().ranges.len(); - self.range_arena_mut().ranges.push(elem); + self.range_arena_mut().ranges.push(elem.clone()); + self.range_arena_mut().map.insert(elem, idx); idx } } diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 6c438999..06c49e32 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -266,7 +266,7 @@ pub trait Cmp: AnalyzerBackend + Sized { loc: Loc, lhs_cvar: ContextVarNode, ) -> Result { - if let Some(lhs_range) = lhs_cvar.range(self).into_expr_err(loc)? { + if let Some(lhs_range) = lhs_cvar.ref_range(self).into_expr_err(loc)? { let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; // invert @@ -277,7 +277,7 @@ pub trait Cmp: AnalyzerBackend + Sized { Elem::Null, )); - return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions)); + return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions.clone())); } } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index f26cec46..93ff0cb6 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -76,7 +76,6 @@ pub trait SolidityCaller: ctx.push_expr(ExprRet::Single(cvar), analyzer) .into_expr_err(loc)?; } else { - println!("not const: [{}]", cvar.range_string(analyzer).unwrap().unwrap()); let var = ContextVar::new_from_builtin( loc, analyzer.builtin_or_add(Builtin::Bytes(32)).into(), From b3cd09cdc8b3d1e62f87f8092939c9ba97d6ebdb Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 09:07:49 -0800 Subject: [PATCH 54/71] more arena work --- crates/graph/src/graph_elements.rs | 2 +- crates/graph/src/nodes/context/underlying.rs | 4 +- crates/graph/src/nodes/context/var/ranging.rs | 4 +- crates/graph/src/nodes/context/variables.rs | 4 +- crates/graph/src/nodes/context/versioning.rs | 33 ++++++--- crates/graph/src/range/elem/concrete.rs | 3 +- crates/graph/src/range/elem/elem_enum.rs | 14 ++-- crates/graph/src/range/elem/elem_trait.rs | 4 +- crates/graph/src/range/elem/expr.rs | 7 +- crates/graph/src/range/elem/map_or_array.rs | 6 +- crates/graph/src/range/elem/reference.rs | 2 +- crates/graph/src/range/solc_range.rs | 4 +- crates/shared/src/graph_like.rs | 2 +- crates/solc-expressions/src/cmp.rs | 71 ++++++++++--------- crates/solc-expressions/src/cond_op.rs | 8 +-- .../src/func_call/func_caller.rs | 6 +- .../solc-expressions/src/func_call/helper.rs | 2 +- .../func_call/intrinsic_call/precompile.rs | 2 +- .../src/func_call/modifier.rs | 4 +- .../solc-expressions/src/yul/yul_cond_op.rs | 8 +-- 20 files changed, 114 insertions(+), 76 deletions(-) diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 460f8cac..2a881c5e 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -369,7 +369,7 @@ pub enum ContextEdge { /// A connection between a variable and the context denoting that the variable is returned Return, /// A continuation of a context - Continue, + Continue(&'static str), /// A connection between a brand new created variable for a function's context and the variable InputVariable, /// A connection to a return variable that should be assigned diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index c3ea9ea2..c7b72ecd 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -108,8 +108,10 @@ impl Context { let modifier_state = if let Some(mstate) = modifier_state { Some(mstate) - } else { + } else if fn_call.is_none() || parent_ctx.associated_fn(analyzer)? == fn_call.unwrap() { parent_ctx.underlying(analyzer)?.modifier_state.clone() + } else { + None }; if analyzer.max_depth() < depth { diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index c545162f..6fab5158 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -98,7 +98,7 @@ impl ContextVarNode { pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { - range.cache_flatten(analyzer)?; + // range.cache_flatten(analyzer)?; range.cache_eval(analyzer)?; self.set_range(analyzer, range)?; } @@ -380,3 +380,5 @@ impl ContextVarNode { Ok(()) } } + + diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 3416adb2..54349dc5 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -60,10 +60,10 @@ impl ContextNode { ) -> Result, GraphError> { if let Some(var) = self.var_by_name(analyzer, name) { Ok(Some(var)) - } else if let Some(parent) = self.underlying(analyzer)?.continuation_of { - parent.var_by_name_or_recurse(analyzer, name) } else if let Some(parent) = self.ancestor_in_fn(analyzer, self.associated_fn(analyzer)?)? { parent.var_by_name_or_recurse(analyzer, name) + } else if let Some(parent) = self.underlying(analyzer)?.continuation_of { + parent.var_by_name_or_recurse(analyzer, name) } else { Ok(None) } diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 1eba34ec..8e3ab416 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,3 +1,5 @@ +use petgraph::visit::EdgeRef; +use petgraph::Direction; use crate::ContextEdge; use crate::Edge; use crate::{ @@ -17,25 +19,36 @@ impl ContextNode { pub fn set_continuation_ctx( &self, analyzer: &mut impl AnalyzerBackend, - continuation_ctx: ContextNode, + continuation_of_ctx: ContextNode, + ty: &'static str ) -> Result<(), GraphError> { assert!( - self.0 > continuation_ctx.0, + self.0 > continuation_of_ctx.0, "{} {}", self.0, - continuation_ctx.0 + continuation_of_ctx.0 ); - if let Some(cont) = self.underlying_mut(analyzer)?.continuation_of { - cont.set_continuation_ctx(analyzer, continuation_ctx) + + let parent_list = self.parent_list(analyzer)?; + // if `continuation_of` already has a continuation, build off that continuation if it is in the parent list + if let Some(cont) = analyzer + .graph() + .edges_directed(continuation_of_ctx.into(), Direction::Incoming) + .find(|edge| { + matches!(edge.weight(), Edge::Context(ContextEdge::Continue(_))) + && parent_list.contains(&ContextNode::from(edge.source())) + }) + .map(|edge| ContextNode::from(edge.source())) + { + self.set_continuation_ctx(analyzer, cont, ty) } else { analyzer.add_edge( *self, - continuation_ctx, - Edge::Context(ContextEdge::Continue), + continuation_of_ctx, + Edge::Context(ContextEdge::Continue(ty)), ); - - self.underlying_mut(analyzer)?.continuation_of = Some(continuation_ctx); - self.underlying_mut(analyzer)?.cache.vars = continuation_ctx.underlying(analyzer)?.cache.vars.clone(); + self.underlying_mut(analyzer)?.continuation_of = Some(continuation_of_ctx); + self.underlying_mut(analyzer)?.cache.vars = continuation_of_ctx.underlying(analyzer)?.cache.vars.clone(); Ok(()) } } diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 356a3b8d..e3cf4b18 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -34,8 +34,9 @@ impl RangeConcrete { impl RangeElem for RangeConcrete { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { let _ = analyzer.range_arena_idx_or_upsert(Elem::Concrete(self.clone())); + Ok(()) } fn has_cycle( diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 0c1e11c4..7d096688 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -595,19 +595,20 @@ impl std::fmt::Display for Elem { impl RangeElem for Elem { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { match self { - Self::Arena(_) => return, - Self::Reference(d) => d.arenaize(analyzer), - Self::ConcreteDyn(d) => d.arenaize(analyzer), + Self::Arena(_) => return Ok(()), + Self::Reference(d) => d.arenaize(analyzer)?, + Self::ConcreteDyn(d) => d.arenaize(analyzer)?, Self::Expr(expr) => { - expr.arenaize(analyzer); + expr.arenaize(analyzer)?; }, _ => {} } let self_take = std::mem::take(self); *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(self_take)); + Ok(()) } fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { @@ -656,6 +657,9 @@ impl RangeElem for Elem { } fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + if self.is_flatten_cached(analyzer) { + return Ok(()) + } match self { Self::Reference(d) => d.cache_flatten(analyzer), Self::Concrete(c) => c.cache_flatten(analyzer), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 2582aa9d..f34f40e0 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -1,7 +1,7 @@ use crate::{ nodes::ContextVarNode, range::elem::{Elem, RangeExpr, RangeOp}, - GraphBackend, + GraphBackend, GraphError }; use shared::NodeIdx; @@ -76,5 +76,5 @@ pub trait RangeElem { /// cyclic dependency. fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); - fn arenaize(&mut self, analyzer: &mut impl GraphBackend); + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError>; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 91213ad7..7bb277f6 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -105,9 +105,10 @@ impl RangeExpr { impl RangeElem for RangeExpr { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { self.lhs.arenaize(analyzer); self.rhs.arenaize(analyzer); + Ok(()) } fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { @@ -175,6 +176,8 @@ impl RangeElem for RangeExpr { Ok(*cached) } else if self.op == RangeOp::SetIndices { self.simplify_exec_op(true, &mut Default::default(), analyzer) + } else if let Some(flat_max) = &self.flattened_max { + flat_max.maximize(analyzer) } else { self.exec_op(true, analyzer) } @@ -184,6 +187,8 @@ impl RangeElem for RangeExpr { Ok(*cached) } else if self.op == RangeOp::SetIndices { self.simplify_exec_op(false, &mut Default::default(), analyzer) + } else if let Some(flat_min) = &self.flattened_min { + flat_min.minimize(analyzer) } else { self.exec_op(false, analyzer) } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 20002017..eca94e02 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -170,7 +170,10 @@ impl RangeDyn { impl RangeElem for RangeDyn { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) { + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.cache_flatten(analyzer)?; + self.cache_minimize(analyzer)?; + self.cache_maximize(analyzer)?; self.len.arenaize(analyzer); self.val = self.val.iter_mut().map(|(k, (v, op))| { let mut new_k = k.clone(); @@ -179,6 +182,7 @@ impl RangeElem for RangeDyn { new_v.arenaize(analyzer); (new_k, (new_v, *op)) }).collect(); + Ok(()) } fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 23cd8efa..3020e0cb 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -51,7 +51,7 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) {} + fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { false diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 927a1ee5..5983c2d6 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -565,15 +565,15 @@ impl Range for SolcRange { } fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + self.min.arenaize(analyzer); + self.max.arenaize(analyzer); if self.max_cached.is_none() { let max = self.range_max_mut(); - max.cache_flatten(analyzer)?; max.cache_maximize(analyzer)?; self.max_cached = Some(self.range_max().maximize(analyzer)?); } if self.min_cached.is_none() { let min = self.range_min_mut(); - min.cache_flatten(analyzer)?; min.cache_minimize(analyzer)?; self.min_cached = Some(self.range_min().minimize(analyzer)?); } diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index ddd4579a..5e3f2976 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -26,7 +26,7 @@ pub struct RangeArena { pub trait GraphLike { type Node; type Edge: Ord + PartialEq + Heirarchical + Copy; - type RangeElem: Hash + PartialEq + Eq + PartialOrd + Clone; + type RangeElem: Hash + PartialEq + Eq + PartialOrd + Clone + std::fmt::Display; /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 06c49e32..4eeef180 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -45,7 +45,12 @@ pub trait Cmp: AnalyzerBackend + Sized { ExprRet::Single(lhs) | ExprRet::SingleLiteral(lhs) => { let lhs_cvar = ContextVarNode::from(lhs); tracing::trace!("not: {}", lhs_cvar.display_name(self).into_expr_err(loc)?); - let range = self.not_eval(ctx, loc, lhs_cvar)?; + + let mut elem = Elem::Expr(RangeExpr::new(Elem::from(lhs_cvar), RangeOp::Not, Elem::Null)); + elem.arenaize(self); + let mut range = SolcRange::new(elem.clone(), elem, vec![]); + + range.cache_eval(self).into_expr_err(loc)?; let out_var = ContextVar { loc: Some(loc), name: format!( @@ -260,42 +265,42 @@ pub trait Cmp: AnalyzerBackend + Sized { } } - fn not_eval( - &self, - _ctx: ContextNode, - loc: Loc, - lhs_cvar: ContextVarNode, - ) -> Result { - if let Some(lhs_range) = lhs_cvar.ref_range(self).into_expr_err(loc)? { - let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + // fn not_eval( + // &mut self, + // _ctx: ContextNode, + // loc: Loc, + // lhs_cvar: ContextVarNode, + // ) -> Result { + // if let Some(lhs_range) = lhs_cvar.ref_range(self).into_expr_err(loc)? { + // let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; - // invert - if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?, self) { - let val = Elem::Expr(RangeExpr::new( - lhs_range.range_min().into_owned(), - RangeOp::Not, - Elem::Null, - )); + // // invert + // if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?, self) { + // let val = Elem::Expr(RangeExpr::new( + // lhs_range.range_min().into_owned(), + // RangeOp::Not, + // Elem::Null, + // )); - return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions.clone())); - } - } + // return Ok(SolcRange::new(val.clone(), val, lhs_range.exclusions.clone())); + // } + // } - let min = RangeConcrete { - val: Concrete::Bool(false), - loc, - }; + // let min = Elem::Concrete(RangeConcrete { + // val: Concrete::Bool(false), + // loc, + // }).arenaize(self); - let max = RangeConcrete { - val: Concrete::Bool(true), - loc, - }; - Ok(SolcRange::new( - Elem::Concrete(min), - Elem::Concrete(max), - vec![], - )) - } + // let max = Elem::Concrete(RangeConcrete { + // val: Concrete::Bool(true), + // loc, + // }).arenaize(self); + // Ok(SolcRange::new( + // min, + // max, + // vec![], + // )) + // } fn range_eval( &self, diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 07d0e0ea..656c8b80 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -37,10 +37,10 @@ pub trait CondOp: AnalyzerBackend + Requir ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; true_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "fork_true") .into_expr_err(loc)?; false_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "fork_false") .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); @@ -161,10 +161,10 @@ pub trait CondOp: AnalyzerBackend + Requir ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; true_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "fork_true") .into_expr_err(loc)?; false_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "fork_false") .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 7d33cffc..08ebced6 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -435,7 +435,7 @@ pub trait FuncCaller: } /// Actually executes the function - #[tracing::instrument(level = "trace", skip_all)] + // #[tracing::instrument(level = "trace", skip_all)] fn execute_call_inner( &mut self, loc: Loc, @@ -445,6 +445,7 @@ pub trait FuncCaller: _renamed_inputs: &BTreeMap, func_call_str: Option<&str>, ) -> Result<(), ExprErr> { + tracing::trace!("executing: {}", func_node.name(self).into_expr_err(loc)?); if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { // add return nodes into the subctx func_node @@ -462,6 +463,7 @@ pub trait FuncCaller: } }); + // parse the function body self.parse_ctx_statement(&body, false, Some(callee_ctx)); if let Some(mod_state) = &callee_ctx.underlying(self).into_expr_err(loc)?.modifier_state.clone() { if mod_state.num == 0 { @@ -491,7 +493,7 @@ pub trait FuncCaller: ) .unwrap(); let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); - ret_subctx.set_continuation_ctx(self, caller_ctx).into_expr_err(loc)?; + ret_subctx.set_continuation_ctx(self, caller_ctx, "execute_call_inner").into_expr_err(loc)?; let res = callee_ctx .set_child_call(ret_subctx, self) diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 4e2d27e9..0cb90915 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -360,7 +360,7 @@ pub trait CallerHelper: AnalyzerBackend + .into_expr_err(loc)?; let ret_subctx = ContextNode::from(self.add_node(Node::Context(ctx))); ret_subctx - .set_continuation_ctx(self, caller_ctx) + .set_continuation_ctx(self, caller_ctx, "ctx_rets") .into_expr_err(loc)?; let res = callee_ctx diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 7115d388..4a9887a0 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -193,7 +193,7 @@ pub trait PrecompileCaller: // the return is a continuation of the ctx not the ecrecover ctx ContextNode::from(ret_ctx) - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "ecrecover") .into_expr_err(loc)?; let tmp_ret = ContextVarNode::from(cvar) diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index 0dc65b8a..fbc02669 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -121,7 +121,7 @@ pub trait ModifierCaller: let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); new_parent_subctx - .set_continuation_ctx(analyzer, modifier_state.parent_ctx) + .set_continuation_ctx(analyzer, modifier_state.parent_ctx, "resume_from_modifier_nonfinal") .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; @@ -150,7 +150,7 @@ pub trait ModifierCaller: .unwrap(); let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); new_parent_subctx - .set_continuation_ctx(analyzer, modifier_state.parent_ctx) + .set_continuation_ctx(analyzer, modifier_state.parent_ctx, "resume_from_modifier_final") .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index ab15178c..9be9fe32 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -43,10 +43,10 @@ pub trait YulCondOp: ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; true_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "yul_fork_true") .into_expr_err(loc)?; false_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "yul_fork_false") .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); @@ -126,10 +126,10 @@ pub trait YulCondOp: ctx.set_child_fork(true_subctx, false_subctx, analyzer) .into_expr_err(loc)?; true_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "yul_fork_true") .into_expr_err(loc)?; false_subctx - .set_continuation_ctx(analyzer, ctx) + .set_continuation_ctx(analyzer, ctx, "yul_fork_false") .into_expr_err(loc)?; let ctx_fork = analyzer.add_node(Node::ContextFork); analyzer.add_edge(ctx_fork, ctx, Edge::Context(ContextEdge::ContextFork)); From 62948e3c0ee347e879fec82735d6234425407499 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 11:07:04 -0800 Subject: [PATCH 55/71] fix binop --- crates/cli/src/main.rs | 10 +- crates/graph/src/nodes/context/solving.rs | 8 +- crates/graph/src/nodes/context/var/ranging.rs | 20 +- crates/graph/src/solvers/atoms.rs | 17 +- crates/graph/src/solvers/brute.rs | 8 +- crates/graph/src/solvers/dl.rs | 6 +- crates/pyrometer/src/analyzer.rs | 80 ++++++ crates/solc-expressions/src/bin_op.rs | 234 ++++++------------ 8 files changed, 192 insertions(+), 191 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index c7d42bb6..7ff232ac 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -96,6 +96,10 @@ struct Args { /// Max stack depth to evaluate to #[clap(long, default_value = "200")] pub max_stack_depth: usize, + + /// Print stats about the IR + #[clap(long)] + pub stats: bool, } pub fn subscriber() { @@ -236,10 +240,14 @@ fn main() { let t0 = std::time::Instant::now(); let maybe_entry = analyzer.parse(&sol, ¤t_path, true); - let parse_time = t0.elapsed().as_millis(); + let t_end = t0.elapsed(); + let parse_time = t_end.as_millis(); println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); + if args.stats { + println!("{}", analyzer.stats(t_end)); + } // println!("Arena: {:#?}", analyzer.range_arena); // use self.sources to fill a BTreeMap with the file_no and SourcePath.path_to_solidity_file diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index ab0ab5a9..d5dba573 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -41,10 +41,10 @@ impl ContextNode { Ok(ranges .iter() .filter_map(|(_dep, range)| { - if let Some(atom) = range.min.atomize() { + if let Some(atom) = range.min.atomize(analyzer) { Some(atom) } else { - range.max.atomize() + range.max.atomize(analyzer) } }) .collect::>()) @@ -84,11 +84,11 @@ impl ContextNode { let range = dep.ref_range(analyzer)?.unwrap(); let r = range.flattened_range(analyzer)?.into_owned(); // add the atomic constraint - if let Some(atom) = r.min.atomize() { + if let Some(atom) = r.min.atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); solver.add_constraints(vec![atom], analyzer); self.underlying_mut(analyzer)?.dl_solver = solver; - } else if let Some(atom) = r.max.atomize() { + } else if let Some(atom) = r.max.atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); solver.add_constraints(vec![atom], analyzer); self.underlying_mut(analyzer)?.dl_solver = solver; diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 6fab5158..bba86aa2 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -177,7 +177,7 @@ impl ContextVarNode { } } - new_min.arenaize(analyzer); + new_min.arenaize(analyzer)?; // new_min.cache_flatten(analyzer)?; // new_min.cache_minimize(analyzer)?; @@ -222,7 +222,7 @@ impl ContextVarNode { } } - new_max.arenaize(analyzer); + new_max.arenaize(analyzer)?; tracing::trace!( "setting range maximum: {:?}, {}, current: {}, new: {}", @@ -268,9 +268,9 @@ impl ContextVarNode { None }; - new_exclusions.iter_mut().for_each(|excl| { - excl.arenaize(analyzer); - }); + new_exclusions.iter_mut().try_for_each(|excl| { + excl.arenaize(analyzer) + })?; self.underlying_mut(analyzer)? .set_range_exclusions(new_exclusions, fallback)?; @@ -289,7 +289,7 @@ impl ContextVarNode { } } - new_min.arenaize(analyzer); + new_min.arenaize(analyzer)?; if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); @@ -320,7 +320,7 @@ impl ContextVarNode { } } - new_max.arenaize(analyzer); + new_max.arenaize(analyzer)?; if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); @@ -355,9 +355,9 @@ impl ContextVarNode { None }; - new_exclusions.iter_mut().for_each(|excl| { - excl.arenaize(analyzer); - }); + new_exclusions.iter_mut().try_for_each(|excl| { + excl.arenaize(analyzer) + })?; Ok(self .underlying_mut(analyzer)? diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index d1dd5493..d6a40d69 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -1,3 +1,4 @@ +use crate::range::exec_traits::ExecOp; use crate::{ nodes::{Concrete, ContextVarNode}, range::{ @@ -229,19 +230,19 @@ pub static LIA_OPS: &[RangeOp] = &[ ]; pub trait Atomize { - fn atoms_or_part(&self) -> AtomOrPart; - fn atomize(&self) -> Option; + fn atoms_or_part(&self, analyzer: &impl GraphBackend) -> AtomOrPart; + fn atomize(&self, analyzer: &impl GraphBackend) -> Option; } impl Atomize for Elem { - fn atoms_or_part(&self) -> AtomOrPart { + fn atoms_or_part(&self, analyzer: &impl GraphBackend) -> AtomOrPart { match self { Elem::Arena(_) => todo!(), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), Elem::Expr(expr) => { // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); - match (expr.lhs.atoms_or_part(), expr.rhs.atoms_or_part()) { + match (expr.lhs.atoms_or_part(analyzer), expr.rhs.atoms_or_part(analyzer)) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { match (l, r) { (_, Elem::Arena(_)) => todo!(), @@ -291,8 +292,8 @@ impl Atomize for Elem { (Elem::Concrete(_), Elem::Expr(_)) => { todo!("here4"); } - (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => { - todo!("Should have simplified? {l} {} {r}", expr.op.to_string()) + (Elem::Concrete(_), Elem::Concrete(_)) => { + expr.exec_op(true, analyzer).unwrap().atoms_or_part(analyzer) } (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), @@ -315,7 +316,7 @@ impl Atomize for Elem { } } - fn atomize(&self) -> Option { + fn atomize(&self, analyzer: &impl GraphBackend) -> Option { use Elem::*; match self { @@ -325,7 +326,7 @@ impl Atomize for Elem { ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, Expr(_) => { // println!("atomized: was expr"); - let AtomOrPart::Atom(mut a) = self.atoms_or_part() else { + let AtomOrPart::Atom(mut a) = self.atoms_or_part(analyzer) else { return None; }; a.update_max_ty(); diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 701eba66..2425b7c8 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -290,10 +290,10 @@ impl SolcSolver for BruteBinSearchSolver { // println!("dep: {}", dep.display_name(analyzer).unwrap()); // println!("atom: {atom:#?}"); - if let Some(atom) = range.min.atomize() { + if let Some(atom) = range.min.atomize(analyzer) { Some(atom) } else { - range.max.atomize() + range.max.atomize(analyzer) } }) .collect::>(); @@ -607,7 +607,7 @@ impl SolcSolver for BruteBinSearchSolver { .min .simplify_minimize(&mut Default::default(), analyzer) .unwrap() - .atomize() + .atomize(analyzer) { Some(atom) } else { @@ -615,7 +615,7 @@ impl SolcSolver for BruteBinSearchSolver { .max .simplify_maximize(&mut Default::default(), analyzer) .unwrap() - .atomize() + .atomize(analyzer) } }) .collect::>(); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 856172d9..a3c8238f 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -612,7 +612,7 @@ impl DLSolver { .lhs .into_elem() .wrapping_sub(constraint.rhs.into_elem()) - .atomize() + .atomize(analyzer) .expect("unable to atomize?"), ); Self::dl_atom_normalize(SolverAtom { @@ -630,7 +630,7 @@ impl DLSolver { .lhs .into_elem() .wrapping_sub(Elem::from(Concrete::from(U256::zero()))) - .atomize() + .atomize(analyzer) .expect("unable to atomize?"), ); @@ -645,7 +645,7 @@ impl DLSolver { let new_lhs = AtomOrPart::Atom( Elem::from(Concrete::from(U256::zero())) .wrapping_sub(constraint.rhs.into_elem()) - .atomize() + .atomize(analyzer) .expect("unable to atomize?"), ); Self::dl_atom_normalize(SolverAtom { diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 36cebac6..559ba485 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -187,6 +187,86 @@ impl Default for Analyzer { } impl Analyzer { + pub fn stats(&self, duration: std::time::Duration) -> String { + let num_nodes = self.graph.node_count(); + let num_contracts = self.number_of_contracts(); + let num_funcs = self.number_of_functions(); + let num_vars = self.number_of_variables(); + let num_contexts = self.number_of_contexts(); + vec![ + format!(""), + format!(" Analyzer stats"), + format!("====================================="), + format!(""), + format!(" Number of nodes: {}, {} nodes/ms", num_nodes, num_nodes as f64 / duration.as_millis() as f64), + format!(" Number of Contracts: {}, {} contracts/ms", num_contracts, num_contracts as f64 / duration.as_millis() as f64), + format!(" Number of Functions: {}, {} functions/ms", num_funcs, num_funcs as f64 / duration.as_millis() as f64), + format!(" Number of Variables: {}, {} variables/ms", num_vars, num_vars as f64 / duration.as_millis() as f64), + format!(""), + format!(" Unique Range Elements: {}", self.range_arena.ranges.len()), + format!(""), + format!(" Number of Contexts: {}, {} contexts/ms", num_contexts, num_contexts as f64 / duration.as_millis() as f64), + format!(" Max depth of Contexts: {}", self.max_context_depth()), + format!(" Max width of Contexts: {}", self.max_context_width()), + format!(""), + format!("====================================="), + ].join("\n") + } + + pub fn number_of_contexts(&self) -> usize { + self.graph.node_weights().filter(|n| matches!(n, Node::Context(_))).count() + } + + pub fn number_of_forks(&self) -> usize { + self.graph.node_weights().filter(|n| matches!(n, Node::ContextFork)).count() + } + + pub fn number_of_variables(&self) -> usize { + self.graph.node_weights().filter(|n| matches!(n, Node::ContextVar(_))).count() + } + + pub fn number_of_functions(&self) -> usize { + self.graph.node_weights().filter(|n| matches!(n, Node::Function(_))).count() + } + + pub fn number_of_contracts(&self) -> usize { + self.graph.node_weights().filter(|n| matches!(n, Node::Contract(_))).count() + } + + pub fn max_context_depth(&self) -> usize { + self.graph.node_weights().filter_map(|n| { + if let Node::Context(c) = n { + Some(c) + } else { + None + } + }).fold(0, |mut acc, c| { + if c.depth > acc { + acc = c.depth; + acc + } else { + acc + } + }) + } + + pub fn max_context_width(&self) -> usize { + self.graph.node_weights().filter_map(|n| { + if let Node::Context(c) = n { + Some(c) + } else { + None + } + }).fold(0, |mut acc, c| { + if c.width > acc { + acc = c.width; + acc + } else { + acc + } + }) + } + pub fn complicated_parse( &mut self, expr: &Expression, diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 0d85c6f0..7d15a51e 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -262,71 +262,6 @@ pub trait BinOp: AnalyzerBackend + Sized { { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } - - // let tmp_rhs = tmp_rhs.latest_version(self); - - // let tmp_var = ContextVar { - // loc: Some(loc), - // name: format!( - // "tmp{}({} != 0)", - // ctx.new_tmp(self).into_expr_err(loc)?, - // tmp_rhs.name(self).into_expr_err(loc)?, - // ), - // display_name: format!( - // "({} != 0)", - // tmp_rhs.display_name(self).into_expr_err(loc)?, - // ), - // storage: None, - // is_tmp: true, - // tmp_of: Some(TmpConstruction::new( - // new_lhs, - // RangeOp::Neq, - // Some(zero_node.into()), - // )), - // is_symbolic: true, - // is_return: false, - // ty: VarType::BuiltIn( - // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - // SolcRange::from(Concrete::Bool(true)), - // ), - // }; - - // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - - // let range = tmp_rhs - // .ref_range(self) - // .into_expr_err(loc)? - // .expect("No range?"); - // if range.min_is_negative(self).into_expr_err(loc)? { - // let mut range_excls = range.range_exclusions(); - // let excl = Elem::from(Concrete::from(I256::zero())); - // if !range_excls.contains(&excl) { - // range_excls.push(excl); - // } - // tmp_rhs - // .set_range_exclusions(self, range_excls) - // .into_expr_err(loc)?; - // } else { - // // the new min is max(1, rhs.min) - // let min = Elem::max( - // Elem::from(Reference::new(new_rhs.into())), - // // tmp_rhs - // // .range_min(self) - // // .into_expr_err(loc)? - // // .unwrap_or_else(|| { - // // panic!("No range minimum: {:?}", tmp_rhs.underlying(self)) - // // }), - // Elem::from(Concrete::from(U256::from(1))).cast( - // Elem::from(Reference::new(tmp_rhs.into())), // .range_min(self) - // // .into_expr_err(loc)? - // // .expect("No range minimum?"), - // ), - // ); - - // tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; - // new_rhs = tmp_rhs; - // } } } RangeOp::Sub(..) => { @@ -373,36 +308,36 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_lhs = tmp_lhs.latest_version(self); tmp_lhs.set_range_min(self, min).into_expr_err(loc)?; - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} >= {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} >= {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Gte, - Some(new_rhs), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; + // let tmp_var = ContextVar { + // loc: Some(loc), + // name: format!( + // "tmp{}({} >= {})", + // ctx.new_tmp(self).into_expr_err(loc)?, + // tmp_lhs.name(self).into_expr_err(loc)?, + // new_rhs.name(self).into_expr_err(loc)?, + // ), + // display_name: format!( + // "({} >= {})", + // tmp_lhs.display_name(self).unwrap(), + // new_rhs.display_name(self).unwrap(), + // ), + // storage: None, + // is_tmp: true, + // tmp_of: Some(TmpConstruction::new( + // tmp_lhs, + // RangeOp::Gte, + // Some(new_rhs), + // )), + // is_symbolic: true, + // is_return: false, + // ty: VarType::BuiltIn( + // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + // SolcRange::from(Concrete::Bool(true)), + // ), + // }; - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; } } RangeOp::Add(..) => { @@ -413,9 +348,6 @@ pub trait BinOp: AnalyzerBackend + Sized { // the new max is min(lhs.max, (2**256 - rhs.min)) let max = Elem::min( Elem::from(Reference::new(lhs_cvar.into())), - // .range_max(self) - // .into_expr_err(loc)? - // .expect("No range max?"), Elem::from(Concrete::from(U256::MAX)) - Elem::from(rhs_cvar), ); @@ -445,6 +377,12 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; + let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { + self.advance_var_in_ctx_forcible(tmp_lhs.latest_version(self), loc, ctx, true)? + } else { + tmp_lhs + }; + if self .require( tmp_lhs, @@ -459,37 +397,6 @@ pub trait BinOp: AnalyzerBackend + Sized { { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} <= 2**256 - 1 - {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} <= 2**256 - 1 - {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Lte, - Some(tmp_rhs.into()), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; } } RangeOp::Mul(..) => { @@ -500,9 +407,6 @@ pub trait BinOp: AnalyzerBackend + Sized { // the new max is min(lhs.max, (2**256 / max(1, rhs.min))) let max = Elem::min( Elem::from(Reference::new(lhs_cvar.into())), - // .range_max(self) - // .into_expr_err(loc)? - // .expect("No range max?"), Elem::from(Concrete::from(U256::MAX)) / Elem::max( Elem::from(Concrete::from(U256::from(1))), @@ -536,6 +440,14 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; + println!("{}", ContextVarNode::from(tmp_rhs).display_name(self).unwrap()); + + let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { + self.advance_var_in_ctx_forcible(tmp_lhs.latest_version(self), loc, ctx, true)? + } else { + tmp_lhs + }; + if self .require( tmp_lhs, @@ -551,38 +463,38 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(ExprRet::CtxKilled(KilledKind::Revert)); } - let tmp_rhs = ContextVarNode::from(tmp_rhs).latest_version(self); + // let tmp_rhs = ContextVarNode::from(tmp_rhs).latest_version(self); - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} <= (2**256 - 1) / {})", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_lhs.name(self).into_expr_err(loc)?, - new_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} <= (2**256 - 1) / {})", - tmp_lhs.display_name(self).unwrap(), - new_rhs.display_name(self).unwrap(), - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_lhs, - RangeOp::Lte, - Some(tmp_rhs), - )), - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; + // let tmp_var = ContextVar { + // loc: Some(loc), + // name: format!( + // "tmp{}({} <= (2**256 - 1) / {})", + // ctx.new_tmp(self).into_expr_err(loc)?, + // tmp_lhs.name(self).into_expr_err(loc)?, + // new_rhs.name(self).into_expr_err(loc)?, + // ), + // display_name: format!( + // "({} <= (2**256 - 1) / {})", + // tmp_lhs.display_name(self).unwrap(), + // new_rhs.display_name(self).unwrap(), + // ), + // storage: None, + // is_tmp: true, + // tmp_of: Some(TmpConstruction::new( + // tmp_lhs, + // RangeOp::Lte, + // Some(tmp_rhs), + // )), + // is_symbolic: true, + // is_return: false, + // ty: VarType::BuiltIn( + // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), + // SolcRange::from(Concrete::Bool(true)), + // ), + // }; - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); + // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; } } RangeOp::Exp => { From 7c2ab66f512cc41c6751931289eb3dd2f5c7b0a0 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 11:30:07 -0800 Subject: [PATCH 56/71] fix cast --- crates/graph/src/nodes/context/var/typing.rs | 63 ++++++++++++++++++-- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index f7d004c8..3ffea470 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -366,14 +366,67 @@ impl ContextVarNode { ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { - if let Some(new_ty) = from_ty.try_cast(&to_ty, analyzer)? { + if let Some(new_ty) = from_ty.clone().try_cast(&to_ty, analyzer)? { self.underlying_mut(analyzer)?.ty = new_ty; } + if let (Some(mut r), Some(r2)) = (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) { - r.min = r.min.cast(r2.min); - r.min.arenaize(analyzer); - r.max = r.max.cast(r2.max); - r.max.arenaize(analyzer); + r.min.arenaize(analyzer)?; + r.max.arenaize(analyzer)?; + + let mut min_expr = r.min.clone() + .cast(r2.min.clone()) + .min( + r.max.clone().cast(r2.min.clone()) + ); + let mut max_expr = r.min.clone() + .cast(r2.min.clone()) + .max( + r.max.clone().cast(r2.min) + ); + + min_expr.arenaize(analyzer)?; + max_expr.arenaize(analyzer)?; + + let zero = Elem::from(Concrete::from(U256::zero())); + if r.contains_elem(&zero, analyzer) { + min_expr = min_expr.min(zero.clone()); + max_expr = max_expr.max(zero); + } + + if let (VarType::BuiltIn(from_bn, _), VarType::BuiltIn(to_bn, _)) = + (self.ty(analyzer)?, to_ty.clone()) + { + match (from_bn.underlying(analyzer)?, to_bn.underlying(analyzer)?) { + (Builtin::Uint(_), int @ Builtin::Int(_)) => { + // from ty is uint, to ty is int, check if type(int.min).bit_representation() + // is in range + if let Some(r) = self.ref_range(analyzer)? { + let int_min = int.min_concrete().unwrap(); + let bit_repr = int_min.bit_representation().unwrap(); + let bit_repr = bit_repr.into(); + if r.contains_elem(&bit_repr, analyzer) { + min_expr = min_expr.min(int_min.clone().into()); + max_expr = max_expr.max(int_min.into()); + } + } + } + (Builtin::Int(_), Builtin::Uint(_size)) => { + // from ty is int, to ty is uint + if let Some(r) = self.ref_range(analyzer)? { + let neg1 = Concrete::from(I256::from(-1i32)); + if r.contains_elem(&neg1.clone().into(), analyzer) { + max_expr = max_expr.max(neg1.bit_representation().unwrap().into()); + } + } + } + _ => {} + } + } + r.min = min_expr; + r.max = max_expr; + r.min.arenaize(analyzer)?; + r.max.arenaize(analyzer)?; self.set_range(analyzer, r)?; } } From 3e0a0dd0981e8420e1dfe4ea11a2f4c434dee577 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 11:33:57 -0800 Subject: [PATCH 57/71] remove debug print --- crates/solc-expressions/src/bin_op.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 7d15a51e..9915c288 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -440,8 +440,6 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; - println!("{}", ContextVarNode::from(tmp_rhs).display_name(self).unwrap()); - let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { self.advance_var_in_ctx_forcible(tmp_lhs.latest_version(self), loc, ctx, true)? } else { From ca4950f9049c48652e3c08cce185ac8b646c6512 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 11:35:09 -0800 Subject: [PATCH 58/71] lint --- crates/analyzers/src/var_analyzer/mod.rs | 11 +- crates/graph/src/nodes/concrete.rs | 10 +- crates/graph/src/nodes/context/node.rs | 10 +- crates/graph/src/nodes/context/typing.rs | 5 +- crates/graph/src/nodes/context/underlying.rs | 6 +- crates/graph/src/nodes/context/var/ranging.rs | 23 +- crates/graph/src/nodes/context/var/typing.rs | 42 +-- crates/graph/src/nodes/context/variables.rs | 12 +- crates/graph/src/nodes/context/versioning.rs | 11 +- crates/graph/src/nodes/contract_ty.rs | 2 +- crates/graph/src/nodes/func_ty.rs | 42 ++- crates/graph/src/range/elem/concrete.rs | 2 +- crates/graph/src/range/elem/elem_enum.rs | 75 +++-- crates/graph/src/range/elem/elem_trait.rs | 11 +- crates/graph/src/range/elem/expr.rs | 164 ++++++---- crates/graph/src/range/elem/map_or_array.rs | 127 +++++--- crates/graph/src/range/elem/reference.rs | 10 +- crates/graph/src/range/exec/exec_op.rs | 41 ++- crates/graph/src/range/exec/modulo.rs | 10 +- crates/graph/src/range/range_string.rs | 4 +- crates/graph/src/range/range_trait.rs | 14 +- crates/graph/src/range/solc_range.rs | 16 +- crates/graph/src/solvers/atoms.rs | 14 +- crates/graph/src/solvers/dl.rs | 300 +++++++++++------- crates/pyrometer/src/analyzer.rs | 140 +++++--- crates/pyrometer/src/graph_backend.rs | 6 +- crates/shared/src/gas.rs | 2 +- crates/shared/src/graph_like.rs | 4 +- crates/shared/src/lib.rs | 2 +- crates/solc-expressions/src/bin_op.rs | 19 +- crates/solc-expressions/src/cmp.rs | 11 +- .../src/context_builder/expr.rs | 17 +- crates/solc-expressions/src/env.rs | 9 +- .../src/func_call/func_caller.rs | 114 +++++-- .../solc-expressions/src/func_call/helper.rs | 31 +- .../src/func_call/internal_call.rs | 7 +- .../src/func_call/intrinsic_call/abi.rs | 77 ++--- .../func_call/intrinsic_call/dyn_builtin.rs | 22 +- .../intrinsic_call/intrinsic_caller.rs | 18 +- .../func_call/intrinsic_call/precompile.rs | 52 +-- .../src/func_call/intrinsic_call/solidity.rs | 33 +- .../src/func_call/intrinsic_call/types.rs | 15 +- .../src/func_call/modifier.rs | 17 +- .../src/func_call/namespaced_call.rs | 33 +- crates/solc-expressions/src/literal.rs | 2 +- crates/solc-expressions/src/loops.rs | 4 +- .../src/member_access/contract_access.rs | 2 +- .../src/member_access/member_trait.rs | 4 +- crates/solc-expressions/src/require.rs | 7 +- crates/solc-expressions/src/variable.rs | 2 - .../solc-expressions/src/yul/yul_builder.rs | 4 +- crates/solc-expressions/src/yul/yul_funcs.rs | 3 +- 52 files changed, 947 insertions(+), 672 deletions(-) diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 6d424564..9b14027b 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -224,11 +224,12 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { } }; - let (comparator, needs_curr) = if let Some(inherited) = curr.previous_or_inherited_version(self) { - (inherited, true) - } else { - (curr, false) - }; + let (comparator, needs_curr) = + if let Some(inherited) = curr.previous_or_inherited_version(self) { + (inherited, true) + } else { + (curr, false) + }; if let Some(curr_range) = comparator.ref_range(self).unwrap() { let mut cr_min = curr_range.evaled_range_min(self).unwrap(); diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index b71e65e7..0dd25243 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -932,23 +932,19 @@ impl Concrete { let mut bytes = [0; 32]; val.to_big_endian(&mut bytes); bytes.to_vec() - }, + } Concrete::Int(_, val) => { let mut bytes = [0; 32]; val.to_big_endian(&mut bytes); bytes.to_vec() - }, - Concrete::Bytes(size, val) => { - val[0..(*size as usize)].to_vec() } + Concrete::Bytes(size, val) => val[0..(*size as usize)].to_vec(), Concrete::Address(_) | Concrete::Bool(_) => { Concrete::Uint(256, self.into_u256().unwrap()).as_bytes() } Concrete::DynBytes(inner) => inner.clone(), Concrete::String(inner) => inner.as_bytes().to_vec(), - Concrete::Array(inner) => { - inner.iter().flat_map(|i| i.as_bytes()).collect() - }, + Concrete::Array(inner) => inner.iter().flat_map(|i| i.as_bytes()).collect(), } } diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 099a556b..446c892a 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -28,7 +28,11 @@ impl ContextNode { todo!("Joining not supported yet"); } - pub fn add_gas_cost(&self, analyzer: &mut impl GraphBackend, cost: u64) -> Result<(), GraphError> { + pub fn add_gas_cost( + &self, + analyzer: &mut impl GraphBackend, + cost: u64, + ) -> Result<(), GraphError> { self.associated_fn(analyzer)?.add_gas_cost(analyzer, cost) } @@ -100,9 +104,7 @@ impl ContextNode { ret: ContextVarNode, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result<(), GraphError> { - self.underlying_mut(analyzer)? - .ret - .push((ret_stmt_loc, ret)); + self.underlying_mut(analyzer)?.ret.push((ret_stmt_loc, ret)); self.propogate_end(analyzer)?; Ok(()) } diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index ad97d933..bd0de0bf 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -11,10 +11,7 @@ impl ContextNode { Ok(underlying.fn_call.is_none() && underlying.ext_fn_call.is_none() && !underlying.is_fork) } - pub fn has_continuation( - &self, - analyzer: &mut impl GraphBackend, - ) -> Result { + pub fn has_continuation(&self, analyzer: &mut impl GraphBackend) -> Result { Ok(self.underlying(analyzer)?.continuation_of.is_some()) } diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index c7b72ecd..ccdf92db 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -285,7 +285,11 @@ impl Context { cache: ContextCache { vars: parent_ctx.underlying(analyzer)?.cache.vars.clone(), visible_funcs: parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone(), - visible_structs: parent_ctx.underlying(analyzer)?.cache.visible_structs.clone(), + visible_structs: parent_ctx + .underlying(analyzer)? + .cache + .visible_structs + .clone(), first_ancestor: parent_ctx.underlying(analyzer)?.cache.first_ancestor, associated_source: None, associated_contract: None, diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index bba86aa2..3605ed15 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{Concrete, ContextNode, ContextVarNode}, + nodes::{Concrete, ContextVarNode}, range::{range_string::ToRangeString, Range, RangeEval}, AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, }; @@ -105,7 +105,10 @@ impl ContextVarNode { Ok(()) } - pub fn cache_flattened_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + pub fn cache_flattened_range( + &self, + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { range.cache_flatten(analyzer)?; self.set_range(analyzer, range)?; @@ -268,10 +271,10 @@ impl ContextVarNode { None }; - new_exclusions.iter_mut().try_for_each(|excl| { - excl.arenaize(analyzer) - })?; - + new_exclusions + .iter_mut() + .try_for_each(|excl| excl.arenaize(analyzer))?; + self.underlying_mut(analyzer)? .set_range_exclusions(new_exclusions, fallback)?; Ok(()) @@ -355,9 +358,9 @@ impl ContextVarNode { None }; - new_exclusions.iter_mut().try_for_each(|excl| { - excl.arenaize(analyzer) - })?; + new_exclusions + .iter_mut() + .try_for_each(|excl| excl.arenaize(analyzer))?; Ok(self .underlying_mut(analyzer)? @@ -380,5 +383,3 @@ impl ContextVarNode { Ok(()) } } - - diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 3ffea470..8b552ba9 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,4 +1,3 @@ - use crate::{ elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, @@ -17,7 +16,11 @@ impl ContextVarNode { Ok(&self.underlying(analyzer)?.ty) } - pub fn ty_eq_ty(&self, other: &VarType, analyzer: &impl GraphBackend) -> Result { + pub fn ty_eq_ty( + &self, + other: &VarType, + analyzer: &impl GraphBackend, + ) -> Result { self.ty(analyzer)?.ty_eq(other, analyzer) } @@ -217,9 +220,11 @@ impl ContextVarNode { pub fn is_return_node(&self, analyzer: &impl GraphBackend) -> Result { if let Some(ctx) = self.maybe_ctx(analyzer) { - return Ok(ctx.underlying(analyzer)?.ret.iter().any(|(_, node)| { - node.name(analyzer).unwrap() == self.name(analyzer).unwrap() - })); + return Ok(ctx + .underlying(analyzer)? + .ret + .iter() + .any(|(_, node)| node.name(analyzer).unwrap() == self.name(analyzer).unwrap())); } Ok(false) } @@ -234,9 +239,7 @@ impl ContextVarNode { .unwrap() .ret .iter() - .any(|(_, node)| { - node.name(analyzer).unwrap() == self.name(analyzer).unwrap() - }) + .any(|(_, node)| node.name(analyzer).unwrap() == self.name(analyzer).unwrap()) }) } @@ -370,20 +373,22 @@ impl ContextVarNode { self.underlying_mut(analyzer)?.ty = new_ty; } - if let (Some(mut r), Some(r2)) = (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) { + if let (Some(mut r), Some(r2)) = + (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) + { r.min.arenaize(analyzer)?; r.max.arenaize(analyzer)?; - let mut min_expr = r.min.clone() + let mut min_expr = r + .min + .clone() .cast(r2.min.clone()) - .min( - r.max.clone().cast(r2.min.clone()) - ); - let mut max_expr = r.min.clone() + .min(r.max.clone().cast(r2.min.clone())); + let mut max_expr = r + .min + .clone() .cast(r2.min.clone()) - .max( - r.max.clone().cast(r2.min) - ); + .max(r.max.clone().cast(r2.min)); min_expr.arenaize(analyzer)?; max_expr.arenaize(analyzer)?; @@ -416,7 +421,8 @@ impl ContextVarNode { if let Some(r) = self.ref_range(analyzer)? { let neg1 = Concrete::from(I256::from(-1i32)); if r.contains_elem(&neg1.clone().into(), analyzer) { - max_expr = max_expr.max(neg1.bit_representation().unwrap().into()); + max_expr = + max_expr.max(neg1.bit_representation().unwrap().into()); } } } diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 54349dc5..cb5ce939 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -9,14 +9,12 @@ use std::collections::BTreeMap; impl ContextNode { /// Debug print the stack - pub fn debug_expr_stack( - &self, - analyzer: &impl GraphBackend, - ) -> Result<(), GraphError> { + pub fn debug_expr_stack(&self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { let underlying_mut = self.underlying(analyzer)?; - underlying_mut.expr_ret_stack.iter().for_each(|elem| { - println!("{}", elem.debug_str(analyzer)) - }); + underlying_mut + .expr_ret_stack + .iter() + .for_each(|elem| println!("{}", elem.debug_str(analyzer))); Ok(()) } diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 8e3ab416..8fda2c5c 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,11 +1,11 @@ -use petgraph::visit::EdgeRef; -use petgraph::Direction; use crate::ContextEdge; use crate::Edge; use crate::{ nodes::{CallFork, ContextNode, FunctionNode, KilledKind}, AnalyzerBackend, GraphBackend, GraphError, Node, }; +use petgraph::visit::EdgeRef; +use petgraph::Direction; use solang_parser::pt::Loc; @@ -20,7 +20,7 @@ impl ContextNode { &self, analyzer: &mut impl AnalyzerBackend, continuation_of_ctx: ContextNode, - ty: &'static str + ty: &'static str, ) -> Result<(), GraphError> { assert!( self.0 > continuation_of_ctx.0, @@ -36,7 +36,7 @@ impl ContextNode { .edges_directed(continuation_of_ctx.into(), Direction::Incoming) .find(|edge| { matches!(edge.weight(), Edge::Context(ContextEdge::Continue(_))) - && parent_list.contains(&ContextNode::from(edge.source())) + && parent_list.contains(&ContextNode::from(edge.source())) }) .map(|edge| ContextNode::from(edge.source())) { @@ -48,7 +48,8 @@ impl ContextNode { Edge::Context(ContextEdge::Continue(ty)), ); self.underlying_mut(analyzer)?.continuation_of = Some(continuation_of_ctx); - self.underlying_mut(analyzer)?.cache.vars = continuation_of_ctx.underlying(analyzer)?.cache.vars.clone(); + self.underlying_mut(analyzer)?.cache.vars = + continuation_of_ctx.underlying(analyzer)?.cache.vars.clone(); Ok(()) } } diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 48f25279..87528211 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -354,7 +354,7 @@ impl Contract { ty: con.ty, name: con.name, inherits, - cached_functions: None + cached_functions: None, }, unhandled_inherits, ) diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 4088e2b3..49a1d141 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -35,7 +35,11 @@ impl FunctionNode { } } - pub fn add_gas_cost(&mut self, analyzer: &mut impl GraphBackend, cost: u64) -> Result<(), GraphError>{ + pub fn add_gas_cost( + &mut self, + analyzer: &mut impl GraphBackend, + cost: u64, + ) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.add_gas_cost(cost); Ok(()) } @@ -143,18 +147,22 @@ impl FunctionNode { } } - pub fn prefix_only_name(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn prefix_only_name( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { match self.underlying(analyzer)?.ty { - FunctionTy::Function => Ok(Some(self - .underlying(analyzer)? - .name - .clone() - .expect("Unnamed function") - .name - .chars() - .take_while(|&ch| ch != '(') - .collect::())), - _ => Ok(None) + FunctionTy::Function => Ok(Some( + self.underlying(analyzer)? + .name + .clone() + .expect("Unnamed function") + .name + .chars() + .take_while(|&ch| ch != '(') + .collect::(), + )), + _ => Ok(None), } } @@ -356,12 +364,18 @@ impl FunctionNode { pub fn ordered_param_names(&self, analyzer: &impl GraphBackend) -> Vec { let param_nodes = self.params(analyzer); - param_nodes.iter().map(|i| i.name(analyzer).unwrap()).collect() + param_nodes + .iter() + .map(|i| i.name(analyzer).unwrap()) + .collect() } pub fn maybe_ordered_param_names(&self, analyzer: &impl GraphBackend) -> Option> { let param_nodes = self.params(analyzer); - let names: Vec = param_nodes.iter().filter_map(|i| i.maybe_name(analyzer).unwrap()).collect(); + let names: Vec = param_nodes + .iter() + .filter_map(|i| i.maybe_name(analyzer).unwrap()) + .collect(); if names.len() == param_nodes.len() { Some(names) } else { diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index e3cf4b18..0cccb11e 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,6 +1,6 @@ use crate::{ nodes::{Concrete, ContextVarNode}, - range::elem::{Elem, RangeElem, RangeOp}, + range::elem::{Elem, RangeElem}, GraphBackend, GraphError, }; diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 7d096688..0b625664 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,5 +1,3 @@ -use std::hash::Hasher; -use std::hash::Hash; use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{ @@ -8,8 +6,10 @@ use crate::{ GraphBackend, GraphError, }; use solang_parser::pt::Loc; +use std::hash::Hash; +use std::hash::Hasher; -use shared::{RangeArenaIdx, NodeIdx}; +use shared::{NodeIdx, RangeArenaIdx}; use ethers_core::types::I256; @@ -65,8 +65,8 @@ impl Elem { expr.minimized = None; } Elem::ConcreteDyn(_d) => todo!(), - Elem::Null => {}, - Elem::Arena(_) => todo!() + Elem::Null => {} + Elem::Arena(_) => todo!(), } } @@ -128,7 +128,7 @@ impl Elem { Self::Expr(expr) => expr.contains_node(node_idx), Self::ConcreteDyn(d) => d.contains_node(node_idx), Self::Null => false, - Elem::Arena(_) => todo!() + Elem::Arena(_) => todo!(), } } @@ -337,14 +337,14 @@ impl Elem { pub fn dearenaize<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a Self { match self { Self::Arena(arena_idx) => &analyzer.range_arena().ranges[*arena_idx], - _ => unreachable!() + _ => unreachable!(), } } - pub fn dearenaize_mut<'a> (&self, analyzer: &'a mut impl GraphBackend) -> &'a mut Self { + pub fn dearenaize_mut<'a>(&self, analyzer: &'a mut impl GraphBackend) -> &'a mut Self { match self { Self::Arena(arena_idx) => &mut analyzer.range_arena_mut().ranges[*arena_idx], - _ => unreachable!() + _ => unreachable!(), } } @@ -354,15 +354,16 @@ impl Elem { (Self::Concrete(a), Self::Concrete(b)) => a == b, (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => { a.len == b.len - && a.val.len() == b.val.len() - && a.val.iter().zip(b.val.iter()).all(|((a, op_a), (b, op_b))| a.arena_eq(b) && op_a == op_b) - }, + && a.val.len() == b.val.len() + && a.val + .iter() + .zip(b.val.iter()) + .all(|((a, op_a), (b, op_b))| a.arena_eq(b) && op_a == op_b) + } (Self::Reference(a), Self::Reference(b)) => a == b, (Self::Expr(a), Self::Expr(b)) => { - a.lhs.arena_eq(&b.lhs) - && a.rhs.arena_eq(&b.rhs) - && a.op == b.op - }, + a.lhs.arena_eq(&b.lhs) && a.rhs.arena_eq(&b.rhs) && a.op == b.op + } (Elem::Null, Elem::Null) => true, _ => false, } @@ -602,7 +603,7 @@ impl RangeElem for Elem { Self::ConcreteDyn(d) => d.arenaize(analyzer)?, Self::Expr(expr) => { expr.arenaize(analyzer)?; - }, + } _ => {} } @@ -613,9 +614,7 @@ impl RangeElem for Elem { fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { match (self, other) { - (Self::Arena(a), Self::Arena(b)) => { - a == b - }, + (Self::Arena(a), Self::Arena(b)) => a == b, (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b, analyzer), (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b, analyzer), (Self::Reference(a), Self::Reference(b)) => a.idx == b.idx, @@ -629,9 +628,10 @@ impl RangeElem for Elem { if a == b { Some(std::cmp::Ordering::Equal) } else { - self.dearenaize(analyzer).range_ord(other.dearenaize(analyzer), analyzer) + self.dearenaize(analyzer) + .range_ord(other.dearenaize(analyzer), analyzer) } - }, + } (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), (Self::Reference(a), Self::Reference(b)) => a.range_ord(b, analyzer), (Elem::Null, Elem::Null) => None, @@ -658,7 +658,7 @@ impl RangeElem for Elem { fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if self.is_flatten_cached(analyzer) { - return Ok(()) + return Ok(()); } match self { Self::Reference(d) => d.cache_flatten(analyzer), @@ -672,11 +672,11 @@ impl RangeElem for Elem { dearenaized.cache_flatten(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) - }, + } } } - fn is_flatten_cached(&self, analyzer: &impl GraphBackend,) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { match self { Self::Reference(d) => d.is_flatten_cached(analyzer), Self::Concrete(c) => c.is_flatten_cached(analyzer), @@ -727,7 +727,12 @@ impl RangeElem for Elem { } } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ) { match self { Self::Reference(ref mut d) => { if d.idx == node_idx { @@ -741,9 +746,9 @@ impl RangeElem for Elem { Self::Arena(idx) => { let idx = *idx; let mut dearenaized = self.dearenaize(analyzer).clone(); - dearenaized.filter_recursion(node_idx, new_idx,analyzer); + dearenaized.filter_recursion(node_idx, new_idx, analyzer); analyzer.range_arena_mut().ranges[idx] = dearenaized; - }, + } } } @@ -794,7 +799,9 @@ impl RangeElem for Elem { _ => expr.simplify_maximize(seen_ops, analyzer), }, Null => Ok(Elem::Null), - Arena(_) => self.dearenaize(analyzer).simplify_maximize(seen_ops, analyzer), + Arena(_) => self + .dearenaize(analyzer) + .simplify_maximize(seen_ops, analyzer), } } @@ -819,7 +826,9 @@ impl RangeElem for Elem { _ => expr.simplify_minimize(seen_ops, analyzer), }, Null => Ok(Elem::Null), - Arena(_) => self.dearenaize(analyzer).simplify_minimize(seen_ops, analyzer), + Arena(_) => self + .dearenaize(analyzer) + .simplify_minimize(seen_ops, analyzer), }?; seen_ops.insert(self.clone(), res.clone()); @@ -847,7 +856,7 @@ impl RangeElem for Elem { dearenaized.cache_maximize(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) - }, + } } } @@ -872,7 +881,7 @@ impl RangeElem for Elem { dearenaized.cache_minimize(analyzer)?; analyzer.range_arena_mut().ranges[idx] = dearenaized; Ok(()) - }, + } } } fn uncache(&mut self) { @@ -883,7 +892,7 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.uncache(), Expr(expr) => expr.uncache(), Null => {} - Arena(_idx) => {}, + Arena(_idx) => {} } } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index f34f40e0..6115cb94 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -1,7 +1,7 @@ use crate::{ nodes::ContextVarNode, range::elem::{Elem, RangeExpr, RangeOp}, - GraphBackend, GraphError + GraphBackend, GraphError, }; use shared::NodeIdx; @@ -47,7 +47,7 @@ pub trait RangeElem { /// Tries to compare the ordering of two range elements fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option; /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). - fn range_op(lhs: Elem, rhs: Elem, op: RangeOp, analyzer: &impl GraphBackend) -> Elem + fn range_op(lhs: Elem, rhs: Elem, op: RangeOp, _analyzer: &impl GraphBackend) -> Elem where Self: Sized, { @@ -74,7 +74,12 @@ pub trait RangeElem { /// e.g.: take the basic expression `x + y`, in normal checked solidity math /// both x and y have the requirement `var <= 2**256 - 1 - other_var`, forming a /// cyclic dependency. - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ); fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError>; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 7bb277f6..b888b989 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -1,5 +1,3 @@ -use std::hash::Hash; -use std::hash::Hasher; use crate::{ nodes::{Concrete, ContextVarNode}, range::{ @@ -8,6 +6,8 @@ use crate::{ }, GraphBackend, GraphError, }; +use std::hash::Hash; +use std::hash::Hasher; use ethers_core::types::U256; use shared::NodeIdx; @@ -111,7 +111,7 @@ impl RangeElem for RangeExpr { Ok(()) } - fn range_eq(&self, _other: &Self, analyzer: &impl GraphBackend) -> bool { + fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { false } @@ -137,7 +137,11 @@ impl RangeElem for RangeExpr { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn range_ord(&self, _other: &Self, _analyzer: &impl GraphBackend) -> Option { + fn range_ord( + &self, + _other: &Self, + _analyzer: &impl GraphBackend, + ) -> Option { todo!() } @@ -166,7 +170,12 @@ impl RangeElem for RangeExpr { Ok(lhs_has_cycle || rhs_has_cycle) } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ) { self.lhs.filter_recursion(node_idx, new_idx, analyzer); self.rhs.filter_recursion(node_idx, new_idx, analyzer); } @@ -207,21 +216,18 @@ impl RangeElem for RangeExpr { let r = self.rhs.simplify_maximize(seen_ops, analyzer)?; let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { - MaybeCollapsed::Concretes(..) => { - RangeExpr::new(l, self.op, r).exec_op(true, analyzer) - } + MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(true, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - let res = RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)?; + let res = + RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => { - return expr.exec_op(true, analyzer) - } + MaybeCollapsed::Concretes(..) => return expr.exec_op(true, analyzer), MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), - _ => {}, + _ => {} } Ok(Elem::Expr(expr)) } @@ -243,20 +249,17 @@ impl RangeElem for RangeExpr { let r = self.rhs.simplify_minimize(seen_ops, analyzer)?; let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { - MaybeCollapsed::Concretes(..) => { - RangeExpr::new(l, self.op, r).exec_op(false, analyzer) - } + MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(false, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { - let res = RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)?; + let res = + RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => { - return expr.exec_op(false, analyzer) - } + MaybeCollapsed::Concretes(..) => return expr.exec_op(false, analyzer), MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), - _ => {}, + _ => {} } Ok(Elem::Expr(expr)) } @@ -313,26 +316,17 @@ pub enum MaybeCollapsed<'a, 'b> { Not(&'a Elem, &'b Elem), } -pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b Elem, analyzer: &'c impl GraphBackend) -> MaybeCollapsed<'a, 'b> { +pub fn collapse<'a, 'b, 'c: 'a + 'b>( + l: &'a Elem, + op: RangeOp, + r: &'b Elem, + analyzer: &'c impl GraphBackend, +) -> MaybeCollapsed<'a, 'b> { let zero = Elem::from(Concrete::from(U256::zero())); let one = Elem::from(Concrete::from(U256::one())); match (l, r) { - (Elem::Arena(_), r) => { - collapse( - l.dearenaize(analyzer), - op, - r, - analyzer - ) - } - (l, Elem::Arena(_)) => { - collapse( - l, - op, - r.dearenaize(analyzer), - analyzer - ) - } + (Elem::Arena(_), r) => collapse(l.dearenaize(analyzer), op, r, analyzer), + (l, Elem::Arena(_)) => collapse(l, op, r.dearenaize(analyzer), analyzer), (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { // try to collapse the expression @@ -346,10 +340,22 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b let y_ord_z = y.range_ord(z, analyzer); let y_eq_z = matches!(y_ord_z, Some(std::cmp::Ordering::Equal)); - let y_eq_zero = matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | None); - let x_eq_zero = matches!(x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal) | None); - let y_eq_one = matches!(y.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal) | None); - let x_eq_one = matches!(x.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal) | None); + let y_eq_zero = matches!( + y.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Equal) | None + ); + let x_eq_zero = matches!( + x.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Equal) | None + ); + let y_eq_one = matches!( + y.range_ord(&one, analyzer), + Some(std::cmp::Ordering::Equal) | None + ); + let x_eq_one = matches!( + x.range_ord(&one, analyzer), + Some(std::cmp::Ordering::Equal) | None + ); match (expr.op, op) { (RangeOp::Sub(_), RangeOp::Eq) | (RangeOp::Div(_), RangeOp::Eq) => { if x_eq_z && !y_eq_zero { @@ -467,7 +473,8 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b as RangeSub>::range_sub }; if let Some(new) = op_fn(y, z) { - let new_expr = Elem::Expr(RangeExpr::new(x.clone(), expr.op, new)); + let new_expr = + Elem::Expr(RangeExpr::new(x.clone(), expr.op, new)); MaybeCollapsed::Collapsed(new_expr) } else { MaybeCollapsed::Not(l, r) @@ -507,7 +514,9 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b }; if let Some(new) = op_fn(y, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), expr.op, new, + x.clone(), + expr.op, + new, ))) } else { MaybeCollapsed::Not(l, r) @@ -555,7 +564,9 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b }; if let Some(new) = op_fn(y, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), expr.op, new, + x.clone(), + expr.op, + new, ))) } else { MaybeCollapsed::Not(l, r) @@ -591,7 +602,9 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b }; if let Some(new) = op_fn(x, z) { MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - new, expr.op, y.clone(), + new, + expr.op, + y.clone(), ))) } else { MaybeCollapsed::Not(l, r) @@ -613,9 +626,17 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b as RangeMul>::range_mul }; if let Some(new) = op_fn(x, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + op, + new, + ))) } else if let Some(new) = op_fn(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + op, + new, + ))) } else { MaybeCollapsed::Not(l, r) } @@ -670,23 +691,35 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) if let Some(new) = div_op(z, x) { - let new_op = if matches!(x.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) + let new_op = if matches!( + x.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Less) + ) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), new_op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + new_op, + new, + ))) } else if let Some(new) = div_op(z, y) { - let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) + let new_op = if matches!( + y.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Less) + ) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), new_op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + new_op, + new, + ))) } else { MaybeCollapsed::Not(l, r) } @@ -707,20 +740,30 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b // .. // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) if let Some(new) = mul_op(z, y) { - let new_op = if matches!(y.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Less)) - && FLIP_INEQ_OPS.contains(&op) + let new_op = if matches!( + y.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Less) + ) && FLIP_INEQ_OPS.contains(&op) { op.inverse().unwrap() } else { op }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), new_op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + new_op, + new, + ))) } else if !FLIP_INEQ_OPS.contains(&op) { if let Some(new) = div_op(x, z) { // y is the dynamic element // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially // but we dont know if y was negative. so we limit to just eq & neq - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + op, + new, + ))) } else { MaybeCollapsed::Not(l, r) } @@ -779,7 +822,10 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>(l: &'a Elem, op: RangeOp, r: &'b }, (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => match op { RangeOp::Sub(_) | RangeOp::Add(_) => { - if matches!(c.range_ord(&zero, analyzer), Some(std::cmp::Ordering::Equal)) { + if matches!( + c.range_ord(&zero, analyzer), + Some(std::cmp::Ordering::Equal) + ) { MaybeCollapsed::Collapsed(le.clone()) } else { MaybeCollapsed::Not(l, r) diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index eca94e02..109603c0 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -1,10 +1,10 @@ -use std::hash::Hasher; -use std::hash::Hash; use crate::{ nodes::{Concrete, ContextVarNode}, - range::elem::{Elem, MinMaxed, RangeElem, RangeOp}, + range::elem::{Elem, MinMaxed, RangeElem}, GraphBackend, GraphError, }; +use std::hash::Hash; +use std::hash::Hasher; use shared::NodeIdx; @@ -134,7 +134,7 @@ impl RangeDyn { as_u256 = as_u256.max(max_key); } } - + if as_u256 > usize::MAX.into() { usize::MAX } else { @@ -143,25 +143,24 @@ impl RangeDyn { }; Some( - self.val.values().map(|v| { - v.0.as_bytes(analyzer, maximize) - }) - .collect::>>>()? - .into_iter() - .flatten() - .take(len) - .collect() + self.val + .values() + .map(|v| v.0.as_bytes(analyzer, maximize)) + .collect::>>>()? + .into_iter() + .flatten() + .take(len) + .collect(), ) } pub fn evaled_max_key(&self, analyzer: &impl GraphBackend) -> Option { - let mut evaled = self.val.keys().filter_map(|key| { - key.maximize(analyzer).ok() - }) - .collect::>(); - evaled.sort_by(|a, b| { - a.range_ord(b, analyzer).unwrap_or(std::cmp::Ordering::Less) - }); + let mut evaled = self + .val + .keys() + .filter_map(|key| key.maximize(analyzer).ok()) + .collect::>(); + evaled.sort_by(|a, b| a.range_ord(b, analyzer).unwrap_or(std::cmp::Ordering::Less)); evaled.iter().take(1).next()?.concrete() } @@ -175,18 +174,25 @@ impl RangeElem for RangeDyn { self.cache_minimize(analyzer)?; self.cache_maximize(analyzer)?; self.len.arenaize(analyzer); - self.val = self.val.iter_mut().map(|(k, (v, op))| { - let mut new_k = k.clone(); - let mut new_v = v.clone(); - new_k.arenaize(analyzer); - new_v.arenaize(analyzer); - (new_k, (new_v, *op)) - }).collect(); + self.val = self + .val + .iter_mut() + .map(|(k, (v, op))| { + let mut new_k = k.clone(); + let mut new_v = v.clone(); + new_k.arenaize(analyzer); + new_v.arenaize(analyzer); + (new_k, (new_v, *op)) + }) + .collect(); Ok(()) } fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { - matches!(self.range_ord(other, analyzer), Some(std::cmp::Ordering::Equal)) + matches!( + self.range_ord(other, analyzer), + Some(std::cmp::Ordering::Equal) + ) } fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { @@ -309,35 +315,48 @@ impl RangeElem for RangeDyn { if self.flattened_max.is_none() { self.len.cache_flatten(analyzer)?; let mapping = std::mem::take(&mut self.val); - self.val = mapping.into_iter().map(|(mut idx, mut val)| { - idx.cache_flatten(analyzer).unwrap(); - val.0.cache_flatten(analyzer).unwrap(); - (idx, val) - }).collect(); + self.val = mapping + .into_iter() + .map(|(mut idx, mut val)| { + idx.cache_flatten(analyzer).unwrap(); + val.0.cache_flatten(analyzer).unwrap(); + (idx, val) + }) + .collect(); let flat_max = self.flatten(true, analyzer)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), analyzer)?; + let simplified_flat_max = + flat_max.simplify_maximize(&mut Default::default(), analyzer)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { self.len.cache_flatten(analyzer)?; let mapping = std::mem::take(&mut self.val); - self.val = mapping.into_iter().map(|(mut idx, mut val)| { - idx.cache_flatten(analyzer).unwrap(); - val.0.cache_flatten(analyzer).unwrap(); - (idx, val) - }).collect(); + self.val = mapping + .into_iter() + .map(|(mut idx, mut val)| { + idx.cache_flatten(analyzer).unwrap(); + val.0.cache_flatten(analyzer).unwrap(); + (idx, val) + }) + .collect(); let flat_min = self.flatten(false, analyzer)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), analyzer)?; + let simplified_flat_min = + flat_min.simplify_minimize(&mut Default::default(), analyzer)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) } - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn filter_recursion(&mut self, node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ) { self.len.filter_recursion(node_idx, new_idx, analyzer); self.val = self .val @@ -459,11 +478,14 @@ impl RangeElem for RangeDyn { if self.maximized.is_none() { self.len.cache_maximize(g)?; let mapping = std::mem::take(&mut self.val); - self.val = mapping.into_iter().map(|(mut idx, mut val)| { - idx.cache_maximize(g).unwrap(); - val.0.cache_maximize(g).unwrap(); - (idx, val) - }).collect(); + self.val = mapping + .into_iter() + .map(|(mut idx, mut val)| { + idx.cache_maximize(g).unwrap(); + val.0.cache_maximize(g).unwrap(); + (idx, val) + }) + .collect(); self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); } Ok(()) @@ -473,11 +495,14 @@ impl RangeElem for RangeDyn { if self.minimized.is_none() { self.len.cache_minimize(g)?; let mapping = std::mem::take(&mut self.val); - self.val = mapping.into_iter().map(|(mut idx, mut val)| { - idx.cache_minimize(g).unwrap(); - val.0.cache_minimize(g).unwrap(); - (idx, val) - }).collect(); + self.val = mapping + .into_iter() + .map(|(mut idx, mut val)| { + idx.cache_minimize(g).unwrap(); + val.0.cache_minimize(g).unwrap(); + (idx, val) + }) + .collect(); self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); } Ok(()) diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 3020e0cb..8031b805 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -1,13 +1,13 @@ -use std::hash::Hash; -use std::hash::Hasher; use crate::{ nodes::{Concrete, ContextVarNode}, range::{ - elem::{Elem, MinMaxed, RangeConcrete, RangeElem, RangeOp}, + elem::{Elem, MinMaxed, RangeConcrete, RangeElem}, Range, }, GraphBackend, GraphError, TypeNode, VarType, }; +use std::hash::Hash; +use std::hash::Hasher; use shared::NodeIdx; @@ -51,7 +51,9 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } + fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + Ok(()) + } fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { false diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 5bacf429..7e03162f 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -264,8 +264,14 @@ impl ExecOp for RangeExpr { let rhs_max_neg = rhs_max.pre_evaled_is_negative(); let consts = ( - matches!(lhs_min.range_ord(&lhs_max, analyzer), Some(std::cmp::Ordering::Equal)), - matches!(rhs_min.range_ord(&rhs_max, analyzer), Some(std::cmp::Ordering::Equal)), + matches!( + lhs_min.range_ord(&lhs_max, analyzer), + Some(std::cmp::Ordering::Equal) + ), + matches!( + rhs_min.range_ord(&rhs_max, analyzer), + Some(std::cmp::Ordering::Equal) + ), ); fn fallback( @@ -285,7 +291,7 @@ impl ExecOp for RangeExpr { let res = match self.op { RangeOp::GetLength => { if maximize { - let mut new = lhs_max.clone(); + let new = lhs_max.clone(); let new_max = new.simplify_minimize(&mut Default::default(), analyzer)?; let res = new_max.range_get_length(); res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) @@ -619,8 +625,10 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (rhs_min.range_ord(&one, analyzer), rhs_max.range_ord(&one, analyzer)) - { + ) = ( + rhs_min.range_ord(&one, analyzer), + rhs_max.range_ord(&one, analyzer), + ) { candidates.push(Some(lhs_max.clone())); candidates.push(Some(lhs_min.clone())); } @@ -629,8 +637,10 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (lhs_min.range_ord(&one, analyzer), lhs_max.range_ord(&one, analyzer)) - { + ) = ( + lhs_min.range_ord(&one, analyzer), + lhs_max.range_ord(&one, analyzer), + ) { candidates.push(Some(rhs_max.clone())); candidates.push(Some(rhs_min.clone())); } @@ -663,16 +673,20 @@ impl ExecOp for RangeExpr { if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (rhs_min.range_ord(&zero, analyzer), rhs_max.range_ord(&zero, analyzer)) - { + ) = ( + rhs_min.range_ord(&zero, analyzer), + rhs_max.range_ord(&zero, analyzer), + ) { candidates.push(Some(zero.clone())); } // check if lhs contains zero if let ( Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = (lhs_min.range_ord(&zero, analyzer), lhs_max.range_ord(&zero, analyzer)) - { + ) = ( + lhs_min.range_ord(&zero, analyzer), + lhs_max.range_ord(&zero, analyzer), + ) { candidates.push(Some(zero.clone())); } candidates.extend(vec![ @@ -1229,7 +1243,10 @@ impl ExecOp for RangeExpr { // true is the maximum is when they are both consts and equal if matches!(consts, (true, true)) { // both are consts, check if they are equal - if matches!(lhs_min.range_ord(&rhs_min, analyzer), Some(std::cmp::Ordering::Equal)) { + if matches!( + lhs_min.range_ord(&rhs_min, analyzer), + Some(std::cmp::Ordering::Equal) + ) { return Ok(Elem::Concrete(RangeConcrete { val: Concrete::Bool(false), loc, diff --git a/crates/graph/src/range/exec/modulo.rs b/crates/graph/src/range/exec/modulo.rs index c81039dc..7e8a8eea 100644 --- a/crates/graph/src/range/exec/modulo.rs +++ b/crates/graph/src/range/exec/modulo.rs @@ -6,10 +6,12 @@ use ethers_core::types::I256; impl RangeMod for RangeConcrete { fn range_mod(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) if rhs_val != 0.into() => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val % rhs_val), - loc: self.loc, - })), + (Some(lhs_val), Some(rhs_val)) if rhs_val != 0.into() => { + Some(Elem::Concrete(RangeConcrete { + val: self.val.u256_as_original(lhs_val % rhs_val), + loc: self.loc, + })) + } _ => match (&self.val, &other.val) { (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { Some(Elem::Concrete(RangeConcrete { diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 2daf2db3..162d57ed 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -71,7 +71,9 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - Elem::Arena(_) => self.dearenaize(analyzer).to_range_string(maximize, analyzer), + Elem::Arena(_) => self + .dearenaize(analyzer) + .to_range_string(maximize, analyzer), } } } diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index fe7dd8da..b1a9c2a2 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -60,9 +60,19 @@ pub trait Range { where Self: std::marker::Sized; /// Replace a potential recursion causing node index with a new index - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); + fn filter_min_recursion( + &mut self, + self_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ); /// Replace a potential recursion causing node index with a new index - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend); + fn filter_max_recursion( + &mut self, + self_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ); /// Cache the flattened range fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 5983c2d6..4cdf919d 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -1,5 +1,5 @@ use crate::{ - nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, + nodes::{Builtin, Concrete, ContextVarNode}, range::{elem::*, range_string::*, Range, RangeEval}, AsDotStr, GraphBackend, GraphError, }; @@ -635,10 +635,20 @@ impl Range for SolcRange { fn set_range_exclusions(&mut self, new: Vec) { self.exclusions = new; } - fn filter_min_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { + fn filter_min_recursion( + &mut self, + self_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ) { self.min.filter_recursion(self_idx, new_idx, analyzer); } - fn filter_max_recursion(&mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend) { + fn filter_max_recursion( + &mut self, + self_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + ) { self.max.filter_recursion(self_idx, new_idx, analyzer); } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index d6a40d69..ecccde7a 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -242,11 +242,14 @@ impl Atomize for Elem { Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), Elem::Expr(expr) => { // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); - match (expr.lhs.atoms_or_part(analyzer), expr.rhs.atoms_or_part(analyzer)) { + match ( + expr.lhs.atoms_or_part(analyzer), + expr.rhs.atoms_or_part(analyzer), + ) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { match (l, r) { (_, Elem::Arena(_)) => todo!(), - (Elem::Arena(_),_) => todo!(), + (Elem::Arena(_), _) => todo!(), (Elem::Reference(Reference { .. }), Elem::Concrete(_)) | (Elem::Concrete(_), Elem::Reference(Reference { .. })) => { let ty = OpType::new(expr.op); @@ -292,9 +295,10 @@ impl Atomize for Elem { (Elem::Concrete(_), Elem::Expr(_)) => { todo!("here4"); } - (Elem::Concrete(_), Elem::Concrete(_)) => { - expr.exec_op(true, analyzer).unwrap().atoms_or_part(analyzer) - } + (Elem::Concrete(_), Elem::Concrete(_)) => expr + .exec_op(true, analyzer) + .unwrap() + .atoms_or_part(analyzer), (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), (Elem::Null, _) => AtomOrPart::Part(Elem::Null), diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index a3c8238f..9ff19707 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -190,7 +190,12 @@ impl DLSolver { .all(|constraint| constraint.ty == OpType::DL) }) }) - .map(|constraint| (constraint.clone(), Self::dl_atom_normalize(constraint, analyzer))) + .map(|constraint| { + ( + constraint.clone(), + Self::dl_atom_normalize(constraint, analyzer), + ) + }) .collect::>>>() } @@ -508,7 +513,10 @@ impl DLSolver { /// Normalizes a DL atom into x <= y - k, where x and y are variables and k is a constant. /// Needed for running negative cycle check. Additionally, if we have an `OR`, we - pub fn dl_atom_normalize(constraint: SolverAtom, analyzer: &impl GraphBackend,) -> Vec> { + pub fn dl_atom_normalize( + constraint: SolverAtom, + analyzer: &impl GraphBackend, + ) -> Vec> { // println!("normalizing: {}", constraint.into_expr_elem()); let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); let false_part = AtomOrPart::Part(Elem::from(Concrete::from(false))); @@ -539,65 +547,79 @@ impl DLSolver { match constraint.op { RangeOp::Eq => { // convert `x == y` into `x <= y - 0 || y <= x - 0` - let mut res = Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: constraint.lhs.clone(), - op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + let mut res = Self::dl_atom_normalize( + SolverAtom { ty: OpType::DL, - lhs: constraint.rhs.clone(), - op: RangeOp::Sub(true), - rhs: Box::new(zero_part.clone()), - })), - }, analyzer); - - assert!(res.len() == 1); - res[0].extend( - Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs, + lhs: constraint.lhs.clone(), op: RangeOp::Lte, rhs: Box::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, - lhs: constraint.lhs, + lhs: constraint.rhs.clone(), op: RangeOp::Sub(true), rhs: Box::new(zero_part.clone()), })), - }, analyzer) + }, + analyzer, + ); + + assert!(res.len() == 1); + res[0].extend( + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Sub(true), + rhs: Box::new(zero_part.clone()), + })), + }, + analyzer, + ) .remove(0), ); res } RangeOp::Neq => { // convert `x != y` into `x <= y - 1 || y <= x - 1` - let mut res = Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: constraint.lhs.clone(), - op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs.clone(), - op: RangeOp::Sub(true), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::from(1))))), - })), - }, analyzer); - - assert!(res.len() == 1); - - res[0].extend( - Self::dl_atom_normalize(SolverAtom { + let mut res = Self::dl_atom_normalize( + SolverAtom { ty: OpType::DL, - lhs: constraint.rhs, + lhs: constraint.lhs.clone(), op: RangeOp::Lte, rhs: Box::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, - lhs: constraint.lhs, + lhs: constraint.rhs.clone(), op: RangeOp::Sub(true), rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( U256::from(1), )))), })), - }, analyzer) + }, + analyzer, + ); + + assert!(res.len() == 1); + + res[0].extend( + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Sub(true), + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + U256::from(1), + )))), + })), + }, + analyzer, + ) .remove(0), ); res @@ -615,14 +637,17 @@ impl DLSolver { .atomize(analyzer) .expect("unable to atomize?"), ); - Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: Box::new(new_lhs), - op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( - I256::from(-1), - )))), - }, analyzer) + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + I256::from(-1), + )))), + }, + analyzer, + ) } (true, false) => { let new_lhs = AtomOrPart::Atom( @@ -634,12 +659,15 @@ impl DLSolver { .expect("unable to atomize?"), ); - Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: Box::new(new_lhs), - op: RangeOp::Lte, - rhs: constraint.rhs, - }, analyzer) + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: constraint.rhs, + }, + analyzer, + ) } (false, true) => { let new_lhs = AtomOrPart::Atom( @@ -648,12 +676,15 @@ impl DLSolver { .atomize(analyzer) .expect("unable to atomize?"), ); - Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: Box::new(new_lhs), - op: RangeOp::Lte, - rhs: constraint.lhs, - }, analyzer) + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: Box::new(new_lhs), + op: RangeOp::Lte, + rhs: constraint.lhs, + }, + analyzer, + ) } _ => panic!("here"), } @@ -672,64 +703,79 @@ impl DLSolver { // (k - x <= y) // ==> (-k + x >= y) // ==> (y <= x - k) - Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: constraint.rhs, - op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + Self::dl_atom_normalize( + SolverAtom { ty: constraint.ty, - lhs: lhs_atom.rhs, - op: RangeOp::Sub(true), - rhs: Box::new(*lhs_atom.lhs), - })), - }, analyzer) + lhs: constraint.rhs, + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: lhs_atom.rhs, + op: RangeOp::Sub(true), + rhs: Box::new(*lhs_atom.lhs), + })), + }, + analyzer, + ) } _ => { // (x - k <= y) // ==> (x <= y + k) - Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), - op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + Self::dl_atom_normalize( + SolverAtom { ty: constraint.ty, - lhs: constraint.rhs, - op: RangeOp::Add(true), - rhs: Box::new(*lhs_atom.rhs), - })), - }, analyzer) + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Add(true), + rhs: Box::new(*lhs_atom.rhs), + })), + }, + analyzer, + ) } } } RangeOp::Add(_) => { // (k + x <= y) || (x + k <= y) // ==> (x <= y - k) - Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), - op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + Self::dl_atom_normalize( + SolverAtom { ty: constraint.ty, - lhs: constraint.rhs, - op: RangeOp::Sub(true), - rhs: Box::new(*lhs_atom.rhs), - })), - }, analyzer) + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: Box::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: Box::new(*lhs_atom.rhs), + })), + }, + analyzer, + ) } RangeOp::And => { - let mut res = Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), - op: constraint.op, - rhs: constraint.rhs.clone(), - }, analyzer); - - let mut rhs = Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: Box::new(*lhs_atom.rhs), - op: constraint.op, - rhs: constraint.rhs.clone(), - }, analyzer); + let mut res = Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.lhs), + op: constraint.op, + rhs: constraint.rhs.clone(), + }, + analyzer, + ); + + let mut rhs = Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: Box::new(*lhs_atom.rhs), + op: constraint.op, + rhs: constraint.rhs.clone(), + }, + analyzer, + ); match (res.len() > 1, rhs.len() > 1) { (true, true) => { res.extend(rhs); @@ -792,31 +838,43 @@ impl DLSolver { rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), }); - Self::dl_atom_normalize(SolverAtom { - ty: constraint.ty, - lhs: constraint.lhs, - op: constraint.op, - rhs: Box::new(new_rhs), - }, analyzer) + Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: constraint.lhs, + op: constraint.op, + rhs: Box::new(new_rhs), + }, + analyzer, + ) } else { vec![vec![constraint]] } } - RangeOp::Gte => Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs, - op: RangeOp::Lte, - rhs: constraint.lhs, - }, analyzer), - RangeOp::Gt => Self::dl_atom_normalize(SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs, - op: RangeOp::Lt, - rhs: constraint.lhs, - }, analyzer), + RangeOp::Gte => Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: constraint.lhs, + }, + analyzer, + ), + RangeOp::Gt => Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lt, + rhs: constraint.lhs, + }, + analyzer, + ), RangeOp::Or => { let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); - res.extend(Self::dl_atom_normalize(constraint.rhs.as_solver_atom(), analyzer)); + res.extend(Self::dl_atom_normalize( + constraint.rhs.as_solver_atom(), + analyzer, + )); res } _other => { diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 559ba485..29b8e3ac 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -1,6 +1,6 @@ +use crate::builtin_fns; use graph::elem::Elem; use shared::RangeArena; -use crate::builtin_fns; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; @@ -157,11 +157,14 @@ impl Default for Analyzer { max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), debug_panic: false, - range_arena: RangeArena { ranges: vec![Elem::Null], map: { - let mut map: HashMap, usize> = Default::default(); - map.insert(Elem::Null, 0); - map - } } + range_arena: RangeArena { + ranges: vec![Elem::Null], + map: { + let mut map: HashMap, usize> = Default::default(); + map.insert(Elem::Null, 0); + map + }, + }, }; a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); @@ -198,73 +201,118 @@ impl Analyzer { format!(" Analyzer stats"), format!("====================================="), format!(""), - format!(" Number of nodes: {}, {} nodes/ms", num_nodes, num_nodes as f64 / duration.as_millis() as f64), - format!(" Number of Contracts: {}, {} contracts/ms", num_contracts, num_contracts as f64 / duration.as_millis() as f64), - format!(" Number of Functions: {}, {} functions/ms", num_funcs, num_funcs as f64 / duration.as_millis() as f64), - format!(" Number of Variables: {}, {} variables/ms", num_vars, num_vars as f64 / duration.as_millis() as f64), + format!( + " Number of nodes: {}, {} nodes/ms", + num_nodes, + num_nodes as f64 / duration.as_millis() as f64 + ), + format!( + " Number of Contracts: {}, {} contracts/ms", + num_contracts, + num_contracts as f64 / duration.as_millis() as f64 + ), + format!( + " Number of Functions: {}, {} functions/ms", + num_funcs, + num_funcs as f64 / duration.as_millis() as f64 + ), + format!( + " Number of Variables: {}, {} variables/ms", + num_vars, + num_vars as f64 / duration.as_millis() as f64 + ), format!(""), - format!(" Unique Range Elements: {}", self.range_arena.ranges.len()), + format!( + " Unique Range Elements: {}", + self.range_arena.ranges.len() + ), format!(""), - format!(" Number of Contexts: {}, {} contexts/ms", num_contexts, num_contexts as f64 / duration.as_millis() as f64), + format!( + " Number of Contexts: {}, {} contexts/ms", + num_contexts, + num_contexts as f64 / duration.as_millis() as f64 + ), format!(" Max depth of Contexts: {}", self.max_context_depth()), format!(" Max width of Contexts: {}", self.max_context_width()), format!(""), format!("====================================="), - ].join("\n") + ] + .join("\n") } pub fn number_of_contexts(&self) -> usize { - self.graph.node_weights().filter(|n| matches!(n, Node::Context(_))).count() + self.graph + .node_weights() + .filter(|n| matches!(n, Node::Context(_))) + .count() } pub fn number_of_forks(&self) -> usize { - self.graph.node_weights().filter(|n| matches!(n, Node::ContextFork)).count() + self.graph + .node_weights() + .filter(|n| matches!(n, Node::ContextFork)) + .count() } pub fn number_of_variables(&self) -> usize { - self.graph.node_weights().filter(|n| matches!(n, Node::ContextVar(_))).count() + self.graph + .node_weights() + .filter(|n| matches!(n, Node::ContextVar(_))) + .count() } pub fn number_of_functions(&self) -> usize { - self.graph.node_weights().filter(|n| matches!(n, Node::Function(_))).count() + self.graph + .node_weights() + .filter(|n| matches!(n, Node::Function(_))) + .count() } pub fn number_of_contracts(&self) -> usize { - self.graph.node_weights().filter(|n| matches!(n, Node::Contract(_))).count() + self.graph + .node_weights() + .filter(|n| matches!(n, Node::Contract(_))) + .count() } pub fn max_context_depth(&self) -> usize { - self.graph.node_weights().filter_map(|n| { - if let Node::Context(c) = n { - Some(c) - } else { - None - } - }).fold(0, |mut acc, c| { - if c.depth > acc { - acc = c.depth; - acc - } else { - acc - } - }) + self.graph + .node_weights() + .filter_map(|n| { + if let Node::Context(c) = n { + Some(c) + } else { + None + } + }) + .fold(0, |mut acc, c| { + if c.depth > acc { + acc = c.depth; + acc + } else { + acc + } + }) } pub fn max_context_width(&self) -> usize { - self.graph.node_weights().filter_map(|n| { - if let Node::Context(c) = n { - Some(c) - } else { - None - } - }).fold(0, |mut acc, c| { - if c.width > acc { - acc = c.width; - acc - } else { - acc - } - }) + self.graph + .node_weights() + .filter_map(|n| { + if let Node::Context(c) = n { + Some(c) + } else { + None + } + }) + .fold(0, |mut acc, c| { + if c.width > acc { + acc = c.width; + acc + } else { + acc + } + }) } pub fn complicated_parse( diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index cd3d554b..5e1d2c27 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,7 +1,7 @@ -use shared::RangeArena; -use graph::nodes::Concrete; -use graph::elem::Elem; use crate::Analyzer; +use graph::elem::Elem; +use graph::nodes::Concrete; +use shared::RangeArena; use graph::{ as_dot_str, nodes::ContextNode, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, diff --git a/crates/shared/src/gas.rs b/crates/shared/src/gas.rs index 62fe1204..14391644 100644 --- a/crates/shared/src/gas.rs +++ b/crates/shared/src/gas.rs @@ -9,4 +9,4 @@ pub const EXT_FUNC_CALL_GAS: u64 = 100; /// Read a storage variable gas cost pub const SLOAD_GAS: u64 = 10; /// Set a storage variable gas cost -pub const SSTORE_GAS: u64 = 10; \ No newline at end of file +pub const SSTORE_GAS: u64 = 10; diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 5e3f2976..3b000e41 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,7 +1,7 @@ -use std::hash::Hash; -use std::collections::HashMap; use crate::AnalyzerLike; use crate::Heirarchical; +use std::collections::HashMap; +use std::hash::Hash; use petgraph::{ graph::{EdgeIndex, Graph, NodeIndex}, diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index bb8f2765..eb85d13c 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -1,7 +1,7 @@ mod analyzer_like; +pub mod gas; mod graph_like; mod search; -pub mod gas; pub use analyzer_like::*; pub use graph_like::*; diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 9915c288..39a719b6 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -28,7 +28,8 @@ pub trait BinOp: AnalyzerBackend + Sized { op: RangeOp, assign: bool, ) -> Result<(), ExprErr> { - ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(loc)?; + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) + .into_expr_err(loc)?; self.parse_ctx_expr(rhs_expr, ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -378,11 +379,16 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { - self.advance_var_in_ctx_forcible(tmp_lhs.latest_version(self), loc, ctx, true)? + self.advance_var_in_ctx_forcible( + tmp_lhs.latest_version(self), + loc, + ctx, + true, + )? } else { tmp_lhs }; - + if self .require( tmp_lhs, @@ -441,7 +447,12 @@ pub trait BinOp: AnalyzerBackend + Sized { let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { - self.advance_var_in_ctx_forcible(tmp_lhs.latest_version(self), loc, ctx, true)? + self.advance_var_in_ctx_forcible( + tmp_lhs.latest_version(self), + loc, + ctx, + true, + )? } else { tmp_lhs }; diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 4eeef180..d3bc7140 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -3,8 +3,7 @@ use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ elem::*, nodes::{ - BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, - TmpConstruction, + BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TmpConstruction, }, AnalyzerBackend, GraphError, Node, Range, SolcRange, VarType, }; @@ -45,8 +44,12 @@ pub trait Cmp: AnalyzerBackend + Sized { ExprRet::Single(lhs) | ExprRet::SingleLiteral(lhs) => { let lhs_cvar = ContextVarNode::from(lhs); tracing::trace!("not: {}", lhs_cvar.display_name(self).into_expr_err(loc)?); - - let mut elem = Elem::Expr(RangeExpr::new(Elem::from(lhs_cvar), RangeOp::Not, Elem::Null)); + + let mut elem = Elem::Expr(RangeExpr::new( + Elem::from(lhs_cvar), + RangeOp::Not, + Elem::Null, + )); elem.arenaize(self); let mut range = SolcRange::new(elem.clone(), elem, vec![]); diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index b9e3807e..15164aa5 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -59,7 +59,9 @@ pub trait ExpressionParser: // ); match expr { // literals - NumberLiteral(loc, int, exp, unit) => self.number_literal(ctx, *loc, int, exp, false, unit), + NumberLiteral(loc, int, exp, unit) => { + self.number_literal(ctx, *loc, int, exp, false, unit) + } AddressLiteral(loc, addr) => self.address_literal(ctx, *loc, addr), StringLiteral(lits) => lits .iter() @@ -281,7 +283,7 @@ pub trait ExpressionParser: } FunctionCall(loc, func_expr, input_exprs) => { let updated_func_expr = match **func_expr { - FunctionCallBlock(_loc, ref inner_func_expr, ref call_block) => { + FunctionCallBlock(_loc, ref inner_func_expr, ref _call_block) => { // we dont currently handle the `{value: .. gas: ..}` msg updating // println!("call block: {call_block:#?}"); @@ -301,14 +303,9 @@ pub trait ExpressionParser: match &**expr { Expression::FunctionCall(_loc, func, inputs) => { // parse the type - self.new_call( - loc, - func, - inputs, - ctx - ) - }, - _ => panic!("Bad new call") + self.new_call(loc, func, inputs, ctx) + } + _ => panic!("Bad new call"), } } This(loc) => { diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 8bee98f6..cba2736b 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -20,13 +20,15 @@ pub trait Env: AnalyzerBackend + Sized { ) -> Result, ExprErr> { match &*ident.name { "msg" | "tx" => { - ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(ident.loc)?; + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) + .into_expr_err(ident.loc)?; ctx.push_expr(ExprRet::Single(self.msg().into()), self) .into_expr_err(ident.loc)?; Ok(Some(())) } "block" => { - ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(ident.loc)?; + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) + .into_expr_err(ident.loc)?; ctx.push_expr(ExprRet::Single(self.block().into()), self) .into_expr_err(ident.loc)?; Ok(Some(())) @@ -40,7 +42,8 @@ pub trait Env: AnalyzerBackend + Sized { .modifier_state .clone() { - ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS).into_expr_err(ident.loc)?; + ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS) + .into_expr_err(ident.loc)?; self.resume_from_modifier(ctx, mod_state.clone())?; self.modifier_inherit_return(ctx, mod_state.parent_ctx); Ok(Some(())) diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 08ebced6..9f1e1abb 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,12 +1,12 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. -use std::rc::Rc; -use std::cell::RefCell; use crate::{ func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, StatementParser, }; +use std::cell::RefCell; +use std::rc::Rc; use graph::{ nodes::{ @@ -21,25 +21,24 @@ use solang_parser::pt::{Expression, Loc, NamedArgument}; use std::collections::BTreeMap; - #[derive(Debug)] pub enum NamedOrUnnamedArgs<'a> { Named(&'a [NamedArgument]), - Unnamed(&'a [Expression]) + Unnamed(&'a [Expression]), } impl<'a> NamedOrUnnamedArgs<'a> { pub fn named_args(&self) -> Option<&'a [NamedArgument]> { match self { NamedOrUnnamedArgs::Named(inner) => Some(inner), - _ => None + _ => None, } } pub fn unnamed_args(&self) -> Option<&'a [Expression]> { match self { NamedOrUnnamedArgs::Unnamed(inner) => Some(inner), - _ => None + _ => None, } } @@ -64,7 +63,14 @@ impl<'a> NamedOrUnnamedArgs<'a> { } } - pub fn parse(&self, analyzer: &mut (impl AnalyzerBackend + Sized + GraphBackend), ctx: ContextNode, loc: Loc) -> Result<(), ExprErr> { + pub fn parse( + &self, + analyzer: &mut (impl AnalyzerBackend + + Sized + + GraphBackend), + ctx: ContextNode, + loc: Loc, + ) -> Result<(), ExprErr> { match self { NamedOrUnnamedArgs::Unnamed(inner) => analyzer.parse_inputs(ctx, loc, inner), NamedOrUnnamedArgs::Named(inner) => { @@ -86,11 +92,19 @@ impl<'a> NamedOrUnnamedArgs<'a> { } else { Ok(()) } - }, + } } } - pub fn parse_n(&self, n: usize, analyzer: &mut (impl AnalyzerBackend + Sized + GraphBackend), ctx: ContextNode, loc: Loc) -> Result<(), ExprErr> { + pub fn parse_n( + &self, + n: usize, + analyzer: &mut (impl AnalyzerBackend + + Sized + + GraphBackend), + ctx: ContextNode, + loc: Loc, + ) -> Result<(), ExprErr> { let append = Rc::new(RefCell::new(false)); match self { NamedOrUnnamedArgs::Unnamed(inner) => { @@ -111,7 +125,7 @@ impl<'a> NamedOrUnnamedArgs<'a> { } else { Ok(()) } - }, + } NamedOrUnnamedArgs::Named(inner) => { inner.iter().take(n).try_for_each(|arg| { analyzer.parse_input(ctx, loc, &arg.expr, &append)?; @@ -130,7 +144,7 @@ impl<'a> NamedOrUnnamedArgs<'a> { } else { Ok(()) } - }, + } } } @@ -140,19 +154,23 @@ impl<'a> NamedOrUnnamedArgs<'a> { } else { match self { NamedOrUnnamedArgs::Unnamed(_inner) => inputs, - NamedOrUnnamedArgs::Named(inner) => { - ExprRet::Multi(ordered_params.iter().map(|param| { - let index = inner.iter().enumerate().find(|(_i, arg)| { - &arg.name.name == param - }).unwrap().0; - match &inputs { - ExprRet::Multi(inner) => { - inner[index].clone() + NamedOrUnnamedArgs::Named(inner) => ExprRet::Multi( + ordered_params + .iter() + .map(|param| { + let index = inner + .iter() + .enumerate() + .find(|(_i, arg)| &arg.name.name == param) + .unwrap() + .0; + match &inputs { + ExprRet::Multi(inner) => inner[index].clone(), + _ => panic!("Mismatched ExprRet type"), } - _ => panic!("Mismatched ExprRet type") - } - }).collect()) - }, + }) + .collect(), + ), } } } @@ -177,9 +195,13 @@ pub trait FuncCaller: ) -> Result<(), ExprErr> { use solang_parser::pt::Expression::*; match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_func(ctx, loc, member_expr, ident, NamedOrUnnamedArgs::Named(input_exprs)) - } + MemberAccess(loc, member_expr, ident) => self.call_name_spaced_func( + ctx, + loc, + member_expr, + ident, + NamedOrUnnamedArgs::Named(input_exprs), + ), Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), e => Err(ExprErr::IntrinsicNamedArgs( *loc, @@ -198,10 +220,20 @@ pub trait FuncCaller: ) -> Result<(), ExprErr> { use solang_parser::pt::Expression::*; match func_expr { - MemberAccess(loc, member_expr, ident) => { - self.call_name_spaced_func(ctx, loc, member_expr, ident, NamedOrUnnamedArgs::Unnamed(input_exprs)) - } - Variable(ident) => self.call_internal_func(ctx, loc, ident, func_expr, NamedOrUnnamedArgs::Unnamed(input_exprs)), + MemberAccess(loc, member_expr, ident) => self.call_name_spaced_func( + ctx, + loc, + member_expr, + ident, + NamedOrUnnamedArgs::Unnamed(input_exprs), + ), + Variable(ident) => self.call_internal_func( + ctx, + loc, + ident, + func_expr, + NamedOrUnnamedArgs::Unnamed(input_exprs), + ), _ => { self.parse_ctx_expr(func_expr, ctx)?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { @@ -215,7 +247,12 @@ pub trait FuncCaller: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_intrinsic_fallback(ctx, &loc, &NamedOrUnnamedArgs::Unnamed(input_exprs), ret) + analyzer.match_intrinsic_fallback( + ctx, + &loc, + &NamedOrUnnamedArgs::Unnamed(input_exprs), + ret, + ) }) } } @@ -465,12 +502,17 @@ pub trait FuncCaller: // parse the function body self.parse_ctx_statement(&body, false, Some(callee_ctx)); - if let Some(mod_state) = &callee_ctx.underlying(self).into_expr_err(loc)?.modifier_state.clone() { + if let Some(mod_state) = &callee_ctx + .underlying(self) + .into_expr_err(loc)? + .modifier_state + .clone() + { if mod_state.num == 0 { - return self.ctx_rets(loc, mod_state.parent_caller_ctx, callee_ctx) + return self.ctx_rets(loc, mod_state.parent_caller_ctx, callee_ctx); } } - + if callee_ctx != caller_ctx { self.ctx_rets(loc, caller_ctx, callee_ctx) } else { @@ -493,7 +535,9 @@ pub trait FuncCaller: ) .unwrap(); let ret_subctx = ContextNode::from(self.add_node(Node::Context(ret_ctx))); - ret_subctx.set_continuation_ctx(self, caller_ctx, "execute_call_inner").into_expr_err(loc)?; + ret_subctx + .set_continuation_ctx(self, caller_ctx, "execute_call_inner") + .into_expr_err(loc)?; let res = callee_ctx .set_child_call(ret_subctx, self) diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 0cb90915..36c29abe 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -13,7 +13,7 @@ use graph::{ }; use shared::{NodeIdx, StorageLocation}; -use solang_parser::pt::{Expression, Loc, CodeLocation}; +use solang_parser::pt::{CodeLocation, Expression, Loc}; use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; @@ -84,11 +84,18 @@ pub trait CallerHelper: AnalyzerBackend + r.range_min().into_owned().cast(r2.range_min().into_owned()); let new_max = r.range_max().into_owned().cast(r2.range_max().into_owned()); - let res = node.latest_version(self).try_set_range_min(self, new_min).into_expr_err(loc); + let res = node + .latest_version(self) + .try_set_range_min(self, new_min) + .into_expr_err(loc); self.add_if_err(res); - let res = node.latest_version(self).try_set_range_max(self, new_max).into_expr_err(loc); + let res = node + .latest_version(self) + .try_set_range_max(self, new_max) + .into_expr_err(loc); self.add_if_err(res); - let res = node.latest_version(self) + let res = node + .latest_version(self) .try_set_range_exclusions(self, r.exclusions) .into_expr_err(loc); self.add_if_err(res); @@ -120,9 +127,9 @@ pub trait CallerHelper: AnalyzerBackend + Rc::new(RefCell::new(false)) }; - inputs.iter().try_for_each(|input| { - self.parse_input(ctx, loc, input, &append) - })?; + inputs + .iter() + .try_for_each(|input| self.parse_input(ctx, loc, input, &append))?; if !inputs.is_empty() { self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { @@ -177,9 +184,13 @@ pub trait CallerHelper: AnalyzerBackend + ) -> Result { let fn_ext = curr_ctx.is_fn_ext(func_node, self).into_expr_err(loc)?; if fn_ext { - curr_ctx.add_gas_cost(self, shared::gas::EXT_FUNC_CALL_GAS).into_expr_err(loc)?; + curr_ctx + .add_gas_cost(self, shared::gas::EXT_FUNC_CALL_GAS) + .into_expr_err(loc)?; } else { - curr_ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS).into_expr_err(loc)?; + curr_ctx + .add_gas_cost(self, shared::gas::FUNC_CALL_GAS) + .into_expr_err(loc)?; } let ctx = Context::new_subctx( curr_ctx, @@ -305,7 +316,7 @@ pub trait CallerHelper: AnalyzerBackend + .add_return_node(*loc, cvar, self) .into_expr_err(*loc)?; self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); - + Ok(()) })?; } diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 13d1dc66..48b58f39 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -215,7 +215,8 @@ pub trait InternalFuncCaller: false } else if matches!(input_exprs, NamedOrUnnamedArgs::Named(_)) { params.iter().all(|param| { - input_exprs.named_args() + input_exprs + .named_args() .unwrap() .iter() .any(|input| input.name.name == param.name(self).unwrap()) @@ -253,7 +254,9 @@ pub trait InternalFuncCaller: .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? .unwrap_or_else(|| ExprRet::Multi(vec![])); - inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + inputs = if let Some(ordered_param_names) = + possible_funcs[0].maybe_ordered_param_names(analyzer) + { input_exprs.order(inputs, ordered_param_names) } else { inputs diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 4e42561b..80eaee23 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -33,20 +33,11 @@ pub trait AbiCaller: AnalyzerBackend + Siz match ret { ExprRet::Single(ty) => match analyzer.node(ty) { Node::Builtin(_) => { - let var = ContextVar::new_from_builtin( - *loc, - ty.into(), - analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) + let var = ContextVar::new_from_builtin(*loc, ty.into(), analyzer) .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) @@ -54,70 +45,44 @@ pub trait AbiCaller: AnalyzerBackend + Siz Node::ContextVar(cvar) => { let bn = analyzer .builtin_or_add( - cvar.ty - .as_builtin(analyzer) - .into_expr_err(*loc)?, + cvar.ty.as_builtin(analyzer).into_expr_err(*loc)?, ) .into(); - let var = - ContextVar::new_from_builtin(*loc, bn, analyzer) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) + let var = ContextVar::new_from_builtin(*loc, bn, analyzer) .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) } Node::Struct(_) => { - let var = ContextVar::new_from_struct( - *loc, - ty.into(), - ctx, - analyzer, - ) - .into_expr_err(*loc)?; + let var = + ContextVar::new_from_struct(*loc, ty.into(), ctx, analyzer) + .into_expr_err(*loc)?; let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) - .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) } Node::Contract(_) => { - let var = ContextVar::new_from_contract( - *loc, - ty.into(), - analyzer, - ) - .into_expr_err(*loc)?; - let node = analyzer.add_node(Node::ContextVar(var)); - ctx.add_var(node.into(), analyzer) + let var = ContextVar::new_from_contract(*loc, ty.into(), analyzer) .into_expr_err(*loc)?; - analyzer.add_edge( - node, - ctx, - Edge::Context(ContextEdge::Variable), - ); + let node = analyzer.add_node(Node::ContextVar(var)); + ctx.add_var(node.into(), analyzer).into_expr_err(*loc)?; + analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); ctx.push_expr(ExprRet::Single(node), analyzer) .into_expr_err(*loc)?; Ok(()) } e => todo!("Unhandled type in abi.decode: {e:?}"), }, - ExprRet::Multi(inner) => inner.iter().try_for_each(|i| { - match_decode(ctx, loc, i.clone(), analyzer) - }), + ExprRet::Multi(inner) => inner + .iter() + .try_for_each(|i| match_decode(ctx, loc, i.clone(), analyzer)), ExprRet::CtxKilled(kind) => { ctx.kill(analyzer, *loc, kind).into_expr_err(*loc) } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index 438b8020..945a4673 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -44,16 +44,18 @@ pub trait DynBuiltinCaller: AnalyzerBackend Result<(), ExprErr> { - input_exprs.unnamed_args().unwrap()[1..].iter().try_for_each(|expr| { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let input = ctx - .pop_expr_latest(loc, analyzer) - .into_expr_err(loc)? - .unwrap_or(ExprRet::Null); - ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) - }) - })?; + input_exprs.unnamed_args().unwrap()[1..] + .iter() + .try_for_each(|expr| { + self.parse_ctx_expr(expr, ctx)?; + self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + let input = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + .unwrap_or(ExprRet::Null); + ctx.append_tmp_expr(input, analyzer).into_expr_err(loc) + }) + })?; self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { let Some(inputs) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index 3e7ea5ad..381a6ac4 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -1,9 +1,6 @@ -use crate::func_call::func_caller::FuncCaller; use crate::context_builder::ExpressionParser; -use graph::nodes::ContextVarNode; +use crate::func_call::func_caller::FuncCaller; use crate::func_caller::NamedOrUnnamedArgs; -use graph::nodes::ContractNode; -use graph::nodes::ContextVar; use crate::{ func_call::helper::CallerHelper, intrinsic_call::{ @@ -12,6 +9,9 @@ use crate::{ }, ContextBuilder, ExprErr, IntoExprErr, }; +use graph::nodes::ContextVar; +use graph::nodes::ContextVarNode; +use graph::nodes::ContractNode; use graph::{ nodes::{Builtin, ContextNode, ExprRet}, @@ -229,9 +229,13 @@ pub trait IntrinsicFuncCaller: self.solidity_call(func_name.name.clone(), input_exprs, *loc, ctx) } // typing - "type" | "wrap" | "unwrap" => { - self.types_call(func_name.name.clone(), func_idx, input_exprs, *loc, ctx) - } + "type" | "wrap" | "unwrap" => self.types_call( + func_name.name.clone(), + func_idx, + input_exprs, + *loc, + ctx, + ), e => Err(ExprErr::Todo( *loc, format!("builtin function: {e:?} doesn't exist or isn't implemented"), diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 4a9887a0..20dbd601 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -1,8 +1,8 @@ -use graph::nodes::FunctionNode; use crate::func_caller::NamedOrUnnamedArgs; use crate::{ func_call::helper::CallerHelper, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; +use graph::nodes::FunctionNode; use graph::{ nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, @@ -99,25 +99,11 @@ pub trait PrecompileCaller: ctx.set_child_call(call_ctx.into(), analyzer) .into_expr_err(loc)?; let call_node = analyzer.add_node(Node::FunctionCall); - analyzer.add_edge( - call_node, - func_idx, - Edge::Context(ContextEdge::Call), - ); - analyzer.add_edge( - call_node, - ctx, - Edge::Context(ContextEdge::Subcontext), - ); - analyzer.add_edge( - call_ctx, - call_node, - Edge::Context(ContextEdge::Subcontext), - ); + analyzer.add_edge(call_node, func_idx, Edge::Context(ContextEdge::Call)); + analyzer.add_edge(call_node, ctx, Edge::Context(ContextEdge::Subcontext)); + analyzer.add_edge(call_ctx, call_node, Edge::Context(ContextEdge::Subcontext)); - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, "ecrecover did not receive inputs".to_string(), @@ -140,16 +126,12 @@ pub trait PrecompileCaller: let mut inner_vals = vec![]; match input { ExprRet::Single(var) | ExprRet::SingleLiteral(var) => { - inner_vals.push( - ContextVarNode::from(var) - .display_name(analyzer) - .unwrap(), - ); + inner_vals + .push(ContextVarNode::from(var).display_name(analyzer).unwrap()); } _ => inner_vals.push("".to_string()), } - let inner_name = - inner_vals.into_iter().collect::>().join(", "); + let inner_name = inner_vals.into_iter().collect::>().join(", "); let mut var = ContextVar::new_from_builtin( loc, analyzer.builtin_or_add(Builtin::Address).into(), @@ -161,16 +143,8 @@ pub trait PrecompileCaller: var.is_return = true; let cvar = analyzer.add_node(Node::ContextVar(var)); ctx.add_var(cvar.into(), analyzer).into_expr_err(loc)?; - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - cvar, - call_ctx, - Edge::Context(ContextEdge::Return), - ); + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Variable)); + analyzer.add_edge(cvar, call_ctx, Edge::Context(ContextEdge::Return)); ContextNode::from(call_ctx) .add_return_node(loc, cvar.into(), analyzer) .into_expr_err(loc)?; @@ -210,11 +184,7 @@ pub trait PrecompileCaller: tmp_ret.underlying_mut(analyzer).unwrap().display_name = format!("ecrecover({}).return", inner_name); ctx.add_var(tmp_ret, analyzer).into_expr_err(loc)?; - analyzer.add_edge( - tmp_ret, - ret_ctx, - Edge::Context(ContextEdge::Variable), - ); + analyzer.add_edge(tmp_ret, ret_ctx, Edge::Context(ContextEdge::Variable)); ContextNode::from(ret_ctx) .push_expr(ExprRet::Single(tmp_ret.into()), analyzer) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index 93ff0cb6..e024f557 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -5,7 +5,7 @@ use crate::{ }; use graph::{ - nodes::{Builtin, ContextNode, ContextVar, ExprRet, Concrete, ConcreteNode, ContextVarNode}, + nodes::{Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, Node, }; @@ -33,29 +33,19 @@ pub trait SolidityCaller: "keccak256" => { self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(input) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "No input into keccak256" - .to_string(), - )); + let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { + return Err(ExprErr::NoRhs(loc, "No input into keccak256".to_string())); }; let cvar = if let Ok(var) = input.expect_single() { ContextVarNode::from(var) } else { - return Err(ExprErr::NoRhs( - loc, - "No input into keccak256" - .to_string(), - )); + return Err(ExprErr::NoRhs(loc, "No input into keccak256".to_string())); }; - if cvar.is_const(analyzer).into_expr_err(loc)? { - let bytes = cvar.evaled_range_min(analyzer) + let bytes = cvar + .evaled_range_min(analyzer) .unwrap() .unwrap() .as_bytes(analyzer, true) @@ -65,13 +55,8 @@ pub trait SolidityCaller: let hash = Node::Concrete(Concrete::from(H256(out))); let hash_node = ConcreteNode::from(analyzer.add_node(hash)); - let var = ContextVar::new_from_concrete( - loc, - ctx, - hash_node, - analyzer, - ) - .into_expr_err(loc)?; + let var = ContextVar::new_from_concrete(loc, ctx, hash_node, analyzer) + .into_expr_err(loc)?; let cvar = analyzer.add_node(Node::ContextVar(var)); ctx.push_expr(ExprRet::Single(cvar), analyzer) .into_expr_err(loc)?; @@ -86,7 +71,7 @@ pub trait SolidityCaller: ctx.push_expr(ExprRet::Single(cvar), analyzer) .into_expr_err(loc)?; } - + Ok(()) }) } diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 7942f436..57098922 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,9 +1,6 @@ -use graph::nodes::FunctionNode; use crate::func_caller::NamedOrUnnamedArgs; -use crate::{ - func_call::helper::CallerHelper, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, - IntoExprErr, -}; +use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; +use graph::nodes::FunctionNode; use graph::{ elem::*, @@ -43,7 +40,9 @@ pub trait TypesCaller: AnalyzerBackend + S )); }; - let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + let input = if let Some(ordered_param_names) = + FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) + { input_exprs.order(input, ordered_param_names) } else { input @@ -80,7 +79,9 @@ pub trait TypesCaller: AnalyzerBackend + S )); }; - let input = if let Some(ordered_param_names) = FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) { + let input = if let Some(ordered_param_names) = + FunctionNode::from(func_idx).maybe_ordered_param_names(analyzer) + { input_exprs.order(input, ordered_param_names) } else { input diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index fbc02669..f0bd2b86 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -7,7 +7,7 @@ use crate::{ use graph::{ nodes::{Context, ContextNode, ExprRet, FunctionNode, ModifierState}, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, + AnalyzerBackend, Edge, GraphBackend, Node, }; use solang_parser::pt::{CodeLocation, Expression, Loc}; @@ -28,7 +28,7 @@ pub trait ModifierCaller: + FuncCaller + CallerHelper { - /// Calls a modifier for a function + /// Calls a modifier for a function #[tracing::instrument(level = "trace", skip_all)] fn call_modifier_for_fn( &mut self, @@ -81,7 +81,6 @@ pub trait ModifierCaller: }) } - /// Resumes the parent function of a modifier #[tracing::instrument(level = "trace", skip_all)] fn resume_from_modifier( @@ -121,7 +120,11 @@ pub trait ModifierCaller: let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); new_parent_subctx - .set_continuation_ctx(analyzer, modifier_state.parent_ctx, "resume_from_modifier_nonfinal") + .set_continuation_ctx( + analyzer, + modifier_state.parent_ctx, + "resume_from_modifier_nonfinal", + ) .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; @@ -150,7 +153,11 @@ pub trait ModifierCaller: .unwrap(); let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); new_parent_subctx - .set_continuation_ctx(analyzer, modifier_state.parent_ctx, "resume_from_modifier_final") + .set_continuation_ctx( + analyzer, + modifier_state.parent_ctx, + "resume_from_modifier_final", + ) .into_expr_err(loc)?; ctx.set_child_call(new_parent_subctx, analyzer) .into_expr_err(modifier_state.loc)?; diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index 50f8dfc9..fa4c778e 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -1,15 +1,17 @@ //! Traits & blanket implementations that facilitate performing namespaced function calls. use crate::assign::Assign; -use graph::VarType; -use graph::ContextEdge; -use graph::nodes::ContextVar; -use graph::Edge; use crate::{ - func_call::func_caller::{NamedOrUnnamedArgs, FuncCaller}, func_call::helper::CallerHelper, - intrinsic_call::IntrinsicFuncCaller, member_access::MemberAccess, ContextBuilder, ExprErr, - ExpressionParser, IntoExprErr, + func_call::func_caller::{FuncCaller, NamedOrUnnamedArgs}, + func_call::helper::CallerHelper, + intrinsic_call::IntrinsicFuncCaller, + member_access::MemberAccess, + ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; +use graph::nodes::ContextVar; +use graph::ContextEdge; +use graph::Edge; +use graph::VarType; use graph::{ nodes::{ContextNode, ContextVarNode, ExprRet, FunctionNode}, @@ -78,7 +80,9 @@ pub trait NameSpaceFuncCaller: ExprRet::Multi(vec![]) }; if possible_funcs.len() == 1 { - let mut inputs = if let Some(ordered_param_names) = possible_funcs[0].maybe_ordered_param_names(analyzer) { + let mut inputs = if let Some(ordered_param_names) = + possible_funcs[0].maybe_ordered_param_names(analyzer) + { input_exprs.order(inputs, ordered_param_names).as_vec() } else { inputs.as_vec() @@ -167,9 +171,16 @@ pub trait NameSpaceFuncCaller: ret: ExprRet, ) -> Result<(), ExprErr> { match ret { - ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { - self.call_name_spaced_func_inner(ctx, loc, member_expr, ident, input_exprs, inner, true) - } + ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => self + .call_name_spaced_func_inner( + ctx, + loc, + member_expr, + ident, + input_exprs, + inner, + true, + ), ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { self.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) }), diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index f265c11f..a37e14c3 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -105,7 +105,7 @@ pub trait Literal: AnalyzerBackend + Sized { if let Some(unit) = unit { rational_range = rational_range * Elem::from(Concrete::from(self.unit_to_uint(unit))) } - + let cvar = ContextVar::new_from_builtin(loc, self.builtin_or_add(Builtin::Uint(256)).into(), self) .into_expr_err(loc)?; diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index 99b11ae7..e54f50dc 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -1,6 +1,6 @@ -use graph::Edge; -use graph::ContextEdge; use crate::{variable::Variable, ContextBuilder, ExprErr, IntoExprErr, StatementParser}; +use graph::ContextEdge; +use graph::Edge; use graph::{ nodes::{Context, ContextNode}, diff --git a/crates/solc-expressions/src/member_access/contract_access.rs b/crates/solc-expressions/src/member_access/contract_access.rs index 081344ca..d64a3ff0 100644 --- a/crates/solc-expressions/src/member_access/contract_access.rs +++ b/crates/solc-expressions/src/member_access/contract_access.rs @@ -155,7 +155,7 @@ pub trait ContractAccess: AnalyzerBackend .map(|func| func.name(self).unwrap()) .collect::>() ), - )) + )); } } } diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index 4ab86604..dd192dde 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -1,9 +1,9 @@ -use graph::nodes::ConcreteNode; -use graph::nodes::Concrete; use crate::{ BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, ExpressionParser, IntoExprErr, ListAccess, StructAccess, }; +use graph::nodes::Concrete; +use graph::nodes::ConcreteNode; use graph::{ nodes::{ diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index c3975a76..89a843f3 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -47,7 +47,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Handles a require expression #[tracing::instrument(level = "trace", skip_all)] fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { - ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS).into_expr_err(inputs[0].loc())?; + ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) + .into_expr_err(inputs[0].loc())?; match inputs.first().expect("No lhs input for require statement") { Expression::Equal(loc, lhs, rhs) => { self.parse_ctx_expr(rhs, ctx)?; @@ -395,7 +396,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ContextVarNode::from(lhs_paths.expect_single().into_expr_err(loc)?); let underlying = lhs_cvar.underlying(analyzer).into_expr_err(loc)?; if let Some(tmp) = underlying.tmp_of { - if let Some((op, inv_op, pair)) = tmp.op.require_parts() { + if let Some((op, _inv_op, pair)) = tmp.op.require_parts() { analyzer.handle_require_inner( ctx, loc, @@ -413,7 +414,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ContextVarNode::from(rhs_paths.expect_single().into_expr_err(loc)?); let underlying = rhs_cvar.underlying(analyzer).into_expr_err(loc)?; if let Some(tmp) = underlying.tmp_of { - if let Some((op, inv_op, pair)) = tmp.op.require_parts() { + if let Some((op, _inv_op, pair)) = tmp.op.require_parts() { analyzer.handle_require_inner( ctx, loc, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 65caaa2e..308255d7 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,5 +1,3 @@ -use graph::elem::RangeElem; -use graph::Range; use crate::{assign::Assign, env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 14003b4a..1a169940 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -5,8 +5,8 @@ use crate::{ }; use graph::{ - nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, BuiltInNode}, - AnalyzerBackend, ContextEdge, Edge, Node, VarType, SolcRange, + nodes::{BuiltInNode, Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + AnalyzerBackend, ContextEdge, Edge, Node, SolcRange, VarType, }; use solang_parser::{ diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index f79f781e..8e396373 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -1,5 +1,6 @@ use crate::{ - assign::Assign, variable::Variable, yul::YulBuilder, BinOp, Cmp, ContextBuilder, Env, ExprErr, IntoExprErr, + assign::Assign, variable::Variable, yul::YulBuilder, BinOp, Cmp, ContextBuilder, Env, ExprErr, + IntoExprErr, }; use graph::{ From a2feff9baec62c83b7a93903ebae79d9f0caf3b9 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 19:18:50 -0800 Subject: [PATCH 59/71] simple pure func joining --- crates/cli/src/main.rs | 1 + crates/graph/src/graph_elements.rs | 1 + crates/graph/src/nodes/context/node.rs | 132 +- crates/graph/src/nodes/context/solving.rs | 9 +- crates/graph/src/nodes/context/underlying.rs | 3 +- crates/graph/src/nodes/context/var/ranging.rs | 18 + crates/graph/src/nodes/context/variables.rs | 13 + crates/graph/src/nodes/func_ty.rs | 11 +- crates/graph/src/range/elem/concrete.rs | 4 + crates/graph/src/range/elem/elem_enum.rs | 71 +- crates/graph/src/range/elem/elem_trait.rs | 1 + crates/graph/src/range/elem/expr.rs | 38 +- crates/graph/src/range/elem/map_or_array.rs | 4 + crates/graph/src/range/elem/reference.rs | 12 + crates/graph/src/range/solc_range.rs | 10 +- crates/graph/src/solvers/atoms.rs | 12 +- crates/graph/src/solvers/brute.rs | 8 +- crates/pyrometer/src/analyzer.rs | 70 +- crates/pyrometer/src/analyzer_backend.rs | 16 +- crates/pyrometer/src/graph_backend.rs | 46 + crates/pyrometer/tests/test_data/math.sol | 1202 ++++++++--------- crates/shared/src/analyzer_like.rs | 18 + crates/shared/src/graph_like.rs | 11 +- .../src/context_builder/fn_calls.rs | 326 +++++ .../src/context_builder/mod.rs | 2 + .../src/func_call/func_caller.rs | 27 +- .../solc-expressions/src/func_call/helper.rs | 6 + .../src/pre_post_in_decrement.rs | 44 +- 28 files changed, 1425 insertions(+), 691 deletions(-) create mode 100644 crates/solc-expressions/src/context_builder/fn_calls.rs diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 7ff232ac..b6d6b729 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -243,6 +243,7 @@ fn main() { let t_end = t0.elapsed(); let parse_time = t_end.as_millis(); + println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); if args.stats { diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index 2a881c5e..bc3bbf95 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -14,6 +14,7 @@ pub trait AnalyzerBackend: Builtin = Builtin, MsgNode = MsgNode, BlockNode = BlockNode, + FunctionNode = FunctionNode, FunctionParam = FunctionParam, FunctionReturn = FunctionReturn, Function = Function, diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 446c892a..bb5693bb 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,3 +1,10 @@ +use crate::VarType; +use crate::range::Range; +use crate::range::elem::RangeElem; +use crate::nodes::ExprRet; +use crate::elem::Elem; +use crate::Edge; +use crate::ContextEdge; use crate::{ nodes::{Context, ContextVarNode, FunctionNode, FunctionParamNode, KilledKind}, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, @@ -21,11 +28,126 @@ impl AsDotStr for ContextNode { impl ContextNode { pub fn join( &self, - _func: FunctionNode, - _mapping: &BTreeMap, - _analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) { - todo!("Joining not supported yet"); + func: FunctionNode, + mapping: &BTreeMap, + analyzer: &mut (impl GraphBackend + AnalyzerBackend), + ) -> Result { + + // ensure no modifiers (for now) + // if pure function: + // grab requirements for context + // grab return node's simplified range + // replace fundamentals with function inputs + // update ctx name in place + + if func.is_pure(analyzer)? { + // pure functions are guaranteed to not require the use of state, so + // the only things we care about are function inputs and function outputs + if let Some(body_ctx) = func.maybe_body_ctx(analyzer) { + let inputs = body_ctx.input_variables(analyzer); + // println!("inputs:"); + let mut replacement_map = BTreeMap::default(); + inputs.iter().for_each(|input| { + let name = input.name(analyzer).unwrap(); + if let Some((param, replacement_input)) = mapping.get(&name) { + if let Some(param_ty) = VarType::try_from_idx(analyzer, param.ty(analyzer).unwrap()) + { + if !replacement_input.ty_eq_ty(¶m_ty, analyzer).unwrap() { + replacement_input.cast_from_ty(param_ty, analyzer).unwrap(); + } + } + let mut replacement = Elem::from(*replacement_input); + replacement.arenaize(analyzer).unwrap(); + + if let Some(next) = input.next_version(analyzer) { + replacement_map.insert(next.0, replacement.clone()); + } + replacement_map.insert(input.0, replacement); + // a lot of time (all the time?) there is an extra version added on + + } + // println!(" name: {}", input.display_name(analyzer).unwrap()); + // println!(" idx: {}", input.0); + }); + + // println!("replacement map: {replacement_map:#?}"); + if body_ctx.underlying(analyzer)?.child.is_some() { + let edges = body_ctx.successful_edges(analyzer)?; + if edges.len() == 1 { + // let ret_nodes = edges[0].return_nodes(analyzer)?; + // println!("return nodes: {:#?}", ret_nodes); + } else { + // println!("multiple edges: {}", edges.len()); + } + } else { + // 1. Create a new variable with name `.` + // 2. Set the range to be the copy of the return's simplified range from the function + // 3. Replace the fundamentals with the input data + let ret: Vec<_> = body_ctx.return_nodes(analyzer)?.iter().enumerate().map(|(i, (_, ret_node))| { + // println!("original return:"); + // println!(" name: {}", ret_node.display_name(analyzer).unwrap()); + // println!(" range: {}", ret_node.simplified_range_string(analyzer).unwrap().unwrap()); + let mut new_var = ret_node.underlying(analyzer).unwrap().clone(); + let new_name = format!("{}.{i}", func.name(analyzer).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep((*replace).into(), replacement.clone(), analyzer); + }); + + range.cache_eval(analyzer).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + + let new_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); + analyzer.add_edge(new_cvar, *self, Edge::Context(ContextEdge::Variable)); + self.add_var(new_cvar, analyzer).unwrap(); + // let new_range = new_cvar.range(analyzer).unwrap().unwrap(); + + // println!("new return:"); + // println!(" name: {}", new_cvar.display_name(analyzer).unwrap()); + // println!(" range: {}", new_cvar.range_string(analyzer).unwrap().unwrap()); + ExprRet::Single(new_cvar.into()) + }).collect(); + + + + // println!("requires:"); + body_ctx.ctx_deps(analyzer)?.iter().for_each(|dep| { + // println!(" name: {}", dep.display_name(analyzer).unwrap()); + let mut new_var = dep.underlying(analyzer).unwrap().clone(); + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep((*replace).into(), replacement.clone(), analyzer); + }); + + range.cache_eval(analyzer).unwrap(); + new_var.ty.set_range(range).unwrap(); + } + + let new_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); + self.add_ctx_dep(new_cvar, analyzer).unwrap(); + }); + + self.underlying_mut(analyzer)?.path = format!( + "{}.{}.resume{{ {} }}", + self.path(analyzer), + func.name(analyzer).unwrap(), + self.associated_fn_name(analyzer).unwrap() + ); + self + .push_expr(ExprRet::Multi(ret), analyzer)?; + return Ok(true); + } + } + + // update path name to reflect that we called the function + } + + Ok(false) + // todo!("Joining not supported yet"); } pub fn add_gas_cost( diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index d5dba573..6170ec8f 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -63,7 +63,12 @@ impl ContextNode { &self, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - Ok(self.underlying(analyzer)?.ctx_deps.clone()) + let deps = self.underlying(analyzer)? + .ctx_deps + .clone() + .into_iter() + .collect::>(); + Ok(deps) } /// Adds a dependency for this context to exit successfully @@ -95,7 +100,7 @@ impl ContextNode { } let underlying = self.underlying_mut(analyzer)?; - underlying.ctx_deps.push(dep); + underlying.ctx_deps.insert(dep); } } Ok(()) diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index ccdf92db..6fdccf03 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -8,6 +8,7 @@ use crate::{ }; use solang_parser::pt::Loc; +use std::collections::BTreeSet; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Context { @@ -21,7 +22,7 @@ pub struct Context { pub continuation_of: Option, /// Variables whose bounds are required to be met for this context fork to exist. i.e. a conditional operator /// like an if statement - pub ctx_deps: Vec, + pub ctx_deps: BTreeSet, /// A string that represents the path taken from the root context (i.e. `fn_entry.fork.1`) pub path: String, /// Denotes whether this context was killed by an unsatisfiable require, assert, etc. statement diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 3605ed15..cbeb8562 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -31,6 +31,24 @@ impl ContextVarNode { } } + pub fn simplified_range_string(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + if let Some(range) = self.ref_range(analyzer)? { + Ok(Some(format!( + "[ {}, {} ]", + range + .simplified_range_min(analyzer)? + .to_range_string(false, analyzer) + .s, + range + .simplified_range_max(analyzer)? + .to_range_string(true, analyzer) + .s + ))) + } else { + Ok(None) + } + } + pub fn ref_range<'a>( &self, analyzer: &'a impl GraphBackend, diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index cb5ce939..3dcbdfd7 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -8,6 +8,19 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; impl ContextNode { + pub fn input_variables(&self, analyzer: &impl GraphBackend) -> Vec { + self.vars(analyzer) + .iter() + .filter_map(|(_, var)| { + if var.is_func_input(analyzer) { + Some(var.first_version(analyzer)) + } else { + None + } + }) + .collect() + } + /// Debug print the stack pub fn debug_expr_stack(&self, analyzer: &impl GraphBackend) -> Result<(), GraphError> { let underlying_mut = self.underlying(analyzer)?; diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 49a1d141..46c6452c 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -11,7 +11,7 @@ use solang_parser::{ helpers::CodeLocation, pt::{ Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, - Parameter, ParameterList, Statement, Type, VariableDefinition, Visibility, + Parameter, ParameterList, Statement, Type, VariableDefinition, Visibility, Mutability }, }; use std::collections::BTreeMap; @@ -454,6 +454,15 @@ impl FunctionNode { })) } + pub fn is_pure(&self, analyzer: &impl GraphBackend) -> Result { + Ok(self.underlying(analyzer)?.attributes.iter().any(|attr| { + matches!( + attr, + FunctionAttribute::Mutability(Mutability::Pure(_)) + ) + })) + } + pub fn get_overriding( &self, other: &Self, diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 0cccb11e..36c8c8a8 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -59,6 +59,10 @@ impl RangeElem for RangeConcrete { true } + fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + (true, true) + } + fn cache_flatten(&mut self, _: &mut impl GraphBackend) -> Result<(), GraphError> { Ok(()) } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 0b625664..08c6cfd9 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -50,26 +50,6 @@ impl Hash for Elem { } impl Elem { - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self) { - match self { - Elem::Reference(Reference { idx, .. }) => { - if *idx == to_replace { - *self = replacement; - } - } - Elem::Concrete(_) => {} - Elem::Expr(expr) => { - expr.lhs.replace_dep(to_replace, replacement.clone()); - expr.rhs.replace_dep(to_replace, replacement); - expr.maximized = None; - expr.minimized = None; - } - Elem::ConcreteDyn(_d) => todo!(), - Elem::Null => {} - Elem::Arena(_) => todo!(), - } - } - pub fn node_idx(&self) -> Option { match self { Self::Reference(Reference { idx, .. }) => Some(*idx), @@ -334,6 +314,39 @@ impl From for Elem { } impl Elem { + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self, analyzer: &mut impl GraphBackend) { + match self { + Elem::Reference(Reference { idx, .. }) => { + if *idx == to_replace { + *self = replacement; + } + } + Elem::Concrete(_) => {} + Elem::Expr(expr) => { + expr.lhs.replace_dep(to_replace, replacement.clone(), analyzer); + expr.rhs.replace_dep(to_replace, replacement, analyzer); + expr.maximized = None; + expr.minimized = None; + } + Elem::ConcreteDyn(_d) => todo!(), + Elem::Null => {} + Elem::Arena(_) => { + let mut s = self.dearenaize(analyzer).clone(); + s.replace_dep(to_replace, replacement, analyzer); + s.arenaize(analyzer).unwrap(); + *self = s; + }, + } + } + + pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Self { + match self { + Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone().recurse_dearenaize(analyzer), + Self::Expr(expr) => expr.recurse_dearenaize(analyzer), + e => e.clone(), + } + } + pub fn dearenaize<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a Self { match self { Self::Arena(arena_idx) => &analyzer.range_arena().ranges[*arena_idx], @@ -660,6 +673,13 @@ impl RangeElem for Elem { if self.is_flatten_cached(analyzer) { return Ok(()); } + + if let Some(idx) = analyzer.range_arena_idx(self) { + if Elem::Arena(idx).is_flatten_cached(analyzer) { + panic!("here"); + } + } + match self { Self::Reference(d) => d.cache_flatten(analyzer), Self::Concrete(c) => c.cache_flatten(analyzer), @@ -687,6 +707,17 @@ impl RangeElem for Elem { } } + fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { + match self { + Self::Reference(d) => d.is_min_max_cached(analyzer), + Self::Concrete(c) => c.is_min_max_cached(analyzer), + Self::Expr(expr) => expr.is_min_max_cached(analyzer), + Self::ConcreteDyn(d) => d.is_min_max_cached(analyzer), + Self::Null => (true, true), + Self::Arena(_) => self.dearenaize(analyzer).is_min_max_cached(analyzer), + } + } + fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { match self { Self::Reference(d) => d.dependent_on(analyzer), diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 6115cb94..96244500 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -18,6 +18,7 @@ pub trait RangeElem { ) -> Result, Self::GraphError>; /// Returns whether `cache_flatten` has been called fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool; + fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool); /// Flattens an element and caches the result fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index b888b989..1c631dde 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -81,6 +81,10 @@ impl RangeExpr { None } } + + pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { + Elem::Expr(Self::new(self.lhs.recurse_dearenaize(analyzer).clone(), self.op, self.rhs.recurse_dearenaize(analyzer).clone())) + } } impl RangeExpr { @@ -137,6 +141,10 @@ impl RangeElem for RangeExpr { self.flattened_min.is_some() && self.flattened_max.is_some() } + fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + (self.minimized.is_some(), self.maximized.is_some()) + } + fn range_ord( &self, _other: &Self, @@ -270,26 +278,46 @@ impl RangeElem for RangeExpr { } fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + if let Some(idx) = g.range_arena_idx(&Elem::Expr(self.clone())) { + if Elem::Arena(idx).is_flatten_cached(g) { + panic!("here"); + } + } + if self.flattened_max.is_none() { + self.lhs.arenaize(g)?; self.lhs.cache_flatten(g)?; + self.rhs.arenaize(g)?; self.rhs.cache_flatten(g)?; - let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; + let mut flat_max = self.flatten(true, g)?; + flat_max.arenaize(g)?; + let mut simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; + simplified_flat_max.arenaize(g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); + let mut s = Elem::Expr(self.clone()); + s.arenaize(g)?; } if self.flattened_min.is_none() { + self.lhs.arenaize(g)?; self.lhs.cache_flatten(g)?; + self.rhs.arenaize(g)?; self.rhs.cache_flatten(g)?; - let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; + let mut flat_min = self.flatten(false, g)?; + flat_min.arenaize(g)?; + let mut simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; + simplified_flat_min.arenaize(g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); + let mut s = Elem::Expr(self.clone()); + s.arenaize(g)?; } Ok(()) } fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.maximized.is_none() { + self.lhs.arenaize(g)?; self.lhs.cache_maximize(g)?; + self.rhs.arenaize(g)?; self.rhs.cache_maximize(g)?; self.cache_exec_op(true, g)?; } @@ -298,7 +326,9 @@ impl RangeElem for RangeExpr { fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.minimized.is_none() { + self.lhs.arenaize(g)?; self.lhs.cache_minimize(g)?; + self.rhs.arenaize(g)?; self.rhs.cache_minimize(g)?; self.cache_exec_op(false, g)?; } diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 109603c0..daf266d3 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -351,6 +351,10 @@ impl RangeElem for RangeDyn { self.flattened_min.is_some() && self.flattened_max.is_some() } + fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + (self.minimized.is_some(), self.maximized.is_some()) + } + fn filter_recursion( &mut self, node_idx: NodeIdx, diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 8031b805..e972371a 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -136,6 +136,10 @@ impl RangeElem for Reference { self.flattened_min.is_some() && self.flattened_max.is_some() } + fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + (self.minimized.is_some(), self.maximized.is_some()) + } + fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { if self.flattened_max.is_none() { let cvar = ContextVarNode::from(self.idx); @@ -143,6 +147,8 @@ impl RangeElem for Reference { let flat_max = self.flatten(true, g)?; let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); + let mut s = Elem::Reference(self.clone()); + s.arenaize(g)?; } if self.flattened_min.is_none() { let cvar = ContextVarNode::from(self.idx); @@ -150,6 +156,8 @@ impl RangeElem for Reference { let flat_min = self.flatten(false, g)?; let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); + let mut s = Elem::Reference(self.clone()); + s.arenaize(g)?; } Ok(()) } @@ -253,6 +261,8 @@ impl RangeElem for Reference { let cvar = ContextVarNode::from(self.idx); cvar.cache_eval_range(g)?; self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + let mut s = Elem::Reference(self.clone()); + s.arenaize(g)?; } Ok(()) } @@ -262,6 +272,8 @@ impl RangeElem for Reference { let cvar = ContextVarNode::from(self.idx); cvar.cache_eval_range(g)?; self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + let mut s = Elem::Reference(self.clone()); + s.arenaize(g)?; } Ok(()) } diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 4cdf919d..7d62bc67 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -90,9 +90,13 @@ impl SolcRange { } } - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Elem) { - self.min.replace_dep(to_replace, replacement.clone()); - self.max.replace_dep(to_replace, replacement); + pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Elem, analyzer: &mut impl GraphBackend) { + if let Some(ref mut flattened) = &mut self.flattened { + flattened.min.replace_dep(to_replace, replacement.clone(), analyzer); + flattened.max.replace_dep(to_replace, replacement.clone(), analyzer); + } + self.min.replace_dep(to_replace, replacement.clone(), analyzer); + self.max.replace_dep(to_replace, replacement, analyzer); self.min_cached = None; self.max_cached = None; } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index ecccde7a..967dee3c 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -37,16 +37,16 @@ impl AtomOrPart { } } - pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + pub fn replace_deps(&self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend) -> Self { match self { AtomOrPart::Part(part) => { let mut new_part = part.clone(); solves.iter().for_each(|(dep, replacement)| { - new_part.replace_dep(dep.0.into(), replacement.clone()) + new_part.replace_dep(dep.0.into(), replacement.clone(), analyzer) }); AtomOrPart::Part(new_part) } - AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves)), + AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves, analyzer)), } } @@ -122,12 +122,12 @@ impl ToRangeString for SolverAtom { } impl SolverAtom { - pub fn replace_deps(&self, solves: &BTreeMap>) -> Self { + pub fn replace_deps(&self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend) -> Self { SolverAtom { ty: self.ty, - lhs: Box::new(self.lhs.clone().replace_deps(solves)), + lhs: Box::new(self.lhs.clone().replace_deps(solves, analyzer)), op: self.op, - rhs: Box::new(self.rhs.clone().replace_deps(solves)), + rhs: Box::new(self.rhs.clone().replace_deps(solves, analyzer)), } } diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 2425b7c8..60cfa139 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -365,7 +365,7 @@ impl SolcSolver for BruteBinSearchSolver { atomic .idxs .iter() - .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()))); + .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer)); }); }); @@ -406,7 +406,7 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .for_each(|(atomic, range)| { atomic.idxs.iter().for_each(|idx| { - new_range.replace_dep(idx.0.into(), range.min.clone()); + new_range.replace_dep(idx.0.into(), range.min.clone(), analyzer); }); }); new_range.cache_eval(analyzer).unwrap(); @@ -680,7 +680,7 @@ impl SolcSolver for BruteBinSearchSolver { atomic .idxs .iter() - .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()))); + .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer)); }); }); @@ -766,7 +766,7 @@ impl SolcSolver for BruteBinSearchSolver { .idxs .iter() .for_each(|atomic_alias| { - new_range.replace_dep(atomic_alias.0.into(), conc.clone()); + new_range.replace_dep(atomic_alias.0.into(), conc.clone(), analyzer); }); new_range.cache_eval(analyzer)?; diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 29b8e3ac..7d2aabbc 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -1,3 +1,4 @@ + use crate::builtin_fns; use graph::elem::Elem; use shared::RangeArena; @@ -5,10 +6,10 @@ use shared::RangeArena; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; -use solc_expressions::{ExprErr, IntoExprErr, StatementParser}; +use solc_expressions::{ExprErr, IntoExprErr, StatementParser, FnCallBuilder}; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; -use petgraph::{graph::*, Directed}; +use petgraph::{graph::*, Directed, stable_graph::StableGraph}; use serde_json::Value; use solang_parser::{ diagnostics::Diagnostic, @@ -129,6 +130,8 @@ pub struct Analyzer { pub parse_fn: FunctionNode, /// Whether to force a panic on first error encountered pub debug_panic: bool, + /// Per function, a list of functions that are called + pub fn_calls_fns: BTreeMap>, /// An arena of ranges pub range_arena: RangeArena>, @@ -157,6 +160,7 @@ impl Default for Analyzer { max_width: 2_i32.pow(14) as usize, parse_fn: NodeIdx::from(0).into(), debug_panic: false, + fn_calls_fns: Default::default(), range_arena: RangeArena { ranges: vec![Elem::Null], map: { @@ -513,11 +517,69 @@ impl Analyzer { }); elems.into_iter().for_each(|final_pass_item| { + final_pass_item.funcs.iter().for_each(|func| { + self.analyze_fn_calls(*func) + }); + let mut handled_funcs = vec![]; + let mut func_mapping = BTreeMap::default(); + let mut call_dep_graph: StableGraph = StableGraph::default(); + let fn_calls_fns = std::mem::take(&mut self.fn_calls_fns); + fn_calls_fns.iter().for_each(|(func, calls)| { + if !calls.is_empty() { + let func_idx = if let Some(idx) = func_mapping.get(func) { + *idx + } else { + let idx = call_dep_graph.add_node(*func); + func_mapping.insert(func, idx); + idx + }; + + calls.iter().for_each(|call| { + let call_idx = if let Some(idx) = func_mapping.get(call) { + *idx + } else { + let idx = call_dep_graph.add_node(*call); + func_mapping.insert(call, idx); + idx + }; + + call_dep_graph.add_edge(func_idx, call_idx, 0); + }); + } else { + handled_funcs.push(func); + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(body, false, Some(*func)); + } + } + }); + + let mut res = petgraph::algo::toposort(&call_dep_graph, None); + while let Err(cycle) = res { + call_dep_graph.remove_node(cycle.node_id()); + res = petgraph::algo::toposort(&call_dep_graph, None); + } + + let indices = res.unwrap(); + + indices.iter().for_each(|idx| { + let func = call_dep_graph.node_weight(*idx).unwrap(); + if !handled_funcs.contains(&func) { + handled_funcs.push(func); + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(body, false, Some(*func)); + } + } + }); + final_pass_item.funcs.into_iter().for_each(|func| { - if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(func)); + if !handled_funcs.contains(&&func) { + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(body, false, Some(func)); + } } }); + + self.fn_calls_fns = fn_calls_fns; }); } diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 5b4c39cf..96ac6e02 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -3,7 +3,7 @@ use crate::Analyzer; use graph::{ nodes::{ BlockNode, Builtin, Concrete, ConcreteNode, Function, FunctionParam, FunctionParamNode, - FunctionReturn, MsgNode, + FunctionReturn, MsgNode, FunctionNode, }, AnalyzerBackend, Edge, Node, VarType, }; @@ -13,7 +13,7 @@ use solc_expressions::{ExprErr, IntoExprErr}; use ethers_core::types::U256; use solang_parser::{helpers::CodeLocation, pt::Expression}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; impl AnalyzerBackend for Analyzer {} @@ -24,6 +24,7 @@ impl AnalyzerLike for Analyzer { type BlockNode = BlockNode; type Function = Function; + type FunctionNode = FunctionNode; type FunctionParam = FunctionParam; type FunctionReturn = FunctionReturn; type Builtin = Builtin; @@ -61,6 +62,10 @@ impl AnalyzerLike for Analyzer { self.entry } + fn parse_fn(&self) -> FunctionNode { + self.parse_fn + } + fn msg(&mut self) -> MsgNode { self.msg } @@ -230,4 +235,11 @@ impl AnalyzerLike for Analyzer { fn debug_panic(&self) -> bool { self.debug_panic } + + fn fn_calls_fns(&self) -> &BTreeMap> { + &self.fn_calls_fns + } + fn fn_calls_fns_mut(&mut self) -> &mut BTreeMap> { + &mut self.fn_calls_fns + } } diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 5e1d2c27..30a21f34 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,3 +1,4 @@ +use graph::elem::RangeElem; use crate::Analyzer; use graph::elem::Elem; use graph::nodes::Concrete; @@ -35,6 +36,47 @@ impl GraphLike for Analyzer { fn range_arena_mut(&mut self) -> &mut RangeArena> { &mut self.range_arena } + + fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { + if let Some(idx) = self.range_arena_idx(&elem) { + let existing = &self.range_arena().ranges[idx]; + let (min_cached, max_cached) = existing.is_min_max_cached(self); + let mut existing_count = 0; + if min_cached { + existing_count += 1; + } + if max_cached { + existing_count += 1; + } + if existing.is_flatten_cached(self) { + existing_count += 1; + } + + + let (min_cached, max_cached) = elem.is_min_max_cached(self); + let mut new_count = 0; + if min_cached { + new_count += 1; + } + if max_cached { + new_count += 1; + } + if elem.is_flatten_cached(self) { + new_count += 1; + } + + if new_count >= existing_count { + self.range_arena_mut().ranges[idx] = elem; + } + + idx + } else { + let idx = self.range_arena().ranges.len(); + self.range_arena_mut().ranges.push(elem.clone()); + self.range_arena_mut().map.insert(elem, idx); + idx + } + } } impl GraphBackend for Analyzer {} @@ -599,6 +641,10 @@ impl GraphLike for G<'_> { fn range_arena_mut(&mut self) -> &mut RangeArena> { panic!("Should not call this") } + + fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { + panic!("Should not call this") + } } impl GraphBackend for G<'_> {} diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index c566b970..1dc0e7cf 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -1,644 +1,644 @@ -contract Div { - function div(uint256 x, uint256 y) public returns (uint256) { - return x / y; - } - - function int_div(int256 x, int256 y) public returns (int256) { - return x / y; - } - - function div_conc() public returns (uint256) { - uint256 a1 = div(100, 1); - require(a1 == 100); - uint256 a2 = div(100, 2); - require(a2 == 50); - uint256 a3 = div(100, 4); - require(a3 == 25); - uint256 a4 = div(100, 8); - require(a4 == 12); - uint256 a5 = div(1000000000, 8); - require(a5 == 125000000); - uint256 a6 = div(1000000000, 16); - require(a6 == 62500000); - uint256 a7 = div(10000000000, 32); - require(a7 == 312500000); - uint256 a8 = div(100000000000000000000, 64); - require(a8 == 1562500000000000000); - uint256 a9 = div(100000000000000000000000000000000000, 128); - require(a9 == 781250000000000000000000000000000); - uint256 a10 = div(1, 255); - require(a10 == 0); - } - - function int_div_conc() public { - int256 a1 = int_div(100, 1); - require(a1 == 100); - int256 a2 = int_div(100, 2); - require(a2 == 50); - int256 a3 = int_div(100, 4); - require(a3 == 25); - int256 a4 = int_div(100, 8); - require(a4 == 12); - int256 a5 = int_div(1000000000, 8); - require(a5 == 125000000); - int256 a6 = int_div(1000000000, 16); - require(a6 == 62500000); - int256 a7 = int_div(10000000000, 32); - require(a7 == 312500000); - int256 a8 = int_div(100000000000000000000, 64); - require(a8 == 1562500000000000000); - int256 a9 = int_div(100000000000000000000000000000000000, 128); - require(a9 == 781250000000000000000000000000000); - int256 a10 = int_div(1, 255); - require(a10 == 0); - - int256 a11 = int_div(-100, 1); - require(a11 == -100); - int256 a12 = int_div(-100, 2); - require(a12 == -50); - int256 a13 = int_div(-100, 4); - require(a13 == -25); - int256 a14 = int_div(-100, 8); - require(a14 == -12); - int256 a15 = int_div(-1000000000, 8); - require(a15 == -125000000); - int256 a16 = int_div(-1000000000, 16); - require(a16 == -62500000); - int256 a17 = int_div(-10000000000, 32); - require(a17 == -312500000); - int256 a18 = int_div(-100000000000000000000, 64); - require(a18 == -1562500000000000000); - int256 a19 = int_div(-100000000000000000000000000000000000, 128); - require(a19 == -781250000000000000000000000000000); - int256 a20 = int_div(-1, 255); - require(a20 == 0); - - int256 a21 = int_div(-100, -1); - require(a21 == 100); - int256 a22 = int_div(-100, -2); - require(a22 == 50); - int256 a23 = int_div(-100, -4); - require(a23 == 25); - int256 a24 = int_div(-100, -8); - require(a24 == 12); - int256 a25 = int_div(-1000000000, -8); - require(a25 == 125000000); - int256 a26 = int_div(-1000000000, -16); - require(a26 == 62500000); - int256 a27 = int_div(-10000000000, -32); - require(a27 == 312500000); - int256 a28 = int_div(-100000000000000000000, -64); - require(a28 == 1562500000000000000); - int256 a29 = int_div(-100000000000000000000000000000000000, -128); - require(a29 == 781250000000000000000000000000000); - int256 a30 = int_div(-1, -255); - require(a30 == 0); - - int256 a31 = int_div(100, -1); - require(a31 == -100); - int256 a32 = int_div(100, -2); - require(a32 == -50); - int256 a33 = int_div(100, -4); - require(a33 == -25); - int256 a34 = int_div(100, -8); - require(a34 == -12); - int256 a35 = int_div(1000000000, -8); - require(a35 == -125000000); - int256 a36 = int_div(1000000000, -16); - require(a36 == -62500000); - int256 a37 = int_div(10000000000, -32); - require(a37 == -312500000); - int256 a38 = int_div(100000000000000000000, -64); - require(a38 == -1562500000000000000); - int256 a39 = int_div(100000000000000000000000000000000000, -128); - require(a39 == -781250000000000000000000000000000); - int256 a40 = int_div(1, -255); - require(a40 == 0); - } -} - -contract Mul { - function mul(uint256 x, uint256 y) public returns (uint256) { - return x * y; - } - - function int_mul(int256 x, int256 y) public returns (int256) { - return x * y; - } - - function mul_conc() public returns (uint256) { - uint256 a1 = mul(100, 1); - require(a1 == 100); - uint256 a2 = mul(100, 2); - require(a2 == 200); - uint256 a3 = mul(100, 4); - require(a3 == 400); - uint256 a4 = mul(100, 8); - require(a4 == 800); - uint256 a5 = mul(1000000000, 8); - require(a5 == 8000000000); - uint256 a6 = mul(1000000000, 16); - require(a6 == 16000000000); - uint256 a7 = mul(10000000000, 32); - require(a7 == 320000000000); - uint256 a8 = mul(100000000000000000000, 64); - require(a8 == 6400000000000000000000); - uint256 a9 = mul(100000000000000000000000000000000000, 128); - require(a9 == 12800000000000000000000000000000000000); - uint256 a10 = mul(1, 255); - require(a10 == 255); - } - - function int_mul_conc() public { - int256 a1 = int_mul(100, 1); - require(a1 == 100); - int256 a2 = int_mul(100, 2); - require(a2 == 200); - int256 a3 = int_mul(100, 4); - require(a3 == 400); - int256 a4 = int_mul(100, 8); - require(a4 == 800); - int256 a5 = int_mul(1000000000, 8); - require(a5 == 8000000000); - int256 a6 = int_mul(1000000000, 16); - require(a6 == 16000000000); - int256 a7 = int_mul(10000000000, 32); - require(a7 == 320000000000); - int256 a8 = int_mul(100000000000000000000, 64); - require(a8 == 6400000000000000000000); - int256 a9 = int_mul(100000000000000000000000000000000000, 128); - require(a9 == 12800000000000000000000000000000000000); - int256 a10 = int_mul(1, 255); - require(a10 == 255); - - int256 a11 = int_mul(-100, 1); - require(a11 == -100); - int256 a12 = int_mul(-100, 2); - require(a12 == -200); - int256 a13 = int_mul(-100, 4); - require(a13 == -400); - int256 a14 = int_mul(-100, 8); - require(a14 == -800); - int256 a15 = int_mul(-1000000000, 8); - require(a15 == -8000000000); - int256 a16 = int_mul(-1000000000, 16); - require(a16 == -16000000000); - int256 a17 = int_mul(-10000000000, 32); - require(a17 == -320000000000); - int256 a18 = int_mul(-100000000000000000000, 64); - require(a18 == -6400000000000000000000); - int256 a19 = int_mul(-100000000000000000000000000000000000, 128); - require(a19 == -12800000000000000000000000000000000000); - int256 a20 = int_mul(-1, 255); - require(a20 == -255); - - int256 a21 = int_mul(-100, -1); - require(a21 == 100); - int256 a22 = int_mul(-100, -2); - require(a22 == 200); - int256 a23 = int_mul(-100, -4); - require(a23 == 400); - int256 a24 = int_mul(-100, -8); - require(a24 == 800); - int256 a25 = int_mul(-1000000000, -8); - require(a25 == 8000000000); - int256 a26 = int_mul(-1000000000, -16); - require(a26 == 16000000000); - int256 a27 = int_mul(-10000000000, -32); - require(a27 == 320000000000); - int256 a28 = int_mul(-100000000000000000000, -64); - require(a28 == 6400000000000000000000); - int256 a29 = int_mul(-100000000000000000000000000000000000, -128); - require(a29 == 12800000000000000000000000000000000000); - int256 a30 = int_mul(-1, -255); - require(a30 == 255); - - int256 a31 = int_mul(100, -1); - require(a31 == -100); - int256 a32 = int_mul(100, -2); - require(a32 == -200); - int256 a33 = int_mul(100, -4); - require(a33 == -400); - int256 a34 = int_mul(100, -8); - require(a34 == -800); - int256 a35 = int_mul(1000000000, -8); - require(a35 == -8000000000); - int256 a36 = int_mul(1000000000, -16); - require(a36 == -16000000000); - int256 a37 = int_mul(10000000000, -32); - require(a37 == -320000000000); - int256 a38 = int_mul(100000000000000000000, -64); - require(a38 == -6400000000000000000000); - int256 a39 = int_mul(100000000000000000000000000000000000, -128); - require(a39 == -12800000000000000000000000000000000000); - int256 a40 = int_mul(1, -255); - require(a40 == -255); - } -} - -contract Add { - function add(uint256 x, uint256 y) public returns (uint256) { - return x + y; - } - - function int_add(int256 x, int256 y) public returns (int256) { - return x + y; - } - - function add_conc() public returns (uint256) { - uint256 a1 = add(100, 1); - require(a1 == 101); - uint256 a2 = add(100, 2); - require(a2 == 102); - uint256 a3 = add(100, 4); - require(a3 == 104); - uint256 a4 = add(100, 8); - require(a4 == 108); - uint256 a5 = add(1000000000, 8); - require(a5 == 1000000008); - uint256 a6 = add(1000000000, 16); - require(a6 == 1000000016); - uint256 a7 = add(10000000000, 32); - require(a7 == 10000000032); - uint256 a8 = add(100000000000000000000, 64); - require(a8 == 100000000000000000064); - uint256 a9 = add(100000000000000000000000000000000000, 128); - require(a9 == 100000000000000000000000000000000128); - uint256 a10 = add(1, 255); - require(a10 == 256); - } - - function int_add_conc() public { - int256 a1 = int_add(100, 1); - require(a1 == 101); - int256 a2 = int_add(100, 2); - require(a2 == 102); - int256 a3 = int_add(100, 4); - require(a3 == 104); - int256 a4 = int_add(100, 8); - require(a4 == 108); - int256 a5 = int_add(1000000000, 8); - require(a5 == 1000000008); - int256 a6 = int_add(1000000000, 16); - require(a6 == 1000000016); - int256 a7 = int_add(10000000000, 32); - require(a7 == 10000000032); - int256 a8 = int_add(100000000000000000000, 64); - require(a8 == 100000000000000000064); - int256 a9 = int_add(100000000000000000000000000000000000, 128); - require(a9 == 100000000000000000000000000000000128); - int256 a10 = int_add(1, 255); - require(a10 == 256); - - int256 a11 = int_add(-100, 1); - require(a11 == -99); - int256 a12 = int_add(-100, 2); - require(a12 == -98); - int256 a13 = int_add(-100, 4); - require(a13 == -96); - int256 a14 = int_add(-100, 8); - require(a14 == -92); - int256 a15 = int_add(-1000000000, 8); - require(a15 == -999999992); - int256 a16 = int_add(-1000000000, 16); - require(a16 == -999999984); - int256 a17 = int_add(-10000000000, 32); - require(a17 == -9999999968); - int256 a18 = int_add(-100000000000000000000, 64); - require(a18 == -99999999999999999936); - int256 a19 = int_add(-100000000000000000000000000000000000, 128); - require(a19 == -99999999999999999999999999999999872); - int256 a20 = int_add(-1, 255); - require(a20 == 254); - - int256 a21 = int_add(-100, -1); - require(a21 == -101); - int256 a22 = int_add(-100, -2); - require(a22 == -102); - int256 a23 = int_add(-100, -4); - require(a23 == -104); - int256 a24 = int_add(-100, -8); - require(a24 == -108); - int256 a25 = int_add(-1000000000, -8); - require(a25 == -1000000008); - int256 a26 = int_add(-1000000000, -16); - require(a26 == -1000000016); - int256 a27 = int_add(-10000000000, -32); - require(a27 == -10000000032); - int256 a28 = int_add(-100000000000000000000, -64); - require(a28 == -100000000000000000064); - int256 a29 = int_add(-100000000000000000000000000000000000, -128); - require(a29 == -100000000000000000000000000000000128); - int256 a30 = int_add(-1, -255); - require(a30 == -256); - - int256 a31 = int_add(100, -1); - require(a31 == 99); - int256 a32 = int_add(100, -2); - require(a32 == 98); - int256 a33 = int_add(100, -4); - require(a33 == 96); - int256 a34 = int_add(100, -8); - require(a34 == 92); - int256 a35 = int_add(1000000000, -8); - require(a35 == 999999992); - int256 a36 = int_add(1000000000, -16); - require(a36 == 999999984); - int256 a37 = int_add(10000000000, -32); - require(a37 == 9999999968); - int256 a38 = int_add(100000000000000000000, -64); - require(a38 == 99999999999999999936); - int256 a39 = int_add(100000000000000000000000000000000000, -128); - require(a39 == 99999999999999999999999999999999872); - int256 a40 = int_add(1, -255); - require(a40 == -254); - } -} - -contract Sub { - function sub(uint256 x, uint256 y) public returns (uint256) { - return x - y; - } - - function int_sub(int256 x, int256 y) public returns (int256) { - return x - y; - } - - function sub_conc() public returns (uint256) { - uint256 a1 = sub(100, 1); - require(a1 == 99); - uint256 a2 = sub(100, 2); - require(a2 == 98); - uint256 a3 = sub(100, 4); - require(a3 == 96); - uint256 a4 = sub(100, 8); - require(a4 == 92); - uint256 a5 = sub(1000000000, 8); - require(a5 == 999999992); - uint256 a6 = sub(1000000000, 16); - require(a6 == 999999984); - uint256 a7 = sub(10000000000, 32); - require(a7 == 9999999968); - uint256 a8 = sub(100000000000000000000, 64); - require(a8 == 99999999999999999936); - uint256 a9 = sub(100000000000000000000000000000000000, 128); - require(a9 == 99999999999999999999999999999999872); - } - - function int_sub_conc() public { - int256 a1 = int_sub(100, 1); - require(a1 == 99); - int256 a2 = int_sub(100, 2); - require(a2 == 98); - int256 a3 = int_sub(100, 4); - require(a3 == 96); - int256 a4 = int_sub(100, 8); - require(a4 == 92); - int256 a5 = int_sub(1000000000, 8); - require(a5 == 999999992); - int256 a6 = int_sub(1000000000, 16); - require(a6 == 999999984); - int256 a7 = int_sub(10000000000, 32); - require(a7 == 9999999968); - int256 a8 = int_sub(100000000000000000000, 64); - require(a8 == 99999999999999999936); - int256 a9 = int_sub(100000000000000000000000000000000000, 128); - require(a9 == 99999999999999999999999999999999872); - int256 a10 = int_sub(1, 255); - require(a10 == -254); - - int256 a11 = int_sub(-100, 1); - require(a11 == -101); - int256 a12 = int_sub(-100, 2); - require(a12 == -102); - int256 a13 = int_sub(-100, 4); - require(a13 == -104); - int256 a14 = int_sub(-100, 8); - require(a14 == -108); - int256 a15 = int_sub(-1000000000, 8); - require(a15 == -1000000008); - int256 a16 = int_sub(-1000000000, 16); - require(a16 == -1000000016); - int256 a17 = int_sub(-10000000000, 32); - require(a17 == -10000000032); - int256 a18 = int_sub(-100000000000000000000, 64); - require(a18 == -100000000000000000064); - int256 a19 = int_sub(-100000000000000000000000000000000000, 128); - require(a19 == -100000000000000000000000000000000128); - int256 a20 = int_sub(-1, 255); - require(a20 == -256); - - int256 a21 = int_sub(-100, -1); - require(a21 == -99); - int256 a22 = int_sub(-100, -2); - require(a22 == -98); - int256 a23 = int_sub(-100, -4); - require(a23 == -96); - int256 a24 = int_sub(-100, -8); - require(a24 == -92); - int256 a25 = int_sub(-1000000000, -8); - require(a25 == -999999992); - int256 a26 = int_sub(-1000000000, -16); - require(a26 == -999999984); - int256 a27 = int_sub(-10000000000, -32); - require(a27 == -9999999968); - int256 a28 = int_sub(-100000000000000000000, -64); - require(a28 == -99999999999999999936); - int256 a29 = int_sub(-100000000000000000000000000000000000, -128); - require(a29 == -99999999999999999999999999999999872); - int256 a30 = int_sub(-1, -255); - require(a30 == 254); - - int256 a31 = int_sub(100, -1); - require(a31 == 101); - int256 a32 = int_sub(100, -2); - require(a32 == 102); - int256 a33 = int_sub(100, -4); - require(a33 == 104); - int256 a34 = int_sub(100, -8); - require(a34 == 108); - int256 a35 = int_sub(1000000000, -8); - require(a35 == 1000000008); - int256 a36 = int_sub(1000000000, -16); - require(a36 == 1000000016); - int256 a37 = int_sub(10000000000, -32); - require(a37 == 10000000032); - int256 a38 = int_sub(100000000000000000000, -64); - require(a38 == 100000000000000000064); - int256 a39 = int_sub(100000000000000000000000000000000000, -128); - require(a39 == 100000000000000000000000000000000128); - int256 a40 = int_sub(1, -255); - require(a40 == 256); - } -} +// contract Div { +// function div(uint256 x, uint256 y) public pure returns (uint256) { +// return x / y; +// } + +// function int_div(int256 x, int256 y) public pure returns (int256) { +// return x / y; +// } + +// function div_conc() public pure returns (uint256) { +// uint256 a1 = div(100, 1); +// require(a1 == 100); +// uint256 a2 = div(100, 2); +// require(a2 == 50); +// uint256 a3 = div(100, 4); +// require(a3 == 25); +// uint256 a4 = div(100, 8); +// require(a4 == 12); +// uint256 a5 = div(1000000000, 8); +// require(a5 == 125000000); +// uint256 a6 = div(1000000000, 16); +// require(a6 == 62500000); +// uint256 a7 = div(10000000000, 32); +// require(a7 == 312500000); +// uint256 a8 = div(100000000000000000000, 64); +// require(a8 == 1562500000000000000); +// uint256 a9 = div(100000000000000000000000000000000000, 128); +// require(a9 == 781250000000000000000000000000000); +// uint256 a10 = div(1, 255); +// require(a10 == 0); +// } + +// function int_div_conc() public pure { +// int256 a1 = int_div(100, 1); +// require(a1 == 100); +// int256 a2 = int_div(100, 2); +// require(a2 == 50); +// int256 a3 = int_div(100, 4); +// require(a3 == 25); +// int256 a4 = int_div(100, 8); +// require(a4 == 12); +// int256 a5 = int_div(1000000000, 8); +// require(a5 == 125000000); +// int256 a6 = int_div(1000000000, 16); +// require(a6 == 62500000); +// int256 a7 = int_div(10000000000, 32); +// require(a7 == 312500000); +// int256 a8 = int_div(100000000000000000000, 64); +// require(a8 == 1562500000000000000); +// int256 a9 = int_div(100000000000000000000000000000000000, 128); +// require(a9 == 781250000000000000000000000000000); +// int256 a10 = int_div(1, 255); +// require(a10 == 0); + +// int256 a11 = int_div(-100, 1); +// require(a11 == -100); +// int256 a12 = int_div(-100, 2); +// require(a12 == -50); +// int256 a13 = int_div(-100, 4); +// require(a13 == -25); +// int256 a14 = int_div(-100, 8); +// require(a14 == -12); +// int256 a15 = int_div(-1000000000, 8); +// require(a15 == -125000000); +// int256 a16 = int_div(-1000000000, 16); +// require(a16 == -62500000); +// int256 a17 = int_div(-10000000000, 32); +// require(a17 == -312500000); +// int256 a18 = int_div(-100000000000000000000, 64); +// require(a18 == -1562500000000000000); +// int256 a19 = int_div(-100000000000000000000000000000000000, 128); +// require(a19 == -781250000000000000000000000000000); +// int256 a20 = int_div(-1, 255); +// require(a20 == 0); + +// int256 a21 = int_div(-100, -1); +// require(a21 == 100); +// int256 a22 = int_div(-100, -2); +// require(a22 == 50); +// int256 a23 = int_div(-100, -4); +// require(a23 == 25); +// int256 a24 = int_div(-100, -8); +// require(a24 == 12); +// int256 a25 = int_div(-1000000000, -8); +// require(a25 == 125000000); +// int256 a26 = int_div(-1000000000, -16); +// require(a26 == 62500000); +// int256 a27 = int_div(-10000000000, -32); +// require(a27 == 312500000); +// int256 a28 = int_div(-100000000000000000000, -64); +// require(a28 == 1562500000000000000); +// int256 a29 = int_div(-100000000000000000000000000000000000, -128); +// require(a29 == 781250000000000000000000000000000); +// int256 a30 = int_div(-1, -255); +// require(a30 == 0); + +// int256 a31 = int_div(100, -1); +// require(a31 == -100); +// int256 a32 = int_div(100, -2); +// require(a32 == -50); +// int256 a33 = int_div(100, -4); +// require(a33 == -25); +// int256 a34 = int_div(100, -8); +// require(a34 == -12); +// int256 a35 = int_div(1000000000, -8); +// require(a35 == -125000000); +// int256 a36 = int_div(1000000000, -16); +// require(a36 == -62500000); +// int256 a37 = int_div(10000000000, -32); +// require(a37 == -312500000); +// int256 a38 = int_div(100000000000000000000, -64); +// require(a38 == -1562500000000000000); +// int256 a39 = int_div(100000000000000000000000000000000000, -128); +// require(a39 == -781250000000000000000000000000000); +// int256 a40 = int_div(1, -255); +// require(a40 == 0); +// } +// } + +// contract Mul { +// function mul(uint256 x, uint256 y) public pure returns (uint256) { +// return x * y; +// } + +// function int_mul(int256 x, int256 y) public pure returns (int256) { +// return x * y; +// } + +// function mul_conc() public pure returns (uint256) { +// uint256 a1 = mul(100, 1); +// require(a1 == 100); +// uint256 a2 = mul(100, 2); +// require(a2 == 200); +// uint256 a3 = mul(100, 4); +// require(a3 == 400); +// uint256 a4 = mul(100, 8); +// require(a4 == 800); +// uint256 a5 = mul(1000000000, 8); +// require(a5 == 8000000000); +// uint256 a6 = mul(1000000000, 16); +// require(a6 == 16000000000); +// uint256 a7 = mul(10000000000, 32); +// require(a7 == 320000000000); +// uint256 a8 = mul(100000000000000000000, 64); +// require(a8 == 6400000000000000000000); +// uint256 a9 = mul(100000000000000000000000000000000000, 128); +// require(a9 == 12800000000000000000000000000000000000); +// uint256 a10 = mul(1, 255); +// require(a10 == 255); +// } + +// function int_mul_conc() public pure { +// int256 a1 = int_mul(100, 1); +// require(a1 == 100); +// int256 a2 = int_mul(100, 2); +// require(a2 == 200); +// int256 a3 = int_mul(100, 4); +// require(a3 == 400); +// int256 a4 = int_mul(100, 8); +// require(a4 == 800); +// int256 a5 = int_mul(1000000000, 8); +// require(a5 == 8000000000); +// int256 a6 = int_mul(1000000000, 16); +// require(a6 == 16000000000); +// int256 a7 = int_mul(10000000000, 32); +// require(a7 == 320000000000); +// int256 a8 = int_mul(100000000000000000000, 64); +// require(a8 == 6400000000000000000000); +// int256 a9 = int_mul(100000000000000000000000000000000000, 128); +// require(a9 == 12800000000000000000000000000000000000); +// int256 a10 = int_mul(1, 255); +// require(a10 == 255); + +// int256 a11 = int_mul(-100, 1); +// require(a11 == -100); +// int256 a12 = int_mul(-100, 2); +// require(a12 == -200); +// int256 a13 = int_mul(-100, 4); +// require(a13 == -400); +// int256 a14 = int_mul(-100, 8); +// require(a14 == -800); +// int256 a15 = int_mul(-1000000000, 8); +// require(a15 == -8000000000); +// int256 a16 = int_mul(-1000000000, 16); +// require(a16 == -16000000000); +// int256 a17 = int_mul(-10000000000, 32); +// require(a17 == -320000000000); +// int256 a18 = int_mul(-100000000000000000000, 64); +// require(a18 == -6400000000000000000000); +// int256 a19 = int_mul(-100000000000000000000000000000000000, 128); +// require(a19 == -12800000000000000000000000000000000000); +// int256 a20 = int_mul(-1, 255); +// require(a20 == -255); + +// int256 a21 = int_mul(-100, -1); +// require(a21 == 100); +// int256 a22 = int_mul(-100, -2); +// require(a22 == 200); +// int256 a23 = int_mul(-100, -4); +// require(a23 == 400); +// int256 a24 = int_mul(-100, -8); +// require(a24 == 800); +// int256 a25 = int_mul(-1000000000, -8); +// require(a25 == 8000000000); +// int256 a26 = int_mul(-1000000000, -16); +// require(a26 == 16000000000); +// int256 a27 = int_mul(-10000000000, -32); +// require(a27 == 320000000000); +// int256 a28 = int_mul(-100000000000000000000, -64); +// require(a28 == 6400000000000000000000); +// int256 a29 = int_mul(-100000000000000000000000000000000000, -128); +// require(a29 == 12800000000000000000000000000000000000); +// int256 a30 = int_mul(-1, -255); +// require(a30 == 255); + +// int256 a31 = int_mul(100, -1); +// require(a31 == -100); +// int256 a32 = int_mul(100, -2); +// require(a32 == -200); +// int256 a33 = int_mul(100, -4); +// require(a33 == -400); +// int256 a34 = int_mul(100, -8); +// require(a34 == -800); +// int256 a35 = int_mul(1000000000, -8); +// require(a35 == -8000000000); +// int256 a36 = int_mul(1000000000, -16); +// require(a36 == -16000000000); +// int256 a37 = int_mul(10000000000, -32); +// require(a37 == -320000000000); +// int256 a38 = int_mul(100000000000000000000, -64); +// require(a38 == -6400000000000000000000); +// int256 a39 = int_mul(100000000000000000000000000000000000, -128); +// require(a39 == -12800000000000000000000000000000000000); +// int256 a40 = int_mul(1, -255); +// require(a40 == -255); +// } +// } + +// contract Add { +// function add(uint256 x, uint256 y) public pure returns (uint256) { +// return x + y; +// } + +// function int_add(int256 x, int256 y) public pure returns (int256) { +// return x + y; +// } + +// function add_conc() public pure returns (uint256) { +// uint256 a1 = add(100, 1); +// require(a1 == 101); +// uint256 a2 = add(100, 2); +// require(a2 == 102); +// uint256 a3 = add(100, 4); +// require(a3 == 104); +// uint256 a4 = add(100, 8); +// require(a4 == 108); +// uint256 a5 = add(1000000000, 8); +// require(a5 == 1000000008); +// uint256 a6 = add(1000000000, 16); +// require(a6 == 1000000016); +// uint256 a7 = add(10000000000, 32); +// require(a7 == 10000000032); +// uint256 a8 = add(100000000000000000000, 64); +// require(a8 == 100000000000000000064); +// uint256 a9 = add(100000000000000000000000000000000000, 128); +// require(a9 == 100000000000000000000000000000000128); +// uint256 a10 = add(1, 255); +// require(a10 == 256); +// } + +// function int_add_conc() public pure { +// int256 a1 = int_add(100, 1); +// require(a1 == 101); +// int256 a2 = int_add(100, 2); +// require(a2 == 102); +// int256 a3 = int_add(100, 4); +// require(a3 == 104); +// int256 a4 = int_add(100, 8); +// require(a4 == 108); +// int256 a5 = int_add(1000000000, 8); +// require(a5 == 1000000008); +// int256 a6 = int_add(1000000000, 16); +// require(a6 == 1000000016); +// int256 a7 = int_add(10000000000, 32); +// require(a7 == 10000000032); +// int256 a8 = int_add(100000000000000000000, 64); +// require(a8 == 100000000000000000064); +// int256 a9 = int_add(100000000000000000000000000000000000, 128); +// require(a9 == 100000000000000000000000000000000128); +// int256 a10 = int_add(1, 255); +// require(a10 == 256); + +// int256 a11 = int_add(-100, 1); +// require(a11 == -99); +// int256 a12 = int_add(-100, 2); +// require(a12 == -98); +// int256 a13 = int_add(-100, 4); +// require(a13 == -96); +// int256 a14 = int_add(-100, 8); +// require(a14 == -92); +// int256 a15 = int_add(-1000000000, 8); +// require(a15 == -999999992); +// int256 a16 = int_add(-1000000000, 16); +// require(a16 == -999999984); +// int256 a17 = int_add(-10000000000, 32); +// require(a17 == -9999999968); +// int256 a18 = int_add(-100000000000000000000, 64); +// require(a18 == -99999999999999999936); +// int256 a19 = int_add(-100000000000000000000000000000000000, 128); +// require(a19 == -99999999999999999999999999999999872); +// int256 a20 = int_add(-1, 255); +// require(a20 == 254); + +// int256 a21 = int_add(-100, -1); +// require(a21 == -101); +// int256 a22 = int_add(-100, -2); +// require(a22 == -102); +// int256 a23 = int_add(-100, -4); +// require(a23 == -104); +// int256 a24 = int_add(-100, -8); +// require(a24 == -108); +// int256 a25 = int_add(-1000000000, -8); +// require(a25 == -1000000008); +// int256 a26 = int_add(-1000000000, -16); +// require(a26 == -1000000016); +// int256 a27 = int_add(-10000000000, -32); +// require(a27 == -10000000032); +// int256 a28 = int_add(-100000000000000000000, -64); +// require(a28 == -100000000000000000064); +// int256 a29 = int_add(-100000000000000000000000000000000000, -128); +// require(a29 == -100000000000000000000000000000000128); +// int256 a30 = int_add(-1, -255); +// require(a30 == -256); + +// int256 a31 = int_add(100, -1); +// require(a31 == 99); +// int256 a32 = int_add(100, -2); +// require(a32 == 98); +// int256 a33 = int_add(100, -4); +// require(a33 == 96); +// int256 a34 = int_add(100, -8); +// require(a34 == 92); +// int256 a35 = int_add(1000000000, -8); +// require(a35 == 999999992); +// int256 a36 = int_add(1000000000, -16); +// require(a36 == 999999984); +// int256 a37 = int_add(10000000000, -32); +// require(a37 == 9999999968); +// int256 a38 = int_add(100000000000000000000, -64); +// require(a38 == 99999999999999999936); +// int256 a39 = int_add(100000000000000000000000000000000000, -128); +// require(a39 == 99999999999999999999999999999999872); +// int256 a40 = int_add(1, -255); +// require(a40 == -254); +// } +// } + +// contract Sub { +// function sub(uint256 x, uint256 y) public pure returns (uint256) { +// return x - y; +// } + +// function int_sub(int256 x, int256 y) public pure returns (int256) { +// return x - y; +// } + +// function sub_conc() public pure returns (uint256) { +// uint256 a1 = sub(100, 1); +// require(a1 == 99); +// uint256 a2 = sub(100, 2); +// require(a2 == 98); +// uint256 a3 = sub(100, 4); +// require(a3 == 96); +// uint256 a4 = sub(100, 8); +// require(a4 == 92); +// uint256 a5 = sub(1000000000, 8); +// require(a5 == 999999992); +// uint256 a6 = sub(1000000000, 16); +// require(a6 == 999999984); +// uint256 a7 = sub(10000000000, 32); +// require(a7 == 9999999968); +// uint256 a8 = sub(100000000000000000000, 64); +// require(a8 == 99999999999999999936); +// uint256 a9 = sub(100000000000000000000000000000000000, 128); +// require(a9 == 99999999999999999999999999999999872); +// } + +// function int_sub_conc() public pure { +// int256 a1 = int_sub(100, 1); +// require(a1 == 99); +// int256 a2 = int_sub(100, 2); +// require(a2 == 98); +// int256 a3 = int_sub(100, 4); +// require(a3 == 96); +// int256 a4 = int_sub(100, 8); +// require(a4 == 92); +// int256 a5 = int_sub(1000000000, 8); +// require(a5 == 999999992); +// int256 a6 = int_sub(1000000000, 16); +// require(a6 == 999999984); +// int256 a7 = int_sub(10000000000, 32); +// require(a7 == 9999999968); +// int256 a8 = int_sub(100000000000000000000, 64); +// require(a8 == 99999999999999999936); +// int256 a9 = int_sub(100000000000000000000000000000000000, 128); +// require(a9 == 99999999999999999999999999999999872); +// int256 a10 = int_sub(1, 255); +// require(a10 == -254); + +// int256 a11 = int_sub(-100, 1); +// require(a11 == -101); +// int256 a12 = int_sub(-100, 2); +// require(a12 == -102); +// int256 a13 = int_sub(-100, 4); +// require(a13 == -104); +// int256 a14 = int_sub(-100, 8); +// require(a14 == -108); +// int256 a15 = int_sub(-1000000000, 8); +// require(a15 == -1000000008); +// int256 a16 = int_sub(-1000000000, 16); +// require(a16 == -1000000016); +// int256 a17 = int_sub(-10000000000, 32); +// require(a17 == -10000000032); +// int256 a18 = int_sub(-100000000000000000000, 64); +// require(a18 == -100000000000000000064); +// int256 a19 = int_sub(-100000000000000000000000000000000000, 128); +// require(a19 == -100000000000000000000000000000000128); +// int256 a20 = int_sub(-1, 255); +// require(a20 == -256); + +// int256 a21 = int_sub(-100, -1); +// require(a21 == -99); +// int256 a22 = int_sub(-100, -2); +// require(a22 == -98); +// int256 a23 = int_sub(-100, -4); +// require(a23 == -96); +// int256 a24 = int_sub(-100, -8); +// require(a24 == -92); +// int256 a25 = int_sub(-1000000000, -8); +// require(a25 == -999999992); +// int256 a26 = int_sub(-1000000000, -16); +// require(a26 == -999999984); +// int256 a27 = int_sub(-10000000000, -32); +// require(a27 == -9999999968); +// int256 a28 = int_sub(-100000000000000000000, -64); +// require(a28 == -99999999999999999936); +// int256 a29 = int_sub(-100000000000000000000000000000000000, -128); +// require(a29 == -99999999999999999999999999999999872); +// int256 a30 = int_sub(-1, -255); +// require(a30 == 254); + +// int256 a31 = int_sub(100, -1); +// require(a31 == 101); +// int256 a32 = int_sub(100, -2); +// require(a32 == 102); +// int256 a33 = int_sub(100, -4); +// require(a33 == 104); +// int256 a34 = int_sub(100, -8); +// require(a34 == 108); +// int256 a35 = int_sub(1000000000, -8); +// require(a35 == 1000000008); +// int256 a36 = int_sub(1000000000, -16); +// require(a36 == 1000000016); +// int256 a37 = int_sub(10000000000, -32); +// require(a37 == 10000000032); +// int256 a38 = int_sub(100000000000000000000, -64); +// require(a38 == 100000000000000000064); +// int256 a39 = int_sub(100000000000000000000000000000000000, -128); +// require(a39 == 100000000000000000000000000000000128); +// int256 a40 = int_sub(1, -255); +// require(a40 == 256); +// } +// } contract AssignMath { - function assignAdd(uint256 x) public { - x += 10; - } + // function assignAdd(uint256 x) public pure { + // x += 10; + // } - function assignSub(uint256 x) public { - x -= 10; - } + // function assignSub(uint256 x) public pure { + // x -= 10; + // } - function assignDiv(uint256 x) public { - x /= 10; - } + // function assignDiv(uint256 x) public pure { + // x /= 10; + // } - function assignMul(uint256 x) public { - x *= 10; - } + // function assignMul(uint256 x) public pure { + // x *= 10; + // } - function preincrement(uint256 x) public returns (uint256, uint256) { + function preincrement(uint256 x) public pure returns (uint256, uint256) { uint256 y = ++x; return (y, x); } - function postincrement(uint256 x) public returns (uint256, uint256) { + function postincrement(uint256 x) public pure returns (uint256, uint256) { uint256 y = x++; return (y, x); } - function predecrement(uint256 x) public returns (uint256, uint256) { + function predecrement(uint256 x) public pure returns (uint256, uint256) { uint256 y = --x; return (y, x); } - function postdecrement(uint256 x) public returns (uint256, uint256) { + function postdecrement(uint256 x) public pure returns (uint256, uint256) { uint256 y = x--; return (y, x); } - function pre_conc() public { + function pre_conc() public pure { (uint256 y, uint256 x) = preincrement(100); require(y == 101); require(x == 101); } - function post_conc() public { + function post_conc() public pure { (uint256 y, uint256 x) = postincrement(100); require(y == 100); require(x == 101); } - function pre_deconc() public { + function pre_deconc() public pure { (uint256 y, uint256 x) = predecrement(100); require(y == 99); require(x == 99); } - function post_deconc() public { + function post_deconc() public pure { (uint256 y, uint256 x) = postdecrement(100); require(y == 100); require(x == 99); } } -contract Math { - function rmod(uint256 x, uint256 y) public returns (uint256) { - return x % y; - } - - function rexp(uint256 x, uint256 y) public returns (uint256) { - return x ** y; - } - - function int_rmod(int256 x, int256 y) public returns (int256) { - return x % y; - } - - function int_rexp(int256 x, uint256 y) public returns (int256) { - return x ** y; - } -} - -contract Unchecked { - function assemblyWrappingSub(uint256 a) public { - assembly { - a := sub(0, 100) - } - require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - int256 y = type(int256).min; - assembly { - a := sub(y, 100) - } - require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - } - - function uncheckedSub(uint256 a) public { - unchecked { - a = 0 - 100; - } - require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - - int256 y = type(int256).min; - unchecked { - a = y - 100; - } - require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); - } - - function uncheckedSymbolicSub(uint256 a, uint256 b) public { - unchecked { - a -= 100; - } - } - - function assemblyWrappingAdd(uint256 a) public { - uint256 m = type(uint256).max; - assembly { - a := add(m, 100) - } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); - } - - function uncheckedAdd(uint256 a) public { - unchecked { - a = type(uint256).max + 100; - } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); - } - - function assemblyWrappingMul(uint256 a) public { - uint256 m = type(uint128).max; - assembly { - a := mul(m, m) - } - require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - a /= 3; - a *= 3; - // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); - } - - function uncheckedMul(uint256 a) public { - unchecked { - a = type(uint256).max + 100; - } - require(a == 99); - a += (type(uint256).max - 99); - require(a == type(uint256).max); - } - - function symbUncheckedMul(int256 a, int b) public { - unchecked { - a = a * b; - int c = a * a / a; - int d = a * c * b; - } - - a = a * b; - int c = a * a / a; - int d = a * c * b; - } - - function asmSymbUncheckedMul(int256 a, int b) public { - assembly { - a := mul(a, b) - } - } -} \ No newline at end of file +// contract Math { +// function rmod(uint256 x, uint256 y) public pure returns (uint256) { +// return x % y; +// } + +// function rexp(uint256 x, uint256 y) public pure returns (uint256) { +// return x ** y; +// } + +// function int_rmod(int256 x, int256 y) public pure returns (int256) { +// return x % y; +// } + +// function int_rexp(int256 x, uint256 y) public pure returns (int256) { +// return x ** y; +// } +// } + +// contract Unchecked { +// function assemblyWrappingSub(uint256 a) public pure { +// assembly { +// a := sub(0, 100) +// } +// require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + +// int256 y = type(int256).min; +// assembly { +// a := sub(y, 100) +// } +// require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); +// } + +// function uncheckedSub(uint256 a) public pure { +// unchecked { +// a = 0 - 100; +// } +// require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + +// int256 y = type(int256).min; +// unchecked { +// a = y - 100; +// } +// require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); +// } + +// function uncheckedSymbolicSub(uint256 a, uint256 b) public pure { +// unchecked { +// a -= 100; +// } +// } + +// function assemblyWrappingAdd(uint256 a) public pure { +// uint256 m = type(uint256).max; +// assembly { +// a := add(m, 100) +// } +// require(a == 99); +// a += (type(uint256).max - 99); +// require(a == type(uint256).max); +// } + +// function uncheckedAdd(uint256 a) public pure { +// unchecked { +// a = type(uint256).max + 100; +// } +// require(a == 99); +// a += (type(uint256).max - 99); +// require(a == type(uint256).max); +// } + +// function assemblyWrappingMul(uint256 a) public pure { +// uint256 m = type(uint128).max; +// assembly { +// a := mul(m, m) +// } +// require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); +// a /= 3; +// a *= 3; +// // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); +// } + +// function uncheckedMul(uint256 a) public pure { +// unchecked { +// a = type(uint256).max + 100; +// } +// require(a == 99); +// a += (type(uint256).max - 99); +// require(a == type(uint256).max); +// } + +// function symbUncheckedMul(int256 a, int b) public pure { +// unchecked { +// a = a * b; +// int c = a * a / a; +// int d = a * c * b; +// } + +// a = a * b; +// int c = a * a / a; +// int d = a * c * b; +// } + +// function asmSymbUncheckedMul(int256 a, int b) public pure { +// assembly { +// a := mul(a, b) +// } +// } +// } \ No newline at end of file diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 7955c8cc..c18acac8 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use crate::{GraphLike, NodeIdx}; use std::collections::HashMap; @@ -14,6 +15,8 @@ pub trait AnalyzerLike: GraphLike { /// Type of a function type Function; + /// Node of a function type + type FunctionNode; /// Type of a function input parameter type FunctionParam; /// Type of a function return paramter @@ -38,6 +41,7 @@ pub trait AnalyzerLike: GraphLike { fn msg(&mut self) -> Self::MsgNode; fn block(&mut self) -> Self::BlockNode; fn entry(&self) -> NodeIdx; + fn parse_fn(&self) -> Self::FunctionNode; fn add_expr_err(&mut self, err: Self::ExprErr); fn expr_errs(&self) -> Vec; @@ -52,6 +56,20 @@ pub trait AnalyzerLike: GraphLike { Self: std::marker::Sized; fn debug_panic(&self) -> bool; + + fn fn_calls_fns(&self) -> &BTreeMap>; + fn fn_calls_fns_mut(&mut self) -> &mut BTreeMap>; + fn add_fn_call(&mut self, caller: Self::FunctionNode, callee: Self::FunctionNode) + where Self::FunctionNode: Ord + { + let calls = self.fn_calls_fns_mut(); + let entry = calls.entry(caller).or_default(); + if !entry.contains(&callee) { + entry.push(callee) + } + } + + fn add_if_err(&mut self, err: Result) -> Option where Self::ExprErr: std::fmt::Debug, diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 3b000e41..e5c3edf8 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -71,16 +71,7 @@ pub trait GraphLike { self.range_arena().map.get(elem).copied() } - fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { - if let Some(idx) = self.range_arena_idx(&elem) { - idx - } else { - let idx = self.range_arena().ranges.len(); - self.range_arena_mut().ranges.push(elem.clone()); - self.range_arena_mut().map.insert(elem, idx); - idx - } - } + fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize; } /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) diff --git a/crates/solc-expressions/src/context_builder/fn_calls.rs b/crates/solc-expressions/src/context_builder/fn_calls.rs new file mode 100644 index 00000000..78bd7113 --- /dev/null +++ b/crates/solc-expressions/src/context_builder/fn_calls.rs @@ -0,0 +1,326 @@ +use solang_parser::helpers::CodeLocation; +use crate::{ + ExprErr, ExpressionParser, StatementParser +}; + +use graph::{ + nodes::{ + Context, ContextNode, FunctionNode, + }, + AnalyzerBackend, ContextEdge, Edge, Node, +}; + +use solang_parser::{ + pt::{Expression, Statement}, +}; + + +impl FnCallBuilder for T where + T: AnalyzerBackend + Sized + StatementParser + ExpressionParser +{ +} + +/// Dispatcher for building up a context of a function +pub trait FnCallBuilder: + AnalyzerBackend + Sized + StatementParser + ExpressionParser +{ + fn analyze_fn_calls(&mut self, caller: FunctionNode) { + self.fn_calls_fns_mut().entry(caller).or_default(); + if let Some(body) = caller.underlying(self).unwrap().body.clone() { + self.analyze_fn_calls_stmt(caller, body); + } + } + + fn analyze_fn_calls_stmt(&mut self, caller: FunctionNode, stmt: Statement) { + use Statement::*; + match stmt { + Block {statements, ..} => { + statements.iter().for_each(|stmt| { + self.analyze_fn_calls_stmt(caller, stmt.clone()); + }); + }, + Assembly {..} => {}, + Args(_, args) => { + args.iter().for_each(|arg| { + self.analyze_fn_calls_expr(caller, arg.expr.clone()); + }); + }, + If(_, expr, stmt_true, maybe_stmt_false) => { + self.analyze_fn_calls_expr(caller, expr); + self.analyze_fn_calls_stmt(caller, *stmt_true); + if let Some(stmt_false) = maybe_stmt_false { + self.analyze_fn_calls_stmt(caller, *stmt_false); + } + }, + While(_, expr, stmt) => { + self.analyze_fn_calls_expr(caller, expr); + self.analyze_fn_calls_stmt(caller, *stmt); + }, + Expression(_, expr) => self.analyze_fn_calls_expr(caller, expr), + VariableDefinition(_, var_decl, maybe_expr) => { + self.analyze_fn_calls_expr(caller, var_decl.ty); + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, expr); + } + }, + For(_, maybe_stmt, maybe_expr, maybe_stmt_1, maybe_stmt_2) => { + if let Some(stmt) = maybe_stmt { + self.analyze_fn_calls_stmt(caller, *stmt); + } + + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr); + } + + if let Some(stmt1) = maybe_stmt_1 { + self.analyze_fn_calls_stmt(caller, *stmt1); + } + + if let Some(stmt2) = maybe_stmt_2 { + self.analyze_fn_calls_stmt(caller, *stmt2); + } + }, + DoWhile(_, stmt, expr) => { + self.analyze_fn_calls_stmt(caller, *stmt); + self.analyze_fn_calls_expr(caller, expr); + }, + Continue(_) => {}, + Break(_) => {}, + Return(_, maybe_expr) => { + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, expr); + } + }, + Revert(_, _, exprs) => { + exprs.iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr.clone()); + }); + }, + RevertNamedArgs(_, _, args) => { + args.iter().for_each(|arg| { + self.analyze_fn_calls_expr(caller, arg.expr.clone()); + }); + }, + Emit(_, expr) => { + self.analyze_fn_calls_expr(caller, expr); + }, + Try(_, expr, maybe_tuple, catch_clauses) => { + self.analyze_fn_calls_expr(caller, expr); + // Option<(ParameterList, Box)> + if let Some((param_list, stmt)) = maybe_tuple { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + self.analyze_fn_calls_stmt(caller, *stmt); + } + + catch_clauses.iter().for_each(|catch_clause| { + match catch_clause { + solang_parser::pt::CatchClause::Simple(_, maybe_param, stmt) => { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + self.analyze_fn_calls_stmt(caller, stmt.clone()); + }, + solang_parser::pt::CatchClause::Named(_, _, param, stmt) => { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + self.analyze_fn_calls_stmt(caller, stmt.clone()); + }, + } + }) + }, + Error(_) => {}, + } + } + + fn analyze_fn_calls_expr(&mut self, caller: FunctionNode, expr: Expression) { + use Expression::*; + match expr { + BoolLiteral(_, _) + | NumberLiteral(_, _, _, _) + | RationalNumberLiteral(_, _, _, _, _) + | HexNumberLiteral(_, _, _) + | StringLiteral(_) + | HexLiteral(_) + | AddressLiteral(_, _) + | Variable(_) + | This(_) => {} + + PostIncrement(_, expr) + | PostDecrement(_, expr) + | New(_, expr) + | Parenthesis(_, expr) + | MemberAccess(_, expr, _) + | Not(_, expr) + | Delete(_, expr) + | PreIncrement(_, expr) + | PreDecrement(_, expr) + | BitwiseNot(_, expr) + | Negate(_, expr) + | UnaryPlus(_, expr) => { + self.analyze_fn_calls_expr(caller, *expr); + } + + Power(_, expr, expr1) + | Multiply(_, expr, expr1) + | Divide(_, expr, expr1) + | Modulo(_, expr, expr1) + | Add(_, expr, expr1) + | Subtract(_, expr, expr1) + | ShiftLeft(_, expr, expr1) + | ShiftRight(_, expr, expr1) + | BitwiseAnd(_, expr, expr1) + | BitwiseXor(_, expr, expr1) + | BitwiseOr(_, expr, expr1) + | Less(_, expr, expr1) + | More(_, expr, expr1) + | LessEqual(_, expr, expr1) + | MoreEqual(_, expr, expr1) + | Equal(_, expr, expr1) + | NotEqual(_, expr, expr1) + | And(_, expr, expr1) + | Or(_, expr, expr1) + | Assign(_, expr, expr1) + | AssignOr(_, expr, expr1) + | AssignAnd(_, expr, expr1) + | AssignXor(_, expr, expr1) + | AssignShiftLeft(_, expr, expr1) + | AssignShiftRight(_, expr, expr1) + | AssignAdd(_, expr, expr1) + | AssignSubtract(_, expr, expr1) + | AssignMultiply(_, expr, expr1) + | AssignDivide(_, expr, expr1) + | AssignModulo(_, expr, expr1) => { + self.analyze_fn_calls_expr(caller, *expr); + self.analyze_fn_calls_expr(caller, *expr1); + } + + ArraySubscript(_, expr, maybe_expr) => { + self.analyze_fn_calls_expr(caller, *expr); + if let Some(expr1) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr1); + } + }, + ArraySlice(_, expr, maybe_expr, maybe_expr1) => { + self.analyze_fn_calls_expr(caller, *expr); + if let Some(expr1) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr1); + } + + if let Some(expr2) = maybe_expr1 { + self.analyze_fn_calls_expr(caller, *expr2); + } + }, + ConditionalOperator(_, expr, expr1, expr2) => { + self.analyze_fn_calls_expr(caller, *expr); + self.analyze_fn_calls_expr(caller, *expr1); + self.analyze_fn_calls_expr(caller, *expr2); + }, + List(_, param_list) => { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + }, + ArrayLiteral(_, exprs) => { + exprs.into_iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr); + }); + }, + + Type(_, ty) => { + match ty { + solang_parser::pt::Type::Mapping { + key, + value, + .. + } => { + self.analyze_fn_calls_expr(caller, *key); + self.analyze_fn_calls_expr(caller, *value); + }, + solang_parser::pt::Type::Function { + params, + returns, + .. + } => { + params.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + if let Some((param_list, _)) = returns { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + } + }, + _ => {} + } + }, + + FunctionCallBlock(_, func_expr, _input_exprs) => { + match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx + .visible_funcs(self) + .unwrap(); + let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + }, + _ => {} + } + } + NamedFunctionCall(_, func_expr, _input_args) => { + match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx + .visible_funcs(self) + .unwrap(); + let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + }, + _ => {} + } + } + FunctionCall(_, func_expr, input_exprs) => { + match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx + .visible_funcs(self) + .unwrap(); + let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + }, + _ => {} + } + + input_exprs.iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr.clone()); + }) + }, + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 35b58142..7b941e65 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -15,9 +15,11 @@ impl ContextBuilder for T where mod expr; mod stmt; +mod fn_calls; pub use expr::*; pub use stmt::*; +pub use fn_calls::*; /// Dispatcher for building up a context of a function pub trait ContextBuilder: diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 9f1e1abb..6a1ddaef 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -400,6 +400,23 @@ pub trait FuncCaller: func_call_str: Option<&str>, modifier_state: Option, ) -> Result<(), ExprErr> { + if !entry_call { + let mapping = params + .iter() + .zip(inputs.iter()) + .filter_map(|(param, input)| { + if let Ok(Some(name)) = param.maybe_name(self) { + Some((name, (*param, *input))) + } else { + None + } + }) + .collect::>(); + if let Ok(true) = ctx.join(func_node, &mapping, self) { + return Ok(()) + } + } + // pseudocode: // 1. Create context for the call // 2. Check for modifiers @@ -412,16 +429,6 @@ pub trait FuncCaller: self.create_call_ctx(ctx, loc, func_node, modifier_state)? }; - // TODO: implement joining - // if !entry_call { - // let mapping = params - // .iter() - // .zip(inputs.iter()) - // .map(|(param, input)| (*input, *param)) - // .collect::>(); - // ctx.join(func_node, &mapping, self); - // } - // handle remapping of variable names and bringing variables into the new context let renamed_inputs = self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 36c29abe..c8b00946 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -58,6 +58,12 @@ pub trait CallerHelper: AnalyzerBackend + let node = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + self.add_edge( + node, + input.latest_version(self), + Edge::Context(ContextEdge::InputVariable), + ); + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { if !node.ty_eq_ty(¶m_ty, self).unwrap() { diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index 48417121..3c43085d 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -131,31 +131,36 @@ pub trait PrePostIncDecrement: Ok(()) } ExprRet::SingleLiteral(var) => { - let res = ContextVarNode::from(*var) + ContextVarNode::from(*var) .try_increase_size(self) - .into_expr_err(loc); - let _ = self.add_if_err(res); + .into_expr_err(loc)?; self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) } ExprRet::Single(var) => { - let cvar = ContextVarNode::from(*var); + let cvar = ContextVarNode::from(*var).latest_version(self); let elem = Elem::from(cvar); let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); + + // if let Some(r) = cvar.range(self).into_expr_err(loc)? { if increment { if pre { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone() + one.clone()); + dup.set_range_max(self, elem.clone() + one.clone()); let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar + new_cvar .set_range_min(self, elem.clone() + one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); - let res = new_cvar.set_range_max(self, elem + one).into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + .into_expr_err(loc)?; + new_cvar + .set_range_max(self, elem + one).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone()); + dup.set_range_max(self, elem.clone()); let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; let res = new_cvar .set_range_min(self, elem.clone() + one.clone()) @@ -164,29 +169,32 @@ pub trait PrePostIncDecrement: new_cvar .set_range_max(self, elem + one) .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(dup.into()), self) + ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) } } else if pre { + let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone() - one.clone()); + dup.set_range_max(self, elem.clone() - one.clone()); let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar + new_cvar .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); + .into_expr_err(loc)?; new_cvar .set_range_max(self, elem - one) .into_expr_err(loc)?; - ctx.push_expr(ExprRet::Single(new_cvar.into()), self) + ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone()); + dup.set_range_max(self, elem.clone()); let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; - let res = new_cvar + new_cvar .set_range_min(self, elem.clone() - one.clone()) - .into_expr_err(loc); - let _ = self.add_if_err(res); + .into_expr_err(loc)?; new_cvar .set_range_max(self, elem - one) .into_expr_err(loc)?; From a9b0b86f1ea1a22443c900e2f4d92fc60b13e951 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 19:19:20 -0800 Subject: [PATCH 60/71] lint --- crates/cli/src/main.rs | 1 - crates/graph/src/nodes/context/node.rs | 93 +-- crates/graph/src/nodes/context/solving.rs | 3 +- crates/graph/src/nodes/context/var/ranging.rs | 5 +- crates/graph/src/nodes/func_ty.rs | 13 +- crates/graph/src/range/elem/elem_enum.rs | 16 +- crates/graph/src/range/elem/expr.rs | 6 +- crates/graph/src/range/solc_range.rs | 18 +- crates/graph/src/solvers/atoms.rs | 12 +- crates/graph/src/solvers/brute.rs | 14 +- crates/pyrometer/src/analyzer.rs | 14 +- crates/pyrometer/src/analyzer_backend.rs | 4 +- crates/pyrometer/src/graph_backend.rs | 7 +- crates/shared/src/analyzer_like.rs | 6 +- .../src/context_builder/fn_calls.rs | 579 +++++++++--------- .../src/context_builder/mod.rs | 4 +- .../src/func_call/func_caller.rs | 2 +- .../solc-expressions/src/func_call/helper.rs | 2 +- .../src/pre_post_in_decrement.rs | 4 +- 19 files changed, 421 insertions(+), 382 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index b6d6b729..7ff232ac 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -243,7 +243,6 @@ fn main() { let t_end = t0.elapsed(); let parse_time = t_end.as_millis(); - println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); if args.stats { diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index bb5693bb..4d7bb6eb 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,10 +1,10 @@ -use crate::VarType; -use crate::range::Range; -use crate::range::elem::RangeElem; -use crate::nodes::ExprRet; use crate::elem::Elem; -use crate::Edge; +use crate::nodes::ExprRet; +use crate::range::elem::RangeElem; +use crate::range::Range; use crate::ContextEdge; +use crate::Edge; +use crate::VarType; use crate::{ nodes::{Context, ContextVarNode, FunctionNode, FunctionParamNode, KilledKind}, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, @@ -32,7 +32,6 @@ impl ContextNode { mapping: &BTreeMap, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { - // ensure no modifiers (for now) // if pure function: // grab requirements for context @@ -50,7 +49,8 @@ impl ContextNode { inputs.iter().for_each(|input| { let name = input.name(analyzer).unwrap(); if let Some((param, replacement_input)) = mapping.get(&name) { - if let Some(param_ty) = VarType::try_from_idx(analyzer, param.ty(analyzer).unwrap()) + if let Some(param_ty) = + VarType::try_from_idx(analyzer, param.ty(analyzer).unwrap()) { if !replacement_input.ty_eq_ty(¶m_ty, analyzer).unwrap() { replacement_input.cast_from_ty(param_ty, analyzer).unwrap(); @@ -58,13 +58,12 @@ impl ContextNode { } let mut replacement = Elem::from(*replacement_input); replacement.arenaize(analyzer).unwrap(); - + if let Some(next) = input.next_version(analyzer) { replacement_map.insert(next.0, replacement.clone()); } replacement_map.insert(input.0, replacement); // a lot of time (all the time?) there is an extra version added on - } // println!(" name: {}", input.display_name(analyzer).unwrap()); // println!(" idx: {}", input.0); @@ -83,36 +82,48 @@ impl ContextNode { // 1. Create a new variable with name `.` // 2. Set the range to be the copy of the return's simplified range from the function // 3. Replace the fundamentals with the input data - let ret: Vec<_> = body_ctx.return_nodes(analyzer)?.iter().enumerate().map(|(i, (_, ret_node))| { - // println!("original return:"); - // println!(" name: {}", ret_node.display_name(analyzer).unwrap()); - // println!(" range: {}", ret_node.simplified_range_string(analyzer).unwrap().unwrap()); - let mut new_var = ret_node.underlying(analyzer).unwrap().clone(); - let new_name = format!("{}.{i}", func.name(analyzer).unwrap()); - new_var.name = new_name.clone(); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep((*replace).into(), replacement.clone(), analyzer); - }); - - range.cache_eval(analyzer).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - let new_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); - analyzer.add_edge(new_cvar, *self, Edge::Context(ContextEdge::Variable)); - self.add_var(new_cvar, analyzer).unwrap(); - // let new_range = new_cvar.range(analyzer).unwrap().unwrap(); - - // println!("new return:"); - // println!(" name: {}", new_cvar.display_name(analyzer).unwrap()); - // println!(" range: {}", new_cvar.range_string(analyzer).unwrap().unwrap()); - ExprRet::Single(new_cvar.into()) - }).collect(); - + let ret: Vec<_> = body_ctx + .return_nodes(analyzer)? + .iter() + .enumerate() + .map(|(i, (_, ret_node))| { + // println!("original return:"); + // println!(" name: {}", ret_node.display_name(analyzer).unwrap()); + // println!(" range: {}", ret_node.simplified_range_string(analyzer).unwrap().unwrap()); + let mut new_var = ret_node.underlying(analyzer).unwrap().clone(); + let new_name = format!("{}.{i}", func.name(analyzer).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep( + (*replace).into(), + replacement.clone(), + analyzer, + ); + }); + + range.cache_eval(analyzer).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + let new_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); + analyzer.add_edge( + new_cvar, + *self, + Edge::Context(ContextEdge::Variable), + ); + self.add_var(new_cvar, analyzer).unwrap(); + // let new_range = new_cvar.range(analyzer).unwrap().unwrap(); + + // println!("new return:"); + // println!(" name: {}", new_cvar.display_name(analyzer).unwrap()); + // println!(" range: {}", new_cvar.range_string(analyzer).unwrap().unwrap()); + ExprRet::Single(new_cvar.into()) + }) + .collect(); // println!("requires:"); body_ctx.ctx_deps(analyzer)?.iter().for_each(|dep| { @@ -127,7 +138,8 @@ impl ContextNode { new_var.ty.set_range(range).unwrap(); } - let new_cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); + let new_cvar = + ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); self.add_ctx_dep(new_cvar, analyzer).unwrap(); }); @@ -137,8 +149,7 @@ impl ContextNode { func.name(analyzer).unwrap(), self.associated_fn_name(analyzer).unwrap() ); - self - .push_expr(ExprRet::Multi(ret), analyzer)?; + self.push_expr(ExprRet::Multi(ret), analyzer)?; return Ok(true); } } diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 6170ec8f..da30b745 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -63,7 +63,8 @@ impl ContextNode { &self, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - let deps = self.underlying(analyzer)? + let deps = self + .underlying(analyzer)? .ctx_deps .clone() .into_iter() diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index cbeb8562..2a1c86c1 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -31,7 +31,10 @@ impl ContextVarNode { } } - pub fn simplified_range_string(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn simplified_range_string( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { Ok(Some(format!( "[ {}, {} ]", diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 46c6452c..81359a15 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -11,7 +11,7 @@ use solang_parser::{ helpers::CodeLocation, pt::{ Base, Expression, FunctionAttribute, FunctionDefinition, FunctionTy, Identifier, Loc, - Parameter, ParameterList, Statement, Type, VariableDefinition, Visibility, Mutability + Mutability, Parameter, ParameterList, Statement, Type, VariableDefinition, Visibility, }, }; use std::collections::BTreeMap; @@ -455,12 +455,11 @@ impl FunctionNode { } pub fn is_pure(&self, analyzer: &impl GraphBackend) -> Result { - Ok(self.underlying(analyzer)?.attributes.iter().any(|attr| { - matches!( - attr, - FunctionAttribute::Mutability(Mutability::Pure(_)) - ) - })) + Ok(self + .underlying(analyzer)? + .attributes + .iter() + .any(|attr| matches!(attr, FunctionAttribute::Mutability(Mutability::Pure(_))))) } pub fn get_overriding( diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 08c6cfd9..aba48e24 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -314,7 +314,12 @@ impl From for Elem { } impl Elem { - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Self, analyzer: &mut impl GraphBackend) { + pub fn replace_dep( + &mut self, + to_replace: NodeIdx, + replacement: Self, + analyzer: &mut impl GraphBackend, + ) { match self { Elem::Reference(Reference { idx, .. }) => { if *idx == to_replace { @@ -323,7 +328,8 @@ impl Elem { } Elem::Concrete(_) => {} Elem::Expr(expr) => { - expr.lhs.replace_dep(to_replace, replacement.clone(), analyzer); + expr.lhs + .replace_dep(to_replace, replacement.clone(), analyzer); expr.rhs.replace_dep(to_replace, replacement, analyzer); expr.maximized = None; expr.minimized = None; @@ -335,13 +341,15 @@ impl Elem { s.replace_dep(to_replace, replacement, analyzer); s.arenaize(analyzer).unwrap(); *self = s; - }, + } } } pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Self { match self { - Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone().recurse_dearenaize(analyzer), + Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx] + .clone() + .recurse_dearenaize(analyzer), Self::Expr(expr) => expr.recurse_dearenaize(analyzer), e => e.clone(), } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 1c631dde..d3fbf783 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -83,7 +83,11 @@ impl RangeExpr { } pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { - Elem::Expr(Self::new(self.lhs.recurse_dearenaize(analyzer).clone(), self.op, self.rhs.recurse_dearenaize(analyzer).clone())) + Elem::Expr(Self::new( + self.lhs.recurse_dearenaize(analyzer).clone(), + self.op, + self.rhs.recurse_dearenaize(analyzer).clone(), + )) } } diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 7d62bc67..6de42b53 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -90,12 +90,22 @@ impl SolcRange { } } - pub fn replace_dep(&mut self, to_replace: NodeIdx, replacement: Elem, analyzer: &mut impl GraphBackend) { + pub fn replace_dep( + &mut self, + to_replace: NodeIdx, + replacement: Elem, + analyzer: &mut impl GraphBackend, + ) { if let Some(ref mut flattened) = &mut self.flattened { - flattened.min.replace_dep(to_replace, replacement.clone(), analyzer); - flattened.max.replace_dep(to_replace, replacement.clone(), analyzer); + flattened + .min + .replace_dep(to_replace, replacement.clone(), analyzer); + flattened + .max + .replace_dep(to_replace, replacement.clone(), analyzer); } - self.min.replace_dep(to_replace, replacement.clone(), analyzer); + self.min + .replace_dep(to_replace, replacement.clone(), analyzer); self.max.replace_dep(to_replace, replacement, analyzer); self.min_cached = None; self.max_cached = None; diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 967dee3c..b831b2a2 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -37,7 +37,11 @@ impl AtomOrPart { } } - pub fn replace_deps(&self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend) -> Self { + pub fn replace_deps( + &self, + solves: &BTreeMap>, + analyzer: &mut impl GraphBackend, + ) -> Self { match self { AtomOrPart::Part(part) => { let mut new_part = part.clone(); @@ -122,7 +126,11 @@ impl ToRangeString for SolverAtom { } impl SolverAtom { - pub fn replace_deps(&self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend) -> Self { + pub fn replace_deps( + &self, + solves: &BTreeMap>, + analyzer: &mut impl GraphBackend, + ) -> Self { SolverAtom { ty: self.ty, lhs: Box::new(self.lhs.clone().replace_deps(solves, analyzer)), diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 60cfa139..a504b10e 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -362,10 +362,9 @@ impl SolcSolver for BruteBinSearchSolver { } else { atomic_solves.iter().for_each(|(atomic, val)| { self.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { - atomic - .idxs - .iter() - .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer)); + atomic.idxs.iter().for_each(|idx| { + r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer) + }); }); }); @@ -677,10 +676,9 @@ impl SolcSolver for BruteBinSearchSolver { atomic_solves.iter().for_each(|(atomic, val)| { this.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { - atomic - .idxs - .iter() - .for_each(|idx| r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer)); + atomic.idxs.iter().for_each(|idx| { + r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer) + }); }); }); diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 7d2aabbc..ecc26f28 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -1,4 +1,3 @@ - use crate::builtin_fns; use graph::elem::Elem; use shared::RangeArena; @@ -6,10 +5,10 @@ use shared::RangeArena; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; -use solc_expressions::{ExprErr, IntoExprErr, StatementParser, FnCallBuilder}; +use solc_expressions::{ExprErr, FnCallBuilder, IntoExprErr, StatementParser}; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; -use petgraph::{graph::*, Directed, stable_graph::StableGraph}; +use petgraph::{graph::*, stable_graph::StableGraph, Directed}; use serde_json::Value; use solang_parser::{ diagnostics::Diagnostic, @@ -517,9 +516,10 @@ impl Analyzer { }); elems.into_iter().for_each(|final_pass_item| { - final_pass_item.funcs.iter().for_each(|func| { - self.analyze_fn_calls(*func) - }); + final_pass_item + .funcs + .iter() + .for_each(|func| self.analyze_fn_calls(*func)); let mut handled_funcs = vec![]; let mut func_mapping = BTreeMap::default(); let mut call_dep_graph: StableGraph = StableGraph::default(); @@ -560,7 +560,7 @@ impl Analyzer { } let indices = res.unwrap(); - + indices.iter().for_each(|idx| { let func = call_dep_graph.node_weight(*idx).unwrap(); if !handled_funcs.contains(&func) { diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 96ac6e02..3d78b5c4 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -2,8 +2,8 @@ use crate::Analyzer; use graph::{ nodes::{ - BlockNode, Builtin, Concrete, ConcreteNode, Function, FunctionParam, FunctionParamNode, - FunctionReturn, MsgNode, FunctionNode, + BlockNode, Builtin, Concrete, ConcreteNode, Function, FunctionNode, FunctionParam, + FunctionParamNode, FunctionReturn, MsgNode, }, AnalyzerBackend, Edge, Node, VarType, }; diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 30a21f34..b7eee557 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,6 +1,6 @@ -use graph::elem::RangeElem; use crate::Analyzer; use graph::elem::Elem; +use graph::elem::RangeElem; use graph::nodes::Concrete; use shared::RangeArena; @@ -52,7 +52,6 @@ impl GraphLike for Analyzer { existing_count += 1; } - let (min_cached, max_cached) = elem.is_min_max_cached(self); let mut new_count = 0; if min_cached { @@ -64,7 +63,7 @@ impl GraphLike for Analyzer { if elem.is_flatten_cached(self) { new_count += 1; } - + if new_count >= existing_count { self.range_arena_mut().ranges[idx] = elem; } @@ -642,7 +641,7 @@ impl GraphLike for G<'_> { panic!("Should not call this") } - fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { + fn range_arena_idx_or_upsert(&mut self, _elem: Self::RangeElem) -> usize { panic!("Should not call this") } } diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index c18acac8..0d56bc9e 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -1,5 +1,5 @@ -use std::collections::BTreeMap; use crate::{GraphLike, NodeIdx}; +use std::collections::BTreeMap; use std::collections::HashMap; pub trait AnalyzerLike: GraphLike { @@ -60,7 +60,8 @@ pub trait AnalyzerLike: GraphLike { fn fn_calls_fns(&self) -> &BTreeMap>; fn fn_calls_fns_mut(&mut self) -> &mut BTreeMap>; fn add_fn_call(&mut self, caller: Self::FunctionNode, callee: Self::FunctionNode) - where Self::FunctionNode: Ord + where + Self::FunctionNode: Ord, { let calls = self.fn_calls_fns_mut(); let entry = calls.entry(caller).or_default(); @@ -68,7 +69,6 @@ pub trait AnalyzerLike: GraphLike { entry.push(callee) } } - fn add_if_err(&mut self, err: Result) -> Option where diff --git a/crates/solc-expressions/src/context_builder/fn_calls.rs b/crates/solc-expressions/src/context_builder/fn_calls.rs index 78bd7113..3be6c374 100644 --- a/crates/solc-expressions/src/context_builder/fn_calls.rs +++ b/crates/solc-expressions/src/context_builder/fn_calls.rs @@ -1,22 +1,18 @@ +use crate::{ExprErr, ExpressionParser, StatementParser}; use solang_parser::helpers::CodeLocation; -use crate::{ - ExprErr, ExpressionParser, StatementParser -}; use graph::{ - nodes::{ - Context, ContextNode, FunctionNode, - }, - AnalyzerBackend, ContextEdge, Edge, Node, -}; - -use solang_parser::{ - pt::{Expression, Statement}, + nodes::{Context, ContextNode, FunctionNode}, + AnalyzerBackend, Node, }; +use solang_parser::pt::{Expression, Statement}; impl FnCallBuilder for T where - T: AnalyzerBackend + Sized + StatementParser + ExpressionParser + T: AnalyzerBackend + + Sized + + StatementParser + + ExpressionParser { } @@ -25,302 +21,305 @@ pub trait FnCallBuilder: AnalyzerBackend + Sized + StatementParser + ExpressionParser { fn analyze_fn_calls(&mut self, caller: FunctionNode) { - self.fn_calls_fns_mut().entry(caller).or_default(); + self.fn_calls_fns_mut().entry(caller).or_default(); if let Some(body) = caller.underlying(self).unwrap().body.clone() { - self.analyze_fn_calls_stmt(caller, body); + self.analyze_fn_calls_stmt(caller, body); } } fn analyze_fn_calls_stmt(&mut self, caller: FunctionNode, stmt: Statement) { - use Statement::*; - match stmt { - Block {statements, ..} => { - statements.iter().for_each(|stmt| { - self.analyze_fn_calls_stmt(caller, stmt.clone()); - }); - }, - Assembly {..} => {}, - Args(_, args) => { - args.iter().for_each(|arg| { - self.analyze_fn_calls_expr(caller, arg.expr.clone()); - }); - }, - If(_, expr, stmt_true, maybe_stmt_false) => { - self.analyze_fn_calls_expr(caller, expr); - self.analyze_fn_calls_stmt(caller, *stmt_true); - if let Some(stmt_false) = maybe_stmt_false { - self.analyze_fn_calls_stmt(caller, *stmt_false); - } - }, - While(_, expr, stmt) => { - self.analyze_fn_calls_expr(caller, expr); - self.analyze_fn_calls_stmt(caller, *stmt); - }, - Expression(_, expr) => self.analyze_fn_calls_expr(caller, expr), - VariableDefinition(_, var_decl, maybe_expr) => { - self.analyze_fn_calls_expr(caller, var_decl.ty); - if let Some(expr) = maybe_expr { - self.analyze_fn_calls_expr(caller, expr); - } - }, - For(_, maybe_stmt, maybe_expr, maybe_stmt_1, maybe_stmt_2) => { - if let Some(stmt) = maybe_stmt { - self.analyze_fn_calls_stmt(caller, *stmt); - } - - if let Some(expr) = maybe_expr { - self.analyze_fn_calls_expr(caller, *expr); - } + use Statement::*; + match stmt { + Block { statements, .. } => { + statements.iter().for_each(|stmt| { + self.analyze_fn_calls_stmt(caller, stmt.clone()); + }); + } + Assembly { .. } => {} + Args(_, args) => { + args.iter().for_each(|arg| { + self.analyze_fn_calls_expr(caller, arg.expr.clone()); + }); + } + If(_, expr, stmt_true, maybe_stmt_false) => { + self.analyze_fn_calls_expr(caller, expr); + self.analyze_fn_calls_stmt(caller, *stmt_true); + if let Some(stmt_false) = maybe_stmt_false { + self.analyze_fn_calls_stmt(caller, *stmt_false); + } + } + While(_, expr, stmt) => { + self.analyze_fn_calls_expr(caller, expr); + self.analyze_fn_calls_stmt(caller, *stmt); + } + Expression(_, expr) => self.analyze_fn_calls_expr(caller, expr), + VariableDefinition(_, var_decl, maybe_expr) => { + self.analyze_fn_calls_expr(caller, var_decl.ty); + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, expr); + } + } + For(_, maybe_stmt, maybe_expr, maybe_stmt_1, maybe_stmt_2) => { + if let Some(stmt) = maybe_stmt { + self.analyze_fn_calls_stmt(caller, *stmt); + } - if let Some(stmt1) = maybe_stmt_1 { - self.analyze_fn_calls_stmt(caller, *stmt1); - } - - if let Some(stmt2) = maybe_stmt_2 { - self.analyze_fn_calls_stmt(caller, *stmt2); - } - }, - DoWhile(_, stmt, expr) => { - self.analyze_fn_calls_stmt(caller, *stmt); - self.analyze_fn_calls_expr(caller, expr); - }, - Continue(_) => {}, - Break(_) => {}, - Return(_, maybe_expr) => { - if let Some(expr) = maybe_expr { - self.analyze_fn_calls_expr(caller, expr); - } - }, - Revert(_, _, exprs) => { - exprs.iter().for_each(|expr| { - self.analyze_fn_calls_expr(caller, expr.clone()); - }); - }, - RevertNamedArgs(_, _, args) => { - args.iter().for_each(|arg| { - self.analyze_fn_calls_expr(caller, arg.expr.clone()); - }); - }, - Emit(_, expr) => { - self.analyze_fn_calls_expr(caller, expr); - }, - Try(_, expr, maybe_tuple, catch_clauses) => { - self.analyze_fn_calls_expr(caller, expr); - // Option<(ParameterList, Box)> - if let Some((param_list, stmt)) = maybe_tuple { - param_list.iter().for_each(|(_, maybe_param)| { - if let Some(param) = maybe_param { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - } - }); - self.analyze_fn_calls_stmt(caller, *stmt); - } + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr); + } - catch_clauses.iter().for_each(|catch_clause| { - match catch_clause { - solang_parser::pt::CatchClause::Simple(_, maybe_param, stmt) => { - if let Some(param) = maybe_param { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - } - self.analyze_fn_calls_stmt(caller, stmt.clone()); - }, - solang_parser::pt::CatchClause::Named(_, _, param, stmt) => { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - self.analyze_fn_calls_stmt(caller, stmt.clone()); - }, - } - }) - }, - Error(_) => {}, - } + if let Some(stmt1) = maybe_stmt_1 { + self.analyze_fn_calls_stmt(caller, *stmt1); + } + + if let Some(stmt2) = maybe_stmt_2 { + self.analyze_fn_calls_stmt(caller, *stmt2); + } + } + DoWhile(_, stmt, expr) => { + self.analyze_fn_calls_stmt(caller, *stmt); + self.analyze_fn_calls_expr(caller, expr); + } + Continue(_) => {} + Break(_) => {} + Return(_, maybe_expr) => { + if let Some(expr) = maybe_expr { + self.analyze_fn_calls_expr(caller, expr); + } + } + Revert(_, _, exprs) => { + exprs.iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr.clone()); + }); + } + RevertNamedArgs(_, _, args) => { + args.iter().for_each(|arg| { + self.analyze_fn_calls_expr(caller, arg.expr.clone()); + }); + } + Emit(_, expr) => { + self.analyze_fn_calls_expr(caller, expr); + } + Try(_, expr, maybe_tuple, catch_clauses) => { + self.analyze_fn_calls_expr(caller, expr); + // Option<(ParameterList, Box)> + if let Some((param_list, stmt)) = maybe_tuple { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + self.analyze_fn_calls_stmt(caller, *stmt); + } + + catch_clauses + .iter() + .for_each(|catch_clause| match catch_clause { + solang_parser::pt::CatchClause::Simple(_, maybe_param, stmt) => { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + self.analyze_fn_calls_stmt(caller, stmt.clone()); + } + solang_parser::pt::CatchClause::Named(_, _, param, stmt) => { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + self.analyze_fn_calls_stmt(caller, stmt.clone()); + } + }) + } + Error(_) => {} + } } fn analyze_fn_calls_expr(&mut self, caller: FunctionNode, expr: Expression) { - use Expression::*; + use Expression::*; match expr { - BoolLiteral(_, _) - | NumberLiteral(_, _, _, _) - | RationalNumberLiteral(_, _, _, _, _) - | HexNumberLiteral(_, _, _) - | StringLiteral(_) - | HexLiteral(_) - | AddressLiteral(_, _) - | Variable(_) - | This(_) => {} - - PostIncrement(_, expr) - | PostDecrement(_, expr) - | New(_, expr) - | Parenthesis(_, expr) - | MemberAccess(_, expr, _) - | Not(_, expr) - | Delete(_, expr) - | PreIncrement(_, expr) - | PreDecrement(_, expr) - | BitwiseNot(_, expr) - | Negate(_, expr) - | UnaryPlus(_, expr) => { - self.analyze_fn_calls_expr(caller, *expr); - } + BoolLiteral(_, _) + | NumberLiteral(_, _, _, _) + | RationalNumberLiteral(_, _, _, _, _) + | HexNumberLiteral(_, _, _) + | StringLiteral(_) + | HexLiteral(_) + | AddressLiteral(_, _) + | Variable(_) + | This(_) => {} - Power(_, expr, expr1) - | Multiply(_, expr, expr1) - | Divide(_, expr, expr1) - | Modulo(_, expr, expr1) - | Add(_, expr, expr1) - | Subtract(_, expr, expr1) - | ShiftLeft(_, expr, expr1) - | ShiftRight(_, expr, expr1) - | BitwiseAnd(_, expr, expr1) - | BitwiseXor(_, expr, expr1) - | BitwiseOr(_, expr, expr1) - | Less(_, expr, expr1) - | More(_, expr, expr1) - | LessEqual(_, expr, expr1) - | MoreEqual(_, expr, expr1) - | Equal(_, expr, expr1) - | NotEqual(_, expr, expr1) - | And(_, expr, expr1) - | Or(_, expr, expr1) - | Assign(_, expr, expr1) - | AssignOr(_, expr, expr1) - | AssignAnd(_, expr, expr1) - | AssignXor(_, expr, expr1) - | AssignShiftLeft(_, expr, expr1) - | AssignShiftRight(_, expr, expr1) - | AssignAdd(_, expr, expr1) - | AssignSubtract(_, expr, expr1) - | AssignMultiply(_, expr, expr1) - | AssignDivide(_, expr, expr1) - | AssignModulo(_, expr, expr1) => { - self.analyze_fn_calls_expr(caller, *expr); - self.analyze_fn_calls_expr(caller, *expr1); - } + PostIncrement(_, expr) + | PostDecrement(_, expr) + | New(_, expr) + | Parenthesis(_, expr) + | MemberAccess(_, expr, _) + | Not(_, expr) + | Delete(_, expr) + | PreIncrement(_, expr) + | PreDecrement(_, expr) + | BitwiseNot(_, expr) + | Negate(_, expr) + | UnaryPlus(_, expr) => { + self.analyze_fn_calls_expr(caller, *expr); + } - ArraySubscript(_, expr, maybe_expr) => { - self.analyze_fn_calls_expr(caller, *expr); - if let Some(expr1) = maybe_expr { - self.analyze_fn_calls_expr(caller, *expr1); - } - }, - ArraySlice(_, expr, maybe_expr, maybe_expr1) => { - self.analyze_fn_calls_expr(caller, *expr); - if let Some(expr1) = maybe_expr { - self.analyze_fn_calls_expr(caller, *expr1); - } + Power(_, expr, expr1) + | Multiply(_, expr, expr1) + | Divide(_, expr, expr1) + | Modulo(_, expr, expr1) + | Add(_, expr, expr1) + | Subtract(_, expr, expr1) + | ShiftLeft(_, expr, expr1) + | ShiftRight(_, expr, expr1) + | BitwiseAnd(_, expr, expr1) + | BitwiseXor(_, expr, expr1) + | BitwiseOr(_, expr, expr1) + | Less(_, expr, expr1) + | More(_, expr, expr1) + | LessEqual(_, expr, expr1) + | MoreEqual(_, expr, expr1) + | Equal(_, expr, expr1) + | NotEqual(_, expr, expr1) + | And(_, expr, expr1) + | Or(_, expr, expr1) + | Assign(_, expr, expr1) + | AssignOr(_, expr, expr1) + | AssignAnd(_, expr, expr1) + | AssignXor(_, expr, expr1) + | AssignShiftLeft(_, expr, expr1) + | AssignShiftRight(_, expr, expr1) + | AssignAdd(_, expr, expr1) + | AssignSubtract(_, expr, expr1) + | AssignMultiply(_, expr, expr1) + | AssignDivide(_, expr, expr1) + | AssignModulo(_, expr, expr1) => { + self.analyze_fn_calls_expr(caller, *expr); + self.analyze_fn_calls_expr(caller, *expr1); + } - if let Some(expr2) = maybe_expr1 { - self.analyze_fn_calls_expr(caller, *expr2); - } - }, - ConditionalOperator(_, expr, expr1, expr2) => { - self.analyze_fn_calls_expr(caller, *expr); - self.analyze_fn_calls_expr(caller, *expr1); - self.analyze_fn_calls_expr(caller, *expr2); - }, - List(_, param_list) => { - param_list.iter().for_each(|(_, maybe_param)| { - if let Some(param) = maybe_param { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - } - }); - }, - ArrayLiteral(_, exprs) => { - exprs.into_iter().for_each(|expr| { - self.analyze_fn_calls_expr(caller, expr); - }); - }, - - Type(_, ty) => { - match ty { - solang_parser::pt::Type::Mapping { - key, - value, - .. - } => { - self.analyze_fn_calls_expr(caller, *key); - self.analyze_fn_calls_expr(caller, *value); - }, - solang_parser::pt::Type::Function { - params, - returns, - .. - } => { - params.iter().for_each(|(_, maybe_param)| { - if let Some(param) = maybe_param { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - } - }); - if let Some((param_list, _)) = returns { - param_list.iter().for_each(|(_, maybe_param)| { - if let Some(param) = maybe_param { - self.analyze_fn_calls_expr(caller, param.ty.clone()); - } - }); - } - }, - _ => {} - } - }, + ArraySubscript(_, expr, maybe_expr) => { + self.analyze_fn_calls_expr(caller, *expr); + if let Some(expr1) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr1); + } + } + ArraySlice(_, expr, maybe_expr, maybe_expr1) => { + self.analyze_fn_calls_expr(caller, *expr); + if let Some(expr1) = maybe_expr { + self.analyze_fn_calls_expr(caller, *expr1); + } - FunctionCallBlock(_, func_expr, _input_exprs) => { - match *func_expr { - Variable(ref ident) => { - let loc = func_expr.loc(); - let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); - let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - let visible_funcs = ctx - .visible_funcs(self) - .unwrap(); - let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); - if possible_funcs.len() == 1 { - let func = possible_funcs[0]; - self.add_fn_call(caller, func); - } - }, - _ => {} - } + if let Some(expr2) = maybe_expr1 { + self.analyze_fn_calls_expr(caller, *expr2); + } } - NamedFunctionCall(_, func_expr, _input_args) => { - match *func_expr { - Variable(ref ident) => { - let loc = func_expr.loc(); - let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); - let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - let visible_funcs = ctx - .visible_funcs(self) - .unwrap(); - let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); - if possible_funcs.len() == 1 { - let func = possible_funcs[0]; - self.add_fn_call(caller, func); - } - }, - _ => {} - } + ConditionalOperator(_, expr, expr1, expr2) => { + self.analyze_fn_calls_expr(caller, *expr); + self.analyze_fn_calls_expr(caller, *expr1); + self.analyze_fn_calls_expr(caller, *expr2); + } + List(_, param_list) => { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + } + ArrayLiteral(_, exprs) => { + exprs.into_iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr); + }); } - FunctionCall(_, func_expr, input_exprs) => { - match *func_expr { - Variable(ref ident) => { - let loc = func_expr.loc(); - let ctx = Context::new(caller, format!("<{}_parser_fn>", caller.name(self).unwrap()), loc); - let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - let visible_funcs = ctx - .visible_funcs(self) - .unwrap(); - let possible_funcs: Vec<_> = visible_funcs.into_iter().filter(|f| f.name(self).unwrap().starts_with(&ident.name)).collect(); - if possible_funcs.len() == 1 { - let func = possible_funcs[0]; - self.add_fn_call(caller, func); - } - }, - _ => {} - } - input_exprs.iter().for_each(|expr| { - self.analyze_fn_calls_expr(caller, expr.clone()); - }) + Type(_, ty) => match ty { + solang_parser::pt::Type::Mapping { key, value, .. } => { + self.analyze_fn_calls_expr(caller, *key); + self.analyze_fn_calls_expr(caller, *value); + } + solang_parser::pt::Type::Function { + params, returns, .. + } => { + params.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + if let Some((param_list, _)) = returns { + param_list.iter().for_each(|(_, maybe_param)| { + if let Some(param) = maybe_param { + self.analyze_fn_calls_expr(caller, param.ty.clone()); + } + }); + } + } + _ => {} }, + + FunctionCallBlock(_, func_expr, _input_exprs) => match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new( + caller, + format!("<{}_parser_fn>", caller.name(self).unwrap()), + loc, + ); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx.visible_funcs(self).unwrap(); + let possible_funcs: Vec<_> = visible_funcs + .into_iter() + .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) + .collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + } + _ => {} + }, + NamedFunctionCall(_, func_expr, _input_args) => match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new( + caller, + format!("<{}_parser_fn>", caller.name(self).unwrap()), + loc, + ); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx.visible_funcs(self).unwrap(); + let possible_funcs: Vec<_> = visible_funcs + .into_iter() + .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) + .collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + } + _ => {} + }, + FunctionCall(_, func_expr, input_exprs) => { + match *func_expr { + Variable(ref ident) => { + let loc = func_expr.loc(); + let ctx = Context::new( + caller, + format!("<{}_parser_fn>", caller.name(self).unwrap()), + loc, + ); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx.visible_funcs(self).unwrap(); + let possible_funcs: Vec<_> = visible_funcs + .into_iter() + .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) + .collect(); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); + } + } + _ => {} + } + + input_exprs.iter().for_each(|expr| { + self.analyze_fn_calls_expr(caller, expr.clone()); + }) + } } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index 7b941e65..a4249979 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -14,12 +14,12 @@ impl ContextBuilder for T where } mod expr; -mod stmt; mod fn_calls; +mod stmt; pub use expr::*; -pub use stmt::*; pub use fn_calls::*; +pub use stmt::*; /// Dispatcher for building up a context of a function pub trait ContextBuilder: diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 6a1ddaef..402f28dd 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -413,7 +413,7 @@ pub trait FuncCaller: }) .collect::>(); if let Ok(true) = ctx.join(func_node, &mapping, self) { - return Ok(()) + return Ok(()); } } diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index c8b00946..6a075cef 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -63,7 +63,7 @@ pub trait CallerHelper: AnalyzerBackend + input.latest_version(self), Edge::Context(ContextEdge::InputVariable), ); - + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { if !node.ty_eq_ty(¶m_ty, self).unwrap() { diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index 3c43085d..d0afc313 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -141,7 +141,6 @@ pub trait PrePostIncDecrement: let elem = Elem::from(cvar); let one = Elem::from(Concrete::from(U256::from(1))).cast(elem.clone()); - // if let Some(r) = cvar.range(self).into_expr_err(loc)? { if increment { if pre { @@ -153,7 +152,8 @@ pub trait PrePostIncDecrement: .set_range_min(self, elem.clone() + one.clone()) .into_expr_err(loc)?; new_cvar - .set_range_max(self, elem + one).into_expr_err(loc)?; + .set_range_max(self, elem + one) + .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) From 0d425515b8aaf420034e037bb09d893279bb4b18 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 21:09:57 -0800 Subject: [PATCH 61/71] fix returns in pure func joins --- crates/graph/src/nodes/context/node.rs | 135 ---------- .../src/context_builder/stmt.rs | 6 +- .../src/func_call/func_caller.rs | 69 +++-- .../solc-expressions/src/func_call/helper.rs | 4 +- crates/solc-expressions/src/func_call/join.rs | 252 ++++++++++++++++++ crates/solc-expressions/src/func_call/mod.rs | 1 + .../src/pre_post_in_decrement.rs | 16 +- 7 files changed, 299 insertions(+), 184 deletions(-) create mode 100644 crates/solc-expressions/src/func_call/join.rs diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 4d7bb6eb..3db86831 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -26,141 +26,6 @@ impl AsDotStr for ContextNode { } impl ContextNode { - pub fn join( - &self, - func: FunctionNode, - mapping: &BTreeMap, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { - // ensure no modifiers (for now) - // if pure function: - // grab requirements for context - // grab return node's simplified range - // replace fundamentals with function inputs - // update ctx name in place - - if func.is_pure(analyzer)? { - // pure functions are guaranteed to not require the use of state, so - // the only things we care about are function inputs and function outputs - if let Some(body_ctx) = func.maybe_body_ctx(analyzer) { - let inputs = body_ctx.input_variables(analyzer); - // println!("inputs:"); - let mut replacement_map = BTreeMap::default(); - inputs.iter().for_each(|input| { - let name = input.name(analyzer).unwrap(); - if let Some((param, replacement_input)) = mapping.get(&name) { - if let Some(param_ty) = - VarType::try_from_idx(analyzer, param.ty(analyzer).unwrap()) - { - if !replacement_input.ty_eq_ty(¶m_ty, analyzer).unwrap() { - replacement_input.cast_from_ty(param_ty, analyzer).unwrap(); - } - } - let mut replacement = Elem::from(*replacement_input); - replacement.arenaize(analyzer).unwrap(); - - if let Some(next) = input.next_version(analyzer) { - replacement_map.insert(next.0, replacement.clone()); - } - replacement_map.insert(input.0, replacement); - // a lot of time (all the time?) there is an extra version added on - } - // println!(" name: {}", input.display_name(analyzer).unwrap()); - // println!(" idx: {}", input.0); - }); - - // println!("replacement map: {replacement_map:#?}"); - if body_ctx.underlying(analyzer)?.child.is_some() { - let edges = body_ctx.successful_edges(analyzer)?; - if edges.len() == 1 { - // let ret_nodes = edges[0].return_nodes(analyzer)?; - // println!("return nodes: {:#?}", ret_nodes); - } else { - // println!("multiple edges: {}", edges.len()); - } - } else { - // 1. Create a new variable with name `.` - // 2. Set the range to be the copy of the return's simplified range from the function - // 3. Replace the fundamentals with the input data - let ret: Vec<_> = body_ctx - .return_nodes(analyzer)? - .iter() - .enumerate() - .map(|(i, (_, ret_node))| { - // println!("original return:"); - // println!(" name: {}", ret_node.display_name(analyzer).unwrap()); - // println!(" range: {}", ret_node.simplified_range_string(analyzer).unwrap().unwrap()); - let mut new_var = ret_node.underlying(analyzer).unwrap().clone(); - let new_name = format!("{}.{i}", func.name(analyzer).unwrap()); - new_var.name = new_name.clone(); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep( - (*replace).into(), - replacement.clone(), - analyzer, - ); - }); - - range.cache_eval(analyzer).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - let new_cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); - analyzer.add_edge( - new_cvar, - *self, - Edge::Context(ContextEdge::Variable), - ); - self.add_var(new_cvar, analyzer).unwrap(); - // let new_range = new_cvar.range(analyzer).unwrap().unwrap(); - - // println!("new return:"); - // println!(" name: {}", new_cvar.display_name(analyzer).unwrap()); - // println!(" range: {}", new_cvar.range_string(analyzer).unwrap().unwrap()); - ExprRet::Single(new_cvar.into()) - }) - .collect(); - - // println!("requires:"); - body_ctx.ctx_deps(analyzer)?.iter().for_each(|dep| { - // println!(" name: {}", dep.display_name(analyzer).unwrap()); - let mut new_var = dep.underlying(analyzer).unwrap().clone(); - if let Some(mut range) = new_var.ty.take_range() { - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep((*replace).into(), replacement.clone(), analyzer); - }); - - range.cache_eval(analyzer).unwrap(); - new_var.ty.set_range(range).unwrap(); - } - - let new_cvar = - ContextVarNode::from(analyzer.add_node(Node::ContextVar(new_var))); - self.add_ctx_dep(new_cvar, analyzer).unwrap(); - }); - - self.underlying_mut(analyzer)?.path = format!( - "{}.{}.resume{{ {} }}", - self.path(analyzer), - func.name(analyzer).unwrap(), - self.associated_fn_name(analyzer).unwrap() - ); - self.push_expr(ExprRet::Multi(ret), analyzer)?; - return Ok(true); - } - } - - // update path name to reflect that we called the function - } - - Ok(false) - // todo!("Joining not supported yet"); - } - pub fn add_gas_cost( &self, analyzer: &mut impl GraphBackend, diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs index ade756e1..bee99471 100644 --- a/crates/solc-expressions/src/context_builder/stmt.rs +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -215,10 +215,10 @@ pub trait StatementParser: ctx_node.into(), parent.into().into(), fn_loc, - inputs, - params, - None, + &inputs, + ¶ms, None, + &None, ); if self.widen_if_limit_hit(ctx_node.into(), res) { return; diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 402f28dd..728b9606 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,6 +1,8 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. + use crate::{ + func_call::join::FuncJoiner, func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, StatementParser, @@ -331,16 +333,19 @@ pub trait FuncCaller: ExprRet::Single(input_var) | ExprRet::SingleLiteral(input_var) => { // if we get a single var, we expect the func to only take a single // variable - self.func_call_inner( - false, - ctx, - func, - loc, - vec![ContextVarNode::from(input_var).latest_version(self)], - params, - func_call_str, - modifier_state, - ) + let inputs = vec![ContextVarNode::from(input_var).latest_version(self)]; + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.func_call_inner( + false, + ctx, + func, + loc, + &inputs, + ¶ms, + func_call_str, + &modifier_state, + ) + }) } ExprRet::Multi(ref inputs) => { if ExprRet::Multi(inputs.to_vec()).flatten().has_killed() { @@ -362,16 +367,18 @@ pub trait FuncCaller: Ok(ContextVarNode::from(var).latest_version(self)) }) .collect::, ExprErr>>()?; - self.func_call_inner( - false, - ctx, - func, - loc, - input_vars, - params, - func_call_str, - modifier_state, - ) + self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.func_call_inner( + false, + ctx, + func, + loc, + &input_vars, + ¶ms, + func_call_str, + &modifier_state, + ) + }) } else { Err(ExprErr::InvalidFunctionInput( loc, @@ -395,24 +402,14 @@ pub trait FuncCaller: ctx: ContextNode, func_node: FunctionNode, loc: Loc, - inputs: Vec, - params: Vec, + inputs: &[ContextVarNode], + params: &[FunctionParamNode], func_call_str: Option<&str>, - modifier_state: Option, + modifier_state: &Option, ) -> Result<(), ExprErr> { + if !entry_call { - let mapping = params - .iter() - .zip(inputs.iter()) - .filter_map(|(param, input)| { - if let Ok(Some(name)) = param.maybe_name(self) { - Some((name, (*param, *input))) - } else { - None - } - }) - .collect::>(); - if let Ok(true) = ctx.join(func_node, &mapping, self) { + if let Ok(true) = self.join(ctx, loc, func_node, params, inputs) { return Ok(()); } } @@ -426,7 +423,7 @@ pub trait FuncCaller: let callee_ctx = if entry_call { ctx } else { - self.create_call_ctx(ctx, loc, func_node, modifier_state)? + self.create_call_ctx(ctx, loc, func_node, modifier_state.clone())? }; // handle remapping of variable names and bringing variables into the new context diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 6a075cef..073c8815 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -26,8 +26,8 @@ pub trait CallerHelper: AnalyzerBackend + &mut self, loc: Loc, entry_call: bool, - params: Vec, - inputs: Vec, + params: &[FunctionParamNode], + inputs: &[ContextVarNode], callee_ctx: ContextNode, ) -> Result, ExprErr> { Ok(params diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs new file mode 100644 index 00000000..a183257e --- /dev/null +++ b/crates/solc-expressions/src/func_call/join.rs @@ -0,0 +1,252 @@ +use graph::nodes::ContextVar; +use shared::StorageLocation; +use graph::elem::RangeElem; +use graph::Range; +use graph::elem::Elem; +use graph::VarType; +use crate::member_access::ListAccess; +use crate::{ + helper::CallerHelper, + ExprErr, IntoExprErr, +}; + + + +use graph::{ + nodes::{ + ContextNode, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, +}; + + +use solang_parser::pt::{Expression, Loc}; + +use std::collections::BTreeMap; + +impl FuncJoiner for T where + T: AnalyzerBackend + Sized + GraphBackend + CallerHelper +{ +} +/// A trait for calling a function +pub trait FuncJoiner: + GraphBackend + AnalyzerBackend + Sized +{ + fn join( + &mut self, + ctx: ContextNode, + loc: Loc, + func: FunctionNode, + params: &[FunctionParamNode], + func_inputs: &[ContextVarNode], + ) -> Result { + // ensure no modifiers (for now) + // if pure function: + // grab requirements for context + // grab return node's simplified range + // replace fundamentals with function inputs + // update ctx name in place + + if func.is_pure(self).into_expr_err(loc)? { + // pure functions are guaranteed to not require the use of state, so + // the only things we care about are function inputs and function outputs + if let Some(body_ctx) = func.maybe_body_ctx(self) { + // println!("replacement map: {replacement_map:#?}"); + if body_ctx.underlying(self).into_expr_err(loc)?.child.is_some() { + let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; + if edges.len() == 1 { + // let ret_nodes = edges[0].return_nodes(self)?; + // println!("return nodes: {:#?}", ret_nodes); + } else { + // println!("multiple edges: {}", edges.len()); + } + } else { + let inputs = body_ctx.input_variables(self); + let mut replacement_map = BTreeMap::default(); + params.iter() + .zip(func_inputs.iter()) + .try_for_each(|(param, func_input)| { + if let Some(name) = param.maybe_name(self).into_expr_err(loc)? + { + let mut new_cvar = func_input + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + new_cvar.loc = Some(param.loc(self).unwrap()); + // new_cvar.name = name.clone(); + // new_cvar.display_name = name.clone(); + new_cvar.is_tmp = false; + new_cvar.storage = if let Some(StorageLocation::Storage(_)) = + param.underlying(self).unwrap().storage + { + new_cvar.storage + } else { + None + }; + + let replacement = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + + self.add_edge( + replacement, + *func_input, + Edge::Context(ContextEdge::InputVariable), + ); + + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) + { + if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { + replacement.cast_from_ty(param_ty, self).into_expr_err(loc)?; + } + } + + if let Some(_len_var) = replacement.array_to_len_var(self) { + // bring the length variable along as well + self.get_length(ctx, loc, *func_input, false).unwrap(); + } + + if let (Some(r), Some(r2)) = + (replacement.range(self).unwrap(), param.range(self).unwrap()) + { + let new_min = + r.range_min().into_owned().cast(r2.range_min().into_owned()); + let new_max = + r.range_max().into_owned().cast(r2.range_max().into_owned()); + replacement + .latest_version(self) + .try_set_range_min(self, new_min) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_max(self, new_max) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_exclusions(self, r.exclusions) + .into_expr_err(loc)?; + } + + ctx.add_var(replacement, self).unwrap(); + self.add_edge(replacement, ctx, Edge::Context(ContextEdge::Variable)); + + let Some(correct_input) = inputs.iter().find(|input| { + input.name(self).unwrap() == name + }) else { + return Err(ExprErr::InvalidFunctionInput(loc, "Could not match input to parameter".to_string())) + }; + + let mut replacement_as_elem = Elem::from(replacement); + replacement_as_elem.arenaize(self).into_expr_err(loc)?; + + if let Some(next) = correct_input.next_version(self) { + replacement_map.insert(next.0, replacement_as_elem.clone()); + } + replacement_map.insert(correct_input.0, replacement_as_elem); + } + Ok(()) + })?; + // 1. Create a new variable with name `.` + // 2. Set the range to be the copy of the return's simplified range from the function + // 3. Replace the fundamentals with the input data + let mut rets: Vec<_> = body_ctx + .return_nodes(self) + .into_expr_err(loc)? + .iter() + .enumerate() + .map(|(i, (_, ret_node))| { + // println!("original return:"); + // println!(" name: {}", ret_node.display_name(self).unwrap()); + // println!(" range: {}", ret_node.simplified_range_string(self).unwrap().unwrap()); + let mut new_var = ret_node.underlying(self).unwrap().clone(); + let new_name = format!("{}.{i}", func.name(self).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep( + (*replace).into(), + replacement.clone(), + self, + ); + }); + + range.cache_eval(self).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + + let new_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge( + new_cvar, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.add_var(new_cvar, self).unwrap(); + // let new_range = new_cvar.range(self).unwrap().unwrap(); + + // println!("new return:"); + // println!(" name: {}", new_cvar.display_name(self).unwrap()); + // println!(" range: {}", new_cvar.range_string(self).unwrap().unwrap()); + ExprRet::Single(new_cvar.into()) + }) + .collect(); + + // println!("requires:"); + body_ctx.ctx_deps(self).into_expr_err(loc)?.iter().for_each(|dep| { + // println!(" name: {}", dep.display_name(self).unwrap()); + let mut new_var = dep.underlying(self).unwrap().clone(); + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep((*replace).into(), replacement.clone(), self); + }); + + range.cache_eval(self).unwrap(); + new_var.ty.set_range(range).unwrap(); + } + + let new_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge( + new_cvar, + ctx, + Edge::Context(ContextEdge::Variable), + ); + ctx.add_var(new_cvar, self).unwrap(); + ctx.add_ctx_dep(new_cvar, self).unwrap(); + }); + + func + .returns(self) + .collect::>() + .into_iter() + .for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar.into())); + } + }); + + ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( + "{}.{}.resume{{ {} }}", + ctx.path(self), + func.name(self).unwrap(), + ctx.associated_fn_name(self).unwrap() + ); + ctx.push_expr(ExprRet::Multi(rets), self).into_expr_err(loc)?; + return Ok(true); + } + } + + // update path name to reflect that we called the function + } + + Ok(false) + // todo!("Joining not supported yet"); + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index ac6bd0c2..c97fcccb 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,4 +1,5 @@ pub mod func_caller; +pub mod join; pub mod helper; pub mod internal_call; pub mod intrinsic_call; diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index d0afc313..c340e60c 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -145,8 +145,8 @@ pub trait PrePostIncDecrement: if increment { if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() + one.clone()); - dup.set_range_max(self, elem.clone() + one.clone()); + dup.set_range_min(self, elem.clone() + one.clone()).into_expr_err(loc)?; + dup.set_range_max(self, elem.clone() + one.clone()).into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar .set_range_min(self, elem.clone() + one.clone()) @@ -159,8 +159,8 @@ pub trait PrePostIncDecrement: Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone()); - dup.set_range_max(self, elem.clone()); + dup.set_range_min(self, elem.clone()).into_expr_err(loc)?; + dup.set_range_max(self, elem.clone()).into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; let res = new_cvar .set_range_min(self, elem.clone() + one.clone()) @@ -175,8 +175,8 @@ pub trait PrePostIncDecrement: } } else if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() - one.clone()); - dup.set_range_max(self, elem.clone() - one.clone()); + dup.set_range_min(self, elem.clone() - one.clone()).into_expr_err(loc)?; + dup.set_range_max(self, elem.clone() - one.clone()).into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar .set_range_min(self, elem.clone() - one.clone()) @@ -189,8 +189,8 @@ pub trait PrePostIncDecrement: Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone()); - dup.set_range_max(self, elem.clone()); + dup.set_range_min(self, elem.clone()).into_expr_err(loc)?; + dup.set_range_max(self, elem.clone()).into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar .set_range_min(self, elem.clone() - one.clone()) From c687003d7b0b290cd7de30d0b7942b776207e61e Mon Sep 17 00:00:00 2001 From: brock elmore Date: Thu, 21 Dec 2023 21:10:48 -0800 Subject: [PATCH 62/71] lint --- crates/graph/src/nodes/context/node.rs | 10 +- .../src/func_call/func_caller.rs | 10 +- crates/solc-expressions/src/func_call/join.rs | 305 +++++++++--------- crates/solc-expressions/src/func_call/mod.rs | 2 +- .../src/pre_post_in_decrement.rs | 12 +- 5 files changed, 169 insertions(+), 170 deletions(-) diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 3db86831..1c1f7790 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,19 +1,11 @@ -use crate::elem::Elem; -use crate::nodes::ExprRet; -use crate::range::elem::RangeElem; -use crate::range::Range; -use crate::ContextEdge; -use crate::Edge; -use crate::VarType; use crate::{ - nodes::{Context, ContextVarNode, FunctionNode, FunctionParamNode, KilledKind}, + nodes::{Context, ContextVarNode, KilledKind}, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; use shared::NodeIdx; use solang_parser::pt::Loc; -use std::collections::BTreeMap; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] /// A wrapper of a node index that corresponds to a [`Context`] diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 728b9606..c7318008 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,11 +1,10 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. - use crate::{ - func_call::join::FuncJoiner, - func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, - intrinsic_call::IntrinsicFuncCaller, namespaced_call::NameSpaceFuncCaller, ContextBuilder, - ExprErr, ExpressionParser, IntoExprErr, StatementParser, + func_call::join::FuncJoiner, func_call::modifier::ModifierCaller, helper::CallerHelper, + internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, + namespaced_call::NameSpaceFuncCaller, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, + StatementParser, }; use std::cell::RefCell; use std::rc::Rc; @@ -407,7 +406,6 @@ pub trait FuncCaller: func_call_str: Option<&str>, modifier_state: &Option, ) -> Result<(), ExprErr> { - if !entry_call { if let Ok(true) = self.join(ctx, loc, func_node, params, inputs) { return Ok(()); diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index a183257e..53f28131 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,25 +1,17 @@ -use graph::nodes::ContextVar; -use shared::StorageLocation; +use crate::member_access::ListAccess; +use crate::{helper::CallerHelper, ExprErr, IntoExprErr}; +use graph::elem::Elem; use graph::elem::RangeElem; +use graph::nodes::ContextVar; use graph::Range; -use graph::elem::Elem; use graph::VarType; -use crate::member_access::ListAccess; -use crate::{ - helper::CallerHelper, - ExprErr, IntoExprErr, -}; - - +use shared::StorageLocation; use graph::{ - nodes::{ - ContextNode, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, - }, + nodes::{ContextNode, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; - use solang_parser::pt::{Expression, Loc}; use std::collections::BTreeMap; @@ -32,7 +24,7 @@ impl FuncJoiner for T where pub trait FuncJoiner: GraphBackend + AnalyzerBackend + Sized { - fn join( + fn join( &mut self, ctx: ContextNode, loc: Loc, @@ -52,7 +44,12 @@ pub trait FuncJoiner: // the only things we care about are function inputs and function outputs if let Some(body_ctx) = func.maybe_body_ctx(self) { // println!("replacement map: {replacement_map:#?}"); - if body_ctx.underlying(self).into_expr_err(loc)?.child.is_some() { + if body_ctx + .underlying(self) + .into_expr_err(loc)? + .child + .is_some() + { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { // let ret_nodes = edges[0].return_nodes(self)?; @@ -61,90 +58,106 @@ pub trait FuncJoiner: // println!("multiple edges: {}", edges.len()); } } else { - let inputs = body_ctx.input_variables(self); - let mut replacement_map = BTreeMap::default(); - params.iter() - .zip(func_inputs.iter()) - .try_for_each(|(param, func_input)| { - if let Some(name) = param.maybe_name(self).into_expr_err(loc)? - { - let mut new_cvar = func_input - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - new_cvar.loc = Some(param.loc(self).unwrap()); - // new_cvar.name = name.clone(); - // new_cvar.display_name = name.clone(); - new_cvar.is_tmp = false; - new_cvar.storage = if let Some(StorageLocation::Storage(_)) = - param.underlying(self).unwrap().storage - { - new_cvar.storage - } else { - None - }; - - let replacement = ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); - - self.add_edge( - replacement, - *func_input, - Edge::Context(ContextEdge::InputVariable), - ); - - if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) - { - if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { - replacement.cast_from_ty(param_ty, self).into_expr_err(loc)?; - } - } - - if let Some(_len_var) = replacement.array_to_len_var(self) { - // bring the length variable along as well - self.get_length(ctx, loc, *func_input, false).unwrap(); - } - - if let (Some(r), Some(r2)) = - (replacement.range(self).unwrap(), param.range(self).unwrap()) - { - let new_min = - r.range_min().into_owned().cast(r2.range_min().into_owned()); - let new_max = - r.range_max().into_owned().cast(r2.range_max().into_owned()); - replacement - .latest_version(self) - .try_set_range_min(self, new_min) - .into_expr_err(loc)?; - replacement - .latest_version(self) - .try_set_range_max(self, new_max) - .into_expr_err(loc)?; - replacement - .latest_version(self) - .try_set_range_exclusions(self, r.exclusions) - .into_expr_err(loc)?; - } - - ctx.add_var(replacement, self).unwrap(); - self.add_edge(replacement, ctx, Edge::Context(ContextEdge::Variable)); - - let Some(correct_input) = inputs.iter().find(|input| { - input.name(self).unwrap() == name - }) else { - return Err(ExprErr::InvalidFunctionInput(loc, "Could not match input to parameter".to_string())) - }; - - let mut replacement_as_elem = Elem::from(replacement); - replacement_as_elem.arenaize(self).into_expr_err(loc)?; - - if let Some(next) = correct_input.next_version(self) { - replacement_map.insert(next.0, replacement_as_elem.clone()); - } - replacement_map.insert(correct_input.0, replacement_as_elem); - } - Ok(()) - })?; + let inputs = body_ctx.input_variables(self); + let mut replacement_map = BTreeMap::default(); + params + .iter() + .zip(func_inputs.iter()) + .try_for_each(|(param, func_input)| { + if let Some(name) = param.maybe_name(self).into_expr_err(loc)? { + let mut new_cvar = func_input + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + new_cvar.loc = Some(param.loc(self).unwrap()); + // new_cvar.name = name.clone(); + // new_cvar.display_name = name.clone(); + new_cvar.is_tmp = false; + new_cvar.storage = if let Some(StorageLocation::Storage(_)) = + param.underlying(self).unwrap().storage + { + new_cvar.storage + } else { + None + }; + + let replacement = + ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + + self.add_edge( + replacement, + *func_input, + Edge::Context(ContextEdge::InputVariable), + ); + + if let Some(param_ty) = + VarType::try_from_idx(self, param.ty(self).unwrap()) + { + if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { + replacement + .cast_from_ty(param_ty, self) + .into_expr_err(loc)?; + } + } + + if let Some(_len_var) = replacement.array_to_len_var(self) { + // bring the length variable along as well + self.get_length(ctx, loc, *func_input, false).unwrap(); + } + + if let (Some(r), Some(r2)) = + (replacement.range(self).unwrap(), param.range(self).unwrap()) + { + let new_min = r + .range_min() + .into_owned() + .cast(r2.range_min().into_owned()); + let new_max = r + .range_max() + .into_owned() + .cast(r2.range_max().into_owned()); + replacement + .latest_version(self) + .try_set_range_min(self, new_min) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_max(self, new_max) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_exclusions(self, r.exclusions) + .into_expr_err(loc)?; + } + + ctx.add_var(replacement, self).unwrap(); + self.add_edge( + replacement, + ctx, + Edge::Context(ContextEdge::Variable), + ); + + let Some(correct_input) = inputs + .iter() + .find(|input| input.name(self).unwrap() == name) + else { + return Err(ExprErr::InvalidFunctionInput( + loc, + "Could not match input to parameter".to_string(), + )); + }; + + let mut replacement_as_elem = Elem::from(replacement); + replacement_as_elem.arenaize(self).into_expr_err(loc)?; + + if let Some(next) = correct_input.next_version(self) { + replacement_map.insert(next.0, replacement_as_elem.clone()); + } + replacement_map.insert(correct_input.0, replacement_as_elem); + } + Ok(()) + })?; // 1. Create a new variable with name `.` // 2. Set the range to be the copy of the return's simplified range from the function // 3. Replace the fundamentals with the input data @@ -163,11 +176,7 @@ pub trait FuncJoiner: new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep( - (*replace).into(), - replacement.clone(), - self, - ); + range.replace_dep((*replace).into(), replacement.clone(), self); }); range.cache_eval(self).unwrap(); @@ -177,11 +186,7 @@ pub trait FuncJoiner: let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge( - new_cvar, - ctx, - Edge::Context(ContextEdge::Variable), - ); + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(new_cvar, self).unwrap(); // let new_range = new_cvar.range(self).unwrap().unwrap(); @@ -193,44 +198,43 @@ pub trait FuncJoiner: .collect(); // println!("requires:"); - body_ctx.ctx_deps(self).into_expr_err(loc)?.iter().for_each(|dep| { - // println!(" name: {}", dep.display_name(self).unwrap()); - let mut new_var = dep.underlying(self).unwrap().clone(); - if let Some(mut range) = new_var.ty.take_range() { - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep((*replace).into(), replacement.clone(), self); - }); - - range.cache_eval(self).unwrap(); - new_var.ty.set_range(range).unwrap(); - } - - let new_cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge( - new_cvar, - ctx, - Edge::Context(ContextEdge::Variable), - ); - ctx.add_var(new_cvar, self).unwrap(); - ctx.add_ctx_dep(new_cvar, self).unwrap(); - }); - - func - .returns(self) - .collect::>() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - rets.push(ExprRet::Single(cvar.into())); - } - }); + body_ctx + .ctx_deps(self) + .into_expr_err(loc)? + .iter() + .for_each(|dep| { + // println!(" name: {}", dep.display_name(self).unwrap()); + let mut new_var = dep.underlying(self).unwrap().clone(); + if let Some(mut range) = new_var.ty.take_range() { + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep((*replace).into(), replacement.clone(), self); + }); + + range.cache_eval(self).unwrap(); + new_var.ty.set_range(range).unwrap(); + } + + let new_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(new_cvar, self).unwrap(); + ctx.add_ctx_dep(new_cvar, self).unwrap(); + }); + + func.returns(self) + .collect::>() + .into_iter() + .for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar)); + } + }); ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( "{}.{}.resume{{ {} }}", @@ -238,7 +242,8 @@ pub trait FuncJoiner: func.name(self).unwrap(), ctx.associated_fn_name(self).unwrap() ); - ctx.push_expr(ExprRet::Multi(rets), self).into_expr_err(loc)?; + ctx.push_expr(ExprRet::Multi(rets), self) + .into_expr_err(loc)?; return Ok(true); } } @@ -249,4 +254,4 @@ pub trait FuncJoiner: Ok(false) // todo!("Joining not supported yet"); } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/func_call/mod.rs b/crates/solc-expressions/src/func_call/mod.rs index c97fcccb..2d8fcd1a 100644 --- a/crates/solc-expressions/src/func_call/mod.rs +++ b/crates/solc-expressions/src/func_call/mod.rs @@ -1,7 +1,7 @@ pub mod func_caller; -pub mod join; pub mod helper; pub mod internal_call; pub mod intrinsic_call; +pub mod join; pub mod modifier; pub mod namespaced_call; diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index c340e60c..829b2780 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -145,8 +145,10 @@ pub trait PrePostIncDecrement: if increment { if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() + one.clone()).into_expr_err(loc)?; - dup.set_range_max(self, elem.clone() + one.clone()).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone() + one.clone()) + .into_expr_err(loc)?; + dup.set_range_max(self, elem.clone() + one.clone()) + .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar .set_range_min(self, elem.clone() + one.clone()) @@ -175,8 +177,10 @@ pub trait PrePostIncDecrement: } } else if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() - one.clone()).into_expr_err(loc)?; - dup.set_range_max(self, elem.clone() - one.clone()).into_expr_err(loc)?; + dup.set_range_min(self, elem.clone() - one.clone()) + .into_expr_err(loc)?; + dup.set_range_max(self, elem.clone() - one.clone()) + .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar .set_range_min(self, elem.clone() - one.clone()) From d0bfb2eceaf69e6ff4625151b04368f026beec05 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Wed, 28 Feb 2024 12:18:46 -0700 Subject: [PATCH 63/71] perf improvements --- .gitignore | 2 +- Cargo.lock | 59 +- Cargo.toml | 2 + crates/cli/Cargo.toml | 1 + crates/cli/src/main.rs | 30 +- crates/graph/src/nodes/context/solving.rs | 6 +- crates/graph/src/nodes/context/var/node.rs | 18 +- crates/graph/src/nodes/func_ty.rs | 31 +- crates/graph/src/range/elem/concrete.rs | 19 +- crates/graph/src/range/elem/elem_enum.rs | 296 +++++++--- crates/graph/src/range/elem/elem_trait.rs | 2 - crates/graph/src/range/elem/expr.rs | 191 ++++-- crates/graph/src/range/elem/map_or_array.rs | 37 +- crates/graph/src/range/elem/reference.rs | 29 +- crates/graph/src/range/exec/exec_op.rs | 133 ++++- crates/graph/src/range/exec_traits.rs | 2 - crates/graph/src/range/range_string.rs | 3 +- crates/graph/src/range/range_trait.rs | 13 +- crates/graph/src/range/solc_range.rs | 70 ++- crates/graph/src/solvers/atoms.rs | 63 +- crates/graph/src/solvers/brute.rs | 6 +- crates/graph/src/solvers/dl.rs | 70 +-- crates/pyrometer/Cargo.toml | 1 + crates/pyrometer/src/analyzer.rs | 36 +- crates/pyrometer/src/analyzer_backend.rs | 23 +- crates/pyrometer/src/builtin_fns.rs | 6 +- crates/pyrometer/src/graph_backend.rs | 29 +- crates/pyrometer/tests/helpers.rs | 13 + crates/pyrometer/tests/no_killed_ctxs.rs | 12 + crates/pyrometer/tests/test_data/join.sol | 35 ++ .../tests/test_data/repros/overflow.sol | 37 ++ crates/queries/src/lib.rs | 2 +- crates/shared/Cargo.toml | 3 +- crates/shared/src/analyzer_like.rs | 123 +++- crates/shared/src/graph_like.rs | 13 +- crates/solc-expressions/src/assign.rs | 19 +- .../src/func_call/func_caller.rs | 5 +- .../solc-expressions/src/func_call/helper.rs | 8 +- .../func_call/intrinsic_call/dyn_builtin.rs | 4 +- .../src/func_call/intrinsic_call/types.rs | 9 +- crates/solc-expressions/src/func_call/join.rs | 545 ++++++++++++++---- .../src/member_access/list_access.rs | 172 ++++-- crates/solc-expressions/src/require.rs | 20 +- crates/solc-expressions/src/yul/yul_funcs.rs | 2 +- 44 files changed, 1676 insertions(+), 524 deletions(-) create mode 100644 crates/pyrometer/tests/test_data/join.sol create mode 100644 crates/pyrometer/tests/test_data/repros/overflow.sol diff --git a/.gitignore b/.gitignore index 786ab108..113d56e2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ **/dot.svg **/dot.dot **/flamegraph.svg -**/.swp \ No newline at end of file +**/.swp diff --git a/Cargo.lock b/Cargo.lock index 0de06ed8..0ce4871f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -338,6 +351,7 @@ dependencies = [ "shared", "tracing", "tracing-subscriber", + "tracing-tree", ] [[package]] @@ -1059,6 +1073,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1392,6 +1415,7 @@ dependencies = [ name = "pyrometer" version = "0.2.0" dependencies = [ + "ahash", "analyzers", "ariadne", "criterion", @@ -1739,6 +1763,7 @@ dependencies = [ name = "shared" version = "0.2.0" dependencies = [ + "ahash", "ethers-core", "hex", "petgraph", @@ -2048,7 +2073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", - "nu-ansi-term", + "nu-ansi-term 0.46.0", "once_cell", "regex", "sharded-slab", @@ -2059,6 +2084,18 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-tree" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675" +dependencies = [ + "nu-ansi-term 0.49.0", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "typenum" version = "1.17.0" @@ -2386,6 +2423,26 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 483bdfa6..c6fb748f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,10 +41,12 @@ solc-expressions = { path = "crates/solc-expressions" } solang-parser = { version = "0.2.4", features = ["pt-serde"] } tracing = { version = "0.1", features = ["attributes"] } tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } +tracing-tree = "0.3.0" ethers-core = "*" hex = "0.4.3" ariadne = "0.2.0" petgraph = "0.6.2" +ahash = "0.8.10" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 98cc05ee..5029e551 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -21,6 +21,7 @@ graph.workspace = true ariadne.workspace = true tracing.workspace = true tracing-subscriber.workspace = true +tracing-tree.workspace = true petgraph.workspace = true ethers-core.workspace = true diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 7ff232ac..fc7d4aa3 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,3 +1,4 @@ +use graph::elem::RangeElem; use analyzers::{FunctionVarsBoundAnalyzer, ReportConfig, ReportDisplay}; use graph::{ nodes::{ContractNode, FunctionNode}, @@ -11,7 +12,7 @@ use shared::Search; use ariadne::sources; use clap::{ArgAction, Parser, ValueHint}; -use tracing_subscriber::prelude::*; +use tracing_subscriber::{Registry, prelude::*}; use std::{ collections::{BTreeMap, HashMap}, @@ -109,8 +110,24 @@ pub fn subscriber() { .init() } +pub fn tree_subscriber() { + let subscriber = Registry::default().with( + tracing_tree::HierarchicalLayer::default() + .with_indent_lines(true) + .with_indent_amount(2) + .with_thread_names(true) + // .with_thread_ids(true) + // .with_verbose_exit(true) + // .with_verbose_entry(true) + // .with_targets(true) + ) + .with(tracing_subscriber::filter::EnvFilter::from_default_env()); + tracing::subscriber::set_global_default(subscriber).unwrap(); + +} + fn main() { - subscriber(); + tree_subscriber(); let args = Args::parse(); let verbosity = args.verbosity; let config = match verbosity { @@ -290,6 +307,15 @@ fn main() { analyzer.open_mermaid(); } + // println!("{}", analyzer.range_arena.ranges.iter().map(|i| { + // let j = i.borrow(); + // let (min_cached, max_cached) = j.is_min_max_cached(&analyzer); + // format!("\t{j}, is cached: {min_cached}, {max_cached}\n") + // }).collect::>().join("")); + // println!("{}", analyzer.range_arena.map.iter().map(|(k, v)| { + // format!("\t{}: {}\n", k, v) + // }).collect::>().join("")); + if args.debug { return; } diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index da30b745..bebaf6ce 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -28,11 +28,11 @@ impl ContextNode { } /// Get the dependencies as normalized solver atoms - pub fn dep_atoms(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn dep_atoms(&self, analyzer: &mut impl GraphBackend) -> Result, GraphError> { let deps: Vec<_> = self.ctx_deps(analyzer)?; let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { - let range = dep.ref_range(analyzer)?.unwrap(); + let mut range = dep.range(analyzer)?.unwrap(); let r: Cow<'_, SolcRange> = range.flattened_range(analyzer)?; ranges.insert(*dep, r.into_owned()); Ok(()) @@ -87,7 +87,7 @@ impl ContextNode { // let underlying = self.underlying_mut(analyzer)?; if !self.underlying(analyzer)?.ctx_deps.contains(&dep) { // dep.cache_flattened_range(analyzer)?; - let range = dep.ref_range(analyzer)?.unwrap(); + let mut range = dep.range(analyzer)?.unwrap(); let r = range.flattened_range(analyzer)?.into_owned(); // add the atomic constraint if let Some(atom) = r.min.atomize(analyzer) { diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 2c2a3e42..967fad60 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -146,13 +146,13 @@ impl ContextVarNode { if let Some(ref_range) = self.ref_range(analyzer)? { let min_name = ref_range .range_min() - .simplify_minimize(&mut Default::default(), analyzer)? + .simplify_minimize(analyzer)? .to_range_string(false, analyzer) .s; let max_name = ref_range .range_max() - .simplify_maximize(&mut Default::default(), analyzer)? + .simplify_maximize(analyzer)? .to_range_string(true, analyzer) .s; if max_name == min_name { @@ -205,6 +205,20 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.tmp_of()) } + pub fn struct_to_fields(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + if self.ref_range(analyzer)?.is_none() { + let fields = analyzer + .graph() + .edges_directed(self.first_version(analyzer).into(), Direction::Incoming) + .filter(|edge| *edge.weight() == Edge::Context(ContextEdge::AttrAccess("field"))) + .map(|edge| ContextVarNode::from(edge.source()).latest_version(analyzer)) + .collect::>(); + Ok(fields) + } else { + Ok(vec![]) + } + } + pub fn array_to_len_var(&self, analyzer: &impl GraphBackend) -> Option { if let Some(len) = analyzer .graph() diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 81359a15..a4db26ef 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -433,15 +433,26 @@ impl FunctionNode { Ok(()) } + // fn returns_inner( + // &self, + // analyzer: &impl GraphBackend, + // ) -> Vec { + // self.underlying(analyzer).unwrap().cache.returns.iter() + // // } else { + // // analyzer + // // .graph() + // // .edges_directed(self.0.into(), Direction::Incoming) + // // .filter(|edge| Edge::FunctionReturn == *edge.weight()) + // // .map(|edge| FunctionReturnNode::from(edge.source())) + // // .collect() + // // } + // } + pub fn returns<'a>( &self, analyzer: &'a impl GraphBackend, - ) -> impl Iterator + 'a { - analyzer - .graph() - .edges_directed(self.0.into(), Direction::Incoming) - .filter(|edge| Edge::FunctionReturn == *edge.weight()) - .map(|edge| FunctionReturnNode::from(edge.source())) + ) -> &'a [FunctionReturnNode] { + self.underlying(analyzer).unwrap().cache.returns.as_ref().unwrap() } pub fn is_public_or_ext(&self, analyzer: &impl GraphBackend) -> Result { @@ -462,6 +473,14 @@ impl FunctionNode { .any(|attr| matches!(attr, FunctionAttribute::Mutability(Mutability::Pure(_))))) } + pub fn is_view(&self, analyzer: &impl GraphBackend) -> Result { + Ok(self + .underlying(analyzer)? + .attributes + .iter() + .any(|attr| matches!(attr, FunctionAttribute::Mutability(Mutability::View(_))))) + } + pub fn get_overriding( &self, other: &Self, diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 36c8c8a8..aad962f5 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,3 +1,4 @@ + use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{Elem, RangeElem}, @@ -7,16 +8,30 @@ use crate::{ use shared::NodeIdx; use std::collections::BTreeMap; +use std::hash::{Hash, Hasher}; use solang_parser::pt::Loc; /// A concrete value for a range element -#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[derive(Default, Clone, Debug, Ord, PartialOrd)] pub struct RangeConcrete { pub val: T, pub loc: Loc, } +impl PartialEq for RangeConcrete { + fn eq(&self, other: &Self) -> bool { + self.val == other.val + } +} +impl Eq for RangeConcrete {} + +impl Hash for RangeConcrete { + fn hash(&self, state: &mut H) { + self.val.hash(state); + } +} + impl From for RangeConcrete { fn from(c: Concrete) -> Self { Self { @@ -149,14 +164,12 @@ impl RangeElem for RangeConcrete { fn simplify_maximize( &self, - _seen_ops: &mut BTreeMap, Elem>, _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_minimize( &self, - _seen_ops: &mut BTreeMap, Elem>, _analyzer: &impl GraphBackend, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index aba48e24..18106228 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,3 +1,7 @@ +use std::borrow::Cow; +use crate::elem::MinMaxed; +use std::cell::RefCell; +use std::rc::Rc; use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{ @@ -334,13 +338,19 @@ impl Elem { expr.maximized = None; expr.minimized = None; } - Elem::ConcreteDyn(_d) => todo!(), + Elem::ConcreteDyn(d) => { + d.len.replace_dep(to_replace, replacement.clone(), analyzer); + let vals = std::mem::take(&mut d.val); + d.val = vals.into_iter().map(|(mut k, (mut v, op))| { + k.replace_dep(to_replace, replacement.clone(), analyzer); + v.replace_dep(to_replace, replacement.clone(), analyzer); + (k, (v, op)) + }).collect(); + }, Elem::Null => {} Elem::Arena(_) => { - let mut s = self.dearenaize(analyzer).clone(); - s.replace_dep(to_replace, replacement, analyzer); - s.arenaize(analyzer).unwrap(); - *self = s; + let s = self.dearenaize(analyzer).clone(); + s.borrow_mut().replace_dep(to_replace, replacement, analyzer); } } } @@ -348,6 +358,7 @@ impl Elem { pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Self { match self { Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx] + .borrow() .clone() .recurse_dearenaize(analyzer), Self::Expr(expr) => expr.recurse_dearenaize(analyzer), @@ -355,16 +366,11 @@ impl Elem { } } - pub fn dearenaize<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a Self { + pub fn dearenaize(&self, analyzer: &impl GraphBackend) -> Rc> { match self { - Self::Arena(arena_idx) => &analyzer.range_arena().ranges[*arena_idx], - _ => unreachable!(), - } - } - - pub fn dearenaize_mut<'a>(&self, analyzer: &'a mut impl GraphBackend) -> &'a mut Self { - match self { - Self::Arena(arena_idx) => &mut analyzer.range_arena_mut().ranges[*arena_idx], + Self::Arena(arena_idx) => { + analyzer.range_arena().ranges[*arena_idx].clone() + }, _ => unreachable!(), } } @@ -620,12 +626,15 @@ impl RangeElem for Elem { fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { match self { Self::Arena(_) => return Ok(()), - Self::Reference(d) => d.arenaize(analyzer)?, + Self::Reference(d) => { + d.arenaize(analyzer)? + }, Self::ConcreteDyn(d) => d.arenaize(analyzer)?, Self::Expr(expr) => { expr.arenaize(analyzer)?; } - _ => {} + Self::Concrete(c) => c.arenaize(analyzer)?, + Self::Null => {}, } let self_take = std::mem::take(self); @@ -650,7 +659,8 @@ impl RangeElem for Elem { Some(std::cmp::Ordering::Equal) } else { self.dearenaize(analyzer) - .range_ord(other.dearenaize(analyzer), analyzer) + .borrow() + .range_ord(&other.dearenaize(analyzer).borrow(), analyzer) } } (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), @@ -673,7 +683,35 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.flatten(maximize, analyzer), Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), Self::Null => Ok(Elem::Null), - Self::Arena(_) => self.dearenaize(analyzer).flatten(maximize, analyzer), + Self::Arena(_) => { + let de = self.dearenaize(analyzer); + let res = de.borrow().flatten(maximize, analyzer)?; + match &mut *de.borrow_mut() { + Self::Reference(ref mut d) => { + if maximize { + d.flattened_max = Some(Box::new(res.clone())); + } else { + d.flattened_min = Some(Box::new(res.clone())); + } + } + Self::Expr(ref mut expr) => { + if maximize { + expr.flattened_max = Some(Box::new(res.clone())); + } else { + expr.flattened_min = Some(Box::new(res.clone())); + } + } + Self::ConcreteDyn(ref mut d) => { + if maximize { + d.flattened_max = Some(Box::new(res.clone())); + } else { + d.flattened_min = Some(Box::new(res.clone())); + } + } + _ => {} + } + Ok(res) + }, } } @@ -682,23 +720,16 @@ impl RangeElem for Elem { return Ok(()); } - if let Some(idx) = analyzer.range_arena_idx(self) { - if Elem::Arena(idx).is_flatten_cached(analyzer) { - panic!("here"); - } - } - match self { Self::Reference(d) => d.cache_flatten(analyzer), Self::Concrete(c) => c.cache_flatten(analyzer), Self::Expr(expr) => expr.cache_flatten(analyzer), Self::ConcreteDyn(d) => d.cache_flatten(analyzer), Self::Null => Ok(()), - Self::Arena(idx) => { - let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer).clone(); + Self::Arena(_idx) => { + let mut dearenaized = self.dearenaize(analyzer).borrow().clone(); dearenaized.cache_flatten(analyzer)?; - analyzer.range_arena_mut().ranges[idx] = dearenaized; + *self.dearenaize(analyzer).borrow_mut() = dearenaized; Ok(()) } } @@ -711,7 +742,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.is_flatten_cached(analyzer), Self::ConcreteDyn(d) => d.is_flatten_cached(analyzer), Self::Null => true, - Self::Arena(_) => self.dearenaize(analyzer).is_flatten_cached(analyzer), + Self::Arena(_) => self.dearenaize(analyzer).borrow().is_flatten_cached(analyzer), } } @@ -722,7 +753,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.is_min_max_cached(analyzer), Self::ConcreteDyn(d) => d.is_min_max_cached(analyzer), Self::Null => (true, true), - Self::Arena(_) => self.dearenaize(analyzer).is_min_max_cached(analyzer), + Self::Arena(_) => self.dearenaize(analyzer).borrow().is_min_max_cached(analyzer), } } @@ -733,7 +764,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.dependent_on(analyzer), Self::ConcreteDyn(d) => d.dependent_on(analyzer), Self::Null => vec![], - Self::Arena(_) => self.dearenaize(analyzer).dependent_on(analyzer), + Self::Arena(_) => self.dearenaize(analyzer).borrow().dependent_on(analyzer), } } @@ -747,7 +778,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.recursive_dependent_on(analyzer), Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer), Self::Null => Ok(vec![]), - Self::Arena(_) => self.dearenaize(analyzer).recursive_dependent_on(analyzer), + Self::Arena(_) => self.dearenaize(analyzer).borrow().recursive_dependent_on(analyzer), } } @@ -762,7 +793,7 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.has_cycle(seen, analyzer), Self::ConcreteDyn(d) => d.has_cycle(seen, analyzer), Self::Null => Ok(false), - Self::Arena(_) => self.dearenaize(analyzer).has_cycle(seen, analyzer), + Self::Arena(_) => self.dearenaize(analyzer).borrow().has_cycle(seen, analyzer), } } @@ -782,16 +813,28 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx, analyzer), Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx, analyzer), Self::Null => {} - Self::Arena(idx) => { - let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer).clone(); - dearenaized.filter_recursion(node_idx, new_idx, analyzer); - analyzer.range_arena_mut().ranges[idx] = dearenaized; + Self::Arena(_idx) => { + let dearenaized = self.dearenaize(analyzer); + dearenaized.borrow_mut().filter_recursion(node_idx, new_idx, analyzer); } } } fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + if let Some(idx) = analyzer.range_arena_idx(self) { + let (_min, max) = Elem::Arena(idx).is_min_max_cached(analyzer); + if max { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => return dy.maximize(analyzer), + Concrete(inner) => return inner.maximize(analyzer), + ConcreteDyn(inner) => return inner.maximize(analyzer), + Expr(expr) => return expr.maximize(analyzer), + Null => return Ok(Elem::Null), + _ => {} + } + } + } + use Elem::*; let res = match self { Reference(dy) => dy.maximize(analyzer)?, @@ -799,78 +842,183 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.maximize(analyzer)?, Expr(expr) => expr.maximize(analyzer)?, Null => Elem::Null, - Arena(_) => self.dearenaize(analyzer).maximize(analyzer)?, + Arena(_) => { + let dearenaized = self.dearenaize(analyzer); + let res = dearenaized.borrow().maximize(analyzer)?; + match &mut *dearenaized.borrow_mut() { + Self::Reference(ref mut d) => { + d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + Self::Expr(ref mut expr) => { + expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + Self::ConcreteDyn(ref mut d) => { + d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + _ => {} + } + res + }, }; Ok(res) } fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { use Elem::*; + + if let Some(idx) = analyzer.range_arena_idx(self) { + let (min, _max) = Elem::Arena(idx).is_min_max_cached(analyzer); + if min { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => return dy.minimize(analyzer), + Concrete(inner) => return inner.minimize(analyzer), + ConcreteDyn(inner) => return inner.minimize(analyzer), + Expr(expr) => return expr.minimize(analyzer), + Null => return Ok(Elem::Null), + _ => {} + } + } + } + let res = match self { Reference(dy) => dy.minimize(analyzer)?, Concrete(inner) => inner.minimize(analyzer)?, ConcreteDyn(inner) => inner.minimize(analyzer)?, Expr(expr) => expr.minimize(analyzer)?, Null => Elem::Null, - Arena(_) => self.dearenaize(analyzer).minimize(analyzer)?, + Arena(_) => { + let dearenaized = self.dearenaize(analyzer); + let res = dearenaized.borrow().minimize(analyzer)?; + match &mut *dearenaized.borrow_mut() { + Self::Reference(ref mut d) => { + d.maximized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + Self::Expr(ref mut expr) => { + expr.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + Self::ConcreteDyn(ref mut d) => { + d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + _ => {} + } + res + }, }; Ok(res) } fn simplify_maximize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if let Some(res) = seen_ops.get(self) { - return Ok(res.clone()); - } - use Elem::*; + match self { - Reference(dy) => dy.simplify_maximize(seen_ops, analyzer), - Concrete(inner) => inner.simplify_maximize(seen_ops, analyzer), - ConcreteDyn(inner) => inner.simplify_maximize(seen_ops, analyzer), + Arena(_) => {} + _ => { + if let Some(idx) = analyzer.range_arena_idx(self) { + if Elem::Arena(idx).is_flatten_cached(analyzer) { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => return dy.simplify_maximize(analyzer), + Concrete(inner) => return inner.simplify_maximize(analyzer), + ConcreteDyn(inner) => return inner.simplify_maximize(analyzer), + Expr(expr) => return expr.simplify_maximize(analyzer), + Null => return Ok(Elem::Null), + _ => {} + } + } + } + } + } + + + match self { + Reference(dy) => dy.simplify_maximize(analyzer), + Concrete(inner) => inner.simplify_maximize(analyzer), + ConcreteDyn(inner) => inner.simplify_maximize(analyzer), Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_maximize(seen_ops, analyzer) + collapsed.simplify_maximize(analyzer) } - _ => expr.simplify_maximize(seen_ops, analyzer), + _ => expr.simplify_maximize(analyzer), }, Null => Ok(Elem::Null), - Arena(_) => self - .dearenaize(analyzer) - .simplify_maximize(seen_ops, analyzer), + Arena(_) => { + let dearenaized = self.dearenaize(analyzer); + let flat = dearenaized.borrow().flatten(true, analyzer)?; + let res = flat.simplify_maximize(analyzer)?; + match &mut *dearenaized.borrow_mut() { + Self::Reference(ref mut d) => { + d.flattened_max = Some(Box::new(res.clone())); + } + Self::Expr(ref mut expr) => { + expr.flattened_max = Some(Box::new(res.clone())); + } + Self::ConcreteDyn(ref mut d) => { + d.flattened_max = Some(Box::new(res.clone())); + } + _ => {} + } + Ok(res) + } } } fn simplify_minimize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if let Some(res) = seen_ops.get(self) { - return Ok(res.clone()); + use Elem::*; + + match self { + Arena(_) => {} + _ => { + if let Some(idx) = analyzer.range_arena_idx(self) { + if Elem::Arena(idx).is_flatten_cached(analyzer) { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => return dy.simplify_minimize(analyzer), + Concrete(inner) => return inner.simplify_minimize(analyzer), + ConcreteDyn(inner) => return inner.simplify_minimize(analyzer), + Expr(expr) => return expr.simplify_minimize(analyzer), + Null => return Ok(Elem::Null), + _ => {} + } + } + } + } } - use Elem::*; let res = match self { - Reference(dy) => dy.simplify_minimize(seen_ops, analyzer), - Concrete(inner) => inner.simplify_minimize(seen_ops, analyzer), - ConcreteDyn(inner) => inner.simplify_minimize(seen_ops, analyzer), + Reference(dy) => dy.simplify_minimize(analyzer), + Concrete(inner) => inner.simplify_minimize(analyzer), + ConcreteDyn(inner) => inner.simplify_minimize(analyzer), Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_minimize(seen_ops, analyzer) + collapsed.simplify_minimize(analyzer) } - _ => expr.simplify_minimize(seen_ops, analyzer), + _ => expr.simplify_minimize(analyzer), }, Null => Ok(Elem::Null), - Arena(_) => self - .dearenaize(analyzer) - .simplify_minimize(seen_ops, analyzer), + Arena(_) => { + let dearenaized = self.dearenaize(analyzer); + let flat = dearenaized.borrow().flatten(true, analyzer)?; + let res = flat.simplify_minimize(analyzer)?; + match &mut *dearenaized.borrow_mut() { + Self::Reference(ref mut d) => { + d.flattened_min = Some(Box::new(res.clone())); + } + Self::Expr(ref mut expr) => { + expr.flattened_min = Some(Box::new(res.clone())); + } + Self::ConcreteDyn(d) => { + d.flattened_min = Some(Box::new(res.clone())); + } + _ => {} + } + Ok(res) + } }?; - seen_ops.insert(self.clone(), res.clone()); Ok(res) } @@ -889,11 +1037,9 @@ impl RangeElem for Elem { _ => expr.cache_maximize(analyzer), }, Null => Ok(()), - Arena(idx) => { - let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer).clone(); - dearenaized.cache_maximize(analyzer)?; - analyzer.range_arena_mut().ranges[idx] = dearenaized; + Arena(_idx) => { + let dearenaized = self.dearenaize(analyzer); + dearenaized.borrow_mut().cache_maximize(analyzer)?; Ok(()) } } @@ -914,11 +1060,9 @@ impl RangeElem for Elem { _ => expr.cache_minimize(analyzer), }, Null => Ok(()), - Arena(idx) => { - let idx = *idx; - let mut dearenaized = self.dearenaize(analyzer).clone(); - dearenaized.cache_minimize(analyzer)?; - analyzer.range_arena_mut().ranges[idx] = dearenaized; + Arena(_idx) => { + let dearenaized = self.dearenaize(analyzer); + dearenaized.borrow_mut().cache_minimize(analyzer)?; Ok(()) } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 96244500..1184558a 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -34,13 +34,11 @@ pub trait RangeElem { /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) fn simplify_maximize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) fn simplify_minimize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; /// Checks if two range elements are equal diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index d3fbf783..39147265 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -37,7 +37,7 @@ pub static EQ_OPS: &[RangeOp] = &[ pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; /// A range expression composed of other range [`Elem`] -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Clone, Debug, Ord, PartialOrd)] pub struct RangeExpr { pub maximized: Option>, pub minimized: Option>, @@ -48,6 +48,16 @@ pub struct RangeExpr { pub rhs: Box>, } + +impl PartialEq for RangeExpr { + fn eq(&self, other: &Self) -> bool { + self.lhs == other.lhs + && self.rhs == other.rhs + && self.op == other.op + } +} +impl Eq for RangeExpr {} + impl Hash for RangeExpr { fn hash(&self, state: &mut H) { (*self.lhs).hash(state); @@ -89,6 +99,60 @@ impl RangeExpr { self.rhs.recurse_dearenaize(analyzer).clone(), )) } + + pub fn arena_idx(&self, analyzer: &impl GraphBackend) -> Option { + let expr = Elem::Expr(RangeExpr::new( + Elem::Arena(analyzer.range_arena_idx(&self.lhs)?), + self.op, + Elem::Arena(analyzer.range_arena_idx(&self.rhs)?), + )); + analyzer.range_arena_idx(&expr) + } + + pub fn arenaized_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option> { + if let Some(idx) = self.arena_idx(analyzer) { + let Elem::Expr(ref arenaized) = *analyzer.range_arena().ranges[idx].borrow() else { + return None; + }; + return if max { + arenaized.maximized.clone() + } else { + arenaized.minimized.clone() + }; + } + None + } + + pub fn arenaized_flat_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option>> { + if let Some(idx) = self.arena_idx(analyzer) { + let Elem::Expr(ref arenaized) = *analyzer.range_arena().ranges[idx].borrow() else { + return None; + }; + return if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + }; + } + None + } + + pub fn set_arenaized_flattened(&self, max: bool, elem: Elem, analyzer: &impl GraphBackend) { + if let Some(idx) = self.arena_idx(analyzer) { + if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + let Elem::Expr(arenaized) = &mut *t else { + return; + }; + + if max { + arenaized.flattened_max = Some(Box::new(elem)); + } else { + arenaized.flattened_min = Some(Box::new(elem)); + } + } + } + } + } impl RangeExpr { @@ -113,9 +177,16 @@ impl RangeExpr { impl RangeElem for RangeExpr { type GraphError = GraphError; + #[tracing::instrument(level = "trace", skip_all)] fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.lhs.arenaize(analyzer); - self.rhs.arenaize(analyzer); + // self.lhs.clone().arenaize(analyzer)?; + // self.rhs.clone().arenaize(analyzer)?; + if self.arena_idx(analyzer).is_none() { + let mut self_copy = self.clone(); + *self_copy.lhs = *Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*self.lhs.clone()))); + *self_copy.rhs = *Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*self.rhs.clone()))); + let _ = analyzer.range_arena_idx_or_upsert(Elem::Expr(self_copy)); + } Ok(()) } @@ -123,6 +194,7 @@ impl RangeElem for RangeExpr { false } + #[tracing::instrument(level = "trace", skip_all)] fn flatten( &self, maximize: bool, @@ -134,6 +206,11 @@ impl RangeElem for RangeExpr { } _ => {} } + + if let Some(arenaized) = self.arenaized_flat_cache(maximize, analyzer) { + return Ok(*arenaized) + } + Ok(Elem::Expr(RangeExpr::new( self.lhs.flatten(maximize, analyzer)?, self.op, @@ -163,6 +240,7 @@ impl RangeElem for RangeExpr { deps } + #[tracing::instrument(level = "trace", skip_all)] fn recursive_dependent_on( &self, analyzer: &impl GraphBackend, @@ -172,6 +250,7 @@ impl RangeElem for RangeExpr { Ok(deps) } + #[tracing::instrument(level = "trace", skip_all)] fn has_cycle( &self, seen: &mut Vec, @@ -182,6 +261,7 @@ impl RangeElem for RangeExpr { Ok(lhs_has_cycle || rhs_has_cycle) } + #[tracing::instrument(level = "trace", skip_all)] fn filter_recursion( &mut self, node_idx: NodeIdx, @@ -192,40 +272,47 @@ impl RangeElem for RangeExpr { self.rhs.filter_recursion(node_idx, new_idx, analyzer); } + #[tracing::instrument(level = "trace", skip_all)] fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { Ok(*cached) + } else if let Some(MinMaxed::Maximized(cached)) = self.arenaized_cache(true, analyzer) { + Ok(*cached) } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(true, &mut Default::default(), analyzer) - } else if let Some(flat_max) = &self.flattened_max { - flat_max.maximize(analyzer) + self.simplify_exec_op(true, analyzer) } else { self.exec_op(true, analyzer) } } + + #[tracing::instrument(level = "trace", skip_all)] fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { Ok(*cached) - } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(false, &mut Default::default(), analyzer) - } else if let Some(flat_min) = &self.flattened_min { - flat_min.minimize(analyzer) + } else if let Some(MinMaxed::Minimized(cached)) = self.arenaized_cache(false, analyzer) { + Ok(*cached) + } else if self.op == RangeOp::SetIndices { + self.simplify_exec_op(false, analyzer) } else { self.exec_op(false, analyzer) } } + #[tracing::instrument(level = "trace", skip_all)] fn simplify_maximize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_max) = &self.flattened_max { return Ok(*simp_max.clone()); } - let l = self.lhs.simplify_maximize(seen_ops, analyzer)?; - let r = self.rhs.simplify_maximize(seen_ops, analyzer)?; + if let Some(arenaized) = self.arenaized_flat_cache(true, analyzer) { + return Ok(*arenaized) + } + + let l = self.lhs.simplify_maximize(analyzer)?; + let r = self.rhs.simplify_maximize(analyzer)?; let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(true, analyzer), @@ -233,7 +320,7 @@ impl RangeElem for RangeExpr { MaybeCollapsed::Not(..) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) let res = - RangeExpr::new(l, self.op, r).simplify_exec_op(true, seen_ops, analyzer)?; + RangeExpr::new(l, self.op, r).simplify_exec_op(true, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { @@ -248,24 +335,29 @@ impl RangeElem for RangeExpr { } } } + + #[tracing::instrument(level = "trace", skip_all)] fn simplify_minimize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_min) = &self.flattened_min { return Ok(*simp_min.clone()); } - let l = self.lhs.simplify_minimize(seen_ops, analyzer)?; - let r = self.rhs.simplify_minimize(seen_ops, analyzer)?; + if let Some(arenaized) = self.arenaized_flat_cache(false, analyzer) { + return Ok(*arenaized) + } + + let l = self.lhs.simplify_minimize(analyzer)?; + let r = self.rhs.simplify_minimize(analyzer)?; let collapsed = collapse(&l, self.op, &r, analyzer); match collapsed { MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(false, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { let res = - RangeExpr::new(l, self.op, r).simplify_exec_op(false, seen_ops, analyzer)?; + RangeExpr::new(l, self.op, r).simplify_exec_op(false, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { @@ -281,60 +373,55 @@ impl RangeElem for RangeExpr { } } + #[tracing::instrument(level = "trace", skip_all)] fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - if let Some(idx) = g.range_arena_idx(&Elem::Expr(self.clone())) { - if Elem::Arena(idx).is_flatten_cached(g) { - panic!("here"); - } - } - if self.flattened_max.is_none() { - self.lhs.arenaize(g)?; self.lhs.cache_flatten(g)?; - self.rhs.arenaize(g)?; self.rhs.cache_flatten(g)?; - let mut flat_max = self.flatten(true, g)?; - flat_max.arenaize(g)?; - let mut simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; - simplified_flat_max.arenaize(g)?; + // self.arenaize(g)?; + let flat_max = self.flatten(true, g)?; + let simplified_flat_max = flat_max.simplify_maximize(g)?; + simplified_flat_max.clone().arenaize(g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); - let mut s = Elem::Expr(self.clone()); - s.arenaize(g)?; + self.arenaize(g)?; + // let mut s = Elem::Expr(self.clone()); + // s.arenaize(g)?; } if self.flattened_min.is_none() { - self.lhs.arenaize(g)?; self.lhs.cache_flatten(g)?; - self.rhs.arenaize(g)?; self.rhs.cache_flatten(g)?; - let mut flat_min = self.flatten(false, g)?; - flat_min.arenaize(g)?; - let mut simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; - simplified_flat_min.arenaize(g)?; + // self.arenaize(g)?; + let flat_min = self.flatten(false, g)?; + let simplified_flat_min = flat_min.simplify_minimize(g)?; + simplified_flat_min.clone().arenaize(g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); - let mut s = Elem::Expr(self.clone()); - s.arenaize(g)?; + self.arenaize(g)?; + // let mut s = Elem::Expr(self.clone()); + // s.arenaize(g)?; } Ok(()) } + #[tracing::instrument(level = "trace", skip_all)] fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + tracing::trace!("cache maximizing: {}", Elem::Expr(self.clone())); if self.maximized.is_none() { - self.lhs.arenaize(g)?; self.lhs.cache_maximize(g)?; - self.rhs.arenaize(g)?; self.rhs.cache_maximize(g)?; self.cache_exec_op(true, g)?; + self.arenaize(g)?; } Ok(()) } + #[tracing::instrument(level = "trace", skip_all)] fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + tracing::trace!("cache minimizing: {}", Elem::Expr(self.clone())); if self.minimized.is_none() { - self.lhs.arenaize(g)?; self.lhs.cache_minimize(g)?; - self.rhs.arenaize(g)?; self.rhs.cache_minimize(g)?; self.cache_exec_op(false, g)?; + self.arenaize(g)?; } Ok(()) } @@ -359,8 +446,20 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>( let zero = Elem::from(Concrete::from(U256::zero())); let one = Elem::from(Concrete::from(U256::one())); match (l, r) { - (Elem::Arena(_), r) => collapse(l.dearenaize(analyzer), op, r, analyzer), - (l, Elem::Arena(_)) => collapse(l, op, r.dearenaize(analyzer), analyzer), + (Elem::Arena(_), r) => { + match collapse(&l.dearenaize(analyzer).borrow().clone(), op, r, analyzer) { + MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + } + }, + (l, Elem::Arena(_)) => { + match collapse(l, op, &r.dearenaize(analyzer).borrow().clone(), analyzer) { + MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + } + }, (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { // try to collapse the expression diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index daf266d3..5e66ea8e 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -13,7 +13,7 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; /// A concrete value for a range element -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Clone, Debug, Ord, PartialOrd)] pub struct RangeDyn { /// Cached minimized value pub minimized: Option>, @@ -33,6 +33,15 @@ pub struct RangeDyn { pub loc: Loc, } +impl PartialEq for RangeDyn { + fn eq(&self, other: &Self) -> bool { + self.len == other.len + && self.val == other.val + && self.op_num == other.op_num + } +} +impl Eq for RangeDyn {} + impl Hash for RangeDyn { fn hash(&self, state: &mut H) { (*self.len).hash(state); @@ -170,10 +179,10 @@ impl RangeElem for RangeDyn { type GraphError = GraphError; fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.cache_flatten(analyzer)?; - self.cache_minimize(analyzer)?; - self.cache_maximize(analyzer)?; - self.len.arenaize(analyzer); + // self.cache_flatten(analyzer)?; + // self.cache_minimize(analyzer)?; + // self.cache_maximize(analyzer)?; + self.len.arenaize(analyzer)?; self.val = self .val .iter_mut() @@ -325,7 +334,7 @@ impl RangeElem for RangeDyn { .collect(); let flat_max = self.flatten(true, analyzer)?; let simplified_flat_max = - flat_max.simplify_maximize(&mut Default::default(), analyzer)?; + flat_max.simplify_maximize(analyzer)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { @@ -341,7 +350,7 @@ impl RangeElem for RangeDyn { .collect(); let flat_min = self.flatten(false, analyzer)?; let simplified_flat_min = - flat_min.simplify_minimize(&mut Default::default(), analyzer)?; + flat_min.simplify_minimize(analyzer)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) @@ -388,7 +397,7 @@ impl RangeElem for RangeDyn { // `get_index` can find potential values let maximized = val.0.maximize(analyzer)?; map.insert( - idx.simplify_maximize(&mut Default::default(), analyzer)?, + idx.simplify_maximize(analyzer)?, (maximized, val.1), ); } @@ -416,7 +425,7 @@ impl RangeElem for RangeDyn { // `get_index` can find potential values let minimized = val.0.minimize(analyzer)?; map.insert( - idx.simplify_minimize(&mut Default::default(), analyzer)?, + idx.simplify_minimize(analyzer)?, (minimized, val.1), ); } @@ -432,20 +441,19 @@ impl RangeElem for RangeDyn { fn simplify_maximize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(max) = &self.flattened_max { return Ok(*max.clone()); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_maximize(seen_ops, analyzer)?, + self.len.simplify_maximize(analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_maximize(seen_ops, analyzer)?; + let simplified = val.0.simplify_maximize(analyzer)?; map.insert(idx, (simplified, val.1)); } map @@ -455,7 +463,6 @@ impl RangeElem for RangeDyn { } fn simplify_minimize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(min) = &self.flattened_min { @@ -463,13 +470,13 @@ impl RangeElem for RangeDyn { } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_minimize(seen_ops, analyzer)?, + self.len.simplify_minimize(analyzer)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_minimize(seen_ops, analyzer)?; + let simplified = val.0.simplify_minimize(analyzer)?; map.insert(idx, (simplified, val.1)); } map diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index e972371a..910b1926 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -16,7 +16,7 @@ use solang_parser::pt::Loc; use std::collections::BTreeMap; /// A dynamic range element value -#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Clone, Debug, Ord, PartialOrd)] pub struct Reference { /// Index of the node that is referenced pub idx: NodeIdx, @@ -36,6 +36,14 @@ impl Hash for Reference { } } +impl PartialEq for Reference { + fn eq(&self, other: &Self) -> bool { + self.idx == other.idx + } +} +impl Eq for Reference {} + + impl Reference { pub fn new(idx: NodeIdx) -> Self { Self { @@ -52,6 +60,9 @@ impl RangeElem for Reference { type GraphError = GraphError; fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + // self.cache_flatten(analyzer)?; + // self.cache_minimize(analyzer)?; + // self.cache_maximize(analyzer)?; Ok(()) } @@ -141,11 +152,17 @@ impl RangeElem for Reference { } fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + if let Some(idx) = g.range_arena_idx(&Elem::Reference(self.clone())) { + if Elem::Arena(idx).is_flatten_cached(g) { + return Ok(()) + } + } + if self.flattened_max.is_none() { let cvar = ContextVarNode::from(self.idx); cvar.cache_flattened_range(g)?; let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(&mut Default::default(), g)?; + let simplified_flat_max = flat_max.simplify_maximize(g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); let mut s = Elem::Reference(self.clone()); s.arenaize(g)?; @@ -154,7 +171,7 @@ impl RangeElem for Reference { let cvar = ContextVarNode::from(self.idx); cvar.cache_flattened_range(g)?; let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(&mut Default::default(), g)?; + let simplified_flat_min = flat_min.simplify_minimize(g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); let mut s = Elem::Reference(self.clone()); s.arenaize(g)?; @@ -216,7 +233,6 @@ impl RangeElem for Reference { fn simplify_maximize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_max) = &self.flattened_max { @@ -232,13 +248,12 @@ impl RangeElem for Reference { ))) } else { self.flatten(true, analyzer)? - .simplify_maximize(seen_ops, analyzer) + .simplify_maximize(analyzer) } } fn simplify_minimize( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { if let Some(simp_min) = &self.flattened_min { @@ -252,7 +267,7 @@ impl RangeElem for Reference { ))) } else { self.flatten(false, analyzer)? - .simplify_minimize(seen_ops, analyzer) + .simplify_minimize(analyzer) } } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 7e03162f..b8df6666 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -7,19 +7,33 @@ use crate::{ use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; -use std::collections::BTreeMap; impl ExecOp for RangeExpr { type GraphError = GraphError; + #[tracing::instrument(level = "trace", skip_all)] fn exec_op( &self, maximize: bool, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError> { - self.exec(self.spread(analyzer)?, maximize, analyzer) + let res = self.exec(self.spread(analyzer)?, maximize, analyzer)?; + if let Some(idx) = self.arena_idx(analyzer) { + if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + if let Elem::Expr(expr) = &mut *t { + if maximize { + expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } else { + expr.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + } + } + } + + Ok(res) } + #[tracing::instrument(level = "trace", skip_all)] fn cache_exec_op( &mut self, maximize: bool, @@ -35,6 +49,19 @@ impl ExecOp for RangeExpr { } else { self.minimized = Some(MinMaxed::Minimized(Box::new(res))); } + + if let Some(idx) = self.arena_idx(analyzer) { + if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + if let Elem::Expr(expr) = &mut *t { + if maximize { + expr.maximized = self.maximized.clone(); + } else { + expr.minimized = self.minimized.clone(); + } + } + } + } + Ok(()) } @@ -43,17 +70,25 @@ impl ExecOp for RangeExpr { self.rhs.uncache(); } + #[tracing::instrument(level = "trace", skip_all)] fn simplify_exec_op( &self, maximize: bool, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, GraphError> { - if let Some(res) = seen_ops.get(&Elem::Expr(self.clone())) { - return Ok(res.clone()); + if maximize { + if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { + return Ok(*v) + } + } + + if !maximize { + if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { + return Ok(*v) + } } - let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(seen_ops, analyzer)?; + let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(analyzer)?; tracing::trace!( "simplifying op: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", self.lhs, @@ -66,10 +101,14 @@ impl ExecOp for RangeExpr { ); let lhs_is_conc = lhs_min.is_conc() && lhs_max.is_conc(); let rhs_is_conc = rhs_min.is_conc() && rhs_max.is_conc(); + + let mut finished = false; + let mut ret = Ok(Elem::Null); if self.op == RangeOp::Cast { // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete if lhs_is_conc { - return self.exec_op(maximize, analyzer); + ret = self.exec_op(maximize, analyzer); + finished = true; } else { // we can drop the cast if the max of the dynamic lhs is less than the cast let concretized_lhs = self.lhs.maximize(analyzer)?; @@ -77,19 +116,21 @@ impl ExecOp for RangeExpr { concretized_lhs.range_ord(&self.rhs, analyzer), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ) { - return Ok(*self.lhs.clone()); + ret = Ok(*self.lhs.clone()); + finished = true; } } } else if matches!(self.op, RangeOp::Concat | RangeOp::Memcopy) { // we can always execute a concat or memcopy - return self.exec_op(maximize, analyzer); + ret = self.exec_op(maximize, analyzer); + finished = true; } else if matches!( self.op, RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex ) { match self.op { RangeOp::GetLength => { - return if maximize { + ret = if maximize { Ok(lhs_max .range_get_length() .unwrap_or_else(|| Elem::Expr(self.clone()))) @@ -98,9 +139,10 @@ impl ExecOp for RangeExpr { .range_get_length() .unwrap_or_else(|| Elem::Expr(self.clone()))) }; + finished = true; } RangeOp::SetLength => { - return if maximize { + ret = if maximize { Ok(lhs_max .range_set_length(&rhs_max) .unwrap_or_else(|| Elem::Expr(self.clone()))) @@ -109,11 +151,12 @@ impl ExecOp for RangeExpr { .range_set_length(&rhs_min) .unwrap_or_else(|| Elem::Expr(self.clone()))) }; + finished = true; } RangeOp::GetIndex => { if maximize { let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, .. }) => val + Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val .iter() .try_fold( None, @@ -141,10 +184,11 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| Elem::Null), _ => Elem::Expr(self.clone()), }; - return Ok(res); + ret = Ok(res); + finished = true; } else { let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, .. }) => val + Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val .iter() .try_fold( None, @@ -172,11 +216,12 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| Elem::Null), _ => Elem::Expr(self.clone()), }; - return Ok(res); + ret = Ok(res); + finished = true; } } RangeOp::SetIndices => { - return if maximize { + ret = if maximize { Ok(lhs_max .range_set_indices(&rhs_max) .unwrap_or_else(|| Elem::Expr(self.clone()))) @@ -185,16 +230,27 @@ impl ExecOp for RangeExpr { .range_set_indices(&rhs_min) .unwrap_or_else(|| Elem::Expr(self.clone()))) }; + finished = true; } _ => unreachable!(), } } let parts = (lhs_min, lhs_max, rhs_min, rhs_max); - match (lhs_is_conc, rhs_is_conc) { - (true, true) => self.exec(parts, maximize, analyzer), - _ => Ok(Elem::Expr(self.clone())), + match (lhs_is_conc, rhs_is_conc, finished) { + (true, true, false) => { + ret = self.exec(parts, maximize, analyzer); + }, + (_, _, false) => { + ret = Ok(Elem::Expr(self.clone())); + }, + _ => {} } + + if let Some(_idx) = self.arena_idx(analyzer) { + self.set_arenaized_flattened(maximize, ret.clone()?, analyzer); + } + ret } fn spread( @@ -218,7 +274,6 @@ impl ExecOp for RangeExpr { fn simplify_spread( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result< ( @@ -229,13 +284,14 @@ impl ExecOp for RangeExpr { ), GraphError, > { - let lhs_min = self.lhs.simplify_minimize(seen_ops, analyzer)?; - let lhs_max = self.lhs.simplify_maximize(seen_ops, analyzer)?; - let rhs_min = self.rhs.simplify_minimize(seen_ops, analyzer)?; - let rhs_max = self.rhs.simplify_maximize(seen_ops, analyzer)?; + let lhs_min = self.lhs.simplify_minimize(analyzer)?; + let lhs_max = self.lhs.simplify_maximize(analyzer)?; + let rhs_min = self.rhs.simplify_minimize(analyzer)?; + let rhs_max = self.rhs.simplify_maximize(analyzer)?; Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } + #[tracing::instrument(level = "trace", skip_all)] fn exec( &self, (lhs_min, lhs_max, rhs_min, rhs_max): ( @@ -247,8 +303,23 @@ impl ExecOp for RangeExpr { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, GraphError> { + if maximize { + if let Some(MinMaxed::Maximized(v)) = self.arenaized_cache(maximize, analyzer) { + tracing::trace!("avoided execing via cache"); + return Ok(*v) + } + } + + if !maximize { + if let Some(MinMaxed::Minimized(v)) = self.arenaized_cache(maximize, analyzer) { + tracing::trace!("avoided execing via cache"); + return Ok(*v) + } + } + tracing::trace!( - "executing: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", + "executing {}: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", + if maximize { "maximum" } else { "minimum" }, self.lhs, self.op.to_string(), self.rhs, @@ -292,11 +363,11 @@ impl ExecOp for RangeExpr { RangeOp::GetLength => { if maximize { let new = lhs_max.clone(); - let new_max = new.simplify_minimize(&mut Default::default(), analyzer)?; + let new_max = new.simplify_minimize(analyzer)?; let res = new_max.range_get_length(); res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { - let new_min = lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; + let new_min = lhs_min.simplify_minimize(analyzer)?; let res = new_min.range_get_length(); res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } @@ -349,7 +420,7 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| Elem::Null)), Elem::Reference(_) => { let new_max = - lhs_max.simplify_maximize(&mut Default::default(), analyzer)?; + lhs_max.simplify_maximize(analyzer)?; if new_max == lhs_max { Ok(Elem::Null) } else { @@ -397,7 +468,7 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| Elem::Null)), Elem::Reference(ref _r) => { let new_min = - lhs_min.simplify_minimize(&mut Default::default(), analyzer)?; + lhs_min.simplify_minimize(analyzer)?; if new_min == lhs_min { Ok(Elem::Null) } else { @@ -415,7 +486,7 @@ impl ExecOp for RangeExpr { if maximize { let max = self .rhs - .simplify_maximize(&mut Default::default(), analyzer)?; + .simplify_maximize(analyzer)?; lhs_max.range_set_indices(&rhs_max).unwrap_or_else(|| { lhs_max @@ -425,7 +496,7 @@ impl ExecOp for RangeExpr { } else { let min = self .rhs - .simplify_minimize(&mut Default::default(), analyzer)?; + .simplify_minimize(analyzer)?; lhs_min.range_set_indices(&rhs_min).unwrap_or_else(|| { lhs_min .range_set_indices(&min) diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index 6c5a028a..d32125ed 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -32,7 +32,6 @@ pub trait ExecOp { fn simplify_spread( &self, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; @@ -41,7 +40,6 @@ pub trait ExecOp { fn simplify_exec_op( &self, maximize: bool, - seen_ops: &mut BTreeMap, Elem>, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError>; diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 162d57ed..6a56660d 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -56,7 +56,7 @@ impl ToRangeString for Elem { Elem::ConcreteDyn(rd) => rd.def_string(analyzer), Elem::Expr(expr) => expr.def_string(analyzer), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - Elem::Arena(_) => self.dearenaize(analyzer).def_string(analyzer), + Elem::Arena(_) => self.dearenaize(analyzer).borrow().def_string(analyzer), } } @@ -73,6 +73,7 @@ impl ToRangeString for Elem { Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), Elem::Arena(_) => self .dearenaize(analyzer) + .borrow() .to_range_string(maximize, analyzer), } } diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index b1a9c2a2..adbb1520 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -74,14 +74,21 @@ pub trait Range { analyzer: &mut impl GraphBackend, ); /// Cache the flattened range - fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range fn flattened_range<'a>( - &'a self, - analyzer: &impl GraphBackend, + &'a mut self, + analyzer: &mut impl GraphBackend, ) -> Result, Self::GraphError> where Self: Sized + Clone; + + fn take_flattened_range( + &mut self, + analyzer: &mut impl GraphBackend, + ) -> Result + where + Self: Sized; } pub trait RangeEval>: Range { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 6de42b53..3e24b0d0 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -8,6 +8,7 @@ use shared::NodeIdx; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; +use tracing::instrument; use std::{borrow::Cow, collections::BTreeMap}; @@ -540,25 +541,19 @@ impl SolcRange { Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) } - pub fn into_flattened_range(&self, analyzer: &impl GraphBackend) -> Result { + pub fn into_flattened_range(&mut self, analyzer: &mut impl GraphBackend) -> Result { if let Some(cached) = &self.flattened { return Ok(*cached.clone()); } - let flattened_min = self.range_min().flatten(false, analyzer)?; - let simp_min = if !self.range_min().is_flatten_cached(analyzer) { - flattened_min.simplify_minimize(&mut Default::default(), analyzer)? - } else { - flattened_min - }; - let flattened_max = self.range_max().flatten(true, analyzer)?; - let simp_max = if !self.range_max().is_flatten_cached(analyzer) { - flattened_max.simplify_maximize(&mut Default::default(), analyzer)? - } else { - flattened_max - }; + self.min.cache_flatten(analyzer)?; + self.max.cache_flatten(analyzer)?; + let simp_min = self.min.simplify_minimize(analyzer)?; + let simp_max = self.max.simplify_maximize(analyzer)?; + let flat_range = SolcRange::new(simp_min, simp_max, self.exclusions.clone()); + self.flattened = Some(Box::new(flat_range.clone())); - Ok(SolcRange::new(simp_min, simp_max, self.exclusions.clone())) + Ok(flat_range) } } @@ -579,8 +574,8 @@ impl Range for SolcRange { } fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.min.arenaize(analyzer); - self.max.arenaize(analyzer); + self.min.arenaize(analyzer)?; + self.max.arenaize(analyzer)?; if self.max_cached.is_none() { let max = self.range_max_mut(); max.cache_maximize(analyzer)?; @@ -616,7 +611,7 @@ impl Range for SolcRange { ) -> Result { self.range_min() .flatten(false, analyzer)? - .simplify_minimize(&mut Default::default(), analyzer) + .simplify_minimize(analyzer) } fn simplified_range_max( &self, @@ -624,7 +619,7 @@ impl Range for SolcRange { ) -> Result { self.range_max() .flatten(true, analyzer)? - .simplify_maximize(&mut Default::default(), analyzer) + .simplify_maximize(analyzer) } fn range_exclusions(&self) -> Vec { @@ -666,30 +661,53 @@ impl Range for SolcRange { self.max.filter_recursion(self_idx, new_idx, analyzer); } - fn cache_flatten(&mut self, analyzer: &impl GraphBackend) -> Result<(), Self::GraphError> { + fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError> { if self.flattened.is_none() { - let flat = self.into_flattened_range(analyzer)?; - self.flattened = Some(Box::new(flat)) + self.into_flattened_range(analyzer)?; } Ok(()) } /// Produce a flattened range or use the cached flattened range fn flattened_range<'a>( - &'a self, - analyzer: &impl GraphBackend, + &'a mut self, + analyzer: &mut impl GraphBackend, ) -> Result, Self::GraphError> where Self: Sized + Clone, { - if let Some(flat) = &self.flattened { - Ok(Cow::Borrowed(flat)) + if self.flattened.is_none() { + self.cache_flatten(analyzer)?; + let Some(flat) = &self.flattened else { + unreachable!(); + }; + return Ok(Cow::Borrowed(flat)) + } else if let Some(flat) = &self.flattened { + return Ok(Cow::Borrowed(flat)) + } else { + unreachable!() + } + } + + /// Produce a flattened range or use the cached flattened range + fn take_flattened_range( + &mut self, + analyzer: &mut impl GraphBackend, + ) -> Result + where + Self: Sized, + { + let taken = std::mem::take(&mut self.flattened); + if let Some(flat) = taken { + Ok(*flat) } else { - Ok(Cow::Owned(self.into_flattened_range(analyzer)?)) + self.cache_flatten(analyzer)?; + self.take_flattened_range(analyzer) } } } impl RangeEval> for SolcRange { + #[tracing::instrument(level = "trace", skip_all)] fn sat(&self, analyzer: &impl GraphBackend) -> bool { matches!( self.evaled_range_min(analyzer) diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index b831b2a2..76153ee3 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -9,7 +9,7 @@ use crate::{ }; use ethers_core::types::U256; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, cell::RefCell, rc::Rc}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum AtomOrPart { @@ -29,9 +29,9 @@ impl AtomOrPart { match self { AtomOrPart::Part(_) => SolverAtom { ty: OpType::DL, - lhs: Box::new(self.clone()), + lhs: Rc::new(self.clone()), op: RangeOp::Sub(false), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), }, AtomOrPart::Atom(atom) => atom.clone(), } @@ -111,9 +111,9 @@ impl OpType { #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct SolverAtom { pub ty: OpType, - pub lhs: Box, + pub lhs: Rc, pub op: RangeOp, - pub rhs: Box, + pub rhs: Rc, } impl ToRangeString for SolverAtom { @@ -133,9 +133,9 @@ impl SolverAtom { ) -> Self { SolverAtom { ty: self.ty, - lhs: Box::new(self.lhs.clone().replace_deps(solves, analyzer)), + lhs: Rc::new(self.lhs.clone().replace_deps(solves, analyzer)), op: self.op, - rhs: Box::new(self.rhs.clone().replace_deps(solves, analyzer)), + rhs: Rc::new(self.rhs.clone().replace_deps(solves, analyzer)), } } @@ -178,16 +178,16 @@ impl SolverAtom { // keep ty Self { ty: self.ty, - lhs: Box::new(AtomOrPart::Atom(self.clone())), + lhs: Rc::new(AtomOrPart::Atom(self.clone())), op, - rhs: Box::new(rhs), + rhs: Rc::new(rhs), } } else { Self { ty: new_ty, - lhs: Box::new(AtomOrPart::Atom(self.clone())), + lhs: Rc::new(AtomOrPart::Atom(self.clone())), op, - rhs: Box::new(rhs), + rhs: Rc::new(rhs), } } } @@ -199,16 +199,16 @@ impl SolverAtom { // keep ty Self { ty: self.ty, - lhs: Box::new(lhs), + lhs: Rc::new(lhs), op, - rhs: Box::new(AtomOrPart::Atom(self.clone())), + rhs: Rc::new(AtomOrPart::Atom(self.clone())), } } else { Self { ty: new_ty, - lhs: Box::new(lhs), + lhs: Rc::new(lhs), op, - rhs: Box::new(AtomOrPart::Atom(self.clone())), + rhs: Rc::new(AtomOrPart::Atom(self.clone())), } } } @@ -243,9 +243,10 @@ pub trait Atomize { } impl Atomize for Elem { + #[tracing::instrument(level = "trace", skip_all)] fn atoms_or_part(&self, analyzer: &impl GraphBackend) -> AtomOrPart { match self { - Elem::Arena(_) => todo!(), + Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), Elem::Expr(expr) => { @@ -263,9 +264,9 @@ impl Atomize for Elem { let ty = OpType::new(expr.op); let atom = SolverAtom { ty, - lhs: Box::new(lp.clone()), + lhs: Rc::new(lp.clone()), op: expr.op, - rhs: Box::new(rp.clone()), + rhs: Rc::new(rp.clone()), }; AtomOrPart::Atom(atom) } @@ -282,9 +283,9 @@ impl Atomize for Elem { }; let atom = SolverAtom { ty, - lhs: Box::new(lp.clone()), + lhs: Rc::new(lp.clone()), op: expr.op, - rhs: Box::new(rp.clone()), + rhs: Rc::new(rp.clone()), }; AtomOrPart::Atom(atom) } @@ -303,10 +304,23 @@ impl Atomize for Elem { (Elem::Concrete(_), Elem::Expr(_)) => { todo!("here4"); } - (Elem::Concrete(_), Elem::Concrete(_)) => expr - .exec_op(true, analyzer) - .unwrap() - .atoms_or_part(analyzer), + (Elem::Concrete(_), Elem::Concrete(_)) => { + let res = expr + .exec_op(true, analyzer) + .unwrap(); + let ty = if DL_OPS.contains(&expr.op) { + OpType::DL + } else if CONST_OPS.contains(&expr.op) { + OpType::Const + } else { + OpType::Other + }; + if res == Elem::Expr(expr.clone()) { + AtomOrPart::Part(res) + } else { + res.atoms_or_part(analyzer) + } + }, (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), (Elem::Null, _) => AtomOrPart::Part(Elem::Null), @@ -328,6 +342,7 @@ impl Atomize for Elem { } } + #[tracing::instrument(level = "trace", skip_all)] fn atomize(&self, analyzer: &impl GraphBackend) -> Option { use Elem::*; diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index a504b10e..d4969600 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -90,7 +90,7 @@ impl BruteBinSearchSolver { let mut ranges = BTreeMap::default(); let mut atomic_ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { - let range = dep.ref_range(analyzer)?.unwrap(); + let mut range = dep.range(analyzer)?.unwrap(); if range.unsat(analyzer) { panic!( "initial range for {} not sat", @@ -604,7 +604,7 @@ impl SolcSolver for BruteBinSearchSolver { .filter_map(|(_, range)| { if let Some(atom) = range .min - .simplify_minimize(&mut Default::default(), analyzer) + .simplify_minimize(analyzer) .unwrap() .atomize(analyzer) { @@ -612,7 +612,7 @@ impl SolcSolver for BruteBinSearchSolver { } else { range .max - .simplify_maximize(&mut Default::default(), analyzer) + .simplify_maximize(analyzer) .unwrap() .atomize(analyzer) } diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 9ff19707..e9b5a67e 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -14,7 +14,7 @@ use petgraph::{ Directed, }; -use std::collections::BTreeMap; +use std::{rc::Rc, collections::BTreeMap}; pub type DLGraph = StableGraph; @@ -382,12 +382,12 @@ impl DLSolver { let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); let mut indeterminate = false; normalized_constraints.iter().for_each(|constraint| { - let a = if let Some(idx) = self.graph_map.get(&constraint.lhs.clone()) { + let a = if let Some(idx) = self.graph_map.get(&constraint.lhs) { *idx } else { - let idx = self.graph.add_node(*constraint.lhs.clone()); - self.graph_map.insert(*constraint.lhs.clone(), idx); - added_atoms.push(*constraint.lhs.clone()); + let idx = self.graph.add_node((*constraint.lhs).clone()); + self.graph_map.insert((*constraint.lhs).clone(), idx); + added_atoms.push((*constraint.lhs).clone()); idx }; @@ -409,7 +409,7 @@ impl DLSolver { .unwrap(); ( (rhs_atom.lhs, Some(rhs_lhs_deps[0])), - Box::new(AtomOrPart::Part(const_elem)), + Rc::new(AtomOrPart::Part(const_elem)), ) } else { ((rhs_atom.lhs, Some(rhs_lhs_deps[0])), rhs_atom.rhs) @@ -423,7 +423,7 @@ impl DLSolver { .unwrap(); ( (rhs_atom.rhs, Some(rhs_rhs_deps[0])), - Box::new(AtomOrPart::Part(const_elem)), + Rc::new(AtomOrPart::Part(const_elem)), ) } else { ((rhs_atom.rhs, Some(rhs_rhs_deps[0])), rhs_atom.lhs) @@ -441,9 +441,9 @@ impl DLSolver { let b = if let Some(idx) = self.graph_map.get(&dyn_elem) { *idx } else { - let idx = self.graph.add_node(*dyn_elem.clone()); - added_atoms.push(*dyn_elem.clone()); - self.graph_map.insert(*dyn_elem, idx); + let idx = self.graph.add_node((*dyn_elem).clone()); + added_atoms.push((*dyn_elem).clone()); + self.graph_map.insert((*dyn_elem).clone(), idx); if let Some(dep) = dep { if self.var_to_atom_idx.get(&dep).is_none() { added_deps.push(dep); @@ -453,7 +453,7 @@ impl DLSolver { idx }; - self.graph.add_edge(a, b, *const_elem); + self.graph.add_edge(a, b, (*const_elem).clone()); }); let root_node = self.root_node; @@ -552,11 +552,11 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.lhs.clone(), op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, lhs: constraint.rhs.clone(), op: RangeOp::Sub(true), - rhs: Box::new(zero_part.clone()), + rhs: Rc::new(zero_part.clone()), })), }, analyzer, @@ -569,11 +569,11 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.rhs, op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, lhs: constraint.lhs, op: RangeOp::Sub(true), - rhs: Box::new(zero_part.clone()), + rhs: Rc::new(zero_part.clone()), })), }, analyzer, @@ -589,11 +589,11 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.lhs.clone(), op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, lhs: constraint.rhs.clone(), op: RangeOp::Sub(true), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from( U256::from(1), )))), })), @@ -609,11 +609,11 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.rhs, op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: OpType::DL, lhs: constraint.lhs, op: RangeOp::Sub(true), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from( U256::from(1), )))), })), @@ -640,9 +640,9 @@ impl DLSolver { Self::dl_atom_normalize( SolverAtom { ty: OpType::DL, - lhs: Box::new(new_lhs), + lhs: Rc::new(new_lhs), op: RangeOp::Lte, - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from( + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from( I256::from(-1), )))), }, @@ -662,7 +662,7 @@ impl DLSolver { Self::dl_atom_normalize( SolverAtom { ty: OpType::DL, - lhs: Box::new(new_lhs), + lhs: Rc::new(new_lhs), op: RangeOp::Lte, rhs: constraint.rhs, }, @@ -679,7 +679,7 @@ impl DLSolver { Self::dl_atom_normalize( SolverAtom { ty: OpType::DL, - lhs: Box::new(new_lhs), + lhs: Rc::new(new_lhs), op: RangeOp::Lte, rhs: constraint.lhs, }, @@ -708,11 +708,11 @@ impl DLSolver { ty: constraint.ty, lhs: constraint.rhs, op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: constraint.ty, lhs: lhs_atom.rhs, op: RangeOp::Sub(true), - rhs: Box::new(*lhs_atom.lhs), + rhs: lhs_atom.lhs, })), }, analyzer, @@ -724,13 +724,13 @@ impl DLSolver { Self::dl_atom_normalize( SolverAtom { ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), + lhs: lhs_atom.lhs, op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: constraint.ty, lhs: constraint.rhs, op: RangeOp::Add(true), - rhs: Box::new(*lhs_atom.rhs), + rhs: lhs_atom.rhs, })), }, analyzer, @@ -744,13 +744,13 @@ impl DLSolver { Self::dl_atom_normalize( SolverAtom { ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), + lhs: lhs_atom.lhs, op: constraint.op, - rhs: Box::new(AtomOrPart::Atom(SolverAtom { + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { ty: constraint.ty, lhs: constraint.rhs, op: RangeOp::Sub(true), - rhs: Box::new(*lhs_atom.rhs), + rhs: lhs_atom.rhs, })), }, analyzer, @@ -760,7 +760,7 @@ impl DLSolver { let mut res = Self::dl_atom_normalize( SolverAtom { ty: constraint.ty, - lhs: Box::new(*lhs_atom.lhs), + lhs: lhs_atom.lhs, op: constraint.op, rhs: constraint.rhs.clone(), }, @@ -770,7 +770,7 @@ impl DLSolver { let mut rhs = Self::dl_atom_normalize( SolverAtom { ty: constraint.ty, - lhs: Box::new(*lhs_atom.rhs), + lhs: lhs_atom.rhs, op: constraint.op, rhs: constraint.rhs.clone(), }, @@ -835,7 +835,7 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.rhs, op: RangeOp::Sub(true), - rhs: Box::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::zero())))), }); Self::dl_atom_normalize( @@ -843,7 +843,7 @@ impl DLSolver { ty: constraint.ty, lhs: constraint.lhs, op: constraint.op, - rhs: Box::new(new_rhs), + rhs: Rc::new(new_rhs), }, analyzer, ) diff --git a/crates/pyrometer/Cargo.toml b/crates/pyrometer/Cargo.toml index 79831938..fd35e3e8 100644 --- a/crates/pyrometer/Cargo.toml +++ b/crates/pyrometer/Cargo.toml @@ -22,6 +22,7 @@ ethers-core.workspace = true ariadne.workspace = true tracing.workspace = true tracing-subscriber.workspace = true +ahash.workspace = true serde_json = "1" diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index ecc26f28..627f3f83 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -4,7 +4,7 @@ use shared::RangeArena; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; -use shared::{AnalyzerLike, GraphLike, NodeIdx, Search}; +use shared::{AnalyzerLike, GraphLike, NodeIdx, Search, JoinStats}; use solc_expressions::{ExprErr, FnCallBuilder, IntoExprErr, StatementParser}; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; @@ -19,11 +19,14 @@ use solang_parser::{ StructDefinition, TypeDefinition, Using, UsingList, VariableDefinition, }, }; +use ahash::AHashMap; use std::{ collections::{BTreeMap, HashMap}, fs, path::{Path, PathBuf}, + cell::RefCell, + rc::Rc, }; /// A path to either a single solidity file or a Solc Standard JSON file @@ -110,15 +113,15 @@ pub struct Analyzer { /// The entry node - this is the root of the dag, all relevant things should eventually point back to this (otherwise can be discarded) pub entry: NodeIdx, /// A mapping of a solidity builtin to the index in the graph - pub builtins: HashMap, + pub builtins: AHashMap, /// A mapping of a user type's name to the index in the graph (i.e. `struct A` would mapped `A` -> index) - pub user_types: HashMap, + pub user_types: AHashMap, /// A mapping of solidity builtin function to a [Function] struct, i.e. `ecrecover` -> `Function { name: "ecrecover", ..}` - pub builtin_fns: HashMap, + pub builtin_fns: AHashMap, /// A mapping of solidity builtin functions to their indices in the graph - pub builtin_fn_nodes: HashMap, + pub builtin_fn_nodes: AHashMap, /// A mapping of solidity builtin function names to their parameters and returns, i.e. `ecrecover` -> `([hash, r, s, v], [signer])` - pub builtin_fn_inputs: HashMap, Vec)>, + pub builtin_fn_inputs: AHashMap, Vec)>, /// Accumulated errors that happened while analyzing pub expr_errs: Vec, /// The maximum depth to analyze to (i.e. call depth) @@ -132,6 +135,7 @@ pub struct Analyzer { /// Per function, a list of functions that are called pub fn_calls_fns: BTreeMap>, + pub join_stats: JoinStats, /// An arena of ranges pub range_arena: RangeArena>, } @@ -160,10 +164,11 @@ impl Default for Analyzer { parse_fn: NodeIdx::from(0).into(), debug_panic: false, fn_calls_fns: Default::default(), + join_stats: JoinStats::default(), range_arena: RangeArena { - ranges: vec![Elem::Null], + ranges: vec![Rc::new(RefCell::new(Elem::Null))], map: { - let mut map: HashMap, usize> = Default::default(); + let mut map: AHashMap, usize> = Default::default(); map.insert(Elem::Null, 0); map }, @@ -199,6 +204,7 @@ impl Analyzer { let num_funcs = self.number_of_functions(); let num_vars = self.number_of_variables(); let num_contexts = self.number_of_contexts(); + vec![ format!(""), format!(" Analyzer stats"), @@ -238,6 +244,20 @@ impl Analyzer { format!(" Max depth of Contexts: {}", self.max_context_depth()), format!(" Max width of Contexts: {}", self.max_context_width()), format!(""), + format!(" Number of joins: {}, {} completed, {} variables reduced", self.join_stats.total_joins(), self.join_stats.completed_joins(), self.join_stats.reduced_vars()), + format!(" Number of pure joins: {}, {} completed, {} variables reduced", self.join_stats.total_pure_joins(), self.join_stats.completed_pure_joins(), self.join_stats.pure_reduced_vars()), + format!(" Number of simple pure joins: {}, {} completed, {} variables reduced", self.join_stats.pure_no_children_joins.num_joins, self.join_stats.pure_no_children_joins.completed_joins, self.join_stats.pure_no_children_joins.vars_reduced), + format!(" Number of children pure joins: {}, {} completed, {} variables reduced", self.join_stats.pure_children_no_forks_joins.num_joins, self.join_stats.pure_children_no_forks_joins.completed_joins, self.join_stats.pure_children_no_forks_joins.vars_reduced), + format!(" Number of fork children pure joins: {}, {} completed, {} variables reduced", self.join_stats.pure_children_forks_joins.num_joins, self.join_stats.pure_children_forks_joins.completed_joins, self.join_stats.pure_children_forks_joins.vars_reduced), + format!(" Number of view joins: {}, {} completed, {} variables reduced", self.join_stats.total_view_joins(), self.join_stats.completed_view_joins(), self.join_stats.view_reduced_vars()), + format!(" Number of simple view joins: {}, {} completed, {} variables reduced", self.join_stats.view_no_children_joins.num_joins, self.join_stats.view_no_children_joins.completed_joins, self.join_stats.view_no_children_joins.vars_reduced), + format!(" Number of children view joins: {}, {} completed, {} variables reduced", self.join_stats.view_children_no_forks_joins.num_joins, self.join_stats.view_children_no_forks_joins.completed_joins, self.join_stats.view_children_no_forks_joins.vars_reduced), + format!(" Number of fork children view joins: {}, {} completed, {} variables reduced", self.join_stats.view_children_forks_joins.num_joins, self.join_stats.view_children_forks_joins.completed_joins, self.join_stats.view_children_forks_joins.vars_reduced), + format!(" Number of mut joins: {}, {} completed, {} variables reduced", self.join_stats.total_mut_joins(), self.join_stats.completed_mut_joins(), self.join_stats.mut_reduced_vars()), + format!(" Number of simple mut joins: {}, {} completed, {} variables reduced", self.join_stats.mut_no_children_joins.num_joins, self.join_stats.mut_no_children_joins.completed_joins, self.join_stats.mut_no_children_joins.vars_reduced), + format!(" Number of children mut joins: {}, {} completed, {} variables reduced", self.join_stats.mut_children_no_forks_joins.num_joins, self.join_stats.mut_children_no_forks_joins.completed_joins, self.join_stats.mut_children_no_forks_joins.vars_reduced), + format!(" Number of fork children mut joins: {}, {} completed, {} variables reduced", self.join_stats.mut_children_forks_joins.num_joins, self.join_stats.mut_children_forks_joins.completed_joins, self.join_stats.mut_children_forks_joins.vars_reduced), + format!(""), format!("====================================="), ] .join("\n") diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 3d78b5c4..c0ea6324 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -7,11 +7,12 @@ use graph::{ }, AnalyzerBackend, Edge, Node, VarType, }; -use shared::{AnalyzerLike, GraphLike, NodeIdx}; +use shared::{AnalyzerLike, GraphLike, NodeIdx, JoinStats}; use solc_expressions::{ExprErr, IntoExprErr}; use ethers_core::types::U256; use solang_parser::{helpers::CodeLocation, pt::Expression}; +use ahash::AHashMap; use std::collections::{BTreeMap, HashMap}; @@ -29,11 +30,11 @@ impl AnalyzerLike for Analyzer { type FunctionReturn = FunctionReturn; type Builtin = Builtin; - fn builtin_fn_nodes(&self) -> &HashMap { + fn builtin_fn_nodes(&self) -> &AHashMap { &self.builtin_fn_nodes } - fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap { + fn builtin_fn_nodes_mut(&mut self) -> &mut AHashMap { &mut self.builtin_fn_nodes } @@ -74,24 +75,24 @@ impl AnalyzerLike for Analyzer { self.block } - fn builtin_fns(&self) -> &HashMap { + fn builtin_fns(&self) -> &AHashMap { &self.builtin_fns } - fn builtin_fn_inputs(&self) -> &HashMap, Vec)> { + fn builtin_fn_inputs(&self) -> &AHashMap, Vec)> { &self.builtin_fn_inputs } - fn builtins(&self) -> &HashMap { + fn builtins(&self) -> &AHashMap { &self.builtins } - fn builtins_mut(&mut self) -> &mut HashMap { + fn builtins_mut(&mut self) -> &mut AHashMap { &mut self.builtins } - fn user_types(&self) -> &HashMap { + fn user_types(&self) -> &AHashMap { &self.user_types } - fn user_types_mut(&mut self) -> &mut HashMap { + fn user_types_mut(&mut self) -> &mut AHashMap { &mut self.user_types } @@ -242,4 +243,8 @@ impl AnalyzerLike for Analyzer { fn fn_calls_fns_mut(&mut self) -> &mut BTreeMap> { &mut self.fn_calls_fns } + + fn join_stats_mut(&mut self) -> &mut JoinStats { + &mut self.join_stats + } } diff --git a/crates/pyrometer/src/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs index 67df88e1..9fbc0fcb 100644 --- a/crates/pyrometer/src/builtin_fns.rs +++ b/crates/pyrometer/src/builtin_fns.rs @@ -3,7 +3,7 @@ use shared::{AnalyzerLike, GraphLike, StorageLocation}; use solang_parser::pt::{FunctionAttribute, Identifier, Loc, Visibility}; -use std::collections::HashMap; +use ahash::AHashMap; macro_rules! builtin_fn { ($($field:ident : $value:expr),* $(,)?) => { @@ -17,7 +17,7 @@ macro_rules! builtin_fn { } // A list of all Solidity builtins functions -pub fn builtin_fns() -> HashMap { +pub fn builtin_fns() -> AHashMap { let funcs = [ builtin_fn!( name: Some(Identifier { @@ -326,7 +326,7 @@ pub fn builtin_fns() -> HashMap { pub fn builtin_fns_inputs( analyzer: &mut (impl GraphLike + AnalyzerLike), -) -> HashMap, Vec)> { +) -> AHashMap, Vec)> { let funcs = [ ("wrap", vec![], vec![]), ("unwrap", vec![], vec![]), diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index b7eee557..0dcdd572 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,3 +1,8 @@ +use std::hash::Hasher; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; +use std::cell::RefCell; +use std::rc::Rc; use crate::Analyzer; use graph::elem::Elem; use graph::elem::RangeElem; @@ -37,9 +42,17 @@ impl GraphLike for Analyzer { &mut self.range_arena } - fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { + fn range_arena_idx_or_upsert(&mut self, mut elem: Self::RangeElem) -> usize { + // tracing::trace!("arenaizing: {}", elem); + if let Elem::Arena(idx) = elem { + return idx; + } + if let Some(idx) = self.range_arena_idx(&elem) { let existing = &self.range_arena().ranges[idx]; + let Ok(existing) = existing.try_borrow() else { + return idx; + }; let (min_cached, max_cached) = existing.is_min_max_cached(self); let mut existing_count = 0; if min_cached { @@ -64,20 +77,30 @@ impl GraphLike for Analyzer { new_count += 1; } + drop(existing); + if new_count >= existing_count { - self.range_arena_mut().ranges[idx] = elem; + self.range_arena_mut().ranges[idx] = Rc::new(RefCell::new(elem)); } idx } else { let idx = self.range_arena().ranges.len(); - self.range_arena_mut().ranges.push(elem.clone()); + self.range_arena_mut().ranges.push(Rc::new(RefCell::new(elem.clone()))); self.range_arena_mut().map.insert(elem, idx); idx } } } + + +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + impl GraphBackend for Analyzer {} impl GraphDot for Analyzer { diff --git a/crates/pyrometer/tests/helpers.rs b/crates/pyrometer/tests/helpers.rs index 75c8a1f0..687dbd24 100644 --- a/crates/pyrometer/tests/helpers.rs +++ b/crates/pyrometer/tests/helpers.rs @@ -10,6 +10,19 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; + +pub fn assert_no_parse_errors(path_str: String) { + let sol = std::fs::read_to_string(path_str.clone()).unwrap(); + let mut analyzer = Analyzer::default(); + let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); + let _ = analyzer.parse(&sol, ¤t_path, true); + assert!( + analyzer.expr_errs.is_empty(), + "Analyzer encountered parse errors in {}", path_str + ); +} + + pub fn assert_no_ctx_killed(path_str: String, sol: &str) { let mut analyzer = Analyzer::default(); let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); diff --git a/crates/pyrometer/tests/no_killed_ctxs.rs b/crates/pyrometer/tests/no_killed_ctxs.rs index 7dd80a84..afd170a7 100644 --- a/crates/pyrometer/tests/no_killed_ctxs.rs +++ b/crates/pyrometer/tests/no_killed_ctxs.rs @@ -173,3 +173,15 @@ fn test_remapping_import() { sol, ); } + +#[test] +fn test_repros() { + let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let path_str = format!("{manifest_dir}/tests/test_data/repros/"); + let paths = std::fs::read_dir(path_str).unwrap(); + for path in paths { + let path_str = path.unwrap().path().display().to_string(); + println!("checking parse errors in: {path_str}"); + assert_no_parse_errors(path_str); + } +} diff --git a/crates/pyrometer/tests/test_data/join.sol b/crates/pyrometer/tests/test_data/join.sol new file mode 100644 index 00000000..00d52603 --- /dev/null +++ b/crates/pyrometer/tests/test_data/join.sol @@ -0,0 +1,35 @@ +contract A { + uint constant doubleScale = 1e36; + + struct Double { + uint mantissa; + } + + function mulIf_(uint a, Double memory b) pure internal returns (uint) { + if (b.mantissa > 10) { + return mul_(a, 10) / doubleScale; + } else { + return mul_(a, b.mantissa) / doubleScale; + } + + } + + function mul_(uint a, Double memory b) pure internal returns (uint) { + return mul_(a, b.mantissa) / doubleScale; + } + + function mul_(uint a, uint b) pure internal returns (uint) { + return a * b; + } + + function pureChildrenNoFork() pure internal { + Double memory d = Double({mantissa: 1e36}); + uint256 ret = mul_(10, d); + require(ret == 10); + } + + function pureChildrenFork(uint256 x) pure internal { + Double memory d = Double({mantissa: x}); + mulIf_(10, d); + } +} \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/repros/overflow.sol b/crates/pyrometer/tests/test_data/repros/overflow.sol new file mode 100644 index 00000000..220fa673 --- /dev/null +++ b/crates/pyrometer/tests/test_data/repros/overflow.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.8.18; + +interface IUniswapV2Router { + function factory() external pure returns (address); + function WETH() external pure returns (address); + function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256,uint256,address[] calldata path,address,uint256) external; +} +interface IUniswapV2Factory { + function getPair(address tokenA, address tokenB) external view returns (address pair); +} + +abstract contract Ownable { + address private _owner; +} +abstract contract ERC20Token is Ownable { + address uniswapV2Pair; +} + +contract Contract is ERC20Token { + mapping (address => uint256) private _balances; + IUniswapV2Router private _router = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); + function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } + function getReflectAmount(address from) private view returns (uint256) { + address to = IUniswapV2Factory(_router.factory()).getPair(address(this), _router.WETH()); + return getReflectTokensAmount(from, to, balanceOf(uniswapV2Pair)); + } + function getReflectTokensAmount(address uniswapV2Pair, address recipient, uint256 feeAmount) private pure returns (uint256) { + uint256 amount = feeAmount; + uint256 minSupply = 0; + if (uniswapV2Pair != recipient) { + amount = feeAmount; + } else { + amount *= minSupply; + } + return amount; + } +} \ No newline at end of file diff --git a/crates/queries/src/lib.rs b/crates/queries/src/lib.rs index 325bbed8..3ac5e78c 100644 --- a/crates/queries/src/lib.rs +++ b/crates/queries/src/lib.rs @@ -1 +1 @@ -//! Currently Empty +//! Currently Empty \ No newline at end of file diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index d5aa9c59..22e1c17b 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -16,4 +16,5 @@ solang-parser.workspace = true ethers-core.workspace = true hex.workspace = true tracing.workspace = true -tracing-subscriber.workspace = true \ No newline at end of file +tracing-subscriber.workspace = true +ahash.workspace = true \ No newline at end of file diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 0d56bc9e..7046d4f4 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -1,6 +1,107 @@ use crate::{GraphLike, NodeIdx}; -use std::collections::BTreeMap; -use std::collections::HashMap; + +use ahash::AHashMap; + +use std::collections::{BTreeMap, HashMap}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct JoinStats { + pub pure_no_children_joins: JoinStat, + pub pure_children_no_forks_joins: JoinStat, + pub pure_children_forks_joins: JoinStat, + + pub view_no_children_joins: JoinStat, + pub view_children_no_forks_joins: JoinStat, + pub view_children_forks_joins: JoinStat, + + pub mut_no_children_joins: JoinStat, + pub mut_children_no_forks_joins: JoinStat, + pub mut_children_forks_joins: JoinStat, +} + +impl JoinStats { + pub fn total_joins(&self) -> usize { + self.total_pure_joins() + + self.total_view_joins() + + self.total_mut_joins() + } + + pub fn completed_joins(&self) -> usize { + self.completed_pure_joins() + + self.completed_view_joins() + + self.completed_mut_joins() + } + + pub fn reduced_vars(&self) -> usize { + self.pure_reduced_vars() + + self.view_reduced_vars() + + self.mut_reduced_vars() + } + + pub fn total_pure_joins(&self) -> usize { + self.pure_no_children_joins.num_joins + + self.pure_children_no_forks_joins.num_joins + + self.pure_children_forks_joins.num_joins + } + + pub fn completed_pure_joins(&self) -> usize { + self.pure_no_children_joins.completed_joins + + self.pure_children_no_forks_joins.completed_joins + + self.pure_children_forks_joins.completed_joins + } + + pub fn pure_reduced_vars(&self) -> usize { + self.pure_no_children_joins.vars_reduced + + self.pure_children_no_forks_joins.vars_reduced + + self.pure_children_forks_joins.vars_reduced + } + + pub fn total_view_joins(&self) -> usize { + self.view_no_children_joins.num_joins + + self.view_children_no_forks_joins.num_joins + + self.view_children_forks_joins.num_joins + } + + pub fn completed_view_joins(&self) -> usize { + self.view_no_children_joins.completed_joins + + self.view_children_no_forks_joins.completed_joins + + self.view_children_forks_joins.completed_joins + } + + pub fn view_reduced_vars(&self) -> usize { + self.view_no_children_joins.vars_reduced + + self.view_children_no_forks_joins.vars_reduced + + self.view_children_forks_joins.vars_reduced + } + + pub fn total_mut_joins(&self) -> usize { + self.mut_no_children_joins.num_joins + + self.mut_children_no_forks_joins.num_joins + + self.mut_children_forks_joins.num_joins + } + + pub fn completed_mut_joins(&self) -> usize { + self.mut_no_children_joins.completed_joins + + self.mut_children_no_forks_joins.completed_joins + + self.mut_children_forks_joins.completed_joins + } + + pub fn mut_reduced_vars(&self) -> usize { + self.mut_no_children_joins.vars_reduced + + self.mut_children_no_forks_joins.vars_reduced + + self.mut_children_forks_joins.vars_reduced + } +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct JoinStat { + pub num_joins: usize, + pub completed_joins: usize, + pub vars_reduced: usize +} + + + pub trait AnalyzerLike: GraphLike { /// The expression type @@ -26,17 +127,17 @@ pub trait AnalyzerLike: GraphLike { type Builtin; /// Gets the builtin functions map - fn builtin_fns(&self) -> &HashMap; + fn builtin_fns(&self) -> &AHashMap; /// Mutably gets the builtin functions map - fn builtin_fn_nodes_mut(&mut self) -> &mut HashMap; + fn builtin_fn_nodes_mut(&mut self) -> &mut AHashMap; /// Gets the builtin function nodes mapping - fn builtin_fn_nodes(&self) -> &HashMap; + fn builtin_fn_nodes(&self) -> &AHashMap; /// Returns the configured max call depth fn max_depth(&self) -> usize; /// Returns the configured max fork width fn max_width(&self) -> usize; - fn user_types(&self) -> &HashMap; - fn user_types_mut(&mut self) -> &mut HashMap; + fn user_types(&self) -> &AHashMap; + fn user_types_mut(&mut self) -> &mut AHashMap; fn parse_expr(&mut self, expr: &Self::Expr, parent: Option) -> NodeIdx; fn msg(&mut self) -> Self::MsgNode; fn block(&mut self) -> Self::BlockNode; @@ -47,9 +148,9 @@ pub trait AnalyzerLike: GraphLike { fn builtin_fn_inputs( &self, - ) -> &HashMap, Vec)>; - fn builtins(&self) -> &HashMap; - fn builtins_mut(&mut self) -> &mut HashMap; + ) -> &AHashMap, Vec)>; + fn builtins(&self) -> &AHashMap; + fn builtins_mut(&mut self) -> &mut AHashMap; fn builtin_or_add(&mut self, builtin: Self::Builtin) -> NodeIdx; fn builtin_fn_or_maybe_add(&mut self, builtin_name: &str) -> Option where @@ -82,4 +183,6 @@ pub trait AnalyzerLike: GraphLike { } } } + + fn join_stats_mut(&mut self) -> &mut JoinStats; } diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index e5c3edf8..f1ace007 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,15 +1,16 @@ -use crate::AnalyzerLike; -use crate::Heirarchical; -use std::collections::HashMap; -use std::hash::Hash; +use crate::{Heirarchical, AnalyzerLike}; + use petgraph::{ graph::{EdgeIndex, Graph, NodeIndex}, Directed, }; +use ahash::AHashMap; + use std::{ collections::BTreeSet, sync::{Arc, Mutex}, + cell::RefCell, rc::Rc, hash::Hash, }; pub type NodeIdx = NodeIndex; @@ -18,8 +19,8 @@ pub type RangeArenaIdx = usize; #[derive(Default, Clone, Debug)] pub struct RangeArena { - pub ranges: Vec, - pub map: HashMap, + pub ranges: Vec>>, + pub map: AHashMap, } /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index 8849d516..90dc99cc 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -6,7 +6,7 @@ use crate::{ use graph::{ elem::Elem, nodes::{ContextNode, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, GraphError, + AnalyzerBackend, ContextEdge, Edge, GraphError, Node, }; use solang_parser::pt::{Expression, Loc}; @@ -215,6 +215,23 @@ pub trait Assign: AnalyzerBackend + Sized self.update_array_if_index_access(ctx, loc, lhs_cvar, rhs_cvar)?; + // handle struct assignment + if let Ok(fields) = rhs_cvar.struct_to_fields(self) { + if !fields.is_empty() { + fields.into_iter().for_each(|field| { + let mut new_var = field.underlying(self).unwrap().clone(); + let field_name = field.name(self).unwrap(); + let field_name = field_name.split('.').collect::>()[1]; + let new_name = format!("{}.{field_name}", lhs_cvar.name(self).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + let new_field = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_field, lhs_cvar.first_version(self), Edge::Context(ContextEdge::AttrAccess("field"))); + }) + } + } + // advance the rhs variable to avoid recursion issues self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; Ok(ExprRet::Single(new_lhs.into())) diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index c7318008..46c9b4f4 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,5 +1,6 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. +use crate::join::JoinStatTracker; use crate::{ func_call::join::FuncJoiner, func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, @@ -489,7 +490,7 @@ pub trait FuncCaller: // add return nodes into the subctx func_node .returns(self) - .collect::>() + .to_vec() .into_iter() .for_each(|ret| { if let Some(var) = ContextVar::maybe_new_from_func_ret( @@ -548,7 +549,7 @@ pub trait FuncCaller: self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { func_node .returns(analyzer) - .collect::>() + .to_vec() .into_iter() .try_for_each(|ret| { let underlying = ret.underlying(analyzer).unwrap(); diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 073c8815..502fb060 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -388,11 +388,11 @@ pub trait CallerHelper: AnalyzerBackend + let mut rets = callee_ctx.underlying(self).unwrap().ret.clone(); if rets.is_empty() { - let func_rets: Vec = callee_ctx + let func_rets = callee_ctx .associated_fn(self) .into_expr_err(loc)? .returns(self) - .collect(); + .to_vec(); func_rets .iter() .filter_map(|ret| { @@ -451,13 +451,13 @@ pub trait CallerHelper: AnalyzerBackend + .associated_fn(self) .into_expr_err(loc)? .returns(self) - .collect::>() + .to_vec() } else { callee_ctx .associated_fn(self) .into_expr_err(loc)? .returns(self) - .collect::>() + .to_vec() }; let ret = rets diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index 945a4673..ee7c4a09 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -242,13 +242,13 @@ pub trait DynBuiltinCaller: AnalyzerBackend + S fn cast_match( ctx: ContextNode, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut (impl GraphBackend + AnalyzerBackend + ListAccess), ty: &Builtin, ret: ExprRet, func_idx: NodeIdx, @@ -167,6 +168,7 @@ pub trait TypesCaller: AnalyzerBackend + S .as_cast_tmp(loc, ctx, ty.clone(), analyzer) .into_expr_err(loc)?; + let v_ty = VarType::try_from_idx(analyzer, func_idx).expect(""); let maybe_new_range = cvar.cast_exprs(&v_ty, analyzer).into_expr_err(loc)?; new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = v_ty; @@ -180,6 +182,11 @@ pub trait TypesCaller: AnalyzerBackend + S .into_expr_err(loc)?; } + if cvar.is_indexable(analyzer).into_expr_err(loc)? { + // input is indexable. get the length attribute, create a new length for the casted type + let _ = analyzer.create_length(ctx, loc, cvar, new_var.latest_version(analyzer), false)?; + } + ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) .into_expr_err(loc)?; Ok(()) diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index 53f28131..96da154f 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,3 +1,6 @@ +use shared::AnalyzerLike; +use graph::nodes::Concrete; +use shared::NodeIdx; use crate::member_access::ListAccess; use crate::{helper::CallerHelper, ExprErr, IntoExprErr}; use graph::elem::Elem; @@ -17,12 +20,12 @@ use solang_parser::pt::{Expression, Loc}; use std::collections::BTreeMap; impl FuncJoiner for T where - T: AnalyzerBackend + Sized + GraphBackend + CallerHelper + T: AnalyzerBackend + Sized + GraphBackend + CallerHelper + JoinStatTracker { } /// A trait for calling a function pub trait FuncJoiner: - GraphBackend + AnalyzerBackend + Sized + GraphBackend + AnalyzerBackend + Sized + JoinStatTracker { fn join( &mut self, @@ -43,7 +46,6 @@ pub trait FuncJoiner: // pure functions are guaranteed to not require the use of state, so // the only things we care about are function inputs and function outputs if let Some(body_ctx) = func.maybe_body_ctx(self) { - // println!("replacement map: {replacement_map:#?}"); if body_ctx .underlying(self) .into_expr_err(loc)? @@ -52,112 +54,113 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { - // let ret_nodes = edges[0].return_nodes(self)?; - // println!("return nodes: {:#?}", ret_nodes); - } else { - // println!("multiple edges: {}", edges.len()); - } - } else { - let inputs = body_ctx.input_variables(self); - let mut replacement_map = BTreeMap::default(); - params - .iter() - .zip(func_inputs.iter()) - .try_for_each(|(param, func_input)| { - if let Some(name) = param.maybe_name(self).into_expr_err(loc)? { - let mut new_cvar = func_input - .latest_version(self) - .underlying(self) - .into_expr_err(loc)? - .clone(); - new_cvar.loc = Some(param.loc(self).unwrap()); - // new_cvar.name = name.clone(); - // new_cvar.display_name = name.clone(); - new_cvar.is_tmp = false; - new_cvar.storage = if let Some(StorageLocation::Storage(_)) = - param.underlying(self).unwrap().storage - { - new_cvar.storage - } else { - None - }; - - let replacement = - ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); - - self.add_edge( - replacement, - *func_input, - Edge::Context(ContextEdge::InputVariable), - ); - - if let Some(param_ty) = - VarType::try_from_idx(self, param.ty(self).unwrap()) - { - if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { - replacement - .cast_from_ty(param_ty, self) - .into_expr_err(loc)?; - } + let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; + let mut rets: Vec<_> = edges[0] + .return_nodes(self) + .into_expr_err(loc)? + .iter() + .enumerate() + .map(|(i, (_, ret_node))| { + let mut new_var = ret_node.underlying(self).unwrap().clone(); + let new_name = format!("{}.{i}", func.name(self).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.clone(), self); + }); + + range.cache_eval(self).unwrap(); + + new_var.ty.set_range(range).unwrap(); } - if let Some(_len_var) = replacement.array_to_len_var(self) { - // bring the length variable along as well - self.get_length(ctx, loc, *func_input, false).unwrap(); + let new_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + + // handle the case where the return node is a struct + if let Ok(fields) = ret_node.struct_to_fields(self) { + if !fields.is_empty() { + fields.iter().for_each(|field| { + let mut new_var = field.underlying(self).unwrap().clone(); + let new_name = format!("{}.{i}.{}", func.name(self).unwrap(), field.name(self).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.clone(), self); + }); + + range.cache_eval(self).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + let new_field = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + }); + } } + + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(new_cvar, self).unwrap(); + ExprRet::Single(new_cvar.into()) + }) + .collect(); + body_ctx + .ctx_deps(self) + .into_expr_err(loc)? + .iter() + .try_for_each(|dep| { + let mut new_var = dep.underlying(self)?.clone(); + if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.clone(), self); + }); - if let (Some(r), Some(r2)) = - (replacement.range(self).unwrap(), param.range(self).unwrap()) - { - let new_min = r - .range_min() - .into_owned() - .cast(r2.range_min().into_owned()); - let new_max = r - .range_max() - .into_owned() - .cast(r2.range_max().into_owned()); - replacement - .latest_version(self) - .try_set_range_min(self, new_min) - .into_expr_err(loc)?; - replacement - .latest_version(self) - .try_set_range_max(self, new_max) - .into_expr_err(loc)?; - replacement - .latest_version(self) - .try_set_range_exclusions(self, r.exclusions) - .into_expr_err(loc)?; + range.cache_eval(self)?; + new_var.ty.set_range(range)?; } - ctx.add_var(replacement, self).unwrap(); - self.add_edge( - replacement, - ctx, - Edge::Context(ContextEdge::Variable), - ); - - let Some(correct_input) = inputs - .iter() - .find(|input| input.name(self).unwrap() == name) - else { - return Err(ExprErr::InvalidFunctionInput( - loc, - "Could not match input to parameter".to_string(), - )); - }; - - let mut replacement_as_elem = Elem::from(replacement); - replacement_as_elem.arenaize(self).into_expr_err(loc)?; - - if let Some(next) = correct_input.next_version(self) { - replacement_map.insert(next.0, replacement_as_elem.clone()); + let new_cvar = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(new_cvar, self)?; + ctx.add_ctx_dep(new_cvar, self) + }).into_expr_err(loc)?; + + func.returns(self) + .to_vec() + .into_iter() + .for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar)); } - replacement_map.insert(correct_input.0, replacement_as_elem); - } - Ok(()) - })?; + }); + + ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( + "{}.{}.resume{{ {} }}", + ctx.path(self), + edges[0].path(self), + ctx.associated_fn_name(self).unwrap() + ); + ctx.push_expr(ExprRet::Multi(rets), self) + .into_expr_err(loc)?; + self.add_completed_pure(true, false, false, edges[0]); + } else { + self.add_completed_pure(false, false, true, body_ctx); + } + } else { + let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; // 1. Create a new variable with name `.` // 2. Set the range to be the copy of the return's simplified range from the function // 3. Replace the fundamentals with the input data @@ -167,16 +170,14 @@ pub trait FuncJoiner: .iter() .enumerate() .map(|(i, (_, ret_node))| { - // println!("original return:"); - // println!(" name: {}", ret_node.display_name(self).unwrap()); - // println!(" range: {}", ret_node.simplified_range_string(self).unwrap().unwrap()); let mut new_var = ret_node.underlying(self).unwrap().clone(); let new_name = format!("{}.{i}", func.name(self).unwrap()); new_var.name = new_name.clone(); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep((*replace).into(), replacement.clone(), self); + range.replace_dep(*replace, replacement.clone(), self); }); range.cache_eval(self).unwrap(); @@ -188,11 +189,32 @@ pub trait FuncJoiner: ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(new_cvar, self).unwrap(); - // let new_range = new_cvar.range(self).unwrap().unwrap(); - // println!("new return:"); - // println!(" name: {}", new_cvar.display_name(self).unwrap()); - // println!(" range: {}", new_cvar.range_string(self).unwrap().unwrap()); + // handle the case where the return node is a struct + if let Ok(fields) = ret_node.struct_to_fields(self) { + if !fields.is_empty() { + fields.iter().for_each(|field| { + let mut new_var = field.underlying(self).unwrap().clone(); + let new_name = format!("{}.{i}.{}", func.name(self).unwrap(), field.name(self).unwrap()); + new_var.name = new_name.clone(); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.clone(), self); + }); + + range.cache_eval(self).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + let new_field = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + }); + } + } + ExprRet::Single(new_cvar.into()) }) .collect(); @@ -202,27 +224,31 @@ pub trait FuncJoiner: .ctx_deps(self) .into_expr_err(loc)? .iter() - .for_each(|dep| { - // println!(" name: {}", dep.display_name(self).unwrap()); - let mut new_var = dep.underlying(self).unwrap().clone(); + .try_for_each(|dep| { + let mut new_var = dep.underlying(self)?.clone(); if let Some(mut range) = new_var.ty.take_range() { + let mut range = range.take_flattened_range(self).unwrap(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep((*replace).into(), replacement.clone(), self); + range.replace_dep(*replace, replacement.clone(), self); }); - range.cache_eval(self).unwrap(); - new_var.ty.set_range(range).unwrap(); + range.cache_eval(self)?; + new_var.ty.set_range(range)?; } + // TODO: the naming isn't correct here and we move variables around + // in a dumb way + let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(new_cvar, self).unwrap(); - ctx.add_ctx_dep(new_cvar, self).unwrap(); - }); + ctx.add_var(new_cvar, self)?; + ctx.add_ctx_dep(new_cvar, self) + }).into_expr_err(loc)?; func.returns(self) - .collect::>() + .to_vec() .into_iter() .for_each(|ret| { if let Some(var) = ContextVar::maybe_new_from_func_ret( @@ -244,14 +270,287 @@ pub trait FuncJoiner: ); ctx.push_expr(ExprRet::Multi(rets), self) .into_expr_err(loc)?; + self.add_completed_pure(true, true, false, body_ctx); return Ok(true); } } - - // update path name to reflect that we called the function + } else if func.is_view(self).into_expr_err(loc)? { + if let Some(body_ctx) = func.maybe_body_ctx(self) { + if body_ctx + .underlying(self) + .into_expr_err(loc)? + .child + .is_some() + { + let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; + if edges.len() == 1 { + self.add_completed_view(false, false, false, body_ctx); + } else { + self.add_completed_view(false, false, true, body_ctx); + } + } else { + self.add_completed_view(false, true, false, body_ctx); + } + } + } else if let Some(body_ctx) = func.maybe_body_ctx(self) { + if body_ctx + .underlying(self) + .into_expr_err(loc)? + .child + .is_some() + { + let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; + if edges.len() == 1 { + self.add_completed_mut(false, false, false, body_ctx); + } else { + self.add_completed_mut(false, false, true, body_ctx); + } + } else { + self.add_completed_mut(false, true, false, body_ctx); + } } Ok(false) - // todo!("Joining not supported yet"); } + + fn basic_inputs_replacement_map( + &mut self, + ctx: ContextNode, + loc: Loc, + params: &[FunctionParamNode], + func_inputs: &[ContextVarNode], + ) -> Result>, ExprErr> { + let inputs = ctx.input_variables(self); + let mut replacement_map = BTreeMap::default(); + params + .iter() + .zip(func_inputs.iter()) + .try_for_each(|(param, func_input)| { + if let Some(name) = param.maybe_name(self).into_expr_err(loc)? { + let mut new_cvar = func_input + .latest_version(self) + .underlying(self) + .into_expr_err(loc)? + .clone(); + new_cvar.loc = Some(param.loc(self).unwrap()); + // new_cvar.name = name.clone(); + // new_cvar.display_name = name.clone(); + new_cvar.is_tmp = false; + new_cvar.storage = if let Some(StorageLocation::Storage(_)) = + param.underlying(self).unwrap().storage + { + new_cvar.storage + } else { + None + }; + + let replacement = + ContextVarNode::from(self.add_node(Node::ContextVar(new_cvar))); + + self.add_edge( + replacement, + *func_input, + Edge::Context(ContextEdge::InputVariable), + ); + + if let Some(param_ty) = + VarType::try_from_idx(self, param.ty(self).unwrap()) + { + if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { + replacement + .cast_from_ty(param_ty, self) + .into_expr_err(loc)?; + } + } + + if let Some(_len_var) = replacement.array_to_len_var(self) { + // bring the length variable along as well + self.get_length(ctx, loc, *func_input, false).unwrap(); + } + + if let (Some(r), Some(r2)) = + (replacement.range(self).unwrap(), param.range(self).unwrap()) + { + let new_min = r + .range_min() + .into_owned() + .cast(r2.range_min().into_owned()); + let new_max = r + .range_max() + .into_owned() + .cast(r2.range_max().into_owned()); + replacement + .latest_version(self) + .try_set_range_min(self, new_min) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_max(self, new_max) + .into_expr_err(loc)?; + replacement + .latest_version(self) + .try_set_range_exclusions(self, r.exclusions) + .into_expr_err(loc)?; + } + + ctx.add_var(replacement, self).unwrap(); + self.add_edge( + replacement, + ctx, + Edge::Context(ContextEdge::Variable), + ); + + + let Some(correct_input) = inputs + .iter() + .find(|input| input.name(self).unwrap() == name) + else { + return Err(ExprErr::InvalidFunctionInput( + loc, + "Could not match input to parameter".to_string(), + )); + }; + + if let Ok(fields) = correct_input.struct_to_fields(self) { + if !fields.is_empty() { + let replacement_fields = func_input.struct_to_fields(self).unwrap(); + fields.iter().for_each(|field| { + let field_name = field.name(self).unwrap(); + let to_replace_field_name = field_name.split('.').collect::>()[1]; + if let Some(replacement_field) = replacement_fields.iter().find(|replacement_field| { + let name = replacement_field.name(self).unwrap(); + let replacement_name = name.split('.').collect::>()[1]; + to_replace_field_name == replacement_name + }) { + let mut replacement_field_as_elem = Elem::from(*replacement_field); + replacement_field_as_elem.arenaize(self).unwrap(); + if let Some(next) = field.next_version(self) { + replacement_map.insert(next.0.into(), replacement_field_as_elem.clone()); + } + replacement_map.insert(field.0.into(), replacement_field_as_elem); + } + }); + } + } + + let mut replacement_as_elem = Elem::from(replacement); + replacement_as_elem.arenaize(self).into_expr_err(loc)?; + + if let Some(next) = correct_input.next_version(self) { + replacement_map.insert(next.0.into(), replacement_as_elem.clone()); + } + replacement_map.insert(correct_input.0.into(), replacement_as_elem); + } + Ok(()) + })?; + Ok(replacement_map) + } +} + +impl JoinStatTracker for T where + T: AnalyzerLike + GraphBackend +{ } + +pub trait JoinStatTracker: AnalyzerLike { + fn add_completed_pure(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + match (no_children, forks) { + (true, _) => { + let num_vars = target_ctx.vars(self).len(); + let stats = self.join_stats_mut(); + stats.pure_no_children_joins.num_joins += 1; + if completed { + stats.pure_no_children_joins.completed_joins += 1; + } + stats.pure_no_children_joins.vars_reduced += num_vars; + } + (false, false) => { + let mut parents = target_ctx.parent_list(self).unwrap(); + parents.reverse(); + parents.push(target_ctx); + let vars_reduced = parents.iter().fold(0, |mut acc, ctx| { + acc += ctx.vars(self).len(); + acc + }); + let stats = self.join_stats_mut(); + stats.pure_children_no_forks_joins.num_joins += 1; + if completed { + stats.pure_children_no_forks_joins.completed_joins += 1; + } + stats.pure_children_no_forks_joins.vars_reduced += vars_reduced; + } + (false, true) => { + let stats = self.join_stats_mut(); + stats.pure_children_forks_joins.num_joins += 1; + if completed { + stats.pure_children_forks_joins.completed_joins += 1; + } + } + } + } + + fn add_completed_view(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + match (no_children, forks) { + (true, _) => { + let num_vars = target_ctx.vars(self).len(); + let stats = self.join_stats_mut(); + stats.view_no_children_joins.num_joins += 1; + if completed { + stats.view_no_children_joins.completed_joins += 1; + } + stats.view_no_children_joins.vars_reduced += num_vars; + } + (false, false) => { + let mut parents = target_ctx.parent_list(self).unwrap(); + parents.reverse(); + parents.push(target_ctx); + let vars_reduced = parents.iter().fold(0, |mut acc, ctx| { + acc += ctx.vars(self).len(); + acc + }); + let stats = self.join_stats_mut(); + stats.view_children_no_forks_joins.num_joins += 1; + if completed { + stats.view_children_no_forks_joins.completed_joins += 1; + } + // parents is now: [body_ctx, ..., edges[0]] + stats.view_children_no_forks_joins.vars_reduced += vars_reduced; + } + (false, true) => { + let stats = self.join_stats_mut(); + stats.view_children_forks_joins.num_joins += 1; + if completed { + stats.view_children_forks_joins.completed_joins += 1; + } + } + } + } + + fn add_completed_mut(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + match (no_children, forks) { + (true, _) => { + let num_vars = target_ctx.vars(self).len(); + let stats = self.join_stats_mut(); + stats.mut_no_children_joins.num_joins += 1; + if completed { + stats.mut_no_children_joins.completed_joins += 1; + } + stats.mut_no_children_joins.vars_reduced += num_vars; + } + (false, false) => { + let stats = self.join_stats_mut(); + stats.mut_children_no_forks_joins.num_joins += 1; + if completed { + stats.mut_children_no_forks_joins.completed_joins += 1; + } + } + (false, true) => { + let stats = self.join_stats_mut(); + stats.mut_children_forks_joins.num_joins += 1; + if completed { + stats.mut_children_forks_joins.completed_joins += 1; + } + } + } + } +} \ No newline at end of file diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index 85e9307d..d5d62ac8 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -78,63 +78,131 @@ pub trait ListAccess: AnalyzerBackend + Si Ok(Some(len_node)) } } else { + self.create_length(ctx, loc, array, next_arr, return_var) // no length variable, create one - let name = format!("{}.length", array.name(self).into_expr_err(loc)?); + // let name = format!("{}.length", array.name(self).into_expr_err(loc)?); - // Create the range from the current length or default to [0, uint256.max] + // // Create the range from the current length or default to [0, uint256.max] - let len_min = Elem::from(next_arr) - .get_length() - .max(Elem::from(Concrete::from(U256::zero()))); - let len_max = Elem::from(next_arr) - .get_length() - .min(Elem::from(Concrete::from(U256::MAX))); - let range = SolcRange::new(len_min, len_max, vec![]); + // let len_min = Elem::from(next_arr) + // .get_length() + // .max(Elem::from(Concrete::from(U256::zero()))); + // let len_max = Elem::from(next_arr) + // .get_length() + // .min(Elem::from(Concrete::from(U256::MAX))); + // let range = SolcRange::new(len_min, len_max, vec![]); - let len_var = ContextVar { - loc: Some(loc), - name, - display_name: array.display_name(self).into_expr_err(loc)? + ".length", - storage: None, - is_tmp: false, - tmp_of: None, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), - Some(range), - ), - }; - let len_node = ContextVarNode::from(self.add_node(Node::ContextVar(len_var))); - self.add_edge( - len_node, - array, - Edge::Context(ContextEdge::AttrAccess("length")), - ); - self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(len_node, self).into_expr_err(loc)?; - - // we have to force here to avoid length <-> array recursion - let next_next_arr = - self.advance_var_in_ctx_forcible(array.latest_version(self), loc, ctx, true)?; - let update_array_len = - Elem::from(next_arr.latest_version(self)).set_length(len_node.into()); - - // Update the array - next_next_arr - .set_range_min(self, update_array_len.clone()) - .into_expr_err(loc)?; - next_next_arr - .set_range_max(self, update_array_len.clone()) - .into_expr_err(loc)?; + // let len_var = ContextVar { + // loc: Some(loc), + // name, + // display_name: array.display_name(self).into_expr_err(loc)? + ".length", + // storage: None, + // is_tmp: false, + // tmp_of: None, + // is_symbolic: true, + // is_return: false, + // ty: VarType::BuiltIn( + // BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + // Some(range), + // ), + // }; + // let len_node = ContextVarNode::from(self.add_node(Node::ContextVar(len_var))); + // self.add_edge( + // len_node, + // array, + // Edge::Context(ContextEdge::AttrAccess("length")), + // ); + // self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); + // ctx.add_var(len_node, self).into_expr_err(loc)?; - if !return_var { - ctx.push_expr(ExprRet::Single(len_node.into()), self) - .into_expr_err(loc)?; - Ok(None) - } else { - Ok(Some(len_node)) - } + // // we have to force here to avoid length <-> array recursion + // let next_next_arr = + // self.advance_var_in_ctx_forcible(array.latest_version(self), loc, ctx, true)?; + // let update_array_len = + // Elem::from(next_arr.latest_version(self)).set_length(len_node.into()); + + // // Update the array + // next_next_arr + // .set_range_min(self, update_array_len.clone()) + // .into_expr_err(loc)?; + // next_next_arr + // .set_range_max(self, update_array_len.clone()) + // .into_expr_err(loc)?; + + // if !return_var { + // ctx.push_expr(ExprRet::Single(len_node.into()), self) + // .into_expr_err(loc)?; + // Ok(None) + // } else { + // Ok(Some(len_node)) + // } + } + } + + fn create_length( + &mut self, + ctx: ContextNode, + loc: Loc, + array: ContextVarNode, + target_array: ContextVarNode, + return_var: bool, + ) -> Result, ExprErr> { + // no length variable, create one + let name = format!("{}.length", array.name(self).into_expr_err(loc)?); + + // Create the range from the current length or default to [0, uint256.max] + + let len_min = Elem::from(array) + .get_length() + .max(Elem::from(Concrete::from(U256::zero()))); + let len_max = Elem::from(array) + .get_length() + .min(Elem::from(Concrete::from(U256::MAX))); + let range = SolcRange::new(len_min, len_max, vec![]); + + let len_var = ContextVar { + loc: Some(loc), + name, + display_name: array.display_name(self).into_expr_err(loc)? + ".length", + storage: None, + is_tmp: false, + tmp_of: None, + is_symbolic: true, + is_return: false, + ty: VarType::BuiltIn( + BuiltInNode::from(self.builtin_or_add(Builtin::Uint(256))), + Some(range), + ), + }; + let len_node = ContextVarNode::from(self.add_node(Node::ContextVar(len_var))); + self.add_edge( + len_node, + target_array, + Edge::Context(ContextEdge::AttrAccess("length")), + ); + self.add_edge(len_node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.add_var(len_node, self).into_expr_err(loc)?; + + // we have to force here to avoid length <-> array recursion + let next_target_arr = + self.advance_var_in_ctx_forcible(target_array.latest_version(self), loc, ctx, true)?; + let update_array_len = + Elem::from(target_array.latest_version(self)).set_length(len_node.into()); + + // Update the array + next_target_arr + .set_range_min(self, update_array_len.clone()) + .into_expr_err(loc)?; + next_target_arr + .set_range_max(self, update_array_len.clone()) + .into_expr_err(loc)?; + + if !return_var { + ctx.push_expr(ExprRet::Single(len_node.into()), self) + .into_expr_err(loc)?; + Ok(None) + } else { + Ok(Some(len_node)) } } diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 89a843f3..15d2e626 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -766,6 +766,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ) )); } + tracing::trace!("done range updating"); new_rhs = new_rhs.latest_version(self); new_lhs = new_lhs.latest_version(self); @@ -865,6 +866,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { tmp_cvar = Some(cvar); + tracing::trace!("checking unsat"); any_unsat |= new_var_range.unsat(self); if any_unsat || ctx.unreachable(self).into_expr_err(loc)? { ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; @@ -965,7 +967,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let elem = Elem::from(const_var.latest_version(self)); let evaled_min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; if evaled_min.maybe_concrete().is_none() { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", evaled_min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Eq). Min: {}", evaled_min.to_range_string(false, self).s))); } if !nonconst_range.contains_elem(&elem, self) { @@ -991,7 +993,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // mins are equivalent, add 1 instead of adding an exclusion let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; let Some(min) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq). Min: {}", min.to_range_string(false, self).s))); }; let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); let min = nonconst_range.range_min().into_owned() + Elem::from(one); @@ -1005,7 +1007,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; let Some(max) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq 2). Max: {}", max.to_range_string(true, self).s))); }; let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); let max = nonconst_range.range_max().into_owned() - Elem::from(one); @@ -1033,14 +1035,16 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } // we add one to the element because its strict > - let Some(max_conc) = max.maybe_concrete() else { + let Some(max_conc) = const_var.evaled_range_min(self).unwrap().unwrap().maybe_concrete() + else { return Err(ExprErr::BadRange(loc, format!( - "Expected {} to have a concrete range by now. This is likely a bug. Max: {}, expr: {} {} {}", + "Expected {} to have a concrete range by now. This is likely a bug (update nonconst from const: Gt). Max: {}, expr: {} {} {}, const value: {}", nonconst_var.display_name(self).unwrap(), nonconst_range.max, nonconst_var.display_name(self).unwrap(), op.to_string(), const_var.display_name(self).unwrap(), + const_var.evaled_range_min(self).unwrap().unwrap() ))); }; let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); @@ -1086,7 +1090,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add one to the element because its strict > let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected {} to have a concrete range by now. This is likely a bug. Min: {}", nonconst_var.display_name(self).unwrap(), nonconst_range.min))); + return Err(ExprErr::BadRange(loc, format!("Expected {} to have a concrete range by now. This is likely a bug (update nonconst from const: Lt). Min: {}", nonconst_var.display_name(self).unwrap(), nonconst_range.min))); }; let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); @@ -1220,7 +1224,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } let Some(max_conc) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Max: {}", max.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from nonconst: Gt). Max: {}", max.to_range_string(true, self).s))); }; let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); @@ -1294,7 +1298,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add/sub one to the element because its strict > let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug. Min: {}", min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Lt). Min: {}", min.to_range_string(false, self).s))); }; let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index 8e396373..d618174e 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -698,7 +698,7 @@ pub trait YulFuncCaller: } _ => Err(ExprErr::Todo( *loc, - format!("Unhandled builtin yul function: {id:?}"), + format!("Unhandled yul function: \"{}\"", id.name), )), } } From 7bf324cb5b8d02ae114caafccc2888b4c914173d Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 18 Mar 2024 10:33:43 -0700 Subject: [PATCH 64/71] dunno --- crates/analyzers/src/func_analyzer/mod.rs | 2 +- crates/analyzers/src/var_analyzer/mod.rs | 4 +- crates/graph/src/nodes/context/solving.rs | 13 +- crates/graph/src/nodes/context/var/ranging.rs | 20 +- .../graph/src/nodes/context/var/underlying.rs | 4 +- crates/graph/src/nodes/context/variables.rs | 12 +- crates/graph/src/range/elem/concrete.rs | 9 + crates/graph/src/range/elem/elem_enum.rs | 423 ++++-- crates/graph/src/range/elem/elem_trait.rs | 7 + crates/graph/src/range/elem/expr.rs | 260 +++- crates/graph/src/range/elem/map_or_array.rs | 15 + crates/graph/src/range/elem/mod.rs | 16 + crates/graph/src/range/elem/reference.rs | 159 ++- crates/graph/src/range/exec/exec_op.rs | 50 +- crates/graph/src/range/range_trait.rs | 11 +- crates/graph/src/range/solc_range.rs | 103 +- crates/graph/src/solvers/atoms.rs | 29 +- crates/graph/src/solvers/brute.rs | 4 +- crates/graph/src/solvers/dl.rs | 13 +- crates/pyrometer/src/graph_backend.rs | 16 +- crates/pyrometer/tests/test_data/math.sol | 1186 ++++++++--------- .../tests/test_data/repros/issue69.sol | 14 +- .../tests/test_data/repros/overflow2.sol | 25 + .../tests/test_data/viz/func_call.sol | 45 +- crates/shared/src/graph_like.rs | 9 +- crates/solc-expressions/src/assign.rs | 14 +- crates/solc-expressions/src/bin_op.rs | 2 + crates/solc-expressions/src/cmp.rs | 2 +- .../solc-expressions/src/func_call/helper.rs | 6 +- .../src/func_call/intrinsic_call/address.rs | 53 +- crates/solc-expressions/src/func_call/join.rs | 13 +- .../src/member_access/builtin_access.rs | 8 +- crates/solc-expressions/src/require.rs | 11 +- 33 files changed, 1676 insertions(+), 882 deletions(-) create mode 100644 crates/pyrometer/tests/test_data/repros/overflow2.sol diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index bef2a700..f41db5cd 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -56,7 +56,7 @@ impl<'a> FunctionVarsBoundAnalysis { let deps = ctx.ctx_deps(analyzer).unwrap(); let deps = deps .iter() - .map(|var| (var.display_name(analyzer).unwrap(), var)) + .map(|var| (var.as_controllable_name(analyzer).unwrap(), var)) .collect::>(); // create the bound strings // let atoms = ctx.dep_atoms(analyzer).unwrap(); diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 9b14027b..9fac71ef 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -240,7 +240,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { if let Some(next_range) = curr.ref_range(self).unwrap() { let nr_min = next_range.evaled_range_min(self).unwrap(); let nr_max = next_range.evaled_range_max(self).unwrap(); - let nr_excl = &next_range.exclusions; + let nr_excl = &next_range.range_exclusions(); // check if there was a bound change if report_config.show_all_lines @@ -266,7 +266,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { if let Some(next_range) = next.ref_range(self).unwrap() { let nr_min = next_range.evaled_range_min(self).unwrap(); let nr_max = next_range.evaled_range_max(self).unwrap(); - let nr_excl = &next_range.exclusions; + let nr_excl = &next_range.range_exclusions(); // check if there was a bound change if report_config.show_all_lines diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index bebaf6ce..35f927bf 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,3 +1,5 @@ +use crate::FlattenedRange; +use crate::elem::Elem; use crate::SolcRange; use crate::{ as_dot_str, @@ -33,7 +35,7 @@ impl ContextNode { let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { let mut range = dep.range(analyzer)?.unwrap(); - let r: Cow<'_, SolcRange> = range.flattened_range(analyzer)?; + let r: Cow<'_, _> = range.flattened_range(analyzer)?; ranges.insert(*dep, r.into_owned()); Ok(()) })?; @@ -41,10 +43,10 @@ impl ContextNode { Ok(ranges .iter() .filter_map(|(_dep, range)| { - if let Some(atom) = range.min.atomize(analyzer) { + if let Some(atom) = Elem::Arena(range.min).atomize(analyzer) { Some(atom) } else { - range.max.atomize(analyzer) + Elem::Arena(range.max).atomize(analyzer) } }) .collect::>()) @@ -89,12 +91,13 @@ impl ContextNode { // dep.cache_flattened_range(analyzer)?; let mut range = dep.range(analyzer)?.unwrap(); let r = range.flattened_range(analyzer)?.into_owned(); + tracing::trace!("flattened: {}", >::into(r.clone()).as_dot_str(analyzer)); // add the atomic constraint - if let Some(atom) = r.min.atomize(analyzer) { + if let Some(atom) = Elem::Arena(r.min).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); solver.add_constraints(vec![atom], analyzer); self.underlying_mut(analyzer)?.dl_solver = solver; - } else if let Some(atom) = r.max.atomize(analyzer) { + } else if let Some(atom) = Elem::Arena(r.max).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); solver.add_constraints(vec![atom], analyzer); self.underlying_mut(analyzer)?.dl_solver = solver; diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 2a1c86c1..0cece95e 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -203,6 +203,8 @@ impl ContextVarNode { new_min.arenaize(analyzer)?; + + // new_min.cache_flatten(analyzer)?; // new_min.cache_minimize(analyzer)?; @@ -279,7 +281,7 @@ impl ContextVarNode { pub fn set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - mut new_exclusions: Vec>, + mut new_exclusions: Vec, ) -> Result<(), GraphError> { tracing::trace!( "setting range exclusions for {}", @@ -292,9 +294,10 @@ impl ContextVarNode { None }; - new_exclusions - .iter_mut() - .try_for_each(|excl| excl.arenaize(analyzer))?; + // let new_exclusions = new_exclusions + // .into_iter() + // .map(|excl| analyzer.range_arena_idx_or_upsert(excl)) + // .collect(); self.underlying_mut(analyzer)? .set_range_exclusions(new_exclusions, fallback)?; @@ -366,7 +369,7 @@ impl ContextVarNode { pub fn try_set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - mut new_exclusions: Vec>, + mut new_exclusions: Vec, ) -> Result { tracing::trace!( "setting range exclusions for: {}", @@ -379,9 +382,10 @@ impl ContextVarNode { None }; - new_exclusions - .iter_mut() - .try_for_each(|excl| excl.arenaize(analyzer))?; + // let new_exclusions = new_exclusions + // .into_iter() + // .map(|excl| analyzer.range_arena_idx_or_upsert(excl)) + // .collect(); Ok(self .underlying_mut(analyzer)? diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 840b0a79..76a29932 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -357,7 +357,7 @@ impl ContextVar { pub fn set_range_exclusions( &mut self, - new_exclusions: Vec>, + new_exclusions: Vec, fallback_range: Option, ) -> Result<(), GraphError> { match &mut self.ty { @@ -414,7 +414,7 @@ impl ContextVar { pub fn try_set_range_exclusions( &mut self, - new_exclusions: Vec>, + new_exclusions: Vec, fallback_range: Option, ) -> bool { match &mut self.ty { diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 3dcbdfd7..ee839759 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -27,7 +27,8 @@ impl ContextNode { underlying_mut .expr_ret_stack .iter() - .for_each(|elem| println!("{}", elem.debug_str(analyzer))); + .enumerate() + .for_each(|(i, elem)| println!("{i}. {}", elem.debug_str(analyzer))); Ok(()) } @@ -212,6 +213,10 @@ impl ContextNode { loc: Loc, analyzer: &mut (impl GraphBackend + AnalyzerBackend), ) -> Result { + tracing::trace!( + "moving expr to {}", + self.path(analyzer) + ); match expr { ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( self.maybe_move_var(var.into(), loc, analyzer)?.into(), @@ -239,6 +244,11 @@ impl ContextNode { let var = var.latest_version(analyzer); if let Some(ctx) = var.maybe_ctx(analyzer) { if ctx != *self { + tracing::trace!( + "moving var {} from {}", + ctx.path(analyzer), + self.path(analyzer) + ); let mut new_cvar = var.latest_version(analyzer).underlying(analyzer)?.clone(); new_cvar.loc = Some(loc); diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index aad962f5..97a91ec5 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -62,6 +62,15 @@ impl RangeElem for RangeConcrete { Ok(false) } + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { + Ok(false) + } + fn flatten( &self, _maximize: bool, diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index 18106228..a34d292a 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,4 +1,3 @@ -use std::borrow::Cow; use crate::elem::MinMaxed; use std::cell::RefCell; use std::rc::Rc; @@ -10,14 +9,14 @@ use crate::{ GraphBackend, GraphError, }; use solang_parser::pt::Loc; -use std::hash::Hash; -use std::hash::Hasher; use shared::{NodeIdx, RangeArenaIdx}; use ethers_core::types::I256; +use tracing::instrument; use std::{ + hash::{Hash,Hasher}, collections::BTreeMap, ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}, }; @@ -562,6 +561,113 @@ impl Elem { Self::Arena(_) => todo!(), } } + + pub fn arenaized_flattened(&self, max: bool, analyzer: &impl GraphBackend) -> Option>> { + if let Some(idx) = analyzer.range_arena_idx(self) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + match &*t { + Elem::Expr(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + Elem::Reference(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + Elem::ConcreteDyn(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + c @ Elem::Concrete(_) => { + Some(Box::new(c.clone())) + } + c @ Elem::Null => { + Some(Box::new(c.clone())) + } + a @ Elem::Arena(_) => { + a.arenaized_flattened(max, analyzer) + } + } + } else { + None + } + } else { + None + } + } + + pub fn set_arenaized_flattened(&self, max: bool, elem: &Elem, analyzer: &impl GraphBackend) { + if let Some(idx) = analyzer.range_arena_idx(self) { + if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + match &mut *t { + Elem::Expr(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + Elem::Reference(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + Elem::ConcreteDyn(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + _ => {} + } + + } + } + } + + pub fn set_arenaized_cache(&self, max: bool, elem: &Elem, analyzer: &impl GraphBackend) { + if let Some(idx) = analyzer.range_arena_idx(self) { + if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + match &mut *t { + Elem::Expr(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + Elem::Reference(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + Elem::ConcreteDyn(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + _ => {} + } + + } + } + } } impl From for Elem { @@ -672,6 +778,7 @@ impl RangeElem for Elem { } } + #[instrument(level = "trace", skip_all)] fn flatten( &self, maximize: bool, @@ -686,35 +793,36 @@ impl RangeElem for Elem { Self::Arena(_) => { let de = self.dearenaize(analyzer); let res = de.borrow().flatten(maximize, analyzer)?; - match &mut *de.borrow_mut() { - Self::Reference(ref mut d) => { - if maximize { - d.flattened_max = Some(Box::new(res.clone())); - } else { - d.flattened_min = Some(Box::new(res.clone())); - } - } - Self::Expr(ref mut expr) => { - if maximize { - expr.flattened_max = Some(Box::new(res.clone())); - } else { - expr.flattened_min = Some(Box::new(res.clone())); - } - } - Self::ConcreteDyn(ref mut d) => { - if maximize { - d.flattened_max = Some(Box::new(res.clone())); - } else { - d.flattened_min = Some(Box::new(res.clone())); - } - } - _ => {} - } + // match &mut *de.borrow_mut() { + // Self::Reference(ref mut d) => { + // if maximize { + // d.flattened_max = Some(Box::new(res)); + // } else { + // d.flattened_min = Some(Box::new(res)); + // } + // } + // Self::Expr(ref mut expr) => { + // if maximize { + // expr.flattened_max = Some(Box::new(res)); + // } else { + // expr.flattened_min = Some(Box::new(res)); + // } + // } + // Self::ConcreteDyn(ref mut d) => { + // if maximize { + // d.flattened_max = Some(Box::new(res)); + // } else { + // d.flattened_min = Some(Box::new(res)); + // } + // } + // _ => {} + // } Ok(res) }, } } + #[instrument(level = "trace", skip_all)] fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { if self.is_flatten_cached(analyzer) { return Ok(()); @@ -726,15 +834,43 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.cache_flatten(analyzer), Self::ConcreteDyn(d) => d.cache_flatten(analyzer), Self::Null => Ok(()), - Self::Arena(_idx) => { - let mut dearenaized = self.dearenaize(analyzer).borrow().clone(); - dearenaized.cache_flatten(analyzer)?; - *self.dearenaize(analyzer).borrow_mut() = dearenaized; + Self::Arena(idx) => { + tracing::trace!("flattening for arena idx: {idx}"); + let dearenaized = self.dearenaize(analyzer); + let (min, max) = { + let Ok(t) = dearenaized.try_borrow() else { + return Ok(()) + }; + + let min = t.flatten(false, analyzer)?; + let max = t.flatten(true, analyzer)?; + (min, max) + }; + + match &mut *dearenaized.borrow_mut() { + Self::Reference(ref mut d) => { + d.flattened_min = Some(Box::new(min)); + d.flattened_max = Some(Box::new(max)); + } + Self::Expr(ref mut expr) => { + expr.flattened_min = Some(Box::new(min)); + expr.flattened_max = Some(Box::new(max)); + } + Self::ConcreteDyn(ref mut d) => { + d.flattened_min = Some(Box::new(min)); + d.flattened_max = Some(Box::new(max)); + } + _ => {} + } + // let mut dearenaized = self.dearenaize(analyzer).borrow().clone(); + // dearenaized.cache_flatten(analyzer)?; + // *self.dearenaize(analyzer).borrow_mut() = dearenaized; Ok(()) } } } + #[instrument(level = "trace", skip_all)] fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { match self { Self::Reference(d) => d.is_flatten_cached(analyzer), @@ -742,18 +878,30 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.is_flatten_cached(analyzer), Self::ConcreteDyn(d) => d.is_flatten_cached(analyzer), Self::Null => true, - Self::Arena(_) => self.dearenaize(analyzer).borrow().is_flatten_cached(analyzer), + Self::Arena(_idx) => { + if let Ok(t) = self.dearenaize(analyzer).try_borrow() { + t.is_flatten_cached(analyzer) + } else { + false + } + }, } } fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { match self { Self::Reference(d) => d.is_min_max_cached(analyzer), - Self::Concrete(c) => c.is_min_max_cached(analyzer), + Self::Concrete(_c) => (true, true), Self::Expr(expr) => expr.is_min_max_cached(analyzer), Self::ConcreteDyn(d) => d.is_min_max_cached(analyzer), Self::Null => (true, true), - Self::Arena(_) => self.dearenaize(analyzer).borrow().is_min_max_cached(analyzer), + Self::Arena(_) => { + if let Ok(t) = self.dearenaize(analyzer).try_borrow() { + t.is_min_max_cached(analyzer) + } else { + (false, false) + } + }, } } @@ -764,7 +912,13 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.dependent_on(analyzer), Self::ConcreteDyn(d) => d.dependent_on(analyzer), Self::Null => vec![], - Self::Arena(_) => self.dearenaize(analyzer).borrow().dependent_on(analyzer), + Self::Arena(_) => { + if let Ok(t) = self.dearenaize(analyzer).try_borrow() { + t.dependent_on(analyzer) + } else { + vec![] + } + } } } @@ -797,6 +951,22 @@ impl RangeElem for Elem { } } + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { + match self { + Self::Reference(d) => d.depends_on(var, seen, analyzer), + Self::Concrete(_) => Ok(false), + Self::Expr(expr) => expr.depends_on(var, seen, analyzer), + Self::ConcreteDyn(d) => d.depends_on(var, seen, analyzer), + Self::Null => Ok(false), + Self::Arena(_) => self.dearenaize(analyzer).borrow().depends_on(var, seen, analyzer), + } + } + fn filter_recursion( &mut self, node_idx: NodeIdx, @@ -824,6 +994,7 @@ impl RangeElem for Elem { if let Some(idx) = analyzer.range_arena_idx(self) { let (_min, max) = Elem::Arena(idx).is_min_max_cached(analyzer); if max { + tracing::trace!("maximize cache hit"); match &*analyzer.range_arena().ranges[idx].borrow() { Reference(dy) => return dy.maximize(analyzer), Concrete(inner) => return inner.maximize(analyzer), @@ -844,19 +1015,32 @@ impl RangeElem for Elem { Null => Elem::Null, Arena(_) => { let dearenaized = self.dearenaize(analyzer); - let res = dearenaized.borrow().maximize(analyzer)?; + let res = { + let Ok(t) = dearenaized.try_borrow() else { + return Ok(self.clone()) + }; + t.maximize(analyzer)? + }; + match &mut *dearenaized.borrow_mut() { Self::Reference(ref mut d) => { + tracing::trace!("maximize cache MISS: {self}"); d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); } Self::Expr(ref mut expr) => { + tracing::trace!("maximize cache MISS: {self}"); expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); } Self::ConcreteDyn(ref mut d) => { + tracing::trace!("maximize cache MISS: {self}"); d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); } _ => {} } + + let (_min, max) = self.is_min_max_cached(analyzer); + assert!(max, "????"); + res }, }; @@ -869,6 +1053,7 @@ impl RangeElem for Elem { if let Some(idx) = analyzer.range_arena_idx(self) { let (min, _max) = Elem::Arena(idx).is_min_max_cached(analyzer); if min { + tracing::trace!("minimize cache hit"); match &*analyzer.range_arena().ranges[idx].borrow() { Reference(dy) => return dy.minimize(analyzer), Concrete(inner) => return inner.minimize(analyzer), @@ -888,19 +1073,31 @@ impl RangeElem for Elem { Null => Elem::Null, Arena(_) => { let dearenaized = self.dearenaize(analyzer); - let res = dearenaized.borrow().minimize(analyzer)?; + let res = { + let Ok(t) = dearenaized.try_borrow() else { + return Ok(self.clone()) + }; + t.minimize(analyzer)? + }; + match &mut *dearenaized.borrow_mut() { Self::Reference(ref mut d) => { - d.maximized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + tracing::trace!("minimize cache MISS: {self}"); + d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); } Self::Expr(ref mut expr) => { + tracing::trace!("minimize cache MISS: {self}"); expr.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); } Self::ConcreteDyn(ref mut d) => { + tracing::trace!("minimize cache MISS: {self}"); d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); } _ => {} } + + let (min, _max) = self.is_min_max_cached(analyzer); + assert!(min, "????"); res }, }; @@ -913,53 +1110,72 @@ impl RangeElem for Elem { ) -> Result, GraphError> { use Elem::*; - match self { - Arena(_) => {} - _ => { - if let Some(idx) = analyzer.range_arena_idx(self) { - if Elem::Arena(idx).is_flatten_cached(analyzer) { - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => return dy.simplify_maximize(analyzer), - Concrete(inner) => return inner.simplify_maximize(analyzer), - ConcreteDyn(inner) => return inner.simplify_maximize(analyzer), - Expr(expr) => return expr.simplify_maximize(analyzer), - Null => return Ok(Elem::Null), - _ => {} - } + if let Some(idx) = analyzer.range_arena_idx(self) { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => { + if let Some(max) = &dy.flattened_max { + return Ok(*max.clone()) + } + }, + c @ Concrete(_) => return Ok(c.clone()), + ConcreteDyn(inner) => { + if let Some(max) = &inner.flattened_max { + return Ok(*max.clone()) } } + Expr(expr) => { + if let Some(max) = &expr.flattened_max { + return Ok(*max.clone()) + } + }, + Null => return Ok(Elem::Null), + _ => {} } } - match self { Reference(dy) => dy.simplify_maximize(analyzer), Concrete(inner) => inner.simplify_maximize(analyzer), ConcreteDyn(inner) => inner.simplify_maximize(analyzer), Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_maximize(analyzer) + let res = collapsed.simplify_maximize(analyzer)?; + collapsed.set_arenaized_flattened(true, &res, analyzer); + Ok(res) } - _ => expr.simplify_maximize(analyzer), + _ => { + let res = expr.simplify_maximize(analyzer)?; + expr.set_arenaized_flattened(true, res.clone(), analyzer); + Ok(res) + }, }, Null => Ok(Elem::Null), Arena(_) => { let dearenaized = self.dearenaize(analyzer); let flat = dearenaized.borrow().flatten(true, analyzer)?; - let res = flat.simplify_maximize(analyzer)?; + let max = flat.simplify_maximize(analyzer)?; + // let min = flat.simplify_minimize(analyzer)?; match &mut *dearenaized.borrow_mut() { Self::Reference(ref mut d) => { - d.flattened_max = Some(Box::new(res.clone())); + tracing::trace!("simplify maximize cache MISS: {self}"); + d.flattened_max = Some(Box::new(max.clone())); + // d.flattened_min = Some(Box::new(min.clone())); } Self::Expr(ref mut expr) => { - expr.flattened_max = Some(Box::new(res.clone())); + tracing::trace!("simplify maximize cache MISS: {self}"); + expr.flattened_max = Some(Box::new(max.clone())); + // expr.flattened_min = Some(Box::new(min.clone())); } Self::ConcreteDyn(ref mut d) => { - d.flattened_max = Some(Box::new(res.clone())); + tracing::trace!("simplify maximize cache MISS: {self}"); + d.flattened_max = Some(Box::new(max.clone())); + // d.flattened_min = Some(Box::new(min.clone())); } _ => {} } - Ok(res) + + // assert!(self.is_flatten_cached(analyzer), "????"); + Ok(max) } } } @@ -970,21 +1186,26 @@ impl RangeElem for Elem { ) -> Result, GraphError> { use Elem::*; - match self { - Arena(_) => {} - _ => { - if let Some(idx) = analyzer.range_arena_idx(self) { - if Elem::Arena(idx).is_flatten_cached(analyzer) { - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => return dy.simplify_minimize(analyzer), - Concrete(inner) => return inner.simplify_minimize(analyzer), - ConcreteDyn(inner) => return inner.simplify_minimize(analyzer), - Expr(expr) => return expr.simplify_minimize(analyzer), - Null => return Ok(Elem::Null), - _ => {} - } + if let Some(idx) = analyzer.range_arena_idx(self) { + match &*analyzer.range_arena().ranges[idx].borrow() { + Reference(dy) => { + if let Some(min) = &dy.flattened_min { + return Ok(*min.clone()) + } + }, + c @ Concrete(_) => return Ok(c.clone()), + ConcreteDyn(inner) => { + if let Some(min) = &inner.flattened_min { + return Ok(*min.clone()) } } + Expr(expr) => { + if let Some(min) = &expr.flattened_min { + return Ok(*min.clone()) + } + }, + Null => return Ok(Elem::Null), + _ => {} } } @@ -994,28 +1215,38 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.simplify_minimize(analyzer), Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(collapsed) => { - collapsed.simplify_minimize(analyzer) + let res = collapsed.simplify_minimize(analyzer)?; + collapsed.set_arenaized_flattened(false, &res, analyzer); + Ok(res) } - _ => expr.simplify_minimize(analyzer), + _ => { + let res = expr.simplify_minimize(analyzer)?; + expr.set_arenaized_flattened(false, res.clone(), analyzer); + Ok(res) + }, }, Null => Ok(Elem::Null), Arena(_) => { let dearenaized = self.dearenaize(analyzer); - let flat = dearenaized.borrow().flatten(true, analyzer)?; - let res = flat.simplify_minimize(analyzer)?; + let flat = dearenaized.borrow().flatten(false, analyzer)?; + let min = flat.simplify_minimize(analyzer)?; match &mut *dearenaized.borrow_mut() { Self::Reference(ref mut d) => { - d.flattened_min = Some(Box::new(res.clone())); + tracing::trace!("simplify minimize cache MISS: {self}"); + d.flattened_min = Some(Box::new(min.clone())); } Self::Expr(ref mut expr) => { - expr.flattened_min = Some(Box::new(res.clone())); + tracing::trace!("simplify minimize cache MISS: {self}"); + expr.flattened_min = Some(Box::new(min.clone())); } - Self::ConcreteDyn(d) => { - d.flattened_min = Some(Box::new(res.clone())); + Self::ConcreteDyn(ref mut d) => { + tracing::trace!("simplify minimize cache MISS: {self}"); + d.flattened_min = Some(Box::new(min.clone())); } _ => {} } - Ok(res) + + Ok(min) } }?; @@ -1030,16 +1261,26 @@ impl RangeElem for Elem { ConcreteDyn(inner) => inner.cache_maximize(analyzer), Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { - collapsed.cache_minimize(analyzer)?; + collapsed.cache_maximize(analyzer)?; + let max = collapsed.maximize(analyzer)?; + self.set_arenaized_flattened(true, &max, analyzer); *self = collapsed; Ok(()) } - _ => expr.cache_maximize(analyzer), + _ => { + expr.cache_maximize(analyzer)?; + let max = expr.maximize(analyzer)?; + self.set_arenaized_flattened(true, &max, analyzer); + Ok(()) + }, }, Null => Ok(()), Arena(_idx) => { let dearenaized = self.dearenaize(analyzer); - dearenaized.borrow_mut().cache_maximize(analyzer)?; + if let Ok(mut t) = dearenaized.try_borrow_mut() { + t.cache_maximize(analyzer)?; + } + Ok(()) } } @@ -1054,15 +1295,25 @@ impl RangeElem for Elem { Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Collapsed(mut collapsed) => { collapsed.cache_minimize(analyzer)?; + let min = collapsed.minimize(analyzer)?; + self.set_arenaized_flattened(false, &min, analyzer); *self = collapsed; Ok(()) } - _ => expr.cache_minimize(analyzer), + _ => { + expr.cache_minimize(analyzer)?; + let min = expr.minimize(analyzer)?; + self.set_arenaized_flattened(false, &min, analyzer); + Ok(()) + }, }, Null => Ok(()), Arena(_idx) => { let dearenaized = self.dearenaize(analyzer); - dearenaized.borrow_mut().cache_minimize(analyzer)?; + if let Ok(mut t) = dearenaized.try_borrow_mut() { + t.cache_minimize(analyzer)?; + } + Ok(()) } } diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 1184558a..1ee2bd19 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -66,6 +66,13 @@ pub trait RangeElem { seen: &mut Vec, analyzer: &impl GraphBackend, ) -> Result; + + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result; /// Attempts to replace range elements that form a cyclic dependency by replacing /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now /// but in theory it can make sense. diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 39147265..87c379b6 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -111,7 +111,10 @@ impl RangeExpr { pub fn arenaized_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option> { if let Some(idx) = self.arena_idx(analyzer) { - let Elem::Expr(ref arenaized) = *analyzer.range_arena().ranges[idx].borrow() else { + let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { + return None; + }; + let Elem::Expr(ref arenaized) = *t else { return None; }; return if max { @@ -125,7 +128,10 @@ impl RangeExpr { pub fn arenaized_flat_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option>> { if let Some(idx) = self.arena_idx(analyzer) { - let Elem::Expr(ref arenaized) = *analyzer.range_arena().ranges[idx].borrow() else { + let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { + return None; + }; + let Elem::Expr(ref arenaized) = *t else { return None; }; return if max { @@ -182,10 +188,11 @@ impl RangeElem for RangeExpr { // self.lhs.clone().arenaize(analyzer)?; // self.rhs.clone().arenaize(analyzer)?; if self.arena_idx(analyzer).is_none() { - let mut self_copy = self.clone(); - *self_copy.lhs = *Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*self.lhs.clone()))); - *self_copy.rhs = *Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*self.rhs.clone()))); - let _ = analyzer.range_arena_idx_or_upsert(Elem::Expr(self_copy)); + let lhs = std::mem::take(&mut self.lhs); + let rhs = std::mem::take(&mut self.rhs); + self.lhs = Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*lhs))); + self.rhs = Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*rhs))); + let _ = analyzer.range_arena_idx_or_upsert(Elem::Expr(self.clone())); } Ok(()) } @@ -218,12 +225,42 @@ impl RangeElem for RangeExpr { ))) } - fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() + || { + if let Some(idx) = self.arena_idx(analyzer) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Expr(ref arenaized) = *t { + arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() + } else { + false + } + } else { + false + } + } else { + false + } + } } - fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { - (self.minimized.is_some(), self.maximized.is_some()) + fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { + let (arena_cached_min, arena_cached_max) = { + if let Some(idx) = self.arena_idx(analyzer) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Expr(ref arenaized) = *t { + (arenaized.minimized.is_some(), arenaized.maximized.is_some()) + } else { + (false, false) + } + } else { + (false, false) + } + } else { + (false, false) + } + }; + (self.minimized.is_some() || arena_cached_min, self.maximized.is_some() || arena_cached_max) } fn range_ord( @@ -261,6 +298,17 @@ impl RangeElem for RangeExpr { Ok(lhs_has_cycle || rhs_has_cycle) } + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { + let lhs_deps_on = self.lhs.depends_on(var, seen, analyzer)?; + let rhs_deps_on = self.rhs.depends_on(var, seen, analyzer)?; + Ok(lhs_deps_on || rhs_deps_on) + } + #[tracing::instrument(level = "trace", skip_all)] fn filter_recursion( &mut self, @@ -268,6 +316,7 @@ impl RangeElem for RangeExpr { new_idx: NodeIdx, analyzer: &mut impl GraphBackend, ) { + let _ = self.arenaize(analyzer); self.lhs.filter_recursion(node_idx, new_idx, analyzer); self.rhs.filter_recursion(node_idx, new_idx, analyzer); } @@ -314,7 +363,7 @@ impl RangeElem for RangeExpr { let l = self.lhs.simplify_maximize(analyzer)?; let r = self.rhs.simplify_maximize(analyzer)?; let collapsed = collapse(&l, self.op, &r, analyzer); - match collapsed { + let res = match collapsed { MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(true, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { @@ -333,7 +382,9 @@ impl RangeElem for RangeExpr { other => Ok(other), } } - } + }?; + self.set_arenaized_flattened(true, res.clone(), analyzer); + Ok(res) } #[tracing::instrument(level = "trace", skip_all)] @@ -350,9 +401,12 @@ impl RangeElem for RangeExpr { } let l = self.lhs.simplify_minimize(analyzer)?; + self.lhs.set_arenaized_flattened(false, &l, analyzer); let r = self.rhs.simplify_minimize(analyzer)?; + self.rhs.set_arenaized_flattened(false, &r, analyzer); + let collapsed = collapse(&l, self.op, &r, analyzer); - match collapsed { + let res = match collapsed { MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(false, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { @@ -370,34 +424,170 @@ impl RangeElem for RangeExpr { other => Ok(other), } } - } + }?; + + self.set_arenaized_flattened(false, res.clone(), analyzer); + Ok(res) } #[tracing::instrument(level = "trace", skip_all)] fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + self.arenaize(g)?; + + fn simplify_minimize( + mut this: Elem, + analyzer: &mut impl GraphBackend, + ) -> Result, GraphError> { + let Elem::Expr(this) = this else { + this.cache_flatten(analyzer)?; + if let Some(t) = this.arenaized_flattened(false, analyzer) { + return Ok(*t) + } else { + return Ok(this.clone()) + } + }; + + if let Some(simp_min) = &this.flattened_min { + return Ok(*simp_min.clone()); + } + + if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { + return Ok(*arenaized) + } + + let l = this.lhs.simplify_minimize(analyzer)?; + let r = this.rhs.simplify_minimize(analyzer)?; + let collapsed = collapse(&l, this.op, &r, analyzer); + let res = match collapsed { + MaybeCollapsed::Concretes(..) => RangeExpr::new(l, this.op, r).exec_op(false, analyzer), + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(..) => { + + let res = + RangeExpr::new(l, this.op, r).simplify_exec_op(false, analyzer)?; + + let idx = analyzer.range_arena_idx_or_upsert(res.clone()); + match res { + Elem::Expr(expr) => { + match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + MaybeCollapsed::Concretes(..) => { + let exec_res = expr.exec_op(false, analyzer)?; + Elem::Arena(idx).set_arenaized_flattened(false, &exec_res, analyzer); + return Ok(exec_res) + }, + MaybeCollapsed::Collapsed(collapsed) => { + Elem::Arena(idx).set_arenaized_flattened(false, &collapsed, analyzer); + return Ok(collapsed) + }, + _ => {} + } + Ok(Elem::Expr(expr)) + } + other => Ok(other), + } + } + }?; + + this.set_arenaized_flattened(false, res.clone(), analyzer); + Ok(res) + } + + fn simplify_maximize( + mut this: Elem, + analyzer: &mut impl GraphBackend, + ) -> Result, GraphError> { + let Elem::Expr(this) = this else { + this.cache_flatten(analyzer)?; + if let Some(t) = this.arenaized_flattened(true, analyzer) { + return Ok(*t) + } else { + return Ok(this.clone()) + } + }; + + if let Some(simp_min) = &this.flattened_max { + return Ok(*simp_min.clone()); + } + + if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { + return Ok(*arenaized) + } + + let l = this.lhs.simplify_maximize(analyzer)?; + let r = this.rhs.simplify_maximize(analyzer)?; + let collapsed = collapse(&l, this.op, &r, analyzer); + let res = match collapsed { + MaybeCollapsed::Concretes(..) => RangeExpr::new(l, this.op, r).exec_op(true, analyzer), + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(..) => { + + let res = + RangeExpr::new(l, this.op, r).simplify_exec_op(true, analyzer)?; + + let idx = analyzer.range_arena_idx_or_upsert(res.clone()); + match res { + Elem::Expr(expr) => { + match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + MaybeCollapsed::Concretes(..) => { + let exec_res = expr.exec_op(true, analyzer)?; + Elem::Arena(idx).set_arenaized_flattened(true, &exec_res, analyzer); + return Ok(exec_res) + }, + MaybeCollapsed::Collapsed(collapsed) => { + Elem::Arena(idx).set_arenaized_flattened(true, &collapsed, analyzer); + return Ok(collapsed) + }, + _ => {} + } + Ok(Elem::Expr(expr)) + } + other => Ok(other), + } + } + }?; + + this.set_arenaized_flattened(false, res.clone(), analyzer); + Ok(res) + } + if self.flattened_max.is_none() { + if let Some(idx) = self.arena_idx(g) { + if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { + if arenaized.flattened_max.is_some() { + return Ok(()) + } + }; + } else { + self.arenaize(g)?; + } + self.lhs.cache_flatten(g)?; self.rhs.cache_flatten(g)?; // self.arenaize(g)?; let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(g)?; + let simplified_flat_max = simplify_maximize(flat_max, g)?; simplified_flat_max.clone().arenaize(g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); - self.arenaize(g)?; - // let mut s = Elem::Expr(self.clone()); - // s.arenaize(g)?; } + if self.flattened_min.is_none() { + if let Some(idx) = self.arena_idx(g) { + if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { + if arenaized.flattened_min.is_some() { + return Ok(()) + } + }; + } else { + self.arenaize(g)?; + } + self.lhs.cache_flatten(g)?; self.rhs.cache_flatten(g)?; // self.arenaize(g)?; let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(g)?; + let simplified_flat_min = simplify_minimize(flat_min, g)?; simplified_flat_min.clone().arenaize(g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); - self.arenaize(g)?; - // let mut s = Elem::Expr(self.clone()); - // s.arenaize(g)?; } Ok(()) } @@ -405,11 +595,11 @@ impl RangeElem for RangeExpr { #[tracing::instrument(level = "trace", skip_all)] fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { tracing::trace!("cache maximizing: {}", Elem::Expr(self.clone())); + self.arenaize(g)?; if self.maximized.is_none() { self.lhs.cache_maximize(g)?; self.rhs.cache_maximize(g)?; self.cache_exec_op(true, g)?; - self.arenaize(g)?; } Ok(()) } @@ -417,11 +607,11 @@ impl RangeElem for RangeExpr { #[tracing::instrument(level = "trace", skip_all)] fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { tracing::trace!("cache minimizing: {}", Elem::Expr(self.clone())); + self.arenaize(g)?; if self.minimized.is_none() { self.lhs.cache_minimize(g)?; self.rhs.cache_minimize(g)?; self.cache_exec_op(false, g)?; - self.arenaize(g)?; } Ok(()) } @@ -447,17 +637,25 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>( let one = Elem::from(Concrete::from(U256::one())); match (l, r) { (Elem::Arena(_), r) => { - match collapse(&l.dearenaize(analyzer).borrow().clone(), op, r, analyzer) { - MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), - MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + if let Ok(t) = l.dearenaize(analyzer).try_borrow() { + match collapse(&t, op, r, analyzer) { + MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + } + } else { + MaybeCollapsed::Not(l, r) } }, (l, Elem::Arena(_)) => { - match collapse(l, op, &r.dearenaize(analyzer).borrow().clone(), analyzer) { - MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), - MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + if let Ok(t) = r.dearenaize(analyzer).try_borrow() { + match collapse(l, op, &t, analyzer) { + MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + } + } else { + MaybeCollapsed::Not(l, r) } }, (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index 5e66ea8e..bcd350ea 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -290,6 +290,21 @@ impl RangeElem for RangeDyn { Ok(has_cycle) } + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { + let mut deps_on = false; + deps_on |= self.len.depends_on(var, seen, analyzer)?; + self.val.iter().try_for_each(|(_, val)| { + deps_on |= val.0.depends_on(var, seen, analyzer)?; + Ok(()) + })?; + Ok(deps_on) + } + fn flatten( &self, maximize: bool, diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index 87683672..19ac5c37 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -18,6 +18,22 @@ pub enum MinMaxed { Maximized(Box>), } +impl MinMaxed { + pub fn maxed(self) -> Elem { + match self { + Self::Maximized(t) => *t, + _ => panic!("MinMaxed was min not max") + } + } + + pub fn mined(self) -> Elem { + match self { + Self::Minimized(t) => *t, + _ => panic!("MinMaxed was max not min") + } + } +} + /// An operation to be performed on a range element #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum RangeOp { diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 910b1926..2a3940c2 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -59,10 +59,11 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn arenaize(&mut self, _analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - // self.cache_flatten(analyzer)?; - // self.cache_minimize(analyzer)?; - // self.cache_maximize(analyzer)?; + fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + let smol = Elem::Reference(Reference::new(self.idx)); + if analyzer.range_arena_idx(&smol).is_none() { + let _ = analyzer.range_arena_idx_or_upsert(Elem::Reference(self.clone())); + } Ok(()) } @@ -112,6 +113,30 @@ impl RangeElem for Reference { } } + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + ) -> Result { + let cvar = ContextVarNode::from(self.idx); + if seen.contains(&cvar) { + return Ok(false) + } + + if cvar == var + || cvar.name(analyzer)? == var.name(analyzer)? && self.idx >= var.0.into() { + Ok(true) + } else if let Some(range) = cvar.ref_range(analyzer)? { + seen.push(cvar); + let mut deps_on = range.min.depends_on(var, seen, analyzer)?; + deps_on |= range.max.depends_on(var, seen, analyzer)?; + Ok(deps_on) + } else { + Ok(false) + } + } + fn flatten( &self, maximize: bool, @@ -143,38 +168,81 @@ impl RangeElem for Reference { } } - fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() + || { + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() + } else { + false + } + } else { + false + } + } else { + false + } + } } - fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { - (self.minimized.is_some(), self.maximized.is_some()) + fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { + let (arena_cached_min, arena_cached_max) = { + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + (arenaized.minimized.is_some(), arenaized.maximized.is_some()) + } else { + (false, false) + } + } else { + (false, false) + } + } else { + (false, false) + } + }; + (self.minimized.is_some() || arena_cached_min, self.maximized.is_some() || arena_cached_max) } fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - if let Some(idx) = g.range_arena_idx(&Elem::Reference(self.clone())) { - if Elem::Arena(idx).is_flatten_cached(g) { - return Ok(()) - } - } + self.arenaize(g)?; if self.flattened_max.is_none() { + if let Some(idx) = g.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = g.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + if arenaized.flattened_max.is_some() { + tracing::trace!("reference cache flatten hit"); + return Ok(()) + } + } + } + } + let cvar = ContextVarNode::from(self.idx); cvar.cache_flattened_range(g)?; let flat_max = self.flatten(true, g)?; let simplified_flat_max = flat_max.simplify_maximize(g)?; self.flattened_max = Some(Box::new(simplified_flat_max)); - let mut s = Elem::Reference(self.clone()); - s.arenaize(g)?; } if self.flattened_min.is_none() { + if let Some(idx) = g.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = g.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + if arenaized.flattened_min.is_some() { + tracing::trace!("reference cache flatten hit"); + return Ok(()) + } + } + } + } let cvar = ContextVarNode::from(self.idx); cvar.cache_flattened_range(g)?; let flat_min = self.flatten(false, g)?; let simplified_flat_min = flat_min.simplify_minimize(g)?; self.flattened_min = Some(Box::new(simplified_flat_min)); - let mut s = Elem::Reference(self.clone()); - s.arenaize(g)?; } Ok(()) } @@ -186,6 +254,17 @@ impl RangeElem for Reference { return Ok(*cached); } + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + tracing::trace!("reference maximize cache hit"); + if let Some(MinMaxed::Maximized(cached)) = arenaized.maximized.clone() { + return Ok(*cached); + } + } + } + } + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; match &cvar.ty { VarType::User(TypeNode::Contract(_), maybe_range) @@ -211,6 +290,17 @@ impl RangeElem for Reference { return Ok(*cached); } + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + if let Some(MinMaxed::Minimized(cached)) = arenaized.minimized.clone() { + tracing::trace!("reference minimize cache hit"); + return Ok(*cached); + } + } + } + } + let cvar = ContextVarNode::from(self.idx).underlying(analyzer)?; match &cvar.ty { VarType::User(TypeNode::Contract(_), maybe_range) @@ -239,6 +329,17 @@ impl RangeElem for Reference { return Ok(*simp_max.clone()); } + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + if arenaized.flattened_max.is_some() { + tracing::trace!("reference simplify maximize cache hit"); + return Ok(*arenaized.flattened_max.clone().unwrap()) + } + } + } + } + let cvar = ContextVarNode::from(self.idx); let independent = cvar.is_fundamental(analyzer)?; @@ -260,6 +361,17 @@ impl RangeElem for Reference { return Ok(*simp_min.clone()); } + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Reference(ref arenaized) = *t { + if arenaized.flattened_min.is_some() { + tracing::trace!("reference simplify minimize cache hit"); + return Ok(*arenaized.flattened_min.clone().unwrap()) + } + } + } + } + let cvar = ContextVarNode::from(self.idx); if cvar.is_fundamental(analyzer)? { Ok(Elem::Reference(Reference::new( @@ -272,24 +384,27 @@ impl RangeElem for Reference { } fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + self.arenaize(g)?; if self.maximized.is_none() { let cvar = ContextVarNode::from(self.idx); cvar.cache_eval_range(g)?; - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); - let mut s = Elem::Reference(self.clone()); - s.arenaize(g)?; + let max = self.maximize(g)?; + Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(true, &max, g); + self.maximized = Some(MinMaxed::Maximized(Box::new(max))); } Ok(()) } fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + self.arenaize(g)?; if self.minimized.is_none() { let cvar = ContextVarNode::from(self.idx); cvar.cache_eval_range(g)?; - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); - let mut s = Elem::Reference(self.clone()); - s.arenaize(g)?; + let min = self.minimize(g)?; + Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(false, &min, g); + self.minimized = Some(MinMaxed::Minimized(Box::new(min))); } + Ok(()) } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index b8df6666..23911e4c 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -17,8 +17,24 @@ impl ExecOp for RangeExpr { maximize: bool, analyzer: &impl GraphBackend, ) -> Result, Self::GraphError> { + let idx = self.arena_idx(analyzer); + if let Some(idx) = idx { + if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Elem::Expr(expr) = &*t { + if maximize { + if let Some(MinMaxed::Maximized(max)) = &expr.maximized { + return Ok(*max.clone()) + } + } else if let Some(MinMaxed::Minimized(min)) = &expr.minimized { + return Ok(*min.clone()) + } + } + } + } + let res = self.exec(self.spread(analyzer)?, maximize, analyzer)?; - if let Some(idx) = self.arena_idx(analyzer) { + + if let Some(idx) = idx { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { if let Elem::Expr(expr) = &mut *t { if maximize { @@ -77,15 +93,15 @@ impl ExecOp for RangeExpr { analyzer: &impl GraphBackend, ) -> Result, GraphError> { if maximize { - if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { - return Ok(*v) + if let Some(v) = &self.flattened_max { + return Ok(*v.clone()); } + } else if let Some(v) = &self.flattened_min { + return Ok(*v.clone()); } - if !maximize { - if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { - return Ok(*v) - } + if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { + return Ok(*v) } let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(analyzer)?; @@ -141,7 +157,7 @@ impl ExecOp for RangeExpr { }; finished = true; } - RangeOp::SetLength => { + RangeOp::SetLength => { ret = if maximize { Ok(lhs_max .range_set_length(&rhs_max) @@ -266,9 +282,17 @@ impl ExecOp for RangeExpr { GraphError, > { let lhs_min = self.lhs.minimize(analyzer)?; + self.lhs.set_arenaized_cache(false, &lhs_min, analyzer); + let lhs_max = self.lhs.maximize(analyzer)?; + self.lhs.set_arenaized_cache(true, &lhs_max, analyzer); + let rhs_min = self.rhs.minimize(analyzer)?; + self.rhs.set_arenaized_cache(false, &rhs_min, analyzer); + let rhs_max = self.rhs.maximize(analyzer)?; + self.rhs.set_arenaized_cache(true, &rhs_max, analyzer); + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } @@ -285,9 +309,17 @@ impl ExecOp for RangeExpr { GraphError, > { let lhs_min = self.lhs.simplify_minimize(analyzer)?; + self.lhs.set_arenaized_flattened(false, &lhs_min, analyzer); + let lhs_max = self.lhs.simplify_maximize(analyzer)?; + self.lhs.set_arenaized_flattened(true, &lhs_max, analyzer); + let rhs_min = self.rhs.simplify_minimize(analyzer)?; + self.rhs.set_arenaized_flattened(false, &rhs_min, analyzer); + let rhs_max = self.rhs.simplify_maximize(analyzer)?; + self.rhs.set_arenaized_flattened(true, &rhs_max, analyzer); + Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } @@ -363,7 +395,7 @@ impl ExecOp for RangeExpr { RangeOp::GetLength => { if maximize { let new = lhs_max.clone(); - let new_max = new.simplify_minimize(analyzer)?; + let new_max = new.simplify_maximize(analyzer)?; let res = new_max.range_get_length(); res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) } else { diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index adbb1520..4a5f0853 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -1,3 +1,4 @@ +use crate::FlattenedRange; use crate::{range::elem::RangeElem, GraphBackend}; use shared::NodeIdx; use std::borrow::Cow; @@ -52,11 +53,11 @@ pub trait Range { /// Set the range maximum fn set_range_max(&mut self, new: Self::ElemTy); /// Set the range exclusions - fn set_range_exclusions(&mut self, new: Vec) + fn set_range_exclusions(&mut self, new: Vec) where Self: std::marker::Sized; /// Add an exclusion value to the range - fn add_range_exclusion(&mut self, new: Self::ElemTy) + fn add_range_exclusion(&mut self, new: usize) where Self: std::marker::Sized; /// Replace a potential recursion causing node index with a new index @@ -79,19 +80,19 @@ pub trait Range { fn flattened_range<'a>( &'a mut self, analyzer: &mut impl GraphBackend, - ) -> Result, Self::GraphError> + ) -> Result, Self::GraphError> where Self: Sized + Clone; fn take_flattened_range( &mut self, analyzer: &mut impl GraphBackend, - ) -> Result + ) -> Result where Self: Sized; } -pub trait RangeEval>: Range { +pub trait RangeEval> { fn sat(&self, analyzer: &impl GraphBackend) -> bool; fn unsat(&self, analyzer: &impl GraphBackend) -> bool { !self.sat(analyzer) diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 3e24b0d0..53c3b5a6 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -12,14 +12,28 @@ use tracing::instrument; use std::{borrow::Cow, collections::BTreeMap}; +#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct FlattenedRange { + pub min: usize, + pub max: usize, + pub exclusions: Vec, +} + +impl From for SolcRange { + fn from(range: FlattenedRange) -> Self { + SolcRange::new(Elem::Arena(range.min), Elem::Arena(range.max), range.exclusions) + } +} + + #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct SolcRange { pub min: Elem, - pub min_cached: Option>, + pub min_cached: Option, pub max: Elem, - pub max_cached: Option>, - pub exclusions: Vec>, - pub flattened: Option>, + pub max_cached: Option, + pub exclusions: Vec, + pub flattened: Option, } impl AsDotStr for SolcRange { @@ -36,7 +50,7 @@ impl AsDotStr for SolcRange { .s, self.exclusions .iter() - .map(|excl| excl.to_range_string(false, analyzer).s) + .map(|excl| Elem::Arena(*excl).to_range_string(false, analyzer).s) .collect::>() .join(", ") ) @@ -80,7 +94,7 @@ impl SolcRange { Ok(deps) } - pub fn new(min: Elem, max: Elem, exclusions: Vec>) -> Self { + pub fn new(min: Elem, max: Elem, exclusions: Vec) -> Self { Self { min, min_cached: None, @@ -98,11 +112,9 @@ impl SolcRange { analyzer: &mut impl GraphBackend, ) { if let Some(ref mut flattened) = &mut self.flattened { - flattened - .min + Elem::Arena(flattened.min) .replace_dep(to_replace, replacement.clone(), analyzer); - flattened - .max + Elem::Arena(flattened.max) .replace_dep(to_replace, replacement.clone(), analyzer); } self.min @@ -541,17 +553,26 @@ impl SolcRange { Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) } - pub fn into_flattened_range(&mut self, analyzer: &mut impl GraphBackend) -> Result { + pub fn into_flattened_range(&mut self, analyzer: &mut impl GraphBackend) -> Result { if let Some(cached) = &self.flattened { - return Ok(*cached.clone()); + return Ok(cached.clone()); } - self.min.cache_flatten(analyzer)?; - self.max.cache_flatten(analyzer)?; - let simp_min = self.min.simplify_minimize(analyzer)?; - let simp_max = self.max.simplify_maximize(analyzer)?; - let flat_range = SolcRange::new(simp_min, simp_max, self.exclusions.clone()); - self.flattened = Some(Box::new(flat_range.clone())); + let mut min = Elem::Arena(analyzer.range_arena_idx_or_upsert(self.min.clone())); + let mut max = Elem::Arena(analyzer.range_arena_idx_or_upsert(self.max.clone())); + min.cache_flatten(analyzer)?; + max.cache_flatten(analyzer)?; + + self.min = min.clone(); + self.max = max.clone(); + + let simp_min = min.simplify_minimize(analyzer)?; + let simp_max = max.simplify_maximize(analyzer)?; + let min = analyzer.range_arena_idx_or_upsert(simp_min); + let max = analyzer.range_arena_idx_or_upsert(simp_max); + + let flat_range = FlattenedRange { min, max, exclusions: self.exclusions.clone() }; + self.flattened = Some(flat_range.clone()); Ok(flat_range) } @@ -574,24 +595,26 @@ impl Range for SolcRange { } fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - self.min.arenaize(analyzer)?; - self.max.arenaize(analyzer)?; + let min = std::mem::take(&mut self.min); + let max = std::mem::take(&mut self.max); + self.min = Elem::Arena(analyzer.range_arena_idx_or_upsert(min)); + self.max = Elem::Arena(analyzer.range_arena_idx_or_upsert(max)); if self.max_cached.is_none() { let max = self.range_max_mut(); max.cache_maximize(analyzer)?; - self.max_cached = Some(self.range_max().maximize(analyzer)?); + self.max_cached = Some(analyzer.range_arena_idx_or_upsert(self.range_max().maximize(analyzer)?)); } if self.min_cached.is_none() { let min = self.range_min_mut(); min.cache_minimize(analyzer)?; - self.min_cached = Some(self.range_min().minimize(analyzer)?); + self.min_cached = Some(analyzer.range_arena_idx_or_upsert(self.range_min().minimize(analyzer)?)); } Ok(()) } fn evaled_range_min(&self, analyzer: &impl GraphBackend) -> Result { if let Some(cached) = &self.min_cached { - Ok(cached.clone()) + Ok(Elem::Arena(*cached).dearenaize(analyzer).borrow().clone()) } else { self.range_min().minimize(analyzer) } @@ -599,7 +622,7 @@ impl Range for SolcRange { fn evaled_range_max(&self, analyzer: &impl GraphBackend) -> Result { if let Some(cached) = &self.max_cached { - Ok(cached.clone()) + Ok(Elem::Arena(*cached).dearenaize(analyzer).borrow().clone()) } else { self.range_max().maximize(analyzer) } @@ -623,7 +646,7 @@ impl Range for SolcRange { } fn range_exclusions(&self) -> Vec { - self.exclusions.clone() + self.exclusions.clone().into_iter().map(Elem::Arena).collect() } fn set_range_min(&mut self, new: Self::ElemTy) { self.min_cached = None; @@ -636,12 +659,12 @@ impl Range for SolcRange { self.max = new; } - fn add_range_exclusion(&mut self, new: Self::ElemTy) { + fn add_range_exclusion(&mut self, new: usize) { if !self.exclusions.contains(&new) { self.exclusions.push(new); } } - fn set_range_exclusions(&mut self, new: Vec) { + fn set_range_exclusions(&mut self, new: Vec) { self.exclusions = new; } fn filter_min_recursion( @@ -671,7 +694,7 @@ impl Range for SolcRange { fn flattened_range<'a>( &'a mut self, analyzer: &mut impl GraphBackend, - ) -> Result, Self::GraphError> + ) -> Result, Self::GraphError> where Self: Sized + Clone, { @@ -692,13 +715,13 @@ impl Range for SolcRange { fn take_flattened_range( &mut self, analyzer: &mut impl GraphBackend, - ) -> Result + ) -> Result where Self: Sized, { let taken = std::mem::take(&mut self.flattened); if let Some(flat) = taken { - Ok(*flat) + Ok(flat) } else { self.cache_flatten(analyzer)?; self.take_flattened_range(analyzer) @@ -779,3 +802,23 @@ impl RangeEval> for SolcRange { } } } + +impl RangeEval> for FlattenedRange { + fn sat(&self, analyzer: &impl GraphBackend) -> bool { + >::into(self.clone()).sat(analyzer) + } + fn unsat(&self, analyzer: &impl GraphBackend) -> bool { + !self.sat(analyzer) + } + fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + let other = >::into(other.clone()); + >::into(self.clone()).contains(&other, analyzer) + } + fn contains_elem(&self, other: &Elem, analyzer: &impl GraphBackend) -> bool { + >::into(self.clone()).contains_elem(other, analyzer) + } + fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + let other = >::into(other.clone()); + >::into(self.clone()).overlaps(&other, analyzer) + } +} diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 76153ee3..8a47b1c1 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -238,13 +238,13 @@ pub static LIA_OPS: &[RangeOp] = &[ ]; pub trait Atomize { - fn atoms_or_part(&self, analyzer: &impl GraphBackend) -> AtomOrPart; - fn atomize(&self, analyzer: &impl GraphBackend) -> Option; + fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart; + fn atomize(&self, analyzer: &mut impl GraphBackend) -> Option; } impl Atomize for Elem { #[tracing::instrument(level = "trace", skip_all)] - fn atoms_or_part(&self, analyzer: &impl GraphBackend) -> AtomOrPart { + fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart { match self { Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), @@ -305,16 +305,10 @@ impl Atomize for Elem { todo!("here4"); } (Elem::Concrete(_), Elem::Concrete(_)) => { + expr.clone().arenaize(analyzer); let res = expr .exec_op(true, analyzer) .unwrap(); - let ty = if DL_OPS.contains(&expr.op) { - OpType::DL - } else if CONST_OPS.contains(&expr.op) { - OpType::Const - } else { - OpType::Other - }; if res == Elem::Expr(expr.clone()) { AtomOrPart::Part(res) } else { @@ -343,7 +337,7 @@ impl Atomize for Elem { } #[tracing::instrument(level = "trace", skip_all)] - fn atomize(&self, analyzer: &impl GraphBackend) -> Option { + fn atomize(&self, analyzer: &mut impl GraphBackend) -> Option { use Elem::*; match self { @@ -359,7 +353,18 @@ impl Atomize for Elem { a.update_max_ty(); Some(a) } - Arena(_) => todo!(), + Arena(_) => { + match &*self.dearenaize(analyzer).borrow() { + e @ Expr(_) => { + let AtomOrPart::Atom(mut a) = e.atoms_or_part(analyzer) else { + return None; + }; + a.update_max_ty(); + Some(a) + } + _ => None + } + } } } } diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index d4969600..fa6ed146 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -97,9 +97,9 @@ impl BruteBinSearchSolver { dep.display_name(analyzer).unwrap() ); } - let r = range.flattened_range(analyzer)?; + let r: SolcRange = range.flattened_range(analyzer)?.into_owned().into(); atomic_idxs.extend(r.dependent_on(analyzer)); - ranges.insert(*dep, r.into_owned()); + ranges.insert(*dep, r); Ok(()) })?; diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index e9b5a67e..34bda3e2 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -60,7 +60,7 @@ pub struct DLSolveResult { } impl DLSolver { - pub fn new(mut constraints: Vec, analyzer: &impl GraphBackend) -> Self { + pub fn new(mut constraints: Vec, analyzer: &mut impl GraphBackend) -> Self { constraints.iter_mut().for_each(|c| { c.update_max_ty(); }); @@ -97,7 +97,7 @@ impl DLSolver { pub fn add_constraints( &mut self, constraints: Vec, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> BTreeMap>> { let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { @@ -190,13 +190,14 @@ impl DLSolver { .all(|constraint| constraint.ty == OpType::DL) }) }) + .collect::>() + .iter() .map(|constraint| { ( constraint.clone(), - Self::dl_atom_normalize(constraint, analyzer), + Self::dl_atom_normalize(constraint.clone(), analyzer), ) - }) - .collect::>>>() + }).collect::>>>() } pub fn dl_solvable_constraints(&self) -> Vec>> { @@ -515,7 +516,7 @@ impl DLSolver { /// Needed for running negative cycle check. Additionally, if we have an `OR`, we pub fn dl_atom_normalize( constraint: SolverAtom, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Vec> { // println!("normalizing: {}", constraint.into_expr_elem()); let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 0dcdd572..158380cd 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -42,7 +42,15 @@ impl GraphLike for Analyzer { &mut self.range_arena } - fn range_arena_idx_or_upsert(&mut self, mut elem: Self::RangeElem) -> usize { + fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { + if let Elem::Arena(idx) = elem { + Some(*idx) + } else { + self.range_arena().map.get(elem).copied() + } + } + + fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { // tracing::trace!("arenaizing: {}", elem); if let Elem::Arena(idx) = elem { return idx; @@ -50,7 +58,7 @@ impl GraphLike for Analyzer { if let Some(idx) = self.range_arena_idx(&elem) { let existing = &self.range_arena().ranges[idx]; - let Ok(existing) = existing.try_borrow() else { + let Ok(existing) = existing.try_borrow_mut() else { return idx; }; let (min_cached, max_cached) = existing.is_min_max_cached(self); @@ -664,6 +672,10 @@ impl GraphLike for G<'_> { panic!("Should not call this") } + fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { + panic!("Should not call this") + } + fn range_arena_idx_or_upsert(&mut self, _elem: Self::RangeElem) -> usize { panic!("Should not call this") } diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index 1dc0e7cf..963f87c6 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -1,493 +1,493 @@ -// contract Div { -// function div(uint256 x, uint256 y) public pure returns (uint256) { -// return x / y; -// } - -// function int_div(int256 x, int256 y) public pure returns (int256) { -// return x / y; -// } - -// function div_conc() public pure returns (uint256) { -// uint256 a1 = div(100, 1); -// require(a1 == 100); -// uint256 a2 = div(100, 2); -// require(a2 == 50); -// uint256 a3 = div(100, 4); -// require(a3 == 25); -// uint256 a4 = div(100, 8); -// require(a4 == 12); -// uint256 a5 = div(1000000000, 8); -// require(a5 == 125000000); -// uint256 a6 = div(1000000000, 16); -// require(a6 == 62500000); -// uint256 a7 = div(10000000000, 32); -// require(a7 == 312500000); -// uint256 a8 = div(100000000000000000000, 64); -// require(a8 == 1562500000000000000); -// uint256 a9 = div(100000000000000000000000000000000000, 128); -// require(a9 == 781250000000000000000000000000000); -// uint256 a10 = div(1, 255); -// require(a10 == 0); -// } - -// function int_div_conc() public pure { -// int256 a1 = int_div(100, 1); -// require(a1 == 100); -// int256 a2 = int_div(100, 2); -// require(a2 == 50); -// int256 a3 = int_div(100, 4); -// require(a3 == 25); -// int256 a4 = int_div(100, 8); -// require(a4 == 12); -// int256 a5 = int_div(1000000000, 8); -// require(a5 == 125000000); -// int256 a6 = int_div(1000000000, 16); -// require(a6 == 62500000); -// int256 a7 = int_div(10000000000, 32); -// require(a7 == 312500000); -// int256 a8 = int_div(100000000000000000000, 64); -// require(a8 == 1562500000000000000); -// int256 a9 = int_div(100000000000000000000000000000000000, 128); -// require(a9 == 781250000000000000000000000000000); -// int256 a10 = int_div(1, 255); -// require(a10 == 0); - -// int256 a11 = int_div(-100, 1); -// require(a11 == -100); -// int256 a12 = int_div(-100, 2); -// require(a12 == -50); -// int256 a13 = int_div(-100, 4); -// require(a13 == -25); -// int256 a14 = int_div(-100, 8); -// require(a14 == -12); -// int256 a15 = int_div(-1000000000, 8); -// require(a15 == -125000000); -// int256 a16 = int_div(-1000000000, 16); -// require(a16 == -62500000); -// int256 a17 = int_div(-10000000000, 32); -// require(a17 == -312500000); -// int256 a18 = int_div(-100000000000000000000, 64); -// require(a18 == -1562500000000000000); -// int256 a19 = int_div(-100000000000000000000000000000000000, 128); -// require(a19 == -781250000000000000000000000000000); -// int256 a20 = int_div(-1, 255); -// require(a20 == 0); - -// int256 a21 = int_div(-100, -1); -// require(a21 == 100); -// int256 a22 = int_div(-100, -2); -// require(a22 == 50); -// int256 a23 = int_div(-100, -4); -// require(a23 == 25); -// int256 a24 = int_div(-100, -8); -// require(a24 == 12); -// int256 a25 = int_div(-1000000000, -8); -// require(a25 == 125000000); -// int256 a26 = int_div(-1000000000, -16); -// require(a26 == 62500000); -// int256 a27 = int_div(-10000000000, -32); -// require(a27 == 312500000); -// int256 a28 = int_div(-100000000000000000000, -64); -// require(a28 == 1562500000000000000); -// int256 a29 = int_div(-100000000000000000000000000000000000, -128); -// require(a29 == 781250000000000000000000000000000); -// int256 a30 = int_div(-1, -255); -// require(a30 == 0); - -// int256 a31 = int_div(100, -1); -// require(a31 == -100); -// int256 a32 = int_div(100, -2); -// require(a32 == -50); -// int256 a33 = int_div(100, -4); -// require(a33 == -25); -// int256 a34 = int_div(100, -8); -// require(a34 == -12); -// int256 a35 = int_div(1000000000, -8); -// require(a35 == -125000000); -// int256 a36 = int_div(1000000000, -16); -// require(a36 == -62500000); -// int256 a37 = int_div(10000000000, -32); -// require(a37 == -312500000); -// int256 a38 = int_div(100000000000000000000, -64); -// require(a38 == -1562500000000000000); -// int256 a39 = int_div(100000000000000000000000000000000000, -128); -// require(a39 == -781250000000000000000000000000000); -// int256 a40 = int_div(1, -255); -// require(a40 == 0); -// } -// } - -// contract Mul { -// function mul(uint256 x, uint256 y) public pure returns (uint256) { -// return x * y; -// } - -// function int_mul(int256 x, int256 y) public pure returns (int256) { -// return x * y; -// } - -// function mul_conc() public pure returns (uint256) { -// uint256 a1 = mul(100, 1); -// require(a1 == 100); -// uint256 a2 = mul(100, 2); -// require(a2 == 200); -// uint256 a3 = mul(100, 4); -// require(a3 == 400); -// uint256 a4 = mul(100, 8); -// require(a4 == 800); -// uint256 a5 = mul(1000000000, 8); -// require(a5 == 8000000000); -// uint256 a6 = mul(1000000000, 16); -// require(a6 == 16000000000); -// uint256 a7 = mul(10000000000, 32); -// require(a7 == 320000000000); -// uint256 a8 = mul(100000000000000000000, 64); -// require(a8 == 6400000000000000000000); -// uint256 a9 = mul(100000000000000000000000000000000000, 128); -// require(a9 == 12800000000000000000000000000000000000); -// uint256 a10 = mul(1, 255); -// require(a10 == 255); -// } - -// function int_mul_conc() public pure { -// int256 a1 = int_mul(100, 1); -// require(a1 == 100); -// int256 a2 = int_mul(100, 2); -// require(a2 == 200); -// int256 a3 = int_mul(100, 4); -// require(a3 == 400); -// int256 a4 = int_mul(100, 8); -// require(a4 == 800); -// int256 a5 = int_mul(1000000000, 8); -// require(a5 == 8000000000); -// int256 a6 = int_mul(1000000000, 16); -// require(a6 == 16000000000); -// int256 a7 = int_mul(10000000000, 32); -// require(a7 == 320000000000); -// int256 a8 = int_mul(100000000000000000000, 64); -// require(a8 == 6400000000000000000000); -// int256 a9 = int_mul(100000000000000000000000000000000000, 128); -// require(a9 == 12800000000000000000000000000000000000); -// int256 a10 = int_mul(1, 255); -// require(a10 == 255); - -// int256 a11 = int_mul(-100, 1); -// require(a11 == -100); -// int256 a12 = int_mul(-100, 2); -// require(a12 == -200); -// int256 a13 = int_mul(-100, 4); -// require(a13 == -400); -// int256 a14 = int_mul(-100, 8); -// require(a14 == -800); -// int256 a15 = int_mul(-1000000000, 8); -// require(a15 == -8000000000); -// int256 a16 = int_mul(-1000000000, 16); -// require(a16 == -16000000000); -// int256 a17 = int_mul(-10000000000, 32); -// require(a17 == -320000000000); -// int256 a18 = int_mul(-100000000000000000000, 64); -// require(a18 == -6400000000000000000000); -// int256 a19 = int_mul(-100000000000000000000000000000000000, 128); -// require(a19 == -12800000000000000000000000000000000000); -// int256 a20 = int_mul(-1, 255); -// require(a20 == -255); - -// int256 a21 = int_mul(-100, -1); -// require(a21 == 100); -// int256 a22 = int_mul(-100, -2); -// require(a22 == 200); -// int256 a23 = int_mul(-100, -4); -// require(a23 == 400); -// int256 a24 = int_mul(-100, -8); -// require(a24 == 800); -// int256 a25 = int_mul(-1000000000, -8); -// require(a25 == 8000000000); -// int256 a26 = int_mul(-1000000000, -16); -// require(a26 == 16000000000); -// int256 a27 = int_mul(-10000000000, -32); -// require(a27 == 320000000000); -// int256 a28 = int_mul(-100000000000000000000, -64); -// require(a28 == 6400000000000000000000); -// int256 a29 = int_mul(-100000000000000000000000000000000000, -128); -// require(a29 == 12800000000000000000000000000000000000); -// int256 a30 = int_mul(-1, -255); -// require(a30 == 255); - -// int256 a31 = int_mul(100, -1); -// require(a31 == -100); -// int256 a32 = int_mul(100, -2); -// require(a32 == -200); -// int256 a33 = int_mul(100, -4); -// require(a33 == -400); -// int256 a34 = int_mul(100, -8); -// require(a34 == -800); -// int256 a35 = int_mul(1000000000, -8); -// require(a35 == -8000000000); -// int256 a36 = int_mul(1000000000, -16); -// require(a36 == -16000000000); -// int256 a37 = int_mul(10000000000, -32); -// require(a37 == -320000000000); -// int256 a38 = int_mul(100000000000000000000, -64); -// require(a38 == -6400000000000000000000); -// int256 a39 = int_mul(100000000000000000000000000000000000, -128); -// require(a39 == -12800000000000000000000000000000000000); -// int256 a40 = int_mul(1, -255); -// require(a40 == -255); -// } -// } - -// contract Add { -// function add(uint256 x, uint256 y) public pure returns (uint256) { -// return x + y; -// } - -// function int_add(int256 x, int256 y) public pure returns (int256) { -// return x + y; -// } - -// function add_conc() public pure returns (uint256) { -// uint256 a1 = add(100, 1); -// require(a1 == 101); -// uint256 a2 = add(100, 2); -// require(a2 == 102); -// uint256 a3 = add(100, 4); -// require(a3 == 104); -// uint256 a4 = add(100, 8); -// require(a4 == 108); -// uint256 a5 = add(1000000000, 8); -// require(a5 == 1000000008); -// uint256 a6 = add(1000000000, 16); -// require(a6 == 1000000016); -// uint256 a7 = add(10000000000, 32); -// require(a7 == 10000000032); -// uint256 a8 = add(100000000000000000000, 64); -// require(a8 == 100000000000000000064); -// uint256 a9 = add(100000000000000000000000000000000000, 128); -// require(a9 == 100000000000000000000000000000000128); -// uint256 a10 = add(1, 255); -// require(a10 == 256); -// } - -// function int_add_conc() public pure { -// int256 a1 = int_add(100, 1); -// require(a1 == 101); -// int256 a2 = int_add(100, 2); -// require(a2 == 102); -// int256 a3 = int_add(100, 4); -// require(a3 == 104); -// int256 a4 = int_add(100, 8); -// require(a4 == 108); -// int256 a5 = int_add(1000000000, 8); -// require(a5 == 1000000008); -// int256 a6 = int_add(1000000000, 16); -// require(a6 == 1000000016); -// int256 a7 = int_add(10000000000, 32); -// require(a7 == 10000000032); -// int256 a8 = int_add(100000000000000000000, 64); -// require(a8 == 100000000000000000064); -// int256 a9 = int_add(100000000000000000000000000000000000, 128); -// require(a9 == 100000000000000000000000000000000128); -// int256 a10 = int_add(1, 255); -// require(a10 == 256); - -// int256 a11 = int_add(-100, 1); -// require(a11 == -99); -// int256 a12 = int_add(-100, 2); -// require(a12 == -98); -// int256 a13 = int_add(-100, 4); -// require(a13 == -96); -// int256 a14 = int_add(-100, 8); -// require(a14 == -92); -// int256 a15 = int_add(-1000000000, 8); -// require(a15 == -999999992); -// int256 a16 = int_add(-1000000000, 16); -// require(a16 == -999999984); -// int256 a17 = int_add(-10000000000, 32); -// require(a17 == -9999999968); -// int256 a18 = int_add(-100000000000000000000, 64); -// require(a18 == -99999999999999999936); -// int256 a19 = int_add(-100000000000000000000000000000000000, 128); -// require(a19 == -99999999999999999999999999999999872); -// int256 a20 = int_add(-1, 255); -// require(a20 == 254); - -// int256 a21 = int_add(-100, -1); -// require(a21 == -101); -// int256 a22 = int_add(-100, -2); -// require(a22 == -102); -// int256 a23 = int_add(-100, -4); -// require(a23 == -104); -// int256 a24 = int_add(-100, -8); -// require(a24 == -108); -// int256 a25 = int_add(-1000000000, -8); -// require(a25 == -1000000008); -// int256 a26 = int_add(-1000000000, -16); -// require(a26 == -1000000016); -// int256 a27 = int_add(-10000000000, -32); -// require(a27 == -10000000032); -// int256 a28 = int_add(-100000000000000000000, -64); -// require(a28 == -100000000000000000064); -// int256 a29 = int_add(-100000000000000000000000000000000000, -128); -// require(a29 == -100000000000000000000000000000000128); -// int256 a30 = int_add(-1, -255); -// require(a30 == -256); - -// int256 a31 = int_add(100, -1); -// require(a31 == 99); -// int256 a32 = int_add(100, -2); -// require(a32 == 98); -// int256 a33 = int_add(100, -4); -// require(a33 == 96); -// int256 a34 = int_add(100, -8); -// require(a34 == 92); -// int256 a35 = int_add(1000000000, -8); -// require(a35 == 999999992); -// int256 a36 = int_add(1000000000, -16); -// require(a36 == 999999984); -// int256 a37 = int_add(10000000000, -32); -// require(a37 == 9999999968); -// int256 a38 = int_add(100000000000000000000, -64); -// require(a38 == 99999999999999999936); -// int256 a39 = int_add(100000000000000000000000000000000000, -128); -// require(a39 == 99999999999999999999999999999999872); -// int256 a40 = int_add(1, -255); -// require(a40 == -254); -// } -// } - -// contract Sub { -// function sub(uint256 x, uint256 y) public pure returns (uint256) { -// return x - y; -// } - -// function int_sub(int256 x, int256 y) public pure returns (int256) { -// return x - y; -// } - -// function sub_conc() public pure returns (uint256) { -// uint256 a1 = sub(100, 1); -// require(a1 == 99); -// uint256 a2 = sub(100, 2); -// require(a2 == 98); -// uint256 a3 = sub(100, 4); -// require(a3 == 96); -// uint256 a4 = sub(100, 8); -// require(a4 == 92); -// uint256 a5 = sub(1000000000, 8); -// require(a5 == 999999992); -// uint256 a6 = sub(1000000000, 16); -// require(a6 == 999999984); -// uint256 a7 = sub(10000000000, 32); -// require(a7 == 9999999968); -// uint256 a8 = sub(100000000000000000000, 64); -// require(a8 == 99999999999999999936); -// uint256 a9 = sub(100000000000000000000000000000000000, 128); -// require(a9 == 99999999999999999999999999999999872); -// } - -// function int_sub_conc() public pure { -// int256 a1 = int_sub(100, 1); -// require(a1 == 99); -// int256 a2 = int_sub(100, 2); -// require(a2 == 98); -// int256 a3 = int_sub(100, 4); -// require(a3 == 96); -// int256 a4 = int_sub(100, 8); -// require(a4 == 92); -// int256 a5 = int_sub(1000000000, 8); -// require(a5 == 999999992); -// int256 a6 = int_sub(1000000000, 16); -// require(a6 == 999999984); -// int256 a7 = int_sub(10000000000, 32); -// require(a7 == 9999999968); -// int256 a8 = int_sub(100000000000000000000, 64); -// require(a8 == 99999999999999999936); -// int256 a9 = int_sub(100000000000000000000000000000000000, 128); -// require(a9 == 99999999999999999999999999999999872); -// int256 a10 = int_sub(1, 255); -// require(a10 == -254); - -// int256 a11 = int_sub(-100, 1); -// require(a11 == -101); -// int256 a12 = int_sub(-100, 2); -// require(a12 == -102); -// int256 a13 = int_sub(-100, 4); -// require(a13 == -104); -// int256 a14 = int_sub(-100, 8); -// require(a14 == -108); -// int256 a15 = int_sub(-1000000000, 8); -// require(a15 == -1000000008); -// int256 a16 = int_sub(-1000000000, 16); -// require(a16 == -1000000016); -// int256 a17 = int_sub(-10000000000, 32); -// require(a17 == -10000000032); -// int256 a18 = int_sub(-100000000000000000000, 64); -// require(a18 == -100000000000000000064); -// int256 a19 = int_sub(-100000000000000000000000000000000000, 128); -// require(a19 == -100000000000000000000000000000000128); -// int256 a20 = int_sub(-1, 255); -// require(a20 == -256); - -// int256 a21 = int_sub(-100, -1); -// require(a21 == -99); -// int256 a22 = int_sub(-100, -2); -// require(a22 == -98); -// int256 a23 = int_sub(-100, -4); -// require(a23 == -96); -// int256 a24 = int_sub(-100, -8); -// require(a24 == -92); -// int256 a25 = int_sub(-1000000000, -8); -// require(a25 == -999999992); -// int256 a26 = int_sub(-1000000000, -16); -// require(a26 == -999999984); -// int256 a27 = int_sub(-10000000000, -32); -// require(a27 == -9999999968); -// int256 a28 = int_sub(-100000000000000000000, -64); -// require(a28 == -99999999999999999936); -// int256 a29 = int_sub(-100000000000000000000000000000000000, -128); -// require(a29 == -99999999999999999999999999999999872); -// int256 a30 = int_sub(-1, -255); -// require(a30 == 254); - -// int256 a31 = int_sub(100, -1); -// require(a31 == 101); -// int256 a32 = int_sub(100, -2); -// require(a32 == 102); -// int256 a33 = int_sub(100, -4); -// require(a33 == 104); -// int256 a34 = int_sub(100, -8); -// require(a34 == 108); -// int256 a35 = int_sub(1000000000, -8); -// require(a35 == 1000000008); -// int256 a36 = int_sub(1000000000, -16); -// require(a36 == 1000000016); -// int256 a37 = int_sub(10000000000, -32); -// require(a37 == 10000000032); -// int256 a38 = int_sub(100000000000000000000, -64); -// require(a38 == 100000000000000000064); -// int256 a39 = int_sub(100000000000000000000000000000000000, -128); -// require(a39 == 100000000000000000000000000000000128); -// int256 a40 = int_sub(1, -255); -// require(a40 == 256); -// } -// } +contract Div { + function div(uint256 x, uint256 y) public pure returns (uint256) { + return x / y; + } + + function int_div(int256 x, int256 y) public pure returns (int256) { + return x / y; + } + + function div_conc() public pure returns (uint256) { + uint256 a1 = div(100, 1); + require(a1 == 100); + uint256 a2 = div(100, 2); + require(a2 == 50); + uint256 a3 = div(100, 4); + require(a3 == 25); + uint256 a4 = div(100, 8); + require(a4 == 12); + uint256 a5 = div(1000000000, 8); + require(a5 == 125000000); + uint256 a6 = div(1000000000, 16); + require(a6 == 62500000); + uint256 a7 = div(10000000000, 32); + require(a7 == 312500000); + uint256 a8 = div(100000000000000000000, 64); + require(a8 == 1562500000000000000); + uint256 a9 = div(100000000000000000000000000000000000, 128); + require(a9 == 781250000000000000000000000000000); + uint256 a10 = div(1, 255); + require(a10 == 0); + } + + function int_div_conc() public pure { + int256 a1 = int_div(100, 1); + require(a1 == 100); + int256 a2 = int_div(100, 2); + require(a2 == 50); + int256 a3 = int_div(100, 4); + require(a3 == 25); + int256 a4 = int_div(100, 8); + require(a4 == 12); + int256 a5 = int_div(1000000000, 8); + require(a5 == 125000000); + int256 a6 = int_div(1000000000, 16); + require(a6 == 62500000); + int256 a7 = int_div(10000000000, 32); + require(a7 == 312500000); + int256 a8 = int_div(100000000000000000000, 64); + require(a8 == 1562500000000000000); + int256 a9 = int_div(100000000000000000000000000000000000, 128); + require(a9 == 781250000000000000000000000000000); + int256 a10 = int_div(1, 255); + require(a10 == 0); + + int256 a11 = int_div(-100, 1); + require(a11 == -100); + int256 a12 = int_div(-100, 2); + require(a12 == -50); + int256 a13 = int_div(-100, 4); + require(a13 == -25); + int256 a14 = int_div(-100, 8); + require(a14 == -12); + int256 a15 = int_div(-1000000000, 8); + require(a15 == -125000000); + int256 a16 = int_div(-1000000000, 16); + require(a16 == -62500000); + int256 a17 = int_div(-10000000000, 32); + require(a17 == -312500000); + int256 a18 = int_div(-100000000000000000000, 64); + require(a18 == -1562500000000000000); + int256 a19 = int_div(-100000000000000000000000000000000000, 128); + require(a19 == -781250000000000000000000000000000); + int256 a20 = int_div(-1, 255); + require(a20 == 0); + + int256 a21 = int_div(-100, -1); + require(a21 == 100); + int256 a22 = int_div(-100, -2); + require(a22 == 50); + int256 a23 = int_div(-100, -4); + require(a23 == 25); + int256 a24 = int_div(-100, -8); + require(a24 == 12); + int256 a25 = int_div(-1000000000, -8); + require(a25 == 125000000); + int256 a26 = int_div(-1000000000, -16); + require(a26 == 62500000); + int256 a27 = int_div(-10000000000, -32); + require(a27 == 312500000); + int256 a28 = int_div(-100000000000000000000, -64); + require(a28 == 1562500000000000000); + int256 a29 = int_div(-100000000000000000000000000000000000, -128); + require(a29 == 781250000000000000000000000000000); + int256 a30 = int_div(-1, -255); + require(a30 == 0); + + int256 a31 = int_div(100, -1); + require(a31 == -100); + int256 a32 = int_div(100, -2); + require(a32 == -50); + int256 a33 = int_div(100, -4); + require(a33 == -25); + int256 a34 = int_div(100, -8); + require(a34 == -12); + int256 a35 = int_div(1000000000, -8); + require(a35 == -125000000); + int256 a36 = int_div(1000000000, -16); + require(a36 == -62500000); + int256 a37 = int_div(10000000000, -32); + require(a37 == -312500000); + int256 a38 = int_div(100000000000000000000, -64); + require(a38 == -1562500000000000000); + int256 a39 = int_div(100000000000000000000000000000000000, -128); + require(a39 == -781250000000000000000000000000000); + int256 a40 = int_div(1, -255); + require(a40 == 0); + } +} + +contract Mul { + function mul(uint256 x, uint256 y) public pure returns (uint256) { + return x * y; + } + + function int_mul(int256 x, int256 y) public pure returns (int256) { + return x * y; + } + + function mul_conc() public pure returns (uint256) { + uint256 a1 = mul(100, 1); + require(a1 == 100); + uint256 a2 = mul(100, 2); + require(a2 == 200); + uint256 a3 = mul(100, 4); + require(a3 == 400); + uint256 a4 = mul(100, 8); + require(a4 == 800); + uint256 a5 = mul(1000000000, 8); + require(a5 == 8000000000); + uint256 a6 = mul(1000000000, 16); + require(a6 == 16000000000); + uint256 a7 = mul(10000000000, 32); + require(a7 == 320000000000); + uint256 a8 = mul(100000000000000000000, 64); + require(a8 == 6400000000000000000000); + uint256 a9 = mul(100000000000000000000000000000000000, 128); + require(a9 == 12800000000000000000000000000000000000); + uint256 a10 = mul(1, 255); + require(a10 == 255); + } + + function int_mul_conc() public pure { + int256 a1 = int_mul(100, 1); + require(a1 == 100); + int256 a2 = int_mul(100, 2); + require(a2 == 200); + int256 a3 = int_mul(100, 4); + require(a3 == 400); + int256 a4 = int_mul(100, 8); + require(a4 == 800); + int256 a5 = int_mul(1000000000, 8); + require(a5 == 8000000000); + int256 a6 = int_mul(1000000000, 16); + require(a6 == 16000000000); + int256 a7 = int_mul(10000000000, 32); + require(a7 == 320000000000); + int256 a8 = int_mul(100000000000000000000, 64); + require(a8 == 6400000000000000000000); + int256 a9 = int_mul(100000000000000000000000000000000000, 128); + require(a9 == 12800000000000000000000000000000000000); + int256 a10 = int_mul(1, 255); + require(a10 == 255); + + int256 a11 = int_mul(-100, 1); + require(a11 == -100); + int256 a12 = int_mul(-100, 2); + require(a12 == -200); + int256 a13 = int_mul(-100, 4); + require(a13 == -400); + int256 a14 = int_mul(-100, 8); + require(a14 == -800); + int256 a15 = int_mul(-1000000000, 8); + require(a15 == -8000000000); + int256 a16 = int_mul(-1000000000, 16); + require(a16 == -16000000000); + int256 a17 = int_mul(-10000000000, 32); + require(a17 == -320000000000); + int256 a18 = int_mul(-100000000000000000000, 64); + require(a18 == -6400000000000000000000); + int256 a19 = int_mul(-100000000000000000000000000000000000, 128); + require(a19 == -12800000000000000000000000000000000000); + int256 a20 = int_mul(-1, 255); + require(a20 == -255); + + int256 a21 = int_mul(-100, -1); + require(a21 == 100); + int256 a22 = int_mul(-100, -2); + require(a22 == 200); + int256 a23 = int_mul(-100, -4); + require(a23 == 400); + int256 a24 = int_mul(-100, -8); + require(a24 == 800); + int256 a25 = int_mul(-1000000000, -8); + require(a25 == 8000000000); + int256 a26 = int_mul(-1000000000, -16); + require(a26 == 16000000000); + int256 a27 = int_mul(-10000000000, -32); + require(a27 == 320000000000); + int256 a28 = int_mul(-100000000000000000000, -64); + require(a28 == 6400000000000000000000); + int256 a29 = int_mul(-100000000000000000000000000000000000, -128); + require(a29 == 12800000000000000000000000000000000000); + int256 a30 = int_mul(-1, -255); + require(a30 == 255); + + int256 a31 = int_mul(100, -1); + require(a31 == -100); + int256 a32 = int_mul(100, -2); + require(a32 == -200); + int256 a33 = int_mul(100, -4); + require(a33 == -400); + int256 a34 = int_mul(100, -8); + require(a34 == -800); + int256 a35 = int_mul(1000000000, -8); + require(a35 == -8000000000); + int256 a36 = int_mul(1000000000, -16); + require(a36 == -16000000000); + int256 a37 = int_mul(10000000000, -32); + require(a37 == -320000000000); + int256 a38 = int_mul(100000000000000000000, -64); + require(a38 == -6400000000000000000000); + int256 a39 = int_mul(100000000000000000000000000000000000, -128); + require(a39 == -12800000000000000000000000000000000000); + int256 a40 = int_mul(1, -255); + require(a40 == -255); + } +} + +contract Add { + function add(uint256 x, uint256 y) public pure returns (uint256) { + return x + y; + } + + function int_add(int256 x, int256 y) public pure returns (int256) { + return x + y; + } + + function add_conc() public pure returns (uint256) { + uint256 a1 = add(100, 1); + require(a1 == 101); + uint256 a2 = add(100, 2); + require(a2 == 102); + uint256 a3 = add(100, 4); + require(a3 == 104); + uint256 a4 = add(100, 8); + require(a4 == 108); + uint256 a5 = add(1000000000, 8); + require(a5 == 1000000008); + uint256 a6 = add(1000000000, 16); + require(a6 == 1000000016); + uint256 a7 = add(10000000000, 32); + require(a7 == 10000000032); + uint256 a8 = add(100000000000000000000, 64); + require(a8 == 100000000000000000064); + uint256 a9 = add(100000000000000000000000000000000000, 128); + require(a9 == 100000000000000000000000000000000128); + uint256 a10 = add(1, 255); + require(a10 == 256); + } + + function int_add_conc() public pure { + int256 a1 = int_add(100, 1); + require(a1 == 101); + int256 a2 = int_add(100, 2); + require(a2 == 102); + int256 a3 = int_add(100, 4); + require(a3 == 104); + int256 a4 = int_add(100, 8); + require(a4 == 108); + int256 a5 = int_add(1000000000, 8); + require(a5 == 1000000008); + int256 a6 = int_add(1000000000, 16); + require(a6 == 1000000016); + int256 a7 = int_add(10000000000, 32); + require(a7 == 10000000032); + int256 a8 = int_add(100000000000000000000, 64); + require(a8 == 100000000000000000064); + int256 a9 = int_add(100000000000000000000000000000000000, 128); + require(a9 == 100000000000000000000000000000000128); + int256 a10 = int_add(1, 255); + require(a10 == 256); + + int256 a11 = int_add(-100, 1); + require(a11 == -99); + int256 a12 = int_add(-100, 2); + require(a12 == -98); + int256 a13 = int_add(-100, 4); + require(a13 == -96); + int256 a14 = int_add(-100, 8); + require(a14 == -92); + int256 a15 = int_add(-1000000000, 8); + require(a15 == -999999992); + int256 a16 = int_add(-1000000000, 16); + require(a16 == -999999984); + int256 a17 = int_add(-10000000000, 32); + require(a17 == -9999999968); + int256 a18 = int_add(-100000000000000000000, 64); + require(a18 == -99999999999999999936); + int256 a19 = int_add(-100000000000000000000000000000000000, 128); + require(a19 == -99999999999999999999999999999999872); + int256 a20 = int_add(-1, 255); + require(a20 == 254); + + int256 a21 = int_add(-100, -1); + require(a21 == -101); + int256 a22 = int_add(-100, -2); + require(a22 == -102); + int256 a23 = int_add(-100, -4); + require(a23 == -104); + int256 a24 = int_add(-100, -8); + require(a24 == -108); + int256 a25 = int_add(-1000000000, -8); + require(a25 == -1000000008); + int256 a26 = int_add(-1000000000, -16); + require(a26 == -1000000016); + int256 a27 = int_add(-10000000000, -32); + require(a27 == -10000000032); + int256 a28 = int_add(-100000000000000000000, -64); + require(a28 == -100000000000000000064); + int256 a29 = int_add(-100000000000000000000000000000000000, -128); + require(a29 == -100000000000000000000000000000000128); + int256 a30 = int_add(-1, -255); + require(a30 == -256); + + int256 a31 = int_add(100, -1); + require(a31 == 99); + int256 a32 = int_add(100, -2); + require(a32 == 98); + int256 a33 = int_add(100, -4); + require(a33 == 96); + int256 a34 = int_add(100, -8); + require(a34 == 92); + int256 a35 = int_add(1000000000, -8); + require(a35 == 999999992); + int256 a36 = int_add(1000000000, -16); + require(a36 == 999999984); + int256 a37 = int_add(10000000000, -32); + require(a37 == 9999999968); + int256 a38 = int_add(100000000000000000000, -64); + require(a38 == 99999999999999999936); + int256 a39 = int_add(100000000000000000000000000000000000, -128); + require(a39 == 99999999999999999999999999999999872); + int256 a40 = int_add(1, -255); + require(a40 == -254); + } +} + +contract Sub { + function sub(uint256 x, uint256 y) public pure returns (uint256) { + return x - y; + } + + function int_sub(int256 x, int256 y) public pure returns (int256) { + return x - y; + } + + function sub_conc() public pure returns (uint256) { + uint256 a1 = sub(100, 1); + require(a1 == 99); + uint256 a2 = sub(100, 2); + require(a2 == 98); + uint256 a3 = sub(100, 4); + require(a3 == 96); + uint256 a4 = sub(100, 8); + require(a4 == 92); + uint256 a5 = sub(1000000000, 8); + require(a5 == 999999992); + uint256 a6 = sub(1000000000, 16); + require(a6 == 999999984); + uint256 a7 = sub(10000000000, 32); + require(a7 == 9999999968); + uint256 a8 = sub(100000000000000000000, 64); + require(a8 == 99999999999999999936); + uint256 a9 = sub(100000000000000000000000000000000000, 128); + require(a9 == 99999999999999999999999999999999872); + } + + function int_sub_conc() public pure { + int256 a1 = int_sub(100, 1); + require(a1 == 99); + int256 a2 = int_sub(100, 2); + require(a2 == 98); + int256 a3 = int_sub(100, 4); + require(a3 == 96); + int256 a4 = int_sub(100, 8); + require(a4 == 92); + int256 a5 = int_sub(1000000000, 8); + require(a5 == 999999992); + int256 a6 = int_sub(1000000000, 16); + require(a6 == 999999984); + int256 a7 = int_sub(10000000000, 32); + require(a7 == 9999999968); + int256 a8 = int_sub(100000000000000000000, 64); + require(a8 == 99999999999999999936); + int256 a9 = int_sub(100000000000000000000000000000000000, 128); + require(a9 == 99999999999999999999999999999999872); + int256 a10 = int_sub(1, 255); + require(a10 == -254); + + int256 a11 = int_sub(-100, 1); + require(a11 == -101); + int256 a12 = int_sub(-100, 2); + require(a12 == -102); + int256 a13 = int_sub(-100, 4); + require(a13 == -104); + int256 a14 = int_sub(-100, 8); + require(a14 == -108); + int256 a15 = int_sub(-1000000000, 8); + require(a15 == -1000000008); + int256 a16 = int_sub(-1000000000, 16); + require(a16 == -1000000016); + int256 a17 = int_sub(-10000000000, 32); + require(a17 == -10000000032); + int256 a18 = int_sub(-100000000000000000000, 64); + require(a18 == -100000000000000000064); + int256 a19 = int_sub(-100000000000000000000000000000000000, 128); + require(a19 == -100000000000000000000000000000000128); + int256 a20 = int_sub(-1, 255); + require(a20 == -256); + + int256 a21 = int_sub(-100, -1); + require(a21 == -99); + int256 a22 = int_sub(-100, -2); + require(a22 == -98); + int256 a23 = int_sub(-100, -4); + require(a23 == -96); + int256 a24 = int_sub(-100, -8); + require(a24 == -92); + int256 a25 = int_sub(-1000000000, -8); + require(a25 == -999999992); + int256 a26 = int_sub(-1000000000, -16); + require(a26 == -999999984); + int256 a27 = int_sub(-10000000000, -32); + require(a27 == -9999999968); + int256 a28 = int_sub(-100000000000000000000, -64); + require(a28 == -99999999999999999936); + int256 a29 = int_sub(-100000000000000000000000000000000000, -128); + require(a29 == -99999999999999999999999999999999872); + int256 a30 = int_sub(-1, -255); + require(a30 == 254); + + int256 a31 = int_sub(100, -1); + require(a31 == 101); + int256 a32 = int_sub(100, -2); + require(a32 == 102); + int256 a33 = int_sub(100, -4); + require(a33 == 104); + int256 a34 = int_sub(100, -8); + require(a34 == 108); + int256 a35 = int_sub(1000000000, -8); + require(a35 == 1000000008); + int256 a36 = int_sub(1000000000, -16); + require(a36 == 1000000016); + int256 a37 = int_sub(10000000000, -32); + require(a37 == 10000000032); + int256 a38 = int_sub(100000000000000000000, -64); + require(a38 == 100000000000000000064); + int256 a39 = int_sub(100000000000000000000000000000000000, -128); + require(a39 == 100000000000000000000000000000000128); + int256 a40 = int_sub(1, -255); + require(a40 == 256); + } +} contract AssignMath { - // function assignAdd(uint256 x) public pure { - // x += 10; - // } + function assignAdd(uint256 x) public pure { + x += 10; + } - // function assignSub(uint256 x) public pure { - // x -= 10; - // } + function assignSub(uint256 x) public pure { + x -= 10; + } - // function assignDiv(uint256 x) public pure { - // x /= 10; - // } + function assignDiv(uint256 x) public pure { + x /= 10; + } - // function assignMul(uint256 x) public pure { - // x *= 10; - // } + function assignMul(uint256 x) public pure { + x *= 10; + } function preincrement(uint256 x) public pure returns (uint256, uint256) { uint256 y = ++x; @@ -534,111 +534,111 @@ contract AssignMath { } } -// contract Math { -// function rmod(uint256 x, uint256 y) public pure returns (uint256) { -// return x % y; -// } - -// function rexp(uint256 x, uint256 y) public pure returns (uint256) { -// return x ** y; -// } - -// function int_rmod(int256 x, int256 y) public pure returns (int256) { -// return x % y; -// } - -// function int_rexp(int256 x, uint256 y) public pure returns (int256) { -// return x ** y; -// } -// } - -// contract Unchecked { -// function assemblyWrappingSub(uint256 a) public pure { -// assembly { -// a := sub(0, 100) -// } -// require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - -// int256 y = type(int256).min; -// assembly { -// a := sub(y, 100) -// } -// require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); -// } - -// function uncheckedSub(uint256 a) public pure { -// unchecked { -// a = 0 - 100; -// } -// require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); - -// int256 y = type(int256).min; -// unchecked { -// a = y - 100; -// } -// require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); -// } - -// function uncheckedSymbolicSub(uint256 a, uint256 b) public pure { -// unchecked { -// a -= 100; -// } -// } - -// function assemblyWrappingAdd(uint256 a) public pure { -// uint256 m = type(uint256).max; -// assembly { -// a := add(m, 100) -// } -// require(a == 99); -// a += (type(uint256).max - 99); -// require(a == type(uint256).max); -// } - -// function uncheckedAdd(uint256 a) public pure { -// unchecked { -// a = type(uint256).max + 100; -// } -// require(a == 99); -// a += (type(uint256).max - 99); -// require(a == type(uint256).max); -// } - -// function assemblyWrappingMul(uint256 a) public pure { -// uint256 m = type(uint128).max; -// assembly { -// a := mul(m, m) -// } -// require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); -// a /= 3; -// a *= 3; -// // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); -// } - -// function uncheckedMul(uint256 a) public pure { -// unchecked { -// a = type(uint256).max + 100; -// } -// require(a == 99); -// a += (type(uint256).max - 99); -// require(a == type(uint256).max); -// } - -// function symbUncheckedMul(int256 a, int b) public pure { -// unchecked { -// a = a * b; -// int c = a * a / a; -// int d = a * c * b; -// } - -// a = a * b; -// int c = a * a / a; -// int d = a * c * b; -// } - -// function asmSymbUncheckedMul(int256 a, int b) public pure { -// assembly { -// a := mul(a, b) -// } -// } -// } \ No newline at end of file +contract Mod { + function rmod(uint256 x, uint256 y) public pure returns (uint256) { + return x % y; + } + + function rexp(uint256 x, uint256 y) public pure returns (uint256) { + return x ** y; + } + + function int_rmod(int256 x, int256 y) public pure returns (int256) { + return x % y; + } + + function int_rexp(int256 x, uint256 y) public pure returns (int256) { + return x ** y; + } +} + +contract Unchecked { + function assemblyWrappingSub(uint256 a) public pure { + assembly { + a := sub(0, 100) + } + require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + int256 y = type(int256).min; + assembly { + a := sub(y, 100) + } + require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + } + + function uncheckedSub(uint256 a) public pure { + unchecked { + a = 0 - 100; + } + require(a == 115792089237316195423570985008687907853269984665640564039457584007913129639836); + + int256 y = type(int256).min; + unchecked { + a = y - 100; + } + require(a == 57896044618658097711785492504343953926634992332820282019728792003956564819868); + } + + function uncheckedSymbolicSub(uint256 a, uint256 b) public pure { + unchecked { + a -= 100; + } + } + + function assemblyWrappingAdd(uint256 a) public pure { + uint256 m = type(uint256).max; + assembly { + a := add(m, 100) + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } + + function uncheckedAdd(uint256 a) public pure { + unchecked { + a = type(uint256).max + 100; + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } + + function assemblyWrappingMul(uint256 a) public pure { + uint256 m = type(uint128).max; + assembly { + a := mul(m, m) + } + require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + a /= 3; + a *= 3; + // require(a == 115792089237316195423570985008687907852589419931798687112530834793049593217025); + } + + function uncheckedMul(uint256 a) public pure { + unchecked { + a = type(uint256).max + 100; + } + require(a == 99); + a += (type(uint256).max - 99); + require(a == type(uint256).max); + } + + function symbUncheckedMul(int256 a, int b) public pure { + unchecked { + a = a * b; + int c = a * a / a; + int d = a * c * b; + } + + a = a * b; + int c = a * a / a; + int d = a * c * b; + } + + function asmSymbUncheckedMul(int256 a, int b) public pure { + assembly { + a := mul(a, b) + } + } +} \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/repros/issue69.sol b/crates/pyrometer/tests/test_data/repros/issue69.sol index 232cf4a4..c653635c 100644 --- a/crates/pyrometer/tests/test_data/repros/issue69.sol +++ b/crates/pyrometer/tests/test_data/repros/issue69.sol @@ -1,11 +1,15 @@ -contract SymbolicTest { - // https://github.com/foundry-rs/foundry/issues/2851 - function backdoor(uint256 x) external pure { +contract Test { + function backdoor(uint256 x, uint256 y) external pure { uint256 number = 99; unchecked { uint256 z = x - 1; - if (z == 6912213124124531) { - number = 0; + y = y - 10 + z; + if (y == 69122131241245311234) { + if (z == 6912213124124531) { + number = 0; + } else { + number = 1; + } } else { number = 1; } diff --git a/crates/pyrometer/tests/test_data/repros/overflow2.sol b/crates/pyrometer/tests/test_data/repros/overflow2.sol new file mode 100644 index 00000000..cc284df5 --- /dev/null +++ b/crates/pyrometer/tests/test_data/repros/overflow2.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.8.0; + +library Math { + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + uint256 prod0; + uint256 prod1; + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + require(denominator > prod1); + + + uint256 twos = denominator & (~denominator + 1); + assembly { + twos := add(div(sub(0, twos), twos), 1) + } + + return 0; + } + } +} \ No newline at end of file diff --git a/crates/pyrometer/tests/test_data/viz/func_call.sol b/crates/pyrometer/tests/test_data/viz/func_call.sol index 2e114b10..44e0e697 100644 --- a/crates/pyrometer/tests/test_data/viz/func_call.sol +++ b/crates/pyrometer/tests/test_data/viz/func_call.sol @@ -1,13 +1,32 @@ -contract A { - uint256 storageVariable; - // uint256 public publicStorageVariable; - // uint256 constant const; - - function funcA() public returns (uint256 ret) { - ret = funcB(storageVariable); - } - - function funcB(uint256 innerInput0) internal returns (uint256 ret) { - ret = innerInput0 + 10; - } -} \ No newline at end of file +// contract A { +// uint256 storageVariable; +// // uint256 public publicStorageVariable; +// // uint256 constant const; + +// function funcA() public returns (uint256 ret) { +// ret = funcB(storageVariable); +// } + +// function funcB(uint256 innerInput0) internal returns (uint256 ret) { +// ret = innerInput0 + 10; +// } +// } + +contract InvariantBreaker { + bool public flag0 = true; + bool public flag1 = true; + + function set0(int256 val) public returns (bool) { + if (val % 100 == 0) { + flag0 = false; + } + return flag0; + } + + function set1(int256 val) public returns (bool) { + if (val % 10 == 0 && !flag0) { + flag1 = false; + } + return flag1; + } +} diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index f1ace007..69853082 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -35,11 +35,6 @@ pub trait GraphLike { /// Add a node to the graph fn add_node(&mut self, node: impl Into) -> NodeIdx { let res = self.graph_mut().add_node(node.into()); - // if res == 81.into() { - // panic!("here"); - // } else { - // res - // } res } /// Get a reference to a node in the graph @@ -68,9 +63,7 @@ pub trait GraphLike { fn range_arena(&self) -> &RangeArena; fn range_arena_mut(&mut self) -> &mut RangeArena; - fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { - self.range_arena().map.get(elem).copied() - } + fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option; fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize; } diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index 90dc99cc..85fdd179 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -4,7 +4,7 @@ use crate::{ }; use graph::{ - elem::Elem, + elem::{RangeElem, Elem}, nodes::{ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, GraphError, Node, }; @@ -131,7 +131,17 @@ pub trait Assign: AnalyzerBackend + Sized Elem::from(rhs_cvar.latest_version(self)), ); - let new_lhs = self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)?; + + + let needs_forcible = new_lower_bound.depends_on(lhs_cvar, &mut vec![], self).into_expr_err(loc)? + || new_upper_bound.depends_on(lhs_cvar, &mut vec![], self).into_expr_err(loc)?; + + let new_lhs = if needs_forcible { + self.advance_var_in_ctx_forcible(lhs_cvar.latest_version(self), loc, ctx, true)? + } else { + self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)? + }; + new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = rhs_cvar.tmp_of(self).into_expr_err(loc)?; if lhs_cvar.is_storage(self).into_expr_err(loc)? { diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 39a719b6..ba084aaf 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -720,6 +720,8 @@ pub trait BinOp: AnalyzerBackend + Sized { .set_range_min(self, expr.clone()) .into_expr_err(loc)?; out_var.set_range_max(self, expr).into_expr_err(loc)?; + + self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; ctx.push_expr(ExprRet::Single(out_var.into()), self) .into_expr_err(loc)?; Ok(()) diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index d3bc7140..9fd53e3b 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -192,7 +192,7 @@ pub trait Cmp: AnalyzerBackend + Sized { .ref_range(self) .into_expr_err(loc)? .expect("No lhs range") - .range_exclusions(); + .exclusions.clone(); SolcRange::new(elem.clone(), elem, exclusions) }; diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 502fb060..08b14019 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -102,7 +102,7 @@ pub trait CallerHelper: AnalyzerBackend + self.add_if_err(res); let res = node .latest_version(self) - .try_set_range_exclusions(self, r.exclusions) + .try_set_range_exclusions(self, r.exclusions.clone()) .into_expr_err(loc); self.add_if_err(res); } @@ -525,7 +525,7 @@ pub trait CallerHelper: AnalyzerBackend + let res = new_input .set_range_exclusions( analyzer, - updated_var_range.range_exclusions(), + updated_var_range.exclusions.clone(), ) .into_expr_err(loc); let _ = analyzer.add_if_err(res); @@ -572,7 +572,7 @@ pub trait CallerHelper: AnalyzerBackend + let _ = new_inheritor_var .set_range_max(analyzer, r.range_max().into_owned()); let _ = new_inheritor_var - .set_range_exclusions(analyzer, r.range_exclusions()); + .set_range_exclusions(analyzer, r.exclusions.clone()); } } else { let new_in_inheritor = diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs index 4542c45c..14cd80ec 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -22,28 +22,7 @@ pub trait AddressCaller: AnalyzerBackend + ) -> Result<(), ExprErr> { match &*func_name { "delegatecall" | "staticcall" | "call" => { - // TODO: Check if we have the code for the address - // if we dont, model it as a unrestricted call that can make other calls - ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; - // TODO: try to be smarter based on the address input - let booln = self.builtin_or_add(Builtin::Bool); - let bool_cvar = - ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; - let bool_node = self.add_node(Node::ContextVar(bool_cvar)); - ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; - self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); - - let bn = self.builtin_or_add(Builtin::DynamicBytes); - let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; - let node = self.add_node(Node::ContextVar(cvar)); - ctx.add_var(node.into(), self).into_expr_err(loc)?; - self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); - ctx.push_expr( - ExprRet::Multi(vec![ExprRet::Single(bool_node), ExprRet::Single(node)]), - self, - ) - .into_expr_err(loc)?; - Ok(()) + self.external_call(&func_name, loc, ctx) } "code" => { // TODO: try to be smarter based on the address input @@ -76,4 +55,34 @@ pub trait AddressCaller: AnalyzerBackend + )), } } + + fn external_call( + &mut self, + _ty: &str, + loc: Loc, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + // TODO: Check if we have the code for the address + // if we dont, model it as a unrestricted call that can make other calls + ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; + // TODO: try to be smarter based on the address input + let booln = self.builtin_or_add(Builtin::Bool); + let bool_cvar = + ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; + let bool_node = self.add_node(Node::ContextVar(bool_cvar)); + ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; + self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); + + let bn = self.builtin_or_add(Builtin::DynamicBytes); + let cvar = ContextVar::new_from_builtin(loc, bn.into(), self).into_expr_err(loc)?; + let node = self.add_node(Node::ContextVar(cvar)); + ctx.add_var(node.into(), self).into_expr_err(loc)?; + self.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); + ctx.push_expr( + ExprRet::Multi(vec![ExprRet::Single(bool_node), ExprRet::Single(node)]), + self, + ) + .into_expr_err(loc)?; + Ok(()) + } } diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index 96da154f..03fe0b05 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,3 +1,4 @@ +use graph::SolcRange; use shared::AnalyzerLike; use graph::nodes::Concrete; use shared::NodeIdx; @@ -66,7 +67,7 @@ pub trait FuncJoiner: new_var.name = new_name.clone(); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); @@ -88,7 +89,7 @@ pub trait FuncJoiner: new_var.name = new_name.clone(); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); @@ -116,7 +117,7 @@ pub trait FuncJoiner: .try_for_each(|dep| { let mut new_var = dep.underlying(self)?.clone(); if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); @@ -175,7 +176,7 @@ pub trait FuncJoiner: new_var.name = new_name.clone(); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); @@ -199,7 +200,7 @@ pub trait FuncJoiner: new_var.name = new_name.clone(); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); @@ -227,7 +228,7 @@ pub trait FuncJoiner: .try_for_each(|dep| { let mut new_var = dep.underlying(self)?.clone(); if let Some(mut range) = new_var.ty.take_range() { - let mut range = range.take_flattened_range(self).unwrap(); + let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.clone(), self); }); diff --git a/crates/solc-expressions/src/member_access/builtin_access.rs b/crates/solc-expressions/src/member_access/builtin_access.rs index 04ad8278..d645d4f1 100644 --- a/crates/solc-expressions/src/member_access/builtin_access.rs +++ b/crates/solc-expressions/src/member_access/builtin_access.rs @@ -1,3 +1,4 @@ +use crate::func_call::intrinsic_call::AddressCaller; use crate::{ExprErr, IntoExprErr, LibraryAccess}; use graph::{ @@ -270,7 +271,7 @@ pub trait BuiltinAccess: let node = self.add_node(Node::Concrete(c)).into(); let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) .into_expr_err(loc)?; - var.name = format!("int{size}.min"); + var.name = format!("uint{size}.min"); var.display_name = var.name.clone(); var.is_tmp = true; var.is_symbolic = false; @@ -279,6 +280,11 @@ pub trait BuiltinAccess: self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); Ok(ExprRet::Single(cvar)) } + "call" | "delegatecall" | "staticcall" if size == 160 => { + let builtin_name = ident.name.split('(').collect::>()[0]; + let func_node = self.builtin_fn_or_maybe_add(builtin_name).unwrap(); + Ok(ExprRet::Single(func_node)) + } e => Err(ExprErr::MemberAccessNotFound( loc, format!( diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 15d2e626..08b4a528 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -873,7 +873,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(None); } - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + ctx.add_ctx_dep(conditional_cvar, self).into_expr_err(loc)?; } tracing::trace!( @@ -1014,7 +1014,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var.set_range_max(self, max).into_expr_err(loc)?; } else { // just add as an exclusion - nonconst_range.add_range_exclusion(elem); + let idx = self.range_arena_idx_or_upsert(elem); + nonconst_range.add_range_exclusion(idx); nonconst_var .set_range_exclusions(self, nonconst_range.exclusions) .into_expr_err(loc)?; @@ -1197,14 +1198,16 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_elem = Elem::from(new_rhs.latest_version(self)); // just add as an exclusion - lhs_range.add_range_exclusion(rhs_elem); + let idx = self.range_arena_idx_or_upsert(rhs_elem); + lhs_range.add_range_exclusion(idx); new_lhs .set_range_exclusions(self, lhs_range.exclusions) .into_expr_err(loc)?; let lhs_elem = Elem::from(new_lhs.latest_version(self)); // just add as an exclusion - rhs_range.add_range_exclusion(lhs_elem); + let idx = self.range_arena_idx_or_upsert(lhs_elem); + rhs_range.add_range_exclusion(idx); new_rhs .set_range_exclusions(self, rhs_range.exclusions) .into_expr_err(loc)?; From b703c005911959ce2e5c7f6a4bbaf7325354b815 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 18 Mar 2024 14:49:33 -0700 Subject: [PATCH 65/71] perf --- crates/graph/src/nodes/context/var/node.rs | 83 +++++++++++++------ .../graph/src/nodes/context/var/underlying.rs | 14 ++++ crates/graph/src/nodes/var_ty.rs | 1 + crates/graph/src/range/elem/elem_enum.rs | 5 +- crates/solc-expressions/src/array.rs | 5 ++ crates/solc-expressions/src/assign.rs | 7 ++ crates/solc-expressions/src/bin_op.rs | 21 ++++- crates/solc-expressions/src/cmp.rs | 6 ++ .../func_call/intrinsic_call/constructors.rs | 2 + crates/solc-expressions/src/func_call/join.rs | 72 +++++++++++++--- crates/solc-expressions/src/list.rs | 2 + .../src/member_access/list_access.rs | 2 + crates/solc-expressions/src/require.rs | 15 ++++ crates/solc-expressions/src/variable.rs | 2 + .../solc-expressions/src/yul/yul_builder.rs | 2 + 15 files changed, 199 insertions(+), 40 deletions(-) diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 967fad60..5284127e 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -309,41 +309,74 @@ impl ContextVarNode { .collect() } - pub fn dependent_on( + pub fn set_dependent_on( &self, - analyzer: &impl GraphBackend, - return_self: bool, - ) -> Result, GraphError> { - self.dependent_on_no_recursion(analyzer, &mut vec![*self], return_self) + analyzer: &mut impl GraphBackend, + ) -> Result<(), GraphError> { + let mut return_self = false; + let mut first_iter = true; + let mut stack = vec![*self]; + let mut result = vec![]; + + while let Some(node) = stack.pop() { + if result.contains(&node) { + continue; + } + + let underlying = node.underlying(analyzer)?; + if let Some(tmp) = underlying.tmp_of() { + stack.push(tmp.lhs); + if let Some(rhs) = tmp.rhs { + stack.push(rhs); + } + } else if return_self { + result.push(node); + } + + if first_iter { + first_iter = false; + return_self = true; + } + } + + self.underlying_mut(analyzer)?.dep_on = Some(result); + Ok(()) } - fn dependent_on_no_recursion( + pub fn dependent_on( &self, analyzer: &impl GraphBackend, - seen: &mut Vec, - return_self: bool, + mut return_self: bool, ) -> Result, GraphError> { - let underlying = self.underlying(analyzer)?; - if let Some(tmp) = underlying.tmp_of() { - let mut nodes = if !seen.contains(&tmp.lhs) { - seen.push(tmp.lhs); - tmp.lhs.dependent_on(analyzer, true)? - } else { - vec![] - }; + if let Some(dep_on) = &self.underlying(analyzer)?.dep_on { + return Ok(dep_on.to_vec()); + } + let mut first_iter = true; + let mut stack = vec![*self]; + let mut result = vec![]; - if let Some(rhs) = tmp.rhs { - if !seen.contains(&rhs) { - seen.push(rhs); - nodes.extend(rhs.dependent_on(analyzer, true)?); + while let Some(node) = stack.pop() { + if result.contains(&node) { + continue; + } + + let underlying = node.underlying(analyzer)?; + if let Some(tmp) = underlying.tmp_of() { + stack.push(tmp.lhs); + if let Some(rhs) = tmp.rhs { + stack.push(rhs); } + } else if return_self { + result.push(node); + } + + if first_iter { + first_iter = false; + return_self = true; } - Ok(nodes) - } else if return_self { - Ok(vec![*self]) - } else { - Ok(vec![]) } + + Ok(result) } pub fn graph_dependent_on( diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 76a29932..500ceda3 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -20,6 +20,7 @@ pub struct ContextVar { pub storage: Option, pub is_tmp: bool, pub tmp_of: Option, + pub dep_on: Option>, pub is_symbolic: bool, pub is_return: bool, pub ty: VarType, @@ -76,6 +77,7 @@ impl ContextVar { storage: None, is_tmp: true, tmp_of: None, + dep_on: None, is_symbolic: false, is_return: false, ty: VarType::Concrete(concrete_node), @@ -128,6 +130,7 @@ impl ContextVar { storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::User( @@ -154,6 +157,7 @@ impl ContextVar { storage: Some(StorageLocation::Memory(Loc::Implicit)), is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::User(TypeNode::Struct(struct_node), None), @@ -177,6 +181,7 @@ impl ContextVar { storage: Some(StorageLocation::Memory(Loc::Implicit)), is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::try_from_idx(analyzer, ty_node.0.into()).unwrap(), @@ -195,6 +200,7 @@ impl ContextVar { storage: None, is_tmp: true, tmp_of: None, + dep_on: None, is_symbolic: false, is_return: false, ty: VarType::try_from_idx(analyzer, bn_node.into()).unwrap(), @@ -490,6 +496,7 @@ impl ContextVar { storage, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty, @@ -517,6 +524,7 @@ impl ContextVar { storage: parent_var.storage, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty, @@ -541,6 +549,7 @@ impl ContextVar { storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::User( @@ -566,6 +575,7 @@ impl ContextVar { storage: Some(parent_storage), is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: index.underlying(analyzer)?.is_symbolic, is_return: false, ty: parent_var.dynamic_underlying_ty(analyzer)?, @@ -583,6 +593,7 @@ impl ContextVar { storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: false, is_return: false, ty: VarType::User(TypeNode::Func(func), None), @@ -602,6 +613,7 @@ impl ContextVar { storage: param.storage, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty, @@ -627,6 +639,7 @@ impl ContextVar { storage: ret.storage, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: true, ty, @@ -658,6 +671,7 @@ impl ContextVar { storage: ret.storage, is_tmp, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: true, ty, diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 6503713e..7faeaf02 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -146,6 +146,7 @@ impl VarNode { display_name: self.name(analyzer)?, storage: None, is_tmp: false, + dep_on: None, tmp_of: None, is_symbolic: true, is_return: false, diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index a34d292a..d35671a4 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -348,8 +348,9 @@ impl Elem { }, Elem::Null => {} Elem::Arena(_) => { - let s = self.dearenaize(analyzer).clone(); - s.borrow_mut().replace_dep(to_replace, replacement, analyzer); + let mut s = self.dearenaize(analyzer).borrow().clone(); + s.replace_dep(to_replace, replacement, analyzer); + *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(s)); } } } diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index a7994193..f0412805 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -209,6 +209,11 @@ pub trait Array: AnalyzerBackend + Sized { RangeOp::SetIndices, Some(index), )), + dep_on: { + let mut deps = parent.dependent_on(self, true).into_expr_err(loc)?; + deps.extend(index.dependent_on(self, true).into_expr_err(loc)?); + Some(deps) + }, is_symbolic: true, is_return: false, ty, diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index 85fdd179..567fec7c 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -144,6 +144,13 @@ pub trait Assign: AnalyzerBackend + Sized new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = rhs_cvar.tmp_of(self).into_expr_err(loc)?; + + if let Some(ref mut dep_on) = new_lhs.underlying_mut(self).into_expr_err(loc)?.dep_on { + dep_on.push(rhs_cvar) + } else { + new_lhs.set_dependent_on(self).into_expr_err(loc)?; + } + if lhs_cvar.is_storage(self).into_expr_err(loc)? { self.add_edge(new_lhs, rhs_cvar, Edge::Context(ContextEdge::StorageWrite)); } diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index ba084aaf..27d0924c 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -163,8 +163,16 @@ pub trait BinOp: AnalyzerBackend + Sized { let new_lhs = if assign { let new = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; - new.underlying_mut(self).into_expr_err(loc)?.tmp_of = + let underlying = new.underlying_mut(self).into_expr_err(loc)?; + underlying.tmp_of = Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); + + if let Some(ref mut dep_on) = underlying.dep_on { + dep_on.push(rhs_cvar) + } else { + new.set_dependent_on(self).into_expr_err(loc)?; + } + new } else { let mut new_lhs_underlying = ContextVar { @@ -188,6 +196,11 @@ pub trait BinOp: AnalyzerBackend + Sized { || rhs_cvar.is_symbolic(self).into_expr_err(loc)?, is_return: false, tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), + dep_on: { + let mut deps = lhs_cvar.dependent_on(self, true).into_expr_err(loc)?; + deps.extend(rhs_cvar.dependent_on(self, true).into_expr_err(loc)?); + Some(deps) + }, ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), }; @@ -575,6 +588,11 @@ pub trait BinOp: AnalyzerBackend + Sized { RangeOp::Gte, Some(zero_node.into()), )), + dep_on: { + let mut deps = tmp_rhs.dependent_on(self, true).into_expr_err(loc)?; + deps.push(zero_node.into()); + Some(deps) + }, is_symbolic: true, is_return: false, ty: VarType::BuiltIn( @@ -703,6 +721,7 @@ pub trait BinOp: AnalyzerBackend + Sized { storage: None, is_tmp: true, tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::BitNot, None)), + dep_on: Some(lhs_cvar.dependent_on(self, true).into_expr_err(loc)?), is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, is_return: false, ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index 9fd53e3b..b938617d 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -65,6 +65,7 @@ pub trait Cmp: AnalyzerBackend + Sized { storage: None, is_tmp: true, tmp_of: Some(TmpConstruction::new(lhs_cvar, RangeOp::Not, None)), + dep_on: Some(lhs_cvar.dependent_on(self, true).into_expr_err(loc)?), is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)?, is_return: false, ty: VarType::BuiltIn( @@ -221,6 +222,11 @@ pub trait Cmp: AnalyzerBackend + Sized { .into_expr_err(loc)?, is_return: false, tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), + dep_on: { + let mut deps = lhs_cvar.dependent_on(self, true).into_expr_err(loc)?; + deps.extend(rhs_cvar.dependent_on(self, true).into_expr_err(loc)?); + Some(deps) + }, ty: VarType::BuiltIn( BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), Some(range), diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index 9a01ba20..bcb5b329 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -54,6 +54,7 @@ pub trait ConstructorCaller: is_symbolic: false, is_return: false, tmp_of: None, + dep_on: None, ty: ty.expect("No type for node"), }; @@ -66,6 +67,7 @@ pub trait ConstructorCaller: storage: None, is_tmp: true, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: ContextVarNode::from(len_cvar) diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index 03fe0b05..adb03fcc 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,3 +1,4 @@ +use graph::AsDotStr; use graph::SolcRange; use shared::AnalyzerLike; use graph::nodes::Concrete; @@ -28,6 +29,7 @@ impl FuncJoiner for T where pub trait FuncJoiner: GraphBackend + AnalyzerBackend + Sized + JoinStatTracker { + #[tracing::instrument(level = "trace", skip_all)] fn join( &mut self, ctx: ContextNode, @@ -36,6 +38,7 @@ pub trait FuncJoiner: params: &[FunctionParamNode], func_inputs: &[ContextVarNode], ) -> Result { + tracing::trace!("Trying to join function: {}", func.name(self).into_expr_err(loc)?); // ensure no modifiers (for now) // if pure function: // grab requirements for context @@ -55,6 +58,7 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { + tracing::trace!("Joining function: {}", func.name(self).into_expr_err(loc)?); let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; let mut rets: Vec<_> = edges[0] .return_nodes(self) @@ -69,7 +73,7 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self).unwrap(); @@ -77,6 +81,12 @@ pub trait FuncJoiner: new_var.ty.set_range(range).unwrap(); } + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } + let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); @@ -91,13 +101,19 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self).unwrap(); new_var.ty.set_range(range).unwrap(); } + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } let new_field = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); @@ -119,13 +135,18 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self)?; new_var.ty.set_range(range)?; } + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -158,9 +179,11 @@ pub trait FuncJoiner: .into_expr_err(loc)?; self.add_completed_pure(true, false, false, edges[0]); } else { + tracing::trace!("Branching pure join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_pure(false, false, true, body_ctx); } } else { + tracing::trace!("Childless pure join: {}", func.name(self).into_expr_err(loc)?); let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; // 1. Create a new variable with name `.` // 2. Set the range to be the copy of the return's simplified range from the function @@ -178,7 +201,7 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self).unwrap(); @@ -186,6 +209,12 @@ pub trait FuncJoiner: new_var.ty.set_range(range).unwrap(); } + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } + let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); @@ -202,13 +231,19 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self).unwrap(); new_var.ty.set_range(range).unwrap(); } + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } let new_field = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); @@ -230,7 +265,7 @@ pub trait FuncJoiner: if let Some(mut range) = new_var.ty.take_range() { let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.clone(), self); + range.replace_dep(*replace, replacement.0.clone(), self); }); range.cache_eval(self)?; @@ -240,6 +275,13 @@ pub trait FuncJoiner: // TODO: the naming isn't correct here and we move variables around // in a dumb way + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + }); + } + let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); @@ -285,11 +327,14 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { + tracing::trace!("View join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_view(false, false, false, body_ctx); } else { + tracing::trace!("Branching view join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_view(false, false, true, body_ctx); } } else { + tracing::trace!("Childless view join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_view(false, true, false, body_ctx); } } @@ -302,11 +347,14 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { + tracing::trace!("Mut join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_mut(false, false, false, body_ctx); } else { + tracing::trace!("Branching mut join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_mut(false, false, true, body_ctx); } } else { + tracing::trace!("Childless mut join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_mut(false, true, false, body_ctx); } } @@ -320,9 +368,9 @@ pub trait FuncJoiner: loc: Loc, params: &[FunctionParamNode], func_inputs: &[ContextVarNode], - ) -> Result>, ExprErr> { + ) -> Result, ContextVarNode)>, ExprErr> { let inputs = ctx.input_variables(self); - let mut replacement_map = BTreeMap::default(); + let mut replacement_map: BTreeMap, ContextVarNode)> = BTreeMap::default(); params .iter() .zip(func_inputs.iter()) @@ -426,9 +474,9 @@ pub trait FuncJoiner: let mut replacement_field_as_elem = Elem::from(*replacement_field); replacement_field_as_elem.arenaize(self).unwrap(); if let Some(next) = field.next_version(self) { - replacement_map.insert(next.0.into(), replacement_field_as_elem.clone()); + replacement_map.insert(next.0.into(), (replacement_field_as_elem.clone(), *replacement_field)); } - replacement_map.insert(field.0.into(), replacement_field_as_elem); + replacement_map.insert(field.0.into(), (replacement_field_as_elem, *replacement_field)); } }); } @@ -438,9 +486,9 @@ pub trait FuncJoiner: replacement_as_elem.arenaize(self).into_expr_err(loc)?; if let Some(next) = correct_input.next_version(self) { - replacement_map.insert(next.0.into(), replacement_as_elem.clone()); + replacement_map.insert(next.0.into(), (replacement_as_elem.clone(), replacement)); } - replacement_map.insert(correct_input.0.into(), replacement_as_elem); + replacement_map.insert(correct_input.0.into(), (replacement_as_elem, replacement)); } Ok(()) })?; diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 332f451f..0544bd07 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -68,6 +68,7 @@ pub trait List: AnalyzerBackend + Sized { is_tmp: false, is_symbolic: false, tmp_of: None, + dep_on: None, is_return: false, ty, }; @@ -93,6 +94,7 @@ pub trait List: AnalyzerBackend + Sized { is_tmp: true, is_symbolic: false, tmp_of: None, + dep_on: None, is_return: false, ty, }; diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index d5d62ac8..adbbbb8a 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -167,6 +167,7 @@ pub trait ListAccess: AnalyzerBackend + Si storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::BuiltIn( @@ -233,6 +234,7 @@ pub trait ListAccess: AnalyzerBackend + Si storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::BuiltIn( diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 08b4a528..bd1ad4a1 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -519,6 +519,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { RangeOp::Or, Some(rhs_cvar), )), + dep_on: { + let mut deps = lhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?; + deps.extend(rhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?); + Some(deps) + }, ty: VarType::BuiltIn( analyzer.builtin_or_add(Builtin::Bool).into(), Some(range), @@ -802,6 +807,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { storage: None, is_tmp: true, tmp_of: Some(TmpConstruction::new(new_lhs, op, Some(new_rhs))), + dep_on: { + let mut deps = new_lhs.dependent_on(self, true).into_expr_err(loc)?; + deps.extend(new_rhs.dependent_on(self, true).into_expr_err(loc)?); + Some(deps) + }, is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? || new_rhs.is_symbolic(self).into_expr_err(loc)?, is_return: false, @@ -845,6 +855,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { RangeOp::Eq, Some(conditional_cvar), )), + dep_on: { + let mut deps = tmp_true.dependent_on(self, true).into_expr_err(loc)?; + deps.extend(conditional_cvar.dependent_on(self, true).into_expr_err(loc)?); + Some(deps) + }, is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? || new_rhs.is_symbolic(self).into_expr_err(loc)?, is_return: false, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 308255d7..1dcd2f75 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -172,6 +172,7 @@ pub trait Variable: AnalyzerBackend + Size is_tmp: false, is_symbolic: true, tmp_of: None, + dep_on: None, is_return: false, ty, }; @@ -199,6 +200,7 @@ pub trait Variable: AnalyzerBackend + Size is_tmp: false, is_symbolic: true, tmp_of: None, + dep_on: None, is_return: false, ty, }; diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 1a169940..2fdf9185 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -114,6 +114,7 @@ pub trait YulBuilder: storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::try_from_idx(analyzer, b_ty).unwrap(), @@ -421,6 +422,7 @@ pub trait YulBuilder: storage: None, is_tmp: false, tmp_of: None, + dep_on: None, is_symbolic: true, is_return: false, ty: VarType::BuiltIn( From 7e404bcf55d18b4b7aabfea215dca82818caf943 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Mon, 18 Mar 2024 14:50:31 -0700 Subject: [PATCH 66/71] lint --- crates/cli/src/main.rs | 24 +- crates/graph/src/nodes/builtin.rs | 11 +- crates/graph/src/nodes/concrete.rs | 7 +- crates/graph/src/nodes/context/node.rs | 14 +- crates/graph/src/nodes/context/querying.rs | 16 +- crates/graph/src/nodes/context/solving.rs | 14 +- crates/graph/src/nodes/context/typing.rs | 12 +- crates/graph/src/nodes/context/var/node.rs | 14 +- crates/graph/src/nodes/context/var/ranging.rs | 16 +- crates/graph/src/nodes/context/var/typing.rs | 17 +- .../graph/src/nodes/context/var/underlying.rs | 18 +- crates/graph/src/nodes/context/variables.rs | 26 +- crates/graph/src/nodes/context/versioning.rs | 15 +- crates/graph/src/nodes/contract_ty.rs | 8 +- crates/graph/src/nodes/err_ty.rs | 2 +- crates/graph/src/nodes/func_ty.rs | 48 +-- crates/graph/src/nodes/msg.rs | 4 +- crates/graph/src/nodes/struct_ty.rs | 2 +- crates/graph/src/nodes/ty_ty.rs | 5 +- crates/graph/src/nodes/var_ty.rs | 4 +- crates/graph/src/range/elem/concrete.rs | 2 - crates/graph/src/range/elem/elem_enum.rs | 133 ++++--- crates/graph/src/range/elem/elem_trait.rs | 12 +- crates/graph/src/range/elem/expr.rs | 119 +++--- crates/graph/src/range/elem/map_or_array.rs | 20 +- crates/graph/src/range/elem/mod.rs | 4 +- crates/graph/src/range/elem/reference.rs | 38 +- crates/graph/src/range/exec/exec_op.rs | 43 +-- .../graph/src/range/exec/mem_ops/mem_set.rs | 2 +- crates/graph/src/range/exec_traits.rs | 1 - crates/graph/src/range/solc_range.rs | 41 ++- crates/graph/src/solvers/atoms.rs | 28 +- crates/graph/src/solvers/brute.rs | 16 +- crates/graph/src/solvers/dl.rs | 11 +- crates/graph/src/var_type.rs | 13 +- crates/pyrometer/src/analyzer.rs | 8 +- crates/pyrometer/src/analyzer_backend.rs | 6 +- crates/pyrometer/src/builtin_fns.rs | 4 +- crates/pyrometer/src/graph_backend.rs | 18 +- crates/pyrometer/tests/helpers.rs | 5 +- crates/queries/src/lib.rs | 2 +- crates/shared/src/analyzer_like.rs | 55 ++- crates/shared/src/graph_like.rs | 9 +- crates/solc-expressions/src/assign.rs | 31 +- crates/solc-expressions/src/bin_op.rs | 8 +- crates/solc-expressions/src/cmp.rs | 3 +- .../src/context_builder/expr.rs | 5 +- .../src/context_builder/stmt.rs | 4 +- crates/solc-expressions/src/env.rs | 4 +- .../src/func_call/func_caller.rs | 11 +- .../solc-expressions/src/func_call/helper.rs | 6 +- .../src/func_call/intrinsic_call/address.rs | 14 +- .../src/func_call/intrinsic_call/types.rs | 15 +- crates/solc-expressions/src/func_call/join.rs | 348 ++++++++++++------ .../src/member_access/builtin_access.rs | 9 +- crates/solc-expressions/src/require.rs | 21 +- 56 files changed, 702 insertions(+), 644 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index fc7d4aa3..a473dc7c 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,4 +1,3 @@ -use graph::elem::RangeElem; use analyzers::{FunctionVarsBoundAnalyzer, ReportConfig, ReportDisplay}; use graph::{ nodes::{ContractNode, FunctionNode}, @@ -12,7 +11,7 @@ use shared::Search; use ariadne::sources; use clap::{ArgAction, Parser, ValueHint}; -use tracing_subscriber::{Registry, prelude::*}; +use tracing_subscriber::{prelude::*, Registry}; use std::{ collections::{BTreeMap, HashMap}, @@ -111,19 +110,18 @@ pub fn subscriber() { } pub fn tree_subscriber() { - let subscriber = Registry::default().with( - tracing_tree::HierarchicalLayer::default() - .with_indent_lines(true) - .with_indent_amount(2) - .with_thread_names(true) - // .with_thread_ids(true) - // .with_verbose_exit(true) - // .with_verbose_entry(true) - // .with_targets(true) - ) + let subscriber = Registry::default() + .with( + tracing_tree::HierarchicalLayer::default() + .with_indent_lines(true) + .with_indent_amount(2) + .with_thread_names(true), // .with_thread_ids(true) + // .with_verbose_exit(true) + // .with_verbose_entry(true) + // .with_targets(true) + ) .with(tracing_subscriber::filter::EnvFilter::from_default_env()); tracing::subscriber::set_global_default(subscriber).unwrap(); - } fn main() { diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index d0e63896..c9feff60 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -46,10 +46,7 @@ impl BuiltInNode { } /// Gets the maximum size version of this builtin, i.e. uint16 -> uint256 - pub fn max_size( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + pub fn max_size(&self, analyzer: &mut impl AnalyzerBackend) -> Result { let m = self.underlying(analyzer)?.max_size(); Ok(analyzer.builtin_or_add(m).into()) } @@ -57,7 +54,7 @@ impl BuiltInNode { /// Gets the underlying type of the dynamic builtin backing it. i.e. uint256[] -> uint256 pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { match self.underlying(analyzer)? { Builtin::Array(v_ty) | Builtin::SizedArray(_, v_ty) => { @@ -172,7 +169,7 @@ impl Builtin { /// `mapping (uint => MyType)`, we may not have parsed `MyType`, so we now try to resolve it pub fn unresolved_as_resolved( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { match self { Builtin::Array(n) => Ok(Builtin::Array(n.unresolved_as_resolved(analyzer)?)), @@ -253,7 +250,7 @@ impl Builtin { /// Try to convert from a [`Type`] to a Builtin pub fn try_from_ty( ty: Type, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Option { use Type::*; match ty { diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index 0dd25243..bd1c5ef3 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -26,10 +26,7 @@ impl ConcreteNode { } /// Creates a version of this concrete that is max size - pub fn max_size( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + pub fn max_size(&self, analyzer: &mut impl AnalyzerBackend) -> Result { let c = self.underlying(analyzer)?.max_size(); Ok(analyzer.add_node(Node::Concrete(c)).into()) } @@ -37,7 +34,7 @@ impl ConcreteNode { /// Gets the internal type of the dynamic that backs this. Panics if this is not a dynamic concrete pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let builtin = self.underlying(analyzer)?.dynamic_underlying_ty().unwrap(); let bn = analyzer.builtin_or_add(builtin); diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 1c1f7790..4a6fb6aa 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -27,10 +27,7 @@ impl ContextNode { } /// Gets the total context width - pub fn total_width( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + pub fn total_width(&self, analyzer: &mut impl AnalyzerBackend) -> Result { self.first_ancestor(analyzer)? .number_of_live_edges(analyzer) } @@ -48,7 +45,7 @@ impl ContextNode { /// Gets a mutable reference to the underlying context in the graph pub fn underlying_mut<'a>( &self, - analyzer: &'a mut (impl GraphBackend + AnalyzerBackend), + analyzer: &'a mut impl AnalyzerBackend, ) -> Result<&'a mut Context, GraphError> { match analyzer.node_mut(*self) { Node::Context(c) => Ok(c), @@ -92,7 +89,7 @@ impl ContextNode { &self, ret_stmt_loc: Loc, ret: ContextVarNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.ret.push((ret_stmt_loc, ret)); self.propogate_end(analyzer)?; @@ -100,10 +97,7 @@ impl ContextNode { } /// Propogate that this context has ended up the context graph - pub fn propogate_end( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { + pub fn propogate_end(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { let underlying = &mut self.underlying_mut(analyzer)?; let curr_live = underlying.number_of_live_edges; underlying.number_of_live_edges = 0; diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 8a4ac064..717289eb 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -12,7 +12,7 @@ impl ContextNode { /// Gets the associated contract for the function for the context pub fn associated_contract( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { Ok(self .associated_fn(analyzer)? @@ -23,7 +23,7 @@ impl ContextNode { /// Tries to get the associated function for the context pub fn maybe_associated_contract( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { Ok(self .associated_fn(analyzer)? @@ -33,7 +33,7 @@ impl ContextNode { /// Tries to get the associated source for the context pub fn maybe_associated_source( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Option { let context = self.underlying(analyzer).unwrap(); if let Some(src) = context.cache.associated_source { @@ -54,7 +54,7 @@ impl ContextNode { /// Tries to get the associated source unit part for the context pub fn associated_source_unit_part( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { if let Some(sup) = self .associated_fn(analyzer)? @@ -71,7 +71,7 @@ impl ContextNode { /// Gets visible functions pub fn visible_modifiers( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { // TODO: filter privates let Some(source) = self.maybe_associated_source(analyzer) else { @@ -142,7 +142,7 @@ impl ContextNode { /// Gets visible functions pub fn visible_funcs( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { // TODO: filter privates if let Some(vis) = &self.underlying(analyzer)?.cache.visible_funcs { @@ -188,7 +188,7 @@ impl ContextNode { /// Gets all visible functions pub fn source_funcs( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Vec { // TODO: filter privates let Some(source) = self.maybe_associated_source(analyzer) else { @@ -211,7 +211,7 @@ impl ContextNode { /// Gets all visible structs pub fn visible_structs( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { // TODO: filter privates if let Some(vis) = &self.underlying(analyzer)?.cache.visible_structs { diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 35f927bf..2c2ff5bc 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,5 +1,5 @@ -use crate::FlattenedRange; use crate::elem::Elem; +use crate::FlattenedRange; use crate::SolcRange; use crate::{ as_dot_str, @@ -30,7 +30,10 @@ impl ContextNode { } /// Get the dependencies as normalized solver atoms - pub fn dep_atoms(&self, analyzer: &mut impl GraphBackend) -> Result, GraphError> { + pub fn dep_atoms( + &self, + analyzer: &mut impl GraphBackend, + ) -> Result, GraphError> { let deps: Vec<_> = self.ctx_deps(analyzer)?; let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { @@ -78,7 +81,7 @@ impl ContextNode { pub fn add_ctx_dep( &self, dep: ContextVarNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { tracing::trace!( "Adding ctx dependency: {}, is_controllable: {}", @@ -91,7 +94,10 @@ impl ContextNode { // dep.cache_flattened_range(analyzer)?; let mut range = dep.range(analyzer)?.unwrap(); let r = range.flattened_range(analyzer)?.into_owned(); - tracing::trace!("flattened: {}", >::into(r.clone()).as_dot_str(analyzer)); + tracing::trace!( + "flattened: {}", + >::into(r.clone()).as_dot_str(analyzer) + ); // add the atomic constraint if let Some(atom) = Elem::Arena(r.min).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); diff --git a/crates/graph/src/nodes/context/typing.rs b/crates/graph/src/nodes/context/typing.rs index bd0de0bf..e8a56bda 100644 --- a/crates/graph/src/nodes/context/typing.rs +++ b/crates/graph/src/nodes/context/typing.rs @@ -47,7 +47,7 @@ impl ContextNode { pub fn is_fn_ext( &self, fn_node: FunctionNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { match fn_node.maybe_associated_contract(analyzer) { None => Ok(false), @@ -75,19 +75,13 @@ impl ContextNode { } /// Sets the context to use unchecked math - pub fn set_unchecked( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { + pub fn set_unchecked(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.unchecked = true; Ok(()) } /// Sets the context to use checked math - pub fn unset_unchecked( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { + pub fn unset_unchecked(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { self.underlying_mut(analyzer)?.unchecked = false; Ok(()) } diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 5284127e..4fcb102e 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -205,7 +205,10 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.tmp_of()) } - pub fn struct_to_fields(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn struct_to_fields( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { if self.ref_range(analyzer)?.is_none() { let fields = analyzer .graph() @@ -309,10 +312,7 @@ impl ContextVarNode { .collect() } - pub fn set_dependent_on( - &self, - analyzer: &mut impl GraphBackend, - ) -> Result<(), GraphError> { + pub fn set_dependent_on(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { let mut return_self = false; let mut first_iter = true; let mut stack = vec![*self]; @@ -335,7 +335,7 @@ impl ContextVarNode { if first_iter { first_iter = false; - return_self = true; + return_self = true; } } @@ -372,7 +372,7 @@ impl ContextVarNode { if first_iter { first_iter = false; - return_self = true; + return_self = true; } } diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 0cece95e..4a8b20e3 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -189,7 +189,7 @@ impl ContextVarNode { // #[tracing::instrument(level = "trace", skip_all)] pub fn set_range_min( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, mut new_min: Elem, ) -> Result<(), GraphError> { assert!(self.latest_version(analyzer) == *self); @@ -203,8 +203,6 @@ impl ContextVarNode { new_min.arenaize(analyzer)?; - - // new_min.cache_flatten(analyzer)?; // new_min.cache_minimize(analyzer)?; @@ -238,7 +236,7 @@ impl ContextVarNode { // #[tracing::instrument(level = "trace", skip_all)] pub fn set_range_max( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, mut new_max: Elem, ) -> Result<(), GraphError> { assert!(self.latest_version(analyzer) == *self); @@ -281,7 +279,7 @@ impl ContextVarNode { pub fn set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - mut new_exclusions: Vec, + new_exclusions: Vec, ) -> Result<(), GraphError> { tracing::trace!( "setting range exclusions for {}", @@ -297,7 +295,7 @@ impl ContextVarNode { // let new_exclusions = new_exclusions // .into_iter() // .map(|excl| analyzer.range_arena_idx_or_upsert(excl)) - // .collect(); + // .collect(); self.underlying_mut(analyzer)? .set_range_exclusions(new_exclusions, fallback)?; @@ -306,7 +304,7 @@ impl ContextVarNode { pub fn try_set_range_min( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, mut new_min: Elem, ) -> Result { assert!(self.latest_version(analyzer) == *self); @@ -337,7 +335,7 @@ impl ContextVarNode { pub fn try_set_range_max( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, mut new_max: Elem, ) -> Result { assert!(self.latest_version(analyzer) == *self); @@ -369,7 +367,7 @@ impl ContextVarNode { pub fn try_set_range_exclusions( &self, analyzer: &mut impl GraphBackend, - mut new_exclusions: Vec, + new_exclusions: Vec, ) -> Result { tracing::trace!( "setting range exclusions for: {}", diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 8b552ba9..5603b8b3 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -279,7 +279,7 @@ impl ContextVarNode { loc: Loc, ctx: ContextNode, cast_ty: Builtin, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let new_underlying = self .underlying(analyzer)? @@ -295,7 +295,7 @@ impl ContextVarNode { &self, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let new_underlying = self .underlying(analyzer)? @@ -315,7 +315,7 @@ impl ContextVarNode { pub fn cast_from( &self, other: &Self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let to_ty = other.ty(analyzer)?.clone(); self.cast_from_ty(to_ty, analyzer)?; @@ -325,7 +325,7 @@ impl ContextVarNode { pub fn literal_cast_from( &self, other: &Self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let to_ty = other.ty(analyzer)?.clone(); self.literal_cast_from_ty(to_ty, analyzer)?; @@ -448,7 +448,7 @@ impl ContextVarNode { pub fn literal_cast_from_ty( &self, to_ty: VarType, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { @@ -466,10 +466,7 @@ impl ContextVarNode { Ok(()) } - pub fn try_increase_size( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { + pub fn try_increase_size(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer)?; Ok(()) @@ -482,7 +479,7 @@ impl ContextVarNode { pub fn cast_exprs( &self, to_ty: &VarType, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, Elem)>, GraphError> { if let Some(to_range) = to_ty.range(analyzer)? { let mut min_expr = (*self) diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 500ceda3..5b7f86f3 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -63,7 +63,7 @@ impl ContextVar { loc: Loc, ctx: ContextNode, concrete_node: ConcreteNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let name = format!( "tmp_{}({})", @@ -89,7 +89,7 @@ impl ContextVar { loc: Loc, ctx: ContextNode, cast_ty: Builtin, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let mut new_tmp = self.clone(); new_tmp.loc = Some(loc); @@ -108,7 +108,7 @@ impl ContextVar { &self, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let mut new_tmp = self.clone(); new_tmp.loc = Some(loc); @@ -144,7 +144,7 @@ impl ContextVar { loc: Loc, struct_node: StructNode, ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -168,7 +168,7 @@ impl ContextVar { loc: Loc, ty_node: TyNode, ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { Ok(ContextVar { loc: Some(loc), @@ -535,7 +535,7 @@ impl ContextVar { } pub fn new_from_enum_variant( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ctx: ContextNode, loc: Loc, enum_node: EnumNode, @@ -560,7 +560,7 @@ impl ContextVar { } pub fn new_from_index( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, loc: Loc, parent_name: String, parent_display_name: String, @@ -583,7 +583,7 @@ impl ContextVar { } pub fn new_from_func( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, func: FunctionNode, ) -> Result { Ok(ContextVar { @@ -654,7 +654,7 @@ impl ContextVar { pub fn new_from_func_ret( ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ret: FunctionReturn, ) -> Result, GraphError> { let (is_tmp, name) = if let Some(name) = ret.name { diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index ee839759..476ef244 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -36,7 +36,7 @@ impl ContextNode { pub fn add_var( &self, var: ContextVarNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { // var.cache_range(analyzer)?; let name = var.name(analyzer)?; @@ -108,10 +108,7 @@ impl ContextNode { } /// Reads the current temporary counter and increments the counter - pub fn new_tmp( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + pub fn new_tmp(&self, analyzer: &mut impl AnalyzerBackend) -> Result { let context = self.underlying_mut(analyzer)?; let ret = context.tmp_var_ctr; context.tmp_var_ctr += 1; @@ -122,7 +119,7 @@ impl ContextNode { pub fn push_tmp_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; underlying_mut.tmp_expr.push(Some(expr_ret)); @@ -134,7 +131,7 @@ impl ContextNode { pub fn append_tmp_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; match underlying_mut.tmp_expr.pop() { @@ -174,7 +171,7 @@ impl ContextNode { pub fn pop_tmp_expr( &self, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; if let Some(Some(expr)) = underlying_mut.tmp_expr.pop() { @@ -189,7 +186,7 @@ impl ContextNode { pub fn push_expr( &self, expr_ret: ExprRet, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { tracing::trace!( "pushing: {}, existing: {:?}, path: {}", @@ -211,12 +208,9 @@ impl ContextNode { &self, expr: ExprRet, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { - tracing::trace!( - "moving expr to {}", - self.path(analyzer) - ); + tracing::trace!("moving expr to {}", self.path(analyzer)); match expr { ExprRet::SingleLiteral(var) => Ok(ExprRet::SingleLiteral( self.maybe_move_var(var.into(), loc, analyzer)?.into(), @@ -239,7 +233,7 @@ impl ContextNode { &self, var: ContextVarNode, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let var = var.latest_version(analyzer); if let Some(ctx) = var.maybe_ctx(analyzer) { @@ -273,7 +267,7 @@ impl ContextNode { pub fn pop_expr_latest( &self, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { let underlying_mut = self.underlying_mut(analyzer)?; if let Some(elem) = underlying_mut.expr_ret_stack.pop() { diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 8fda2c5c..714bc308 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -57,7 +57,7 @@ impl ContextNode { /// Gets the first ancestor of this context pub fn first_ancestor( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { if let Some(first_ancestor) = self.underlying(analyzer)?.cache.first_ancestor { Ok(first_ancestor) @@ -285,7 +285,7 @@ impl ContextNode { &self, w1: ContextNode, w2: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { assert!(matches!(analyzer.node(w1), Node::Context(_))); assert!(matches!(analyzer.node(w2), Node::Context(_))); @@ -315,7 +315,7 @@ impl ContextNode { pub fn set_child_call( &self, call: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { assert!(matches!(analyzer.node(call), Node::Context(_))); assert!(*self != call, "Tried to set child to self"); @@ -342,10 +342,7 @@ impl ContextNode { } /// Removes the child of this context - pub fn delete_child( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result<(), GraphError> { + pub fn delete_child(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { if let Some(child) = self.underlying(analyzer)?.child { match child { CallFork::Fork(w1, w2) => { @@ -366,7 +363,7 @@ impl ContextNode { /// parent contexts if all subcontexts of that context are killed pub fn kill( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, kill_loc: Loc, kill_kind: KilledKind, ) -> Result<(), GraphError> { @@ -412,7 +409,7 @@ impl ContextNode { /// Kills if and only if all subcontexts are killed pub fn end_if_all_forks_ended( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, kill_loc: Loc, kill_kind: KilledKind, ) -> Result<(), GraphError> { diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 87528211..85cdda7b 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -72,11 +72,7 @@ impl ContractNode { .collect() } - pub fn inherit( - &self, - inherits: Vec, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) { + pub fn inherit(&self, inherits: Vec, analyzer: &mut impl AnalyzerBackend) { let src = self.associated_source(analyzer); let all_contracts = analyzer.search_children_include_via( src.into(), @@ -184,7 +180,7 @@ impl ContractNode { pub fn funcs_mapping( &self, - analyzer: &(impl GraphBackend + Search + AnalyzerBackend), + analyzer: &(impl Search + AnalyzerBackend), ) -> BTreeMap { analyzer .search_children_depth(self.0.into(), &Edge::Func, 1, 0) diff --git a/crates/graph/src/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs index 2630b4f3..30007db0 100644 --- a/crates/graph/src/nodes/err_ty.rs +++ b/crates/graph/src/nodes/err_ty.rs @@ -96,7 +96,7 @@ impl From for Node { impl ErrorParam { pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, param: ErrorParameter, ) -> Self { ErrorParam { diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index a4db26ef..0fb4f98f 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -66,10 +66,7 @@ impl FunctionNode { } /// Gets an ordered list of modifiers for a given function - pub fn modifiers( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Vec { + pub fn modifiers(&self, analyzer: &mut impl AnalyzerBackend) -> Vec { if let Some(mods) = &self.underlying(analyzer).unwrap().cache.modifiers { mods.values().copied().collect() } else { @@ -168,7 +165,7 @@ impl FunctionNode { pub fn loc_specified_name( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { if let Some(con) = self.maybe_associated_contract(analyzer) { Ok(format!("{}.{}", con.name(analyzer)?, self.name(analyzer)?)) @@ -177,7 +174,7 @@ impl FunctionNode { } } - pub fn body_ctx(&self, analyzer: &mut (impl GraphBackend + AnalyzerBackend)) -> ContextNode { + pub fn body_ctx(&self, analyzer: &mut impl AnalyzerBackend) -> ContextNode { if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { body_ctx } else { @@ -197,10 +194,7 @@ impl FunctionNode { } } - pub fn maybe_body_ctx( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Option { + pub fn maybe_body_ctx(&self, analyzer: &mut impl AnalyzerBackend) -> Option { if let Some(body_ctx) = self.underlying(analyzer).unwrap().cache.body_ctx { Some(body_ctx) } else { @@ -221,7 +215,7 @@ impl FunctionNode { pub fn maybe_associated_contract( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Option { if let Some(maybe_contract) = self .underlying(analyzer) @@ -263,7 +257,7 @@ impl FunctionNode { pub fn maybe_associated_source_unit_part( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Option { if let Some(sup) = self .underlying(analyzer) @@ -304,10 +298,7 @@ impl FunctionNode { } } - pub fn associated_source( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> SourceUnitNode { + pub fn associated_source(&self, analyzer: &mut impl AnalyzerBackend) -> SourceUnitNode { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { src.into() } else { @@ -327,7 +318,7 @@ impl FunctionNode { pub fn maybe_associated_source( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Option { if let Some(src) = self.underlying(analyzer).unwrap().cache.associated_source { Some(src.into()) @@ -385,7 +376,7 @@ impl FunctionNode { pub fn set_params_and_ret( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { let underlying = self.underlying(analyzer)?.clone(); let mut params_strs = vec![]; @@ -445,14 +436,16 @@ impl FunctionNode { // // .filter(|edge| Edge::FunctionReturn == *edge.weight()) // // .map(|edge| FunctionReturnNode::from(edge.source())) // // .collect() - // // } + // // } // } - pub fn returns<'a>( - &self, - analyzer: &'a impl GraphBackend, - ) -> &'a [FunctionReturnNode] { - self.underlying(analyzer).unwrap().cache.returns.as_ref().unwrap() + pub fn returns<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a [FunctionReturnNode] { + self.underlying(analyzer) + .unwrap() + .cache + .returns + .as_ref() + .unwrap() } pub fn is_public_or_ext(&self, analyzer: &impl GraphBackend) -> Result { @@ -884,7 +877,7 @@ impl From for Node { impl FunctionParam { pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, param: Parameter, order: usize, ) -> Self { @@ -983,10 +976,7 @@ pub struct FunctionReturn { } impl FunctionReturn { - pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - param: Parameter, - ) -> Self { + pub fn new(analyzer: &mut impl AnalyzerBackend, param: Parameter) -> Self { FunctionReturn { loc: param.loc, ty: analyzer.parse_expr(¶m.ty, None), diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index 2b1cb310..e882503c 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -61,7 +61,7 @@ impl Msg { elem: &str, loc: Loc, ctx: ContextNode, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { let (node, name) = match elem { "data" => { @@ -181,7 +181,7 @@ impl Msg { }; let mut var = ContextVar::new_from_concrete(loc, ctx, node.into(), analyzer)?; - var.name = name.clone(); + var.name.clone_from(&name); var.display_name = name; var.is_tmp = false; var.is_symbolic = true; diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index c10596be..4eef093b 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -197,7 +197,7 @@ impl From for Node { impl Field { pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, var_def: VariableDeclaration, ) -> Field { let ty_idx = analyzer.parse_expr(&var_def.ty, None); diff --git a/crates/graph/src/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs index 95ff78c4..af658539 100644 --- a/crates/graph/src/nodes/ty_ty.rs +++ b/crates/graph/src/nodes/ty_ty.rs @@ -66,10 +66,7 @@ impl From for Node { } impl Ty { - pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ty: TypeDefinition, - ) -> Ty { + pub fn new(analyzer: &mut impl AnalyzerBackend, ty: TypeDefinition) -> Ty { Ty { loc: ty.loc, ty: analyzer.parse_expr(&ty.ty, None), diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 7faeaf02..4391952c 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -45,7 +45,7 @@ impl VarNode { pub fn parse_initializer( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, parent: NodeIdx, ) -> Result<(), GraphError> { if let Some(expr) = self.underlying(analyzer)?.initializer_expr.clone() { @@ -236,7 +236,7 @@ impl From for Node { impl Var { pub fn new( - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, var: VariableDefinition, in_contract: bool, ) -> Var { diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 97a91ec5..21fa678d 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,4 +1,3 @@ - use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{Elem, RangeElem}, @@ -7,7 +6,6 @@ use crate::{ use shared::NodeIdx; -use std::collections::BTreeMap; use std::hash::{Hash, Hasher}; use solang_parser::pt::Loc; diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs index d35671a4..3252a4c0 100644 --- a/crates/graph/src/range/elem/elem_enum.rs +++ b/crates/graph/src/range/elem/elem_enum.rs @@ -1,6 +1,4 @@ use crate::elem::MinMaxed; -use std::cell::RefCell; -use std::rc::Rc; use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::{ @@ -9,6 +7,8 @@ use crate::{ GraphBackend, GraphError, }; use solang_parser::pt::Loc; +use std::cell::RefCell; +use std::rc::Rc; use shared::{NodeIdx, RangeArenaIdx}; @@ -16,8 +16,8 @@ use ethers_core::types::I256; use tracing::instrument; use std::{ - hash::{Hash,Hasher}, collections::BTreeMap, + hash::{Hash, Hasher}, ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}, }; @@ -340,12 +340,15 @@ impl Elem { Elem::ConcreteDyn(d) => { d.len.replace_dep(to_replace, replacement.clone(), analyzer); let vals = std::mem::take(&mut d.val); - d.val = vals.into_iter().map(|(mut k, (mut v, op))| { - k.replace_dep(to_replace, replacement.clone(), analyzer); - v.replace_dep(to_replace, replacement.clone(), analyzer); - (k, (v, op)) - }).collect(); - }, + d.val = vals + .into_iter() + .map(|(mut k, (mut v, op))| { + k.replace_dep(to_replace, replacement.clone(), analyzer); + v.replace_dep(to_replace, replacement.clone(), analyzer); + (k, (v, op)) + }) + .collect(); + } Elem::Null => {} Elem::Arena(_) => { let mut s = self.dearenaize(analyzer).borrow().clone(); @@ -368,9 +371,7 @@ impl Elem { pub fn dearenaize(&self, analyzer: &impl GraphBackend) -> Rc> { match self { - Self::Arena(arena_idx) => { - analyzer.range_arena().ranges[*arena_idx].clone() - }, + Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone(), _ => unreachable!(), } } @@ -563,8 +564,12 @@ impl Elem { } } - pub fn arenaized_flattened(&self, max: bool, analyzer: &impl GraphBackend) -> Option>> { - if let Some(idx) = analyzer.range_arena_idx(self) { + pub fn arenaized_flattened( + &self, + max: bool, + analyzer: &impl GraphBackend, + ) -> Option>> { + if let Some(idx) = analyzer.range_arena_idx(self) { if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { match &*t { Elem::Expr(ref arenaized) => { @@ -588,15 +593,9 @@ impl Elem { arenaized.flattened_min.clone() } } - c @ Elem::Concrete(_) => { - Some(Box::new(c.clone())) - } - c @ Elem::Null => { - Some(Box::new(c.clone())) - } - a @ Elem::Arena(_) => { - a.arenaized_flattened(max, analyzer) - } + c @ Elem::Concrete(_) => Some(Box::new(c.clone())), + c @ Elem::Null => Some(Box::new(c.clone())), + a @ Elem::Arena(_) => a.arenaized_flattened(max, analyzer), } } else { None @@ -606,8 +605,13 @@ impl Elem { } } - pub fn set_arenaized_flattened(&self, max: bool, elem: &Elem, analyzer: &impl GraphBackend) { - if let Some(idx) = analyzer.range_arena_idx(self) { + pub fn set_arenaized_flattened( + &self, + max: bool, + elem: &Elem, + analyzer: &impl GraphBackend, + ) { + if let Some(idx) = analyzer.range_arena_idx(self) { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { match &mut *t { Elem::Expr(ref mut arenaized) => { @@ -633,13 +637,17 @@ impl Elem { } _ => {} } - } } } - pub fn set_arenaized_cache(&self, max: bool, elem: &Elem, analyzer: &impl GraphBackend) { - if let Some(idx) = analyzer.range_arena_idx(self) { + pub fn set_arenaized_cache( + &self, + max: bool, + elem: &Elem, + analyzer: &impl GraphBackend, + ) { + if let Some(idx) = analyzer.range_arena_idx(self) { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { match &mut *t { Elem::Expr(ref mut arenaized) => { @@ -665,7 +673,6 @@ impl Elem { } _ => {} } - } } } @@ -733,15 +740,13 @@ impl RangeElem for Elem { fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { match self { Self::Arena(_) => return Ok(()), - Self::Reference(d) => { - d.arenaize(analyzer)? - }, + Self::Reference(d) => d.arenaize(analyzer)?, Self::ConcreteDyn(d) => d.arenaize(analyzer)?, Self::Expr(expr) => { expr.arenaize(analyzer)?; } Self::Concrete(c) => c.arenaize(analyzer)?, - Self::Null => {}, + Self::Null => {} } let self_take = std::mem::take(self); @@ -819,7 +824,7 @@ impl RangeElem for Elem { // _ => {} // } Ok(res) - }, + } } } @@ -840,7 +845,7 @@ impl RangeElem for Elem { let dearenaized = self.dearenaize(analyzer); let (min, max) = { let Ok(t) = dearenaized.try_borrow() else { - return Ok(()) + return Ok(()); }; let min = t.flatten(false, analyzer)?; @@ -885,7 +890,7 @@ impl RangeElem for Elem { } else { false } - }, + } } } @@ -902,7 +907,7 @@ impl RangeElem for Elem { } else { (false, false) } - }, + } } } @@ -933,7 +938,10 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.recursive_dependent_on(analyzer), Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer), Self::Null => Ok(vec![]), - Self::Arena(_) => self.dearenaize(analyzer).borrow().recursive_dependent_on(analyzer), + Self::Arena(_) => self + .dearenaize(analyzer) + .borrow() + .recursive_dependent_on(analyzer), } } @@ -964,7 +972,10 @@ impl RangeElem for Elem { Self::Expr(expr) => expr.depends_on(var, seen, analyzer), Self::ConcreteDyn(d) => d.depends_on(var, seen, analyzer), Self::Null => Ok(false), - Self::Arena(_) => self.dearenaize(analyzer).borrow().depends_on(var, seen, analyzer), + Self::Arena(_) => self + .dearenaize(analyzer) + .borrow() + .depends_on(var, seen, analyzer), } } @@ -986,7 +997,9 @@ impl RangeElem for Elem { Self::Null => {} Self::Arena(_idx) => { let dearenaized = self.dearenaize(analyzer); - dearenaized.borrow_mut().filter_recursion(node_idx, new_idx, analyzer); + dearenaized + .borrow_mut() + .filter_recursion(node_idx, new_idx, analyzer); } } } @@ -1018,7 +1031,7 @@ impl RangeElem for Elem { let dearenaized = self.dearenaize(analyzer); let res = { let Ok(t) = dearenaized.try_borrow() else { - return Ok(self.clone()) + return Ok(self.clone()); }; t.maximize(analyzer)? }; @@ -1043,7 +1056,7 @@ impl RangeElem for Elem { assert!(max, "????"); res - }, + } }; Ok(res) } @@ -1076,7 +1089,7 @@ impl RangeElem for Elem { let dearenaized = self.dearenaize(analyzer); let res = { let Ok(t) = dearenaized.try_borrow() else { - return Ok(self.clone()) + return Ok(self.clone()); }; t.minimize(analyzer)? }; @@ -1100,7 +1113,7 @@ impl RangeElem for Elem { let (min, _max) = self.is_min_max_cached(analyzer); assert!(min, "????"); res - }, + } }; Ok(res) } @@ -1115,25 +1128,25 @@ impl RangeElem for Elem { match &*analyzer.range_arena().ranges[idx].borrow() { Reference(dy) => { if let Some(max) = &dy.flattened_max { - return Ok(*max.clone()) + return Ok(*max.clone()); } - }, + } c @ Concrete(_) => return Ok(c.clone()), ConcreteDyn(inner) => { if let Some(max) = &inner.flattened_max { - return Ok(*max.clone()) + return Ok(*max.clone()); } } Expr(expr) => { if let Some(max) = &expr.flattened_max { - return Ok(*max.clone()) + return Ok(*max.clone()); } - }, + } Null => return Ok(Elem::Null), _ => {} } } - + match self { Reference(dy) => dy.simplify_maximize(analyzer), Concrete(inner) => inner.simplify_maximize(analyzer), @@ -1148,7 +1161,7 @@ impl RangeElem for Elem { let res = expr.simplify_maximize(analyzer)?; expr.set_arenaized_flattened(true, res.clone(), analyzer); Ok(res) - }, + } }, Null => Ok(Elem::Null), Arena(_) => { @@ -1191,20 +1204,20 @@ impl RangeElem for Elem { match &*analyzer.range_arena().ranges[idx].borrow() { Reference(dy) => { if let Some(min) = &dy.flattened_min { - return Ok(*min.clone()) + return Ok(*min.clone()); } - }, + } c @ Concrete(_) => return Ok(c.clone()), ConcreteDyn(inner) => { if let Some(min) = &inner.flattened_min { - return Ok(*min.clone()) + return Ok(*min.clone()); } } Expr(expr) => { if let Some(min) = &expr.flattened_min { - return Ok(*min.clone()) + return Ok(*min.clone()); } - }, + } Null => return Ok(Elem::Null), _ => {} } @@ -1224,7 +1237,7 @@ impl RangeElem for Elem { let res = expr.simplify_minimize(analyzer)?; expr.set_arenaized_flattened(false, res.clone(), analyzer); Ok(res) - }, + } }, Null => Ok(Elem::Null), Arena(_) => { @@ -1273,7 +1286,7 @@ impl RangeElem for Elem { let max = expr.maximize(analyzer)?; self.set_arenaized_flattened(true, &max, analyzer); Ok(()) - }, + } }, Null => Ok(()), Arena(_idx) => { @@ -1281,7 +1294,7 @@ impl RangeElem for Elem { if let Ok(mut t) = dearenaized.try_borrow_mut() { t.cache_maximize(analyzer)?; } - + Ok(()) } } @@ -1306,7 +1319,7 @@ impl RangeElem for Elem { let min = expr.minimize(analyzer)?; self.set_arenaized_flattened(false, &min, analyzer); Ok(()) - }, + } }, Null => Ok(()), Arena(_idx) => { diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 1ee2bd19..7f5c13b3 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -6,8 +6,6 @@ use crate::{ use shared::NodeIdx; -use std::collections::BTreeMap; - pub trait RangeElem { type GraphError; /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables @@ -32,15 +30,9 @@ pub trait RangeElem { /// Uncaches the minimum and maximum fn uncache(&mut self); /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) - fn simplify_maximize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, Self::GraphError>; + fn simplify_maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) - fn simplify_minimize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, Self::GraphError>; + fn simplify_minimize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; /// Checks if two range elements are equal fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; /// Tries to compare the ordering of two range elements diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 87c379b6..4ce9abc6 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -12,8 +12,6 @@ use std::hash::Hasher; use ethers_core::types::U256; use shared::NodeIdx; -use std::collections::BTreeMap; - pub static SINGLETON_EQ_OPS: &[RangeOp] = &[ RangeOp::Eq, RangeOp::Neq, @@ -48,12 +46,9 @@ pub struct RangeExpr { pub rhs: Box>, } - impl PartialEq for RangeExpr { fn eq(&self, other: &Self) -> bool { - self.lhs == other.lhs - && self.rhs == other.rhs - && self.op == other.op + self.lhs == other.lhs && self.rhs == other.rhs && self.op == other.op } } impl Eq for RangeExpr {} @@ -107,9 +102,13 @@ impl RangeExpr { Elem::Arena(analyzer.range_arena_idx(&self.rhs)?), )); analyzer.range_arena_idx(&expr) - } + } - pub fn arenaized_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option> { + pub fn arenaized_cache( + &self, + max: bool, + analyzer: &impl GraphBackend, + ) -> Option> { if let Some(idx) = self.arena_idx(analyzer) { let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { return None; @@ -126,7 +125,11 @@ impl RangeExpr { None } - pub fn arenaized_flat_cache(&self, max: bool, analyzer: &impl GraphBackend) -> Option>> { + pub fn arenaized_flat_cache( + &self, + max: bool, + analyzer: &impl GraphBackend, + ) -> Option>> { if let Some(idx) = self.arena_idx(analyzer) { let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { return None; @@ -143,7 +146,12 @@ impl RangeExpr { None } - pub fn set_arenaized_flattened(&self, max: bool, elem: Elem, analyzer: &impl GraphBackend) { + pub fn set_arenaized_flattened( + &self, + max: bool, + elem: Elem, + analyzer: &impl GraphBackend, + ) { if let Some(idx) = self.arena_idx(analyzer) { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { let Elem::Expr(arenaized) = &mut *t else { @@ -158,7 +166,6 @@ impl RangeExpr { } } } - } impl RangeExpr { @@ -215,7 +222,7 @@ impl RangeElem for RangeExpr { } if let Some(arenaized) = self.arenaized_flat_cache(maximize, analyzer) { - return Ok(*arenaized) + return Ok(*arenaized); } Ok(Elem::Expr(RangeExpr::new( @@ -226,8 +233,7 @@ impl RangeElem for RangeExpr { } fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { - self.flattened_min.is_some() && self.flattened_max.is_some() - || { + self.flattened_min.is_some() && self.flattened_max.is_some() || { if let Some(idx) = self.arena_idx(analyzer) { if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { if let Elem::Expr(ref arenaized) = *t { @@ -260,7 +266,10 @@ impl RangeElem for RangeExpr { (false, false) } }; - (self.minimized.is_some() || arena_cached_min, self.maximized.is_some() || arena_cached_max) + ( + self.minimized.is_some() || arena_cached_min, + self.maximized.is_some() || arena_cached_max, + ) } fn range_ord( @@ -340,7 +349,7 @@ impl RangeElem for RangeExpr { Ok(*cached) } else if let Some(MinMaxed::Minimized(cached)) = self.arenaized_cache(false, analyzer) { Ok(*cached) - } else if self.op == RangeOp::SetIndices { + } else if self.op == RangeOp::SetIndices { self.simplify_exec_op(false, analyzer) } else { self.exec_op(false, analyzer) @@ -357,7 +366,7 @@ impl RangeElem for RangeExpr { } if let Some(arenaized) = self.arenaized_flat_cache(true, analyzer) { - return Ok(*arenaized) + return Ok(*arenaized); } let l = self.lhs.simplify_maximize(analyzer)?; @@ -368,8 +377,7 @@ impl RangeElem for RangeExpr { MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - let res = - RangeExpr::new(l, self.op, r).simplify_exec_op(true, analyzer)?; + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(true, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { @@ -397,7 +405,7 @@ impl RangeElem for RangeExpr { } if let Some(arenaized) = self.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized) + return Ok(*arenaized); } let l = self.lhs.simplify_minimize(analyzer)?; @@ -410,8 +418,7 @@ impl RangeElem for RangeExpr { MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(false, analyzer), MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { - let res = - RangeExpr::new(l, self.op, r).simplify_exec_op(false, analyzer)?; + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(false, analyzer)?; match res { Elem::Expr(expr) => { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { @@ -441,9 +448,9 @@ impl RangeElem for RangeExpr { let Elem::Expr(this) = this else { this.cache_flatten(analyzer)?; if let Some(t) = this.arenaized_flattened(false, analyzer) { - return Ok(*t) + return Ok(*t); } else { - return Ok(this.clone()) + return Ok(this.clone()); } }; @@ -452,19 +459,19 @@ impl RangeElem for RangeExpr { } if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized) + return Ok(*arenaized); } let l = this.lhs.simplify_minimize(analyzer)?; let r = this.rhs.simplify_minimize(analyzer)?; let collapsed = collapse(&l, this.op, &r, analyzer); let res = match collapsed { - MaybeCollapsed::Concretes(..) => RangeExpr::new(l, this.op, r).exec_op(false, analyzer), + MaybeCollapsed::Concretes(..) => { + RangeExpr::new(l, this.op, r).exec_op(false, analyzer) + } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { - - let res = - RangeExpr::new(l, this.op, r).simplify_exec_op(false, analyzer)?; + let res = RangeExpr::new(l, this.op, r).simplify_exec_op(false, analyzer)?; let idx = analyzer.range_arena_idx_or_upsert(res.clone()); match res { @@ -472,13 +479,15 @@ impl RangeElem for RangeExpr { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Concretes(..) => { let exec_res = expr.exec_op(false, analyzer)?; - Elem::Arena(idx).set_arenaized_flattened(false, &exec_res, analyzer); - return Ok(exec_res) - }, + Elem::Arena(idx) + .set_arenaized_flattened(false, &exec_res, analyzer); + return Ok(exec_res); + } MaybeCollapsed::Collapsed(collapsed) => { - Elem::Arena(idx).set_arenaized_flattened(false, &collapsed, analyzer); - return Ok(collapsed) - }, + Elem::Arena(idx) + .set_arenaized_flattened(false, &collapsed, analyzer); + return Ok(collapsed); + } _ => {} } Ok(Elem::Expr(expr)) @@ -499,9 +508,9 @@ impl RangeElem for RangeExpr { let Elem::Expr(this) = this else { this.cache_flatten(analyzer)?; if let Some(t) = this.arenaized_flattened(true, analyzer) { - return Ok(*t) + return Ok(*t); } else { - return Ok(this.clone()) + return Ok(this.clone()); } }; @@ -510,19 +519,19 @@ impl RangeElem for RangeExpr { } if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized) + return Ok(*arenaized); } let l = this.lhs.simplify_maximize(analyzer)?; let r = this.rhs.simplify_maximize(analyzer)?; let collapsed = collapse(&l, this.op, &r, analyzer); let res = match collapsed { - MaybeCollapsed::Concretes(..) => RangeExpr::new(l, this.op, r).exec_op(true, analyzer), + MaybeCollapsed::Concretes(..) => { + RangeExpr::new(l, this.op, r).exec_op(true, analyzer) + } MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), MaybeCollapsed::Not(..) => { - - let res = - RangeExpr::new(l, this.op, r).simplify_exec_op(true, analyzer)?; + let res = RangeExpr::new(l, this.op, r).simplify_exec_op(true, analyzer)?; let idx = analyzer.range_arena_idx_or_upsert(res.clone()); match res { @@ -530,13 +539,15 @@ impl RangeElem for RangeExpr { match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { MaybeCollapsed::Concretes(..) => { let exec_res = expr.exec_op(true, analyzer)?; - Elem::Arena(idx).set_arenaized_flattened(true, &exec_res, analyzer); - return Ok(exec_res) - }, + Elem::Arena(idx) + .set_arenaized_flattened(true, &exec_res, analyzer); + return Ok(exec_res); + } MaybeCollapsed::Collapsed(collapsed) => { - Elem::Arena(idx).set_arenaized_flattened(true, &collapsed, analyzer); - return Ok(collapsed) - }, + Elem::Arena(idx) + .set_arenaized_flattened(true, &collapsed, analyzer); + return Ok(collapsed); + } _ => {} } Ok(Elem::Expr(expr)) @@ -554,7 +565,7 @@ impl RangeElem for RangeExpr { if let Some(idx) = self.arena_idx(g) { if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { if arenaized.flattened_max.is_some() { - return Ok(()) + return Ok(()); } }; } else { @@ -574,7 +585,7 @@ impl RangeElem for RangeExpr { if let Some(idx) = self.arena_idx(g) { if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { if arenaized.flattened_min.is_some() { - return Ok(()) + return Ok(()); } }; } else { @@ -641,23 +652,23 @@ pub fn collapse<'a, 'b, 'c: 'a + 'b>( match collapse(&t, op, r, analyzer) { MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), } } else { MaybeCollapsed::Not(l, r) } - }, + } (l, Elem::Arena(_)) => { if let Ok(t) = r.dearenaize(analyzer).try_borrow() { match collapse(l, op, &t, analyzer) { MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e) + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), } } else { MaybeCollapsed::Not(l, r) } - }, + } (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), (Elem::Expr(expr), d @ Elem::Reference(_)) => { // try to collapse the expression diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index bcd350ea..b0aa3763 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -35,9 +35,7 @@ pub struct RangeDyn { impl PartialEq for RangeDyn { fn eq(&self, other: &Self) -> bool { - self.len == other.len - && self.val == other.val - && self.op_num == other.op_num + self.len == other.len && self.val == other.val && self.op_num == other.op_num } } impl Eq for RangeDyn {} @@ -348,8 +346,7 @@ impl RangeElem for RangeDyn { }) .collect(); let flat_max = self.flatten(true, analyzer)?; - let simplified_flat_max = - flat_max.simplify_maximize(analyzer)?; + let simplified_flat_max = flat_max.simplify_maximize(analyzer)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { @@ -364,8 +361,7 @@ impl RangeElem for RangeDyn { }) .collect(); let flat_min = self.flatten(false, analyzer)?; - let simplified_flat_min = - flat_min.simplify_minimize(analyzer)?; + let simplified_flat_min = flat_min.simplify_minimize(analyzer)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) @@ -411,10 +407,7 @@ impl RangeElem for RangeDyn { // We dont maximize the key so that any subsequent // `get_index` can find potential values let maximized = val.0.maximize(analyzer)?; - map.insert( - idx.simplify_maximize(analyzer)?, - (maximized, val.1), - ); + map.insert(idx.simplify_maximize(analyzer)?, (maximized, val.1)); } // map.into_iter().filter(|(k, (v, op))| { @@ -439,10 +432,7 @@ impl RangeElem for RangeDyn { // We dont minimize the key so that any subsequent // `get_index` can find potential values let minimized = val.0.minimize(analyzer)?; - map.insert( - idx.simplify_minimize(analyzer)?, - (minimized, val.1), - ); + map.insert(idx.simplify_minimize(analyzer)?, (minimized, val.1)); } // map.into_iter().filter(|(k, (v, op))| { diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index 19ac5c37..cfb54157 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -22,14 +22,14 @@ impl MinMaxed { pub fn maxed(self) -> Elem { match self { Self::Maximized(t) => *t, - _ => panic!("MinMaxed was min not max") + _ => panic!("MinMaxed was min not max"), } } pub fn mined(self) -> Elem { match self { Self::Minimized(t) => *t, - _ => panic!("MinMaxed was max not min") + _ => panic!("MinMaxed was max not min"), } } } diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 2a3940c2..0ac79c12 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -13,8 +13,6 @@ use shared::NodeIdx; use solang_parser::pt::Loc; -use std::collections::BTreeMap; - /// A dynamic range element value #[derive(Clone, Debug, Ord, PartialOrd)] pub struct Reference { @@ -43,7 +41,6 @@ impl PartialEq for Reference { } impl Eq for Reference {} - impl Reference { pub fn new(idx: NodeIdx) -> Self { Self { @@ -118,14 +115,13 @@ impl RangeElem for Reference { var: ContextVarNode, seen: &mut Vec, analyzer: &impl GraphBackend, - ) -> Result { + ) -> Result { let cvar = ContextVarNode::from(self.idx); if seen.contains(&cvar) { - return Ok(false) + return Ok(false); } - if cvar == var - || cvar.name(analyzer)? == var.name(analyzer)? && self.idx >= var.0.into() { + if cvar == var || cvar.name(analyzer)? == var.name(analyzer)? && self.idx >= var.0.into() { Ok(true) } else if let Some(range) = cvar.ref_range(analyzer)? { seen.push(cvar); @@ -169,9 +165,9 @@ impl RangeElem for Reference { } fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { - self.flattened_min.is_some() && self.flattened_max.is_some() - || { - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + self.flattened_min.is_some() && self.flattened_max.is_some() || { + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) + { if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { if let Elem::Reference(ref arenaized) = *t { arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() @@ -189,7 +185,8 @@ impl RangeElem for Reference { fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { let (arena_cached_min, arena_cached_max) = { - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) + { if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { if let Elem::Reference(ref arenaized) = *t { (arenaized.minimized.is_some(), arenaized.maximized.is_some()) @@ -203,7 +200,10 @@ impl RangeElem for Reference { (false, false) } }; - (self.minimized.is_some() || arena_cached_min, self.maximized.is_some() || arena_cached_max) + ( + self.minimized.is_some() || arena_cached_min, + self.maximized.is_some() || arena_cached_max, + ) } fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { @@ -215,7 +215,7 @@ impl RangeElem for Reference { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_max.is_some() { tracing::trace!("reference cache flatten hit"); - return Ok(()) + return Ok(()); } } } @@ -233,7 +233,7 @@ impl RangeElem for Reference { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_min.is_some() { tracing::trace!("reference cache flatten hit"); - return Ok(()) + return Ok(()); } } } @@ -334,7 +334,7 @@ impl RangeElem for Reference { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_max.is_some() { tracing::trace!("reference simplify maximize cache hit"); - return Ok(*arenaized.flattened_max.clone().unwrap()) + return Ok(*arenaized.flattened_max.clone().unwrap()); } } } @@ -348,8 +348,7 @@ impl RangeElem for Reference { cvar.global_first_version(analyzer).into(), ))) } else { - self.flatten(true, analyzer)? - .simplify_maximize(analyzer) + self.flatten(true, analyzer)?.simplify_maximize(analyzer) } } @@ -366,7 +365,7 @@ impl RangeElem for Reference { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_min.is_some() { tracing::trace!("reference simplify minimize cache hit"); - return Ok(*arenaized.flattened_min.clone().unwrap()) + return Ok(*arenaized.flattened_min.clone().unwrap()); } } } @@ -378,8 +377,7 @@ impl RangeElem for Reference { cvar.global_first_version(analyzer).into(), ))) } else { - self.flatten(false, analyzer)? - .simplify_minimize(analyzer) + self.flatten(false, analyzer)?.simplify_minimize(analyzer) } } diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 23911e4c..8de2986d 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -7,7 +7,6 @@ use crate::{ use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; - impl ExecOp for RangeExpr { type GraphError = GraphError; @@ -23,17 +22,17 @@ impl ExecOp for RangeExpr { if let Elem::Expr(expr) = &*t { if maximize { if let Some(MinMaxed::Maximized(max)) = &expr.maximized { - return Ok(*max.clone()) + return Ok(*max.clone()); } } else if let Some(MinMaxed::Minimized(min)) = &expr.minimized { - return Ok(*min.clone()) + return Ok(*min.clone()); } } } } let res = self.exec(self.spread(analyzer)?, maximize, analyzer)?; - + if let Some(idx) = idx { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { if let Elem::Expr(expr) = &mut *t { @@ -70,9 +69,9 @@ impl ExecOp for RangeExpr { if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { if let Elem::Expr(expr) = &mut *t { if maximize { - expr.maximized = self.maximized.clone(); + expr.maximized.clone_from(&self.maximized); } else { - expr.minimized = self.minimized.clone(); + expr.minimized.clone_from(&self.minimized); } } } @@ -101,7 +100,7 @@ impl ExecOp for RangeExpr { } if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { - return Ok(*v) + return Ok(*v); } let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(analyzer)?; @@ -157,7 +156,7 @@ impl ExecOp for RangeExpr { }; finished = true; } - RangeOp::SetLength => { + RangeOp::SetLength => { ret = if maximize { Ok(lhs_max .range_set_length(&rhs_max) @@ -256,10 +255,10 @@ impl ExecOp for RangeExpr { match (lhs_is_conc, rhs_is_conc, finished) { (true, true, false) => { ret = self.exec(parts, maximize, analyzer); - }, + } (_, _, false) => { ret = Ok(Elem::Expr(self.clone())); - }, + } _ => {} } @@ -283,10 +282,10 @@ impl ExecOp for RangeExpr { > { let lhs_min = self.lhs.minimize(analyzer)?; self.lhs.set_arenaized_cache(false, &lhs_min, analyzer); - + let lhs_max = self.lhs.maximize(analyzer)?; self.lhs.set_arenaized_cache(true, &lhs_max, analyzer); - + let rhs_min = self.rhs.minimize(analyzer)?; self.rhs.set_arenaized_cache(false, &rhs_min, analyzer); @@ -338,17 +337,17 @@ impl ExecOp for RangeExpr { if maximize { if let Some(MinMaxed::Maximized(v)) = self.arenaized_cache(maximize, analyzer) { tracing::trace!("avoided execing via cache"); - return Ok(*v) + return Ok(*v); } } if !maximize { if let Some(MinMaxed::Minimized(v)) = self.arenaized_cache(maximize, analyzer) { tracing::trace!("avoided execing via cache"); - return Ok(*v) + return Ok(*v); } } - + tracing::trace!( "executing {}: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", if maximize { "maximum" } else { "minimum" }, @@ -451,8 +450,7 @@ impl ExecOp for RangeExpr { )? .unwrap_or_else(|| Elem::Null)), Elem::Reference(_) => { - let new_max = - lhs_max.simplify_maximize(analyzer)?; + let new_max = lhs_max.simplify_maximize(analyzer)?; if new_max == lhs_max { Ok(Elem::Null) } else { @@ -499,8 +497,7 @@ impl ExecOp for RangeExpr { )? .unwrap_or_else(|| Elem::Null)), Elem::Reference(ref _r) => { - let new_min = - lhs_min.simplify_minimize(analyzer)?; + let new_min = lhs_min.simplify_minimize(analyzer)?; if new_min == lhs_min { Ok(Elem::Null) } else { @@ -516,9 +513,7 @@ impl ExecOp for RangeExpr { } RangeOp::SetIndices => { if maximize { - let max = self - .rhs - .simplify_maximize(analyzer)?; + let max = self.rhs.simplify_maximize(analyzer)?; lhs_max.range_set_indices(&rhs_max).unwrap_or_else(|| { lhs_max @@ -526,9 +521,7 @@ impl ExecOp for RangeExpr { .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) }) } else { - let min = self - .rhs - .simplify_minimize(analyzer)?; + let min = self.rhs.simplify_minimize(analyzer)?; lhs_min.range_set_indices(&rhs_min).unwrap_or_else(|| { lhs_min .range_set_indices(&min) diff --git a/crates/graph/src/range/exec/mem_ops/mem_set.rs b/crates/graph/src/range/exec/mem_ops/mem_set.rs index 74f3b9d1..6fb7028f 100644 --- a/crates/graph/src/range/exec/mem_ops/mem_set.rs +++ b/crates/graph/src/range/exec/mem_ops/mem_set.rs @@ -182,7 +182,7 @@ impl RangeMemSet for Elem { match (self, other) { (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { let mut a = a.clone(); - a.len = b.len.clone(); + a.len.clone_from(&b.len); Some(Elem::ConcreteDyn(a.clone())) } (a @ Elem::Concrete(_), _b @ Elem::Concrete(_)) => Some(a.clone()), diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index d32125ed..6fb33895 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,5 +1,4 @@ use crate::{range::elem::Elem, GraphBackend}; -use std::collections::BTreeMap; /// For execution of operations to be performed on range expressions pub trait ExecOp { diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index 53c3b5a6..cb6bd8a8 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -8,7 +8,6 @@ use shared::NodeIdx; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; -use tracing::instrument; use std::{borrow::Cow, collections::BTreeMap}; @@ -21,11 +20,14 @@ pub struct FlattenedRange { impl From for SolcRange { fn from(range: FlattenedRange) -> Self { - SolcRange::new(Elem::Arena(range.min), Elem::Arena(range.max), range.exclusions) + SolcRange::new( + Elem::Arena(range.min), + Elem::Arena(range.max), + range.exclusions, + ) } } - #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct SolcRange { pub min: Elem, @@ -112,10 +114,8 @@ impl SolcRange { analyzer: &mut impl GraphBackend, ) { if let Some(ref mut flattened) = &mut self.flattened { - Elem::Arena(flattened.min) - .replace_dep(to_replace, replacement.clone(), analyzer); - Elem::Arena(flattened.max) - .replace_dep(to_replace, replacement.clone(), analyzer); + Elem::Arena(flattened.min).replace_dep(to_replace, replacement.clone(), analyzer); + Elem::Arena(flattened.max).replace_dep(to_replace, replacement.clone(), analyzer); } self.min .replace_dep(to_replace, replacement.clone(), analyzer); @@ -553,7 +553,10 @@ impl SolcRange { Self::new(min.clone().max(max.clone()), min.max(max), self.exclusions) } - pub fn into_flattened_range(&mut self, analyzer: &mut impl GraphBackend) -> Result { + pub fn into_flattened_range( + &mut self, + analyzer: &mut impl GraphBackend, + ) -> Result { if let Some(cached) = &self.flattened { return Ok(cached.clone()); } @@ -571,7 +574,11 @@ impl SolcRange { let min = analyzer.range_arena_idx_or_upsert(simp_min); let max = analyzer.range_arena_idx_or_upsert(simp_max); - let flat_range = FlattenedRange { min, max, exclusions: self.exclusions.clone() }; + let flat_range = FlattenedRange { + min, + max, + exclusions: self.exclusions.clone(), + }; self.flattened = Some(flat_range.clone()); Ok(flat_range) @@ -602,12 +609,14 @@ impl Range for SolcRange { if self.max_cached.is_none() { let max = self.range_max_mut(); max.cache_maximize(analyzer)?; - self.max_cached = Some(analyzer.range_arena_idx_or_upsert(self.range_max().maximize(analyzer)?)); + self.max_cached = + Some(analyzer.range_arena_idx_or_upsert(self.range_max().maximize(analyzer)?)); } if self.min_cached.is_none() { let min = self.range_min_mut(); min.cache_minimize(analyzer)?; - self.min_cached = Some(analyzer.range_arena_idx_or_upsert(self.range_min().minimize(analyzer)?)); + self.min_cached = + Some(analyzer.range_arena_idx_or_upsert(self.range_min().minimize(analyzer)?)); } Ok(()) } @@ -646,7 +655,11 @@ impl Range for SolcRange { } fn range_exclusions(&self) -> Vec { - self.exclusions.clone().into_iter().map(Elem::Arena).collect() + self.exclusions + .clone() + .into_iter() + .map(Elem::Arena) + .collect() } fn set_range_min(&mut self, new: Self::ElemTy) { self.min_cached = None; @@ -703,9 +716,9 @@ impl Range for SolcRange { let Some(flat) = &self.flattened else { unreachable!(); }; - return Ok(Cow::Borrowed(flat)) + return Ok(Cow::Borrowed(flat)); } else if let Some(flat) = &self.flattened { - return Ok(Cow::Borrowed(flat)) + return Ok(Cow::Borrowed(flat)); } else { unreachable!() } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 8a47b1c1..8a46d9de 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -9,7 +9,7 @@ use crate::{ }; use ethers_core::types::U256; -use std::{collections::BTreeMap, cell::RefCell, rc::Rc}; +use std::{collections::BTreeMap, rc::Rc}; #[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub enum AtomOrPart { @@ -306,15 +306,13 @@ impl Atomize for Elem { } (Elem::Concrete(_), Elem::Concrete(_)) => { expr.clone().arenaize(analyzer); - let res = expr - .exec_op(true, analyzer) - .unwrap(); + let res = expr.exec_op(true, analyzer).unwrap(); if res == Elem::Expr(expr.clone()) { AtomOrPart::Part(res) } else { res.atoms_or_part(analyzer) } - }, + } (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), (_, Elem::ConcreteDyn(_)) => AtomOrPart::Part(Elem::Null), (Elem::Null, _) => AtomOrPart::Part(Elem::Null), @@ -353,18 +351,16 @@ impl Atomize for Elem { a.update_max_ty(); Some(a) } - Arena(_) => { - match &*self.dearenaize(analyzer).borrow() { - e @ Expr(_) => { - let AtomOrPart::Atom(mut a) = e.atoms_or_part(analyzer) else { - return None; - }; - a.update_max_ty(); - Some(a) - } - _ => None + Arena(_) => match &*self.dearenaize(analyzer).borrow() { + e @ Expr(_) => { + let AtomOrPart::Atom(mut a) = e.atoms_or_part(analyzer) else { + return None; + }; + a.update_max_ty(); + Some(a) } - } + _ => None, + }, } } } diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index fa6ed146..55c00381 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -12,23 +12,23 @@ use ethers_core::types::U256; use std::collections::BTreeMap; pub trait SolcSolver { - fn simplify(&mut self, analyzer: &(impl GraphBackend + AnalyzerBackend)); + fn simplify(&mut self, analyzer: &impl AnalyzerBackend); fn solve( &mut self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result; fn recurse_check( &mut self, idx: usize, solved_atomics: &mut Vec, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result; fn check( &mut self, solved_for: usize, lmr: (Elem, Elem, Elem), solved_atomics: &mut Vec, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(bool, Option), GraphError>; } @@ -270,11 +270,11 @@ impl BruteBinSearchSolver { } impl SolcSolver for BruteBinSearchSolver { - fn simplify(&mut self, _analyzer: &(impl GraphBackend + AnalyzerBackend)) {} + fn simplify(&mut self, _analyzer: &impl AnalyzerBackend) {} fn solve( &mut self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { // pick a value for a variable. check if it satisfies all dependendies // if is sat, try to reduce using bin search? Not sure how that will @@ -430,7 +430,7 @@ impl SolcSolver for BruteBinSearchSolver { &mut self, i: usize, solved_atomics: &mut Vec, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { // println!("recurse check for: {}", self.atomics[i].idxs[0].display_name(analyzer).unwrap()); if i >= self.lmrs.len() { @@ -514,7 +514,7 @@ impl SolcSolver for BruteBinSearchSolver { solved_for_idx: usize, (low, mid, high): (Elem, Elem, Elem), solved_atomics: &mut Vec, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(bool, Option), GraphError> { let solved_dep = &self.atomics[solved_for_idx].clone(); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 34bda3e2..fdbe646b 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -14,7 +14,7 @@ use petgraph::{ Directed, }; -use std::{rc::Rc, collections::BTreeMap}; +use std::{collections::BTreeMap, rc::Rc}; pub type DLGraph = StableGraph; @@ -197,7 +197,8 @@ impl DLSolver { constraint.clone(), Self::dl_atom_normalize(constraint.clone(), analyzer), ) - }).collect::>>>() + }) + .collect::>>>() } pub fn dl_solvable_constraints(&self) -> Vec>> { @@ -594,9 +595,9 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.rhs.clone(), op: RangeOp::Sub(true), - rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from( - U256::from(1), - )))), + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from(U256::from( + 1, + ))))), })), }, analyzer, diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index 9bd42d87..b56d1df0 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -135,7 +135,7 @@ impl VarType { pub fn concrete_to_builtin( &mut self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { if let VarType::Concrete(cnode) = self { let c = cnode.underlying(analyzer)?.clone(); @@ -257,7 +257,7 @@ impl VarType { pub fn try_cast( self, other: &Self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { match (self, other) { (l, Self::User(TypeNode::Ty(ty), o_r)) => { @@ -314,7 +314,7 @@ impl VarType { pub fn try_literal_cast( self, other: &Self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result, GraphError> { match (self, other) { (Self::BuiltIn(from_bn, sr), Self::User(TypeNode::Ty(ty), _)) => { @@ -387,10 +387,7 @@ impl VarType { } } - pub fn max_size( - &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), - ) -> Result { + pub fn max_size(&self, analyzer: &mut impl AnalyzerBackend) -> Result { match self { Self::BuiltIn(from_bn, _r) => { let bn = from_bn.max_size(analyzer)?; @@ -645,7 +642,7 @@ impl VarType { pub fn dynamic_underlying_ty( &self, - analyzer: &mut (impl GraphBackend + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ) -> Result { match self { Self::BuiltIn(node, _) => node.dynamic_underlying_ty(analyzer), diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 627f3f83..0bae6119 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -4,9 +4,10 @@ use shared::RangeArena; use analyzers::LocStrSpan; use graph::{nodes::*, ContextEdge, Edge, Node, VarType}; -use shared::{AnalyzerLike, GraphLike, NodeIdx, Search, JoinStats}; +use shared::{AnalyzerLike, GraphLike, JoinStats, NodeIdx, Search}; use solc_expressions::{ExprErr, FnCallBuilder, IntoExprErr, StatementParser}; +use ahash::AHashMap; use ariadne::{Cache, Color, Config, Fmt, Label, Report, ReportKind, Source, Span}; use petgraph::{graph::*, stable_graph::StableGraph, Directed}; use serde_json::Value; @@ -19,13 +20,12 @@ use solang_parser::{ StructDefinition, TypeDefinition, Using, UsingList, VariableDefinition, }, }; -use ahash::AHashMap; use std::{ - collections::{BTreeMap, HashMap}, + cell::RefCell, + collections::BTreeMap, fs, path::{Path, PathBuf}, - cell::RefCell, rc::Rc, }; diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index c0ea6324..97de48d9 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -7,14 +7,14 @@ use graph::{ }, AnalyzerBackend, Edge, Node, VarType, }; -use shared::{AnalyzerLike, GraphLike, NodeIdx, JoinStats}; +use shared::{AnalyzerLike, GraphLike, JoinStats, NodeIdx}; use solc_expressions::{ExprErr, IntoExprErr}; +use ahash::AHashMap; use ethers_core::types::U256; use solang_parser::{helpers::CodeLocation, pt::Expression}; -use ahash::AHashMap; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; impl AnalyzerBackend for Analyzer {} diff --git a/crates/pyrometer/src/builtin_fns.rs b/crates/pyrometer/src/builtin_fns.rs index 9fbc0fcb..1c3caeaa 100644 --- a/crates/pyrometer/src/builtin_fns.rs +++ b/crates/pyrometer/src/builtin_fns.rs @@ -1,5 +1,5 @@ use graph::nodes::{Builtin, Function, FunctionParam, FunctionReturn}; -use shared::{AnalyzerLike, GraphLike, StorageLocation}; +use shared::{AnalyzerLike, StorageLocation}; use solang_parser::pt::{FunctionAttribute, Identifier, Loc, Visibility}; @@ -325,7 +325,7 @@ pub fn builtin_fns() -> AHashMap { } pub fn builtin_fns_inputs( - analyzer: &mut (impl GraphLike + AnalyzerLike), + analyzer: &mut impl AnalyzerLike, ) -> AHashMap, Vec)> { let funcs = [ ("wrap", vec![], vec![]), diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index 158380cd..bb859a23 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,13 +1,13 @@ -use std::hash::Hasher; -use std::collections::hash_map::DefaultHasher; -use std::hash::Hash; -use std::cell::RefCell; -use std::rc::Rc; use crate::Analyzer; use graph::elem::Elem; use graph::elem::RangeElem; use graph::nodes::Concrete; use shared::RangeArena; +use std::cell::RefCell; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; +use std::hash::Hasher; +use std::rc::Rc; use graph::{ as_dot_str, nodes::ContextNode, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, @@ -46,7 +46,7 @@ impl GraphLike for Analyzer { if let Elem::Arena(idx) = elem { Some(*idx) } else { - self.range_arena().map.get(elem).copied() + self.range_arena().map.get(elem).copied() } } @@ -94,15 +94,15 @@ impl GraphLike for Analyzer { idx } else { let idx = self.range_arena().ranges.len(); - self.range_arena_mut().ranges.push(Rc::new(RefCell::new(elem.clone()))); + self.range_arena_mut() + .ranges + .push(Rc::new(RefCell::new(elem.clone()))); self.range_arena_mut().map.insert(elem, idx); idx } } } - - fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); diff --git a/crates/pyrometer/tests/helpers.rs b/crates/pyrometer/tests/helpers.rs index 687dbd24..3a14b641 100644 --- a/crates/pyrometer/tests/helpers.rs +++ b/crates/pyrometer/tests/helpers.rs @@ -10,7 +10,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; - pub fn assert_no_parse_errors(path_str: String) { let sol = std::fs::read_to_string(path_str.clone()).unwrap(); let mut analyzer = Analyzer::default(); @@ -18,11 +17,11 @@ pub fn assert_no_parse_errors(path_str: String) { let _ = analyzer.parse(&sol, ¤t_path, true); assert!( analyzer.expr_errs.is_empty(), - "Analyzer encountered parse errors in {}", path_str + "Analyzer encountered parse errors in {}", + path_str ); } - pub fn assert_no_ctx_killed(path_str: String, sol: &str) { let mut analyzer = Analyzer::default(); let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); diff --git a/crates/queries/src/lib.rs b/crates/queries/src/lib.rs index 3ac5e78c..325bbed8 100644 --- a/crates/queries/src/lib.rs +++ b/crates/queries/src/lib.rs @@ -1 +1 @@ -//! Currently Empty \ No newline at end of file +//! Currently Empty diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 7046d4f4..7c901612 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -2,7 +2,7 @@ use crate::{GraphLike, NodeIdx}; use ahash::AHashMap; -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; #[derive(Debug, Clone, Copy, Default)] pub struct JoinStats { @@ -21,75 +21,69 @@ pub struct JoinStats { impl JoinStats { pub fn total_joins(&self) -> usize { - self.total_pure_joins() - + self.total_view_joins() - + self.total_mut_joins() + self.total_pure_joins() + self.total_view_joins() + self.total_mut_joins() } pub fn completed_joins(&self) -> usize { - self.completed_pure_joins() - + self.completed_view_joins() - + self.completed_mut_joins() + self.completed_pure_joins() + self.completed_view_joins() + self.completed_mut_joins() } pub fn reduced_vars(&self) -> usize { - self.pure_reduced_vars() - + self.view_reduced_vars() - + self.mut_reduced_vars() + self.pure_reduced_vars() + self.view_reduced_vars() + self.mut_reduced_vars() } pub fn total_pure_joins(&self) -> usize { self.pure_no_children_joins.num_joins - + self.pure_children_no_forks_joins.num_joins - + self.pure_children_forks_joins.num_joins + + self.pure_children_no_forks_joins.num_joins + + self.pure_children_forks_joins.num_joins } pub fn completed_pure_joins(&self) -> usize { self.pure_no_children_joins.completed_joins - + self.pure_children_no_forks_joins.completed_joins - + self.pure_children_forks_joins.completed_joins + + self.pure_children_no_forks_joins.completed_joins + + self.pure_children_forks_joins.completed_joins } pub fn pure_reduced_vars(&self) -> usize { self.pure_no_children_joins.vars_reduced - + self.pure_children_no_forks_joins.vars_reduced - + self.pure_children_forks_joins.vars_reduced + + self.pure_children_no_forks_joins.vars_reduced + + self.pure_children_forks_joins.vars_reduced } pub fn total_view_joins(&self) -> usize { self.view_no_children_joins.num_joins - + self.view_children_no_forks_joins.num_joins - + self.view_children_forks_joins.num_joins + + self.view_children_no_forks_joins.num_joins + + self.view_children_forks_joins.num_joins } pub fn completed_view_joins(&self) -> usize { self.view_no_children_joins.completed_joins - + self.view_children_no_forks_joins.completed_joins - + self.view_children_forks_joins.completed_joins + + self.view_children_no_forks_joins.completed_joins + + self.view_children_forks_joins.completed_joins } pub fn view_reduced_vars(&self) -> usize { self.view_no_children_joins.vars_reduced - + self.view_children_no_forks_joins.vars_reduced - + self.view_children_forks_joins.vars_reduced + + self.view_children_no_forks_joins.vars_reduced + + self.view_children_forks_joins.vars_reduced } pub fn total_mut_joins(&self) -> usize { self.mut_no_children_joins.num_joins - + self.mut_children_no_forks_joins.num_joins - + self.mut_children_forks_joins.num_joins + + self.mut_children_no_forks_joins.num_joins + + self.mut_children_forks_joins.num_joins } pub fn completed_mut_joins(&self) -> usize { self.mut_no_children_joins.completed_joins - + self.mut_children_no_forks_joins.completed_joins - + self.mut_children_forks_joins.completed_joins + + self.mut_children_no_forks_joins.completed_joins + + self.mut_children_forks_joins.completed_joins } pub fn mut_reduced_vars(&self) -> usize { self.mut_no_children_joins.vars_reduced - + self.mut_children_no_forks_joins.vars_reduced - + self.mut_children_forks_joins.vars_reduced + + self.mut_children_no_forks_joins.vars_reduced + + self.mut_children_forks_joins.vars_reduced } } @@ -97,12 +91,9 @@ impl JoinStats { pub struct JoinStat { pub num_joins: usize, pub completed_joins: usize, - pub vars_reduced: usize + pub vars_reduced: usize, } - - - pub trait AnalyzerLike: GraphLike { /// The expression type type Expr; diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index 69853082..e1c7ba6c 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -1,16 +1,17 @@ -use crate::{Heirarchical, AnalyzerLike}; - +use crate::{AnalyzerLike, Heirarchical}; +use ahash::AHashMap; use petgraph::{ graph::{EdgeIndex, Graph, NodeIndex}, Directed, }; -use ahash::AHashMap; use std::{ + cell::RefCell, collections::BTreeSet, + hash::Hash, + rc::Rc, sync::{Arc, Mutex}, - cell::RefCell, rc::Rc, hash::Hash, }; pub type NodeIdx = NodeIndex; diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index 567fec7c..c3759746 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -4,7 +4,7 @@ use crate::{ }; use graph::{ - elem::{RangeElem, Elem}, + elem::{Elem, RangeElem}, nodes::{ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, GraphError, Node, }; @@ -131,21 +131,23 @@ pub trait Assign: AnalyzerBackend + Sized Elem::from(rhs_cvar.latest_version(self)), ); - - - let needs_forcible = new_lower_bound.depends_on(lhs_cvar, &mut vec![], self).into_expr_err(loc)? - || new_upper_bound.depends_on(lhs_cvar, &mut vec![], self).into_expr_err(loc)?; + let needs_forcible = new_lower_bound + .depends_on(lhs_cvar, &mut vec![], self) + .into_expr_err(loc)? + || new_upper_bound + .depends_on(lhs_cvar, &mut vec![], self) + .into_expr_err(loc)?; let new_lhs = if needs_forcible { self.advance_var_in_ctx_forcible(lhs_cvar.latest_version(self), loc, ctx, true)? } else { - self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)? + self.advance_var_in_ctx(lhs_cvar.latest_version(self), loc, ctx)? }; - + new_lhs.underlying_mut(self).into_expr_err(loc)?.tmp_of = rhs_cvar.tmp_of(self).into_expr_err(loc)?; - - if let Some(ref mut dep_on) = new_lhs.underlying_mut(self).into_expr_err(loc)?.dep_on { + + if let Some(ref mut dep_on) = new_lhs.underlying_mut(self).into_expr_err(loc)?.dep_on { dep_on.push(rhs_cvar) } else { new_lhs.set_dependent_on(self).into_expr_err(loc)?; @@ -240,11 +242,14 @@ pub trait Assign: AnalyzerBackend + Sized let field_name = field.name(self).unwrap(); let field_name = field_name.split('.').collect::>()[1]; let new_name = format!("{}.{field_name}", lhs_cvar.name(self).unwrap()); - new_var.name = new_name.clone(); + new_var.name.clone_from(&new_name); new_var.display_name = new_name; - let new_field = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge(new_field, lhs_cvar.first_version(self), Edge::Context(ContextEdge::AttrAccess("field"))); + let new_field = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge( + new_field, + lhs_cvar.first_version(self), + Edge::Context(ContextEdge::AttrAccess("field")), + ); }) } } diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index 27d0924c..a0f6c475 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -164,9 +164,8 @@ pub trait BinOp: AnalyzerBackend + Sized { let new_lhs = if assign { let new = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; let underlying = new.underlying_mut(self).into_expr_err(loc)?; - underlying.tmp_of = - Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); - + underlying.tmp_of = Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))); + if let Some(ref mut dep_on) = underlying.dep_on { dep_on.push(rhs_cvar) } else { @@ -589,7 +588,8 @@ pub trait BinOp: AnalyzerBackend + Sized { Some(zero_node.into()), )), dep_on: { - let mut deps = tmp_rhs.dependent_on(self, true).into_expr_err(loc)?; + let mut deps = + tmp_rhs.dependent_on(self, true).into_expr_err(loc)?; deps.push(zero_node.into()); Some(deps) }, diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index b938617d..fe29b227 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -193,7 +193,8 @@ pub trait Cmp: AnalyzerBackend + Sized { .ref_range(self) .into_expr_err(loc)? .expect("No lhs range") - .exclusions.clone(); + .exclusions + .clone(); SolcRange::new(elem.clone(), elem, exclusions) }; diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index 15164aa5..d5e03f0e 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -7,7 +7,7 @@ use crate::{ use graph::{ elem::*, nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, + AnalyzerBackend, ContextEdge, Edge, Node, }; use ethers_core::types::I256; @@ -330,8 +330,7 @@ pub trait ExpressionParser: fn delete_match( ctx: ContextNode, loc: &Loc, - analyzer: &mut (impl GraphBackend - + AnalyzerBackend), + analyzer: &mut impl AnalyzerBackend, ret: ExprRet, ) { match ret { diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs index bee99471..85a6b170 100644 --- a/crates/solc-expressions/src/context_builder/stmt.rs +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -35,7 +35,7 @@ pub trait StatementParser: &mut self, stmt: &Statement, unchecked: bool, - parent_ctx: Option + Clone + Copy>, + parent_ctx: Option + Copy>, ) where Self: Sized, { @@ -70,7 +70,7 @@ pub trait StatementParser: &mut self, stmt: &Statement, unchecked: bool, - parent_ctx: Option + Clone + Copy>, + parent_ctx: Option + Copy>, ) where Self: Sized, { diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index cba2736b..5795e670 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -273,7 +273,7 @@ pub trait Env: AnalyzerBackend + Sized { } }; let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; - var.name = name.clone(); + var.name.clone_from(&name); var.display_name = name; var.is_tmp = false; var.is_symbolic = true; @@ -457,7 +457,7 @@ pub trait Env: AnalyzerBackend + Sized { }; let mut var = ContextVar::new_from_concrete(loc, ctx, node, self).into_expr_err(loc)?; - var.name = name.clone(); + var.name.clone_from(&name); var.display_name = name; var.is_tmp = false; var.is_symbolic = true; diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 46c9b4f4..11090938 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -1,6 +1,5 @@ //! Traits & blanket implementations that facilitate performing various forms of function calls. -use crate::join::JoinStatTracker; use crate::{ func_call::join::FuncJoiner, func_call::modifier::ModifierCaller, helper::CallerHelper, internal_call::InternalFuncCaller, intrinsic_call::IntrinsicFuncCaller, @@ -67,9 +66,7 @@ impl<'a> NamedOrUnnamedArgs<'a> { pub fn parse( &self, - analyzer: &mut (impl AnalyzerBackend - + Sized - + GraphBackend), + analyzer: &mut (impl AnalyzerBackend + Sized), ctx: ContextNode, loc: Loc, ) -> Result<(), ExprErr> { @@ -101,9 +98,7 @@ impl<'a> NamedOrUnnamedArgs<'a> { pub fn parse_n( &self, n: usize, - analyzer: &mut (impl AnalyzerBackend - + Sized - + GraphBackend), + analyzer: &mut (impl AnalyzerBackend + Sized), ctx: ContextNode, loc: Loc, ) -> Result<(), ExprErr> { @@ -569,7 +564,7 @@ pub trait FuncCaller: var.name, ctx.new_tmp(analyzer).into_expr_err(loc)? ); - var.display_name = var.name.clone(); + var.display_name.clone_from(&var.name); } let node = analyzer.add_node(Node::ContextVar(var)); diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index 08b14019..ffae7ce9 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -7,7 +7,7 @@ use crate::{ use graph::{ nodes::{ CallFork, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, FunctionReturnNode, ModifierState, + FunctionParamNode, ModifierState, }, AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, }; @@ -45,7 +45,7 @@ pub trait CallerHelper: AnalyzerBackend + .cloned(); let mut new_cvar = self.add_if_err(res)?; new_cvar.loc = Some(param.loc(self).unwrap()); - new_cvar.name = name.clone(); + new_cvar.name.clone_from(&name); new_cvar.display_name = name; new_cvar.is_tmp = false; new_cvar.storage = if let Some(StorageLocation::Storage(_)) = @@ -441,7 +441,7 @@ pub trait CallerHelper: AnalyzerBackend + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Return)); Ok(()) })?; - rets = callee_ctx.underlying(self).unwrap().ret.clone(); + rets.clone_from(&callee_ctx.underlying(self).unwrap().ret); } let target_rets = diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs index 14cd80ec..0abe0230 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/address.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/address.rs @@ -21,9 +21,7 @@ pub trait AddressCaller: AnalyzerBackend + ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { - "delegatecall" | "staticcall" | "call" => { - self.external_call(&func_name, loc, ctx) - } + "delegatecall" | "staticcall" | "call" => self.external_call(&func_name, loc, ctx), "code" => { // TODO: try to be smarter based on the address input let bn = self.builtin_or_add(Builtin::DynamicBytes); @@ -56,19 +54,13 @@ pub trait AddressCaller: AnalyzerBackend + } } - fn external_call( - &mut self, - _ty: &str, - loc: Loc, - ctx: ContextNode, - ) -> Result<(), ExprErr> { + fn external_call(&mut self, _ty: &str, loc: Loc, ctx: ContextNode) -> Result<(), ExprErr> { // TODO: Check if we have the code for the address // if we dont, model it as a unrestricted call that can make other calls ctx.pop_expr_latest(loc, self).into_expr_err(loc)?; // TODO: try to be smarter based on the address input let booln = self.builtin_or_add(Builtin::Bool); - let bool_cvar = - ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; + let bool_cvar = ContextVar::new_from_builtin(loc, booln.into(), self).into_expr_err(loc)?; let bool_node = self.add_node(Node::ContextVar(bool_cvar)); ctx.add_var(bool_node.into(), self).into_expr_err(loc)?; self.add_edge(bool_node, ctx, Edge::Context(ContextEdge::Variable)); diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 9bc1fff7..73950491 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -1,12 +1,12 @@ -use crate::ListAccess; use crate::func_caller::NamedOrUnnamedArgs; +use crate::ListAccess; use crate::{variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::nodes::FunctionNode; use graph::{ elem::*, nodes::{BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode}, - AnalyzerBackend, GraphBackend, Node, Range, VarType, + AnalyzerBackend, Node, Range, VarType, }; use shared::NodeIdx; @@ -154,7 +154,7 @@ pub trait TypesCaller: AnalyzerBackend + S fn cast_match( ctx: ContextNode, loc: Loc, - analyzer: &mut (impl GraphBackend + AnalyzerBackend + ListAccess), + analyzer: &mut impl ListAccess, ty: &Builtin, ret: ExprRet, func_idx: NodeIdx, @@ -168,7 +168,6 @@ pub trait TypesCaller: AnalyzerBackend + S .as_cast_tmp(loc, ctx, ty.clone(), analyzer) .into_expr_err(loc)?; - let v_ty = VarType::try_from_idx(analyzer, func_idx).expect(""); let maybe_new_range = cvar.cast_exprs(&v_ty, analyzer).into_expr_err(loc)?; new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = v_ty; @@ -184,7 +183,13 @@ pub trait TypesCaller: AnalyzerBackend + S if cvar.is_indexable(analyzer).into_expr_err(loc)? { // input is indexable. get the length attribute, create a new length for the casted type - let _ = analyzer.create_length(ctx, loc, cvar, new_var.latest_version(analyzer), false)?; + let _ = analyzer.create_length( + ctx, + loc, + cvar, + new_var.latest_version(analyzer), + false, + )?; } ctx.push_expr(ExprRet::Single(new_var.into()), analyzer) diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index adb03fcc..3724f8b2 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,15 +1,14 @@ -use graph::AsDotStr; -use graph::SolcRange; -use shared::AnalyzerLike; -use graph::nodes::Concrete; -use shared::NodeIdx; use crate::member_access::ListAccess; use crate::{helper::CallerHelper, ExprErr, IntoExprErr}; use graph::elem::Elem; use graph::elem::RangeElem; +use graph::nodes::Concrete; use graph::nodes::ContextVar; use graph::Range; +use graph::SolcRange; use graph::VarType; +use shared::AnalyzerLike; +use shared::NodeIdx; use shared::StorageLocation; use graph::{ @@ -22,7 +21,11 @@ use solang_parser::pt::{Expression, Loc}; use std::collections::BTreeMap; impl FuncJoiner for T where - T: AnalyzerBackend + Sized + GraphBackend + CallerHelper + JoinStatTracker + T: AnalyzerBackend + + Sized + + GraphBackend + + CallerHelper + + JoinStatTracker { } /// A trait for calling a function @@ -38,7 +41,10 @@ pub trait FuncJoiner: params: &[FunctionParamNode], func_inputs: &[ContextVarNode], ) -> Result { - tracing::trace!("Trying to join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Trying to join function: {}", + func.name(self).into_expr_err(loc)? + ); // ensure no modifiers (for now) // if pure function: // grab requirements for context @@ -58,8 +64,12 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { - tracing::trace!("Joining function: {}", func.name(self).into_expr_err(loc)?); - let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; + tracing::trace!( + "Joining function: {}", + func.name(self).into_expr_err(loc)? + ); + let replacement_map = + self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; let mut rets: Vec<_> = edges[0] .return_nodes(self) .into_expr_err(loc)? @@ -68,10 +78,11 @@ pub trait FuncJoiner: .map(|(i, (_, ret_node))| { let mut new_var = ret_node.underlying(self).unwrap().clone(); let new_name = format!("{}.{i}", func.name(self).unwrap()); - new_var.name = new_name.clone(); + new_var.name.clone_from(&new_name); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); + let mut range: SolcRange = + range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.0.clone(), self); }); @@ -83,7 +94,9 @@ pub trait FuncJoiner: if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } }); } @@ -94,15 +107,29 @@ pub trait FuncJoiner: if let Ok(fields) = ret_node.struct_to_fields(self) { if !fields.is_empty() { fields.iter().for_each(|field| { - let mut new_var = field.underlying(self).unwrap().clone(); - let new_name = format!("{}.{i}.{}", func.name(self).unwrap(), field.name(self).unwrap()); - new_var.name = new_name.clone(); + let mut new_var = + field.underlying(self).unwrap().clone(); + let new_name = format!( + "{}.{i}.{}", + func.name(self).unwrap(), + field.name(self).unwrap() + ); + new_var.name.clone_from(&new_name); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); + let mut range: SolcRange = range + .take_flattened_range(self) + .unwrap() + .into(); + replacement_map.iter().for_each( + |(replace, replacement)| { + range.replace_dep( + *replace, + replacement.0.clone(), + self, + ); + }, + ); range.cache_eval(self).unwrap(); @@ -111,16 +138,25 @@ pub trait FuncJoiner: if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = + replacement_map.get(&(*d).into()) + { + *d = *r + } }); } - let new_field = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + let new_field = ContextVarNode::from( + self.add_node(Node::ContextVar(new_var)), + ); + self.add_edge( + new_field, + new_cvar, + Edge::Context(ContextEdge::AttrAccess("field")), + ); }); } } - + self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(new_cvar, self).unwrap(); ExprRet::Single(new_cvar.into()) @@ -133,7 +169,8 @@ pub trait FuncJoiner: .try_for_each(|dep| { let mut new_var = dep.underlying(self)?.clone(); if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); + let mut range: SolcRange = + range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.0.clone(), self); }); @@ -144,7 +181,9 @@ pub trait FuncJoiner: if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } }); } let new_cvar = @@ -152,22 +191,20 @@ pub trait FuncJoiner: self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(new_cvar, self)?; ctx.add_ctx_dep(new_cvar, self) - }).into_expr_err(loc)?; - - func.returns(self) - .to_vec() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - rets.push(ExprRet::Single(cvar)); - } - }); + }) + .into_expr_err(loc)?; + + func.returns(self).to_vec().into_iter().for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar)); + } + }); ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( "{}.{}.resume{{ {} }}", @@ -179,12 +216,19 @@ pub trait FuncJoiner: .into_expr_err(loc)?; self.add_completed_pure(true, false, false, edges[0]); } else { - tracing::trace!("Branching pure join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Branching pure join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_pure(false, false, true, body_ctx); } } else { - tracing::trace!("Childless pure join: {}", func.name(self).into_expr_err(loc)?); - let replacement_map = self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; + tracing::trace!( + "Childless pure join: {}", + func.name(self).into_expr_err(loc)? + ); + let replacement_map = + self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; // 1. Create a new variable with name `.` // 2. Set the range to be the copy of the return's simplified range from the function // 3. Replace the fundamentals with the input data @@ -196,10 +240,11 @@ pub trait FuncJoiner: .map(|(i, (_, ret_node))| { let mut new_var = ret_node.underlying(self).unwrap().clone(); let new_name = format!("{}.{i}", func.name(self).unwrap()); - new_var.name = new_name.clone(); + new_var.name.clone_from(&new_name); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); + let mut range: SolcRange = + range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.0.clone(), self); }); @@ -211,7 +256,9 @@ pub trait FuncJoiner: if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } }); } @@ -225,14 +272,25 @@ pub trait FuncJoiner: if !fields.is_empty() { fields.iter().for_each(|field| { let mut new_var = field.underlying(self).unwrap().clone(); - let new_name = format!("{}.{i}.{}", func.name(self).unwrap(), field.name(self).unwrap()); - new_var.name = new_name.clone(); + let new_name = format!( + "{}.{i}.{}", + func.name(self).unwrap(), + field.name(self).unwrap() + ); + new_var.name.clone_from(&new_name); new_var.display_name = new_name; if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); + let mut range: SolcRange = + range.take_flattened_range(self).unwrap().into(); + replacement_map.iter().for_each( + |(replace, replacement)| { + range.replace_dep( + *replace, + replacement.0.clone(), + self, + ); + }, + ); range.cache_eval(self).unwrap(); @@ -241,12 +299,21 @@ pub trait FuncJoiner: if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = + replacement_map.get(&(*d).into()) + { + *d = *r + } }); } - let new_field = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge(new_field, new_cvar, Edge::Context(ContextEdge::AttrAccess("field"))); + let new_field = ContextVarNode::from( + self.add_node(Node::ContextVar(new_var)), + ); + self.add_edge( + new_field, + new_cvar, + Edge::Context(ContextEdge::AttrAccess("field")), + ); }); } } @@ -263,7 +330,8 @@ pub trait FuncJoiner: .try_for_each(|dep| { let mut new_var = dep.underlying(self)?.clone(); if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range.take_flattened_range(self).unwrap().into(); + let mut range: SolcRange = + range.take_flattened_range(self).unwrap().into(); replacement_map.iter().for_each(|(replace, replacement)| { range.replace_dep(*replace, replacement.0.clone(), self); }); @@ -275,10 +343,11 @@ pub trait FuncJoiner: // TODO: the naming isn't correct here and we move variables around // in a dumb way - if let Some(ref mut dep_on) = &mut new_var.dep_on { dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { *d = *r } + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } }); } @@ -288,22 +357,20 @@ pub trait FuncJoiner: self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(new_cvar, self)?; ctx.add_ctx_dep(new_cvar, self) - }).into_expr_err(loc)?; + }) + .into_expr_err(loc)?; - func.returns(self) - .to_vec() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - rets.push(ExprRet::Single(cvar)); - } - }); + func.returns(self).to_vec().into_iter().for_each(|ret| { + if let Some(var) = ContextVar::maybe_new_from_func_ret( + self, + ret.underlying(self).unwrap().clone(), + ) { + let cvar = self.add_node(Node::ContextVar(var)); + ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar)); + } + }); ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( "{}.{}.resume{{ {} }}", @@ -327,18 +394,27 @@ pub trait FuncJoiner: { let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; if edges.len() == 1 { - tracing::trace!("View join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "View join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_view(false, false, false, body_ctx); } else { - tracing::trace!("Branching view join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Branching view join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_view(false, false, true, body_ctx); } } else { - tracing::trace!("Childless view join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Childless view join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_view(false, true, false, body_ctx); } } - } else if let Some(body_ctx) = func.maybe_body_ctx(self) { + } else if let Some(body_ctx) = func.maybe_body_ctx(self) { if body_ctx .underlying(self) .into_expr_err(loc)? @@ -350,11 +426,17 @@ pub trait FuncJoiner: tracing::trace!("Mut join function: {}", func.name(self).into_expr_err(loc)?); self.add_completed_mut(false, false, false, body_ctx); } else { - tracing::trace!("Branching mut join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Branching mut join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_mut(false, false, true, body_ctx); } } else { - tracing::trace!("Childless mut join function: {}", func.name(self).into_expr_err(loc)?); + tracing::trace!( + "Childless mut join function: {}", + func.name(self).into_expr_err(loc)? + ); self.add_completed_mut(false, true, false, body_ctx); } } @@ -370,7 +452,8 @@ pub trait FuncJoiner: func_inputs: &[ContextVarNode], ) -> Result, ContextVarNode)>, ExprErr> { let inputs = ctx.input_variables(self); - let mut replacement_map: BTreeMap, ContextVarNode)> = BTreeMap::default(); + let mut replacement_map: BTreeMap, ContextVarNode)> = + BTreeMap::default(); params .iter() .zip(func_inputs.iter()) @@ -402,9 +485,7 @@ pub trait FuncJoiner: Edge::Context(ContextEdge::InputVariable), ); - if let Some(param_ty) = - VarType::try_from_idx(self, param.ty(self).unwrap()) - { + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { replacement .cast_from_ty(param_ty, self) @@ -420,14 +501,8 @@ pub trait FuncJoiner: if let (Some(r), Some(r2)) = (replacement.range(self).unwrap(), param.range(self).unwrap()) { - let new_min = r - .range_min() - .into_owned() - .cast(r2.range_min().into_owned()); - let new_max = r - .range_max() - .into_owned() - .cast(r2.range_max().into_owned()); + let new_min = r.range_min().into_owned().cast(r2.range_min().into_owned()); + let new_max = r.range_max().into_owned().cast(r2.range_max().into_owned()); replacement .latest_version(self) .try_set_range_min(self, new_min) @@ -443,12 +518,7 @@ pub trait FuncJoiner: } ctx.add_var(replacement, self).unwrap(); - self.add_edge( - replacement, - ctx, - Edge::Context(ContextEdge::Variable), - ); - + self.add_edge(replacement, ctx, Edge::Context(ContextEdge::Variable)); let Some(correct_input) = inputs .iter() @@ -465,18 +535,29 @@ pub trait FuncJoiner: let replacement_fields = func_input.struct_to_fields(self).unwrap(); fields.iter().for_each(|field| { let field_name = field.name(self).unwrap(); - let to_replace_field_name = field_name.split('.').collect::>()[1]; - if let Some(replacement_field) = replacement_fields.iter().find(|replacement_field| { - let name = replacement_field.name(self).unwrap(); - let replacement_name = name.split('.').collect::>()[1]; - to_replace_field_name == replacement_name - }) { - let mut replacement_field_as_elem = Elem::from(*replacement_field); + let to_replace_field_name = + field_name.split('.').collect::>()[1]; + if let Some(replacement_field) = + replacement_fields.iter().find(|replacement_field| { + let name = replacement_field.name(self).unwrap(); + let replacement_name = + name.split('.').collect::>()[1]; + to_replace_field_name == replacement_name + }) + { + let mut replacement_field_as_elem = + Elem::from(*replacement_field); replacement_field_as_elem.arenaize(self).unwrap(); if let Some(next) = field.next_version(self) { - replacement_map.insert(next.0.into(), (replacement_field_as_elem.clone(), *replacement_field)); + replacement_map.insert( + next.0.into(), + (replacement_field_as_elem.clone(), *replacement_field), + ); } - replacement_map.insert(field.0.into(), (replacement_field_as_elem, *replacement_field)); + replacement_map.insert( + field.0.into(), + (replacement_field_as_elem, *replacement_field), + ); } }); } @@ -486,9 +567,11 @@ pub trait FuncJoiner: replacement_as_elem.arenaize(self).into_expr_err(loc)?; if let Some(next) = correct_input.next_version(self) { - replacement_map.insert(next.0.into(), (replacement_as_elem.clone(), replacement)); + replacement_map + .insert(next.0.into(), (replacement_as_elem.clone(), replacement)); } - replacement_map.insert(correct_input.0.into(), (replacement_as_elem, replacement)); + replacement_map + .insert(correct_input.0.into(), (replacement_as_elem, replacement)); } Ok(()) })?; @@ -496,13 +579,18 @@ pub trait FuncJoiner: } } -impl JoinStatTracker for T where - T: AnalyzerLike + GraphBackend -{ -} +impl JoinStatTracker for T where T: AnalyzerLike + GraphBackend {} pub trait JoinStatTracker: AnalyzerLike { - fn add_completed_pure(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + fn add_completed_pure( + &mut self, + completed: bool, + no_children: bool, + forks: bool, + target_ctx: ContextNode, + ) where + Self: Sized + GraphBackend, + { match (no_children, forks) { (true, _) => { let num_vars = target_ctx.vars(self).len(); @@ -535,10 +623,18 @@ pub trait JoinStatTracker: AnalyzerLike { stats.pure_children_forks_joins.completed_joins += 1; } } - } + } } - fn add_completed_view(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + fn add_completed_view( + &mut self, + completed: bool, + no_children: bool, + forks: bool, + target_ctx: ContextNode, + ) where + Self: Sized + GraphBackend, + { match (no_children, forks) { (true, _) => { let num_vars = target_ctx.vars(self).len(); @@ -572,10 +668,18 @@ pub trait JoinStatTracker: AnalyzerLike { stats.view_children_forks_joins.completed_joins += 1; } } - } + } } - fn add_completed_mut(&mut self, completed: bool, no_children: bool, forks: bool, target_ctx: ContextNode) where Self: Sized + GraphBackend { + fn add_completed_mut( + &mut self, + completed: bool, + no_children: bool, + forks: bool, + target_ctx: ContextNode, + ) where + Self: Sized + GraphBackend, + { match (no_children, forks) { (true, _) => { let num_vars = target_ctx.vars(self).len(); @@ -600,6 +704,6 @@ pub trait JoinStatTracker: AnalyzerLike { stats.mut_children_forks_joins.completed_joins += 1; } } - } + } } -} \ No newline at end of file +} diff --git a/crates/solc-expressions/src/member_access/builtin_access.rs b/crates/solc-expressions/src/member_access/builtin_access.rs index d645d4f1..3ea01028 100644 --- a/crates/solc-expressions/src/member_access/builtin_access.rs +++ b/crates/solc-expressions/src/member_access/builtin_access.rs @@ -1,4 +1,3 @@ -use crate::func_call::intrinsic_call::AddressCaller; use crate::{ExprErr, IntoExprErr, LibraryAccess}; use graph::{ @@ -213,7 +212,7 @@ pub trait BuiltinAccess: let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) .into_expr_err(loc)?; var.name = format!("int{size}.max"); - var.display_name = var.name.clone(); + var.display_name.clone_from(&var.name); var.is_tmp = true; var.is_symbolic = false; let cvar = self.add_node(Node::ContextVar(var)); @@ -228,7 +227,7 @@ pub trait BuiltinAccess: let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) .into_expr_err(loc)?; var.name = format!("int{size}.min"); - var.display_name = var.name.clone(); + var.display_name.clone_from(&var.name); var.is_tmp = true; var.is_symbolic = false; let cvar = self.add_node(Node::ContextVar(var)); @@ -257,7 +256,7 @@ pub trait BuiltinAccess: let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) .into_expr_err(loc)?; var.name = format!("uint{size}.max"); - var.display_name = var.name.clone(); + var.display_name.clone_from(&var.name); var.is_tmp = true; var.is_symbolic = false; let cvar = self.add_node(Node::ContextVar(var)); @@ -272,7 +271,7 @@ pub trait BuiltinAccess: let mut var = ContextVar::new_from_concrete(loc, ctx, node, self) .into_expr_err(loc)?; var.name = format!("uint{size}.min"); - var.display_name = var.name.clone(); + var.display_name.clone_from(&var.name); var.is_tmp = true; var.is_symbolic = false; let cvar = self.add_node(Node::ContextVar(var)); diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index bd1ad4a1..bb63e629 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -520,8 +520,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { Some(rhs_cvar), )), dep_on: { - let mut deps = lhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?; - deps.extend(rhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?); + let mut deps = + lhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?; + deps.extend( + rhs_cvar.dependent_on(analyzer, true).into_expr_err(loc)?, + ); Some(deps) }, ty: VarType::BuiltIn( @@ -857,7 +860,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { )), dep_on: { let mut deps = tmp_true.dependent_on(self, true).into_expr_err(loc)?; - deps.extend(conditional_cvar.dependent_on(self, true).into_expr_err(loc)?); + deps.extend( + conditional_cvar + .dependent_on(self, true) + .into_expr_err(loc)?, + ); Some(deps) }, is_symbolic: new_lhs.is_symbolic(self).into_expr_err(loc)? @@ -1051,8 +1058,12 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } // we add one to the element because its strict > - let Some(max_conc) = const_var.evaled_range_min(self).unwrap().unwrap().maybe_concrete() - else { + let Some(max_conc) = const_var + .evaled_range_min(self) + .unwrap() + .unwrap() + .maybe_concrete() + else { return Err(ExprErr::BadRange(loc, format!( "Expected {} to have a concrete range by now. This is likely a bug (update nonconst from const: Gt). Max: {}, expr: {} {} {}, const value: {}", nonconst_var.display_name(self).unwrap(), From a1f2d445d12e179ea409164ba65d14ce5e7c2f26 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Mar 2024 11:18:48 -0700 Subject: [PATCH 67/71] dl fix --- crates/graph/src/nodes/context/context_tys.rs | 2 + crates/graph/src/nodes/context/solving.rs | 27 ++- crates/graph/src/nodes/context/underlying.rs | 2 + .../graph/src/nodes/context/var/underlying.rs | 38 ++++ .../graph/src/nodes/context/var/versioning.rs | 91 ++++---- crates/graph/src/nodes/context/variables.rs | 24 ++- crates/graph/src/solvers/atoms.rs | 21 +- crates/graph/src/solvers/dl.rs | 201 ++++++++++++++++-- crates/solc-expressions/src/bin_op.rs | 84 ++++---- crates/solc-expressions/src/cond_op.rs | 4 + crates/solc-expressions/src/require.rs | 5 +- crates/solc-expressions/src/variable.rs | 55 +++++ 12 files changed, 434 insertions(+), 120 deletions(-) diff --git a/crates/graph/src/nodes/context/context_tys.rs b/crates/graph/src/nodes/context/context_tys.rs index 0bf8987c..b7b6789c 100644 --- a/crates/graph/src/nodes/context/context_tys.rs +++ b/crates/graph/src/nodes/context/context_tys.rs @@ -73,6 +73,8 @@ impl ModifierState { pub struct ContextCache { /// Variables in this context pub vars: BTreeMap, + /// Temporary variables in this context + pub tmp_vars: BTreeMap, /// Visible functions from this context pub visible_funcs: Option>, /// Visible structs from this context diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 2c2ff5bc..8e1fc2c8 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -22,10 +22,16 @@ use std::collections::BTreeMap; impl ContextNode { /// Use a Difference Logic solver to see if it is unreachable pub fn unreachable(&self, analyzer: &impl GraphBackend) -> Result { + // println!("checking unreachable: {}", self.path(analyzer)); let mut solver = self.dl_solver(analyzer)?.clone(); match solver.solve_partial(analyzer)? { - SolveStatus::Unsat => Ok(true), - _ => Ok(false), + SolveStatus::Unsat => { + Ok(true) + }, + e => { + // println!("other: {e:?}"); + Ok(false) + }, } } @@ -84,7 +90,8 @@ impl ContextNode { analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { tracing::trace!( - "Adding ctx dependency: {}, is_controllable: {}", + "Adding ctx ({}) dependency: {}, is_controllable: {}", + self.path(analyzer), dep.display_name(analyzer)?, dep.is_controllable(analyzer)? ); @@ -94,18 +101,20 @@ impl ContextNode { // dep.cache_flattened_range(analyzer)?; let mut range = dep.range(analyzer)?.unwrap(); let r = range.flattened_range(analyzer)?.into_owned(); - tracing::trace!( - "flattened: {}", - >::into(r.clone()).as_dot_str(analyzer) - ); // add the atomic constraint if let Some(atom) = Elem::Arena(r.min).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); - solver.add_constraints(vec![atom], analyzer); + let constraints = solver.add_constraints(vec![atom], analyzer); + constraints.into_iter().for_each(|(constraint, normalized)| { + solver.add_constraint(constraint, normalized); + }); self.underlying_mut(analyzer)?.dl_solver = solver; } else if let Some(atom) = Elem::Arena(r.max).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); - solver.add_constraints(vec![atom], analyzer); + let constraints = solver.add_constraints(vec![atom], analyzer); + constraints.into_iter().for_each(|(constraint, normalized)| { + solver.add_constraint(constraint, normalized); + }); self.underlying_mut(analyzer)?.dl_solver = solver; } diff --git a/crates/graph/src/nodes/context/underlying.rs b/crates/graph/src/nodes/context/underlying.rs index 6fdccf03..5008c0b6 100644 --- a/crates/graph/src/nodes/context/underlying.rs +++ b/crates/graph/src/nodes/context/underlying.rs @@ -206,6 +206,7 @@ impl Context { number_of_live_edges: 0, cache: ContextCache { vars: Default::default(), + tmp_vars: Default::default(), visible_funcs: if fork_expr.is_some() { parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone() } else if let Some(ret_ctx) = returning_ctx { @@ -285,6 +286,7 @@ impl Context { number_of_live_edges: 0, cache: ContextCache { vars: parent_ctx.underlying(analyzer)?.cache.vars.clone(), + tmp_vars: Default::default(), visible_funcs: parent_ctx.underlying(analyzer)?.cache.visible_funcs.clone(), visible_structs: parent_ctx .underlying(analyzer)? diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index 5b7f86f3..a35c32be 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -59,6 +59,44 @@ impl ContextVar { self.tmp_of } + pub fn new_bin_op_tmp( + lhs_cvar: ContextVarNode, + op: RangeOp, + rhs_cvar: ContextVarNode, + ctx: ContextNode, + loc: Loc, + analyzer: &mut impl AnalyzerBackend, + ) -> Result { + Ok(ContextVar { + loc: Some(loc), + name: format!( + "tmp{}({} {} {})", + ctx.new_tmp(analyzer)?, + lhs_cvar.name(analyzer)?, + op.to_string(), + rhs_cvar.name(analyzer)? + ), + display_name: format!( + "({} {} {})", + lhs_cvar.display_name(analyzer)?, + op.to_string(), + rhs_cvar.display_name(analyzer)? + ), + storage: None, + is_tmp: true, + is_symbolic: lhs_cvar.is_symbolic(analyzer)? + || rhs_cvar.is_symbolic(analyzer)?, + is_return: false, + tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), + dep_on: { + let mut deps = lhs_cvar.dependent_on(analyzer, true)?; + deps.extend(rhs_cvar.dependent_on(analyzer, true)?); + Some(deps) + }, + ty: lhs_cvar.underlying(analyzer)?.ty.clone(), + }) + } + pub fn new_from_concrete( loc: Loc, ctx: ContextNode, diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index c1c6ba93..caf3d91e 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -54,28 +54,32 @@ impl ContextVarNode { } pub fn global_first_version(&self, analyzer: &impl GraphBackend) -> Self { - let first = self.first_version(analyzer); - if let Some(inherited_from) = analyzer - .graph() - .edges_directed(first.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - { - inherited_from.global_first_version(analyzer) - } else if let Some(input_from) = analyzer - .graph() - .edges_directed(first.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - { - input_from.global_first_version(analyzer) - } else { - first + let mut global_first = self.first_version(analyzer); + + let mut stack = vec![global_first]; + + while let Some(current_node) = stack.pop() { + let mut pushed = false; + if let Some(target_node) = analyzer + .graph() + .edges_directed(current_node.0.into(), Direction::Outgoing) + .filter(|edge| { + matches!(edge.weight(), Edge::Context(ContextEdge::InheritedVariable) | Edge::Context(ContextEdge::InputVariable)) + }) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() { + global_first = target_node.first_version(analyzer); + stack.push(global_first); + pushed = true; + } + + if !pushed { + continue; + } } + + global_first } pub fn first_version(&self, analyzer: &impl GraphBackend) -> Self { @@ -110,27 +114,32 @@ impl ContextVarNode { } pub fn global_curr_version_num(&self, analyzer: &impl GraphBackend) -> usize { - let mut curr_num = self.curr_version_num(analyzer); - if let Some(inherited_from) = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InheritedVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - { - curr_num += inherited_from.global_curr_version_num(analyzer); - } else if let Some(input_from) = analyzer - .graph() - .edges_directed(self.0.into(), Direction::Outgoing) - .filter(|edge| Edge::Context(ContextEdge::InputVariable) == *edge.weight()) - .map(|edge| ContextVarNode::from(edge.target())) - .take(1) - .next() - { - curr_num += input_from.global_curr_version_num(analyzer); + let mut stack = vec![*self]; + let mut total_version_num = 0; + + while let Some(current_node) = stack.pop() { + total_version_num += current_node.curr_version_num(analyzer); + + let mut pushed = false; + if let Some(target_node) = analyzer + .graph() + .edges_directed(current_node.0.into(), Direction::Outgoing) + .filter(|edge| { + matches!(edge.weight(), Edge::Context(ContextEdge::InheritedVariable) | Edge::Context(ContextEdge::InputVariable)) + }) + .map(|edge| ContextVarNode::from(edge.target())) + .take(1) + .next() { + stack.push(target_node); + pushed = true; + } + + if !pushed { + continue; + } } - curr_num + + total_version_num } pub fn all_versions(&self, analyzer: &impl GraphBackend) -> Vec { diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 476ef244..6061da17 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -39,10 +39,17 @@ impl ContextNode { analyzer: &mut impl AnalyzerBackend, ) -> Result<(), GraphError> { // var.cache_range(analyzer)?; - let name = var.name(analyzer)?; - let vars = &mut self.underlying_mut(analyzer)?.cache.vars; - vars.insert(name, var); - Ok(()) + if var.underlying(analyzer)?.is_tmp { + let name = var.display_name(analyzer)?; + let vars = &mut self.underlying_mut(analyzer)?.cache.tmp_vars; + vars.insert(name, var); + Ok(()) + } else { + let name = var.name(analyzer)?; + let vars = &mut self.underlying_mut(analyzer)?.cache.vars; + vars.insert(name, var); + Ok(()) + } } /// Returns whether the context's cache contains a variable (by name) @@ -64,6 +71,15 @@ impl ContextNode { .copied() } + pub fn tmp_var_by_name(&self, analyzer: &impl GraphBackend, name: &str) -> Option { + self.underlying(analyzer) + .unwrap() + .cache + .tmp_vars + .get(name) + .copied() + } + /// Gets a variable by name or recurses up the relevant scopes/contexts until it is found pub fn var_by_name_or_recurse( &self, diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 8a46d9de..87ab7eda 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -77,6 +77,14 @@ impl AtomOrPart { } } + pub fn expect_part(&self) -> Elem { + if let AtomOrPart::Part(part) = self { + part.clone() + } else { + panic!("Expected part, was atom: {self:?}") + } + } + pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { match self { AtomOrPart::Part(e) => e.dependent_on(analyzer), @@ -249,13 +257,14 @@ impl Atomize for Elem { Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), - Elem::Expr(expr) => { - // println!("atoms or part: was expr: {:?} {} {:?}", expr.lhs.atoms_or_part(), expr.op.to_string(), expr.rhs.atoms_or_part()); + e @ Elem::Expr(expr) => { + // println!("atoms or part was expr: {e}"); match ( expr.lhs.atoms_or_part(analyzer), expr.rhs.atoms_or_part(analyzer), ) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { + // println!("part part"); match (l, r) { (_, Elem::Arena(_)) => todo!(), (Elem::Arena(_), _) => todo!(), @@ -305,7 +314,7 @@ impl Atomize for Elem { todo!("here4"); } (Elem::Concrete(_), Elem::Concrete(_)) => { - expr.clone().arenaize(analyzer); + let _ = expr.clone().arenaize(analyzer); let res = expr.exec_op(true, analyzer).unwrap(); if res == Elem::Expr(expr.clone()) { AtomOrPart::Part(res) @@ -320,12 +329,16 @@ impl Atomize for Elem { } } (AtomOrPart::Atom(l_atom), r @ AtomOrPart::Part(_)) => { + // println!("atom part"); + AtomOrPart::Atom(l_atom.add_rhs(expr.op, r)) } (l @ AtomOrPart::Part(_), AtomOrPart::Atom(r_atom)) => { + // println!("part atom"); AtomOrPart::Atom(r_atom.add_lhs(expr.op, l)) } (AtomOrPart::Atom(l_atoms), AtomOrPart::Atom(r_atoms)) => { + // println!("atom atom"); AtomOrPart::Atom(r_atoms.add_lhs(expr.op, AtomOrPart::Atom(l_atoms))) } } @@ -346,6 +359,7 @@ impl Atomize for Elem { Expr(_) => { // println!("atomized: was expr"); let AtomOrPart::Atom(mut a) = self.atoms_or_part(analyzer) else { + // println!("returning none"); return None; }; a.update_max_ty(); @@ -354,6 +368,7 @@ impl Atomize for Elem { Arena(_) => match &*self.dearenaize(analyzer).borrow() { e @ Expr(_) => { let AtomOrPart::Atom(mut a) = e.atoms_or_part(analyzer) else { + // println!("returning none arena"); return None; }; a.update_max_ty(); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index fdbe646b..2b2b39b8 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -40,6 +40,7 @@ impl PartialEq for DLSolver { impl Eq for DLSolver {} +#[derive(Debug)] pub enum SolveStatus { Unsat, Sat { @@ -53,6 +54,7 @@ pub enum SolveStatus { pub type SolveMap = BTreeMap>; +#[derive(Debug)] pub struct DLSolveResult { pub status: SolveStatus, pub added_atoms: Vec, @@ -85,7 +87,9 @@ impl DLSolver { mut constraint: SolverAtom, normalized_forms: Vec>, ) { + // println!("adding constraint"); if !self.constraints.contains(&constraint) { + // println!("didnt contain"); constraint.update_max_ty(); self.constraints.push(constraint.clone()); self.normalized_constraints @@ -99,6 +103,7 @@ impl DLSolver { constraints: Vec, analyzer: &mut impl GraphBackend, ) -> BTreeMap>> { + // println!("adding constriants: {constraints:#?}"); let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { let deps = constraint.dependent_on(analyzer); @@ -116,11 +121,15 @@ impl DLSolver { }); }); + // println!("dep_to_solve_ty: {dep_to_solve_ty:#?}"); + let constraints: Vec<_> = constraints .iter() .filter(|c| !self.constraints.contains(c)) .collect(); + // println!("unique constraints: {constraints:#?}"); + constraints.iter().for_each(|constraint| { let deps = constraint.dependent_on(analyzer); deps.into_iter().for_each(|dep| { @@ -137,6 +146,8 @@ impl DLSolver { }); }); + // println!("dep_to_solve_ty2: {dep_to_solve_ty:#?}"); + // filter out self equality let non_self_equality: Vec<_> = dep_to_solve_ty .iter() @@ -147,6 +158,8 @@ impl DLSolver { Some((*dep, atoms)) }) .collect(); + + // println!("non_self_equality: {non_self_equality:#?}"); // solve constant deps let const_solves = non_self_equality .iter() @@ -161,24 +174,26 @@ impl DLSolver { None }) .collect::>(); + // println!("const_solves: {const_solves:#?}"); self.const_solves = const_solves.clone(); // widdle down constraints based on if we constant solved them - let still_unknown_constraints: Vec<_> = self - .constraints - .clone() + let still_unknown_constraints: Vec<_> = constraints .into_iter() .filter(|constraint| { let deps = constraint.dependent_on(analyzer); !deps.iter().all(|dep| const_solves.contains_key(dep)) }) + .cloned() .collect(); + // println!("still_unknown_constraints: {still_unknown_constraints:#?}"); + if still_unknown_constraints.is_empty() { return Default::default(); } - still_unknown_constraints + let res = still_unknown_constraints .into_iter() .filter(|constraint| { let deps = constraint.dependent_on(analyzer); @@ -195,10 +210,12 @@ impl DLSolver { .map(|constraint| { ( constraint.clone(), - Self::dl_atom_normalize(constraint.clone(), analyzer), + Self::dl_atom_normalize(constraint.clone().clone(), analyzer), ) }) - .collect::>>>() + .collect::>>>(); + // println!("normalized map: {res:#?}"); + res } pub fn dl_solvable_constraints(&self) -> Vec>> { @@ -209,6 +226,7 @@ impl DLSolver { &mut self, analyzer: &impl GraphBackend, ) -> Result { + // println!("constraints {:#?}", self.constraints); let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { let deps = constraint.dependent_on(analyzer); @@ -226,6 +244,8 @@ impl DLSolver { }); }); + // println!("dep to solve: {dep_to_solve_ty:#?}"); + if let Some(_self_inequality) = dep_to_solve_ty.iter().find(|(_dep, atoms)| { atoms.iter().any(|atom| { atom.op == RangeOp::Neq @@ -246,6 +266,8 @@ impl DLSolver { Some((*dep, atoms)) }) .collect(); + + // println!("non_self_equality: {non_self_equality:#?}"); // solve constant deps let const_solves = non_self_equality .iter() @@ -274,6 +296,8 @@ impl DLSolver { }) .collect(); + // println!("still unknown: {still_unknown_constraints:#?}"); + if still_unknown_constraints.is_empty() { // TODO: Check that the constraints still hold return Ok(SolveStatus::Sat { @@ -283,6 +307,7 @@ impl DLSolver { } let dl_solvable = self.dl_solvable_constraints(); + // println!("dl solvable: {dl_solvable:#?}"); // constraints -> paths -> constraint let basic: Vec = dl_solvable @@ -294,11 +319,14 @@ impl DLSolver { // check if basics are unsat, if so the extra constraints wont help that // so its truly unsat + // println!("basic: {basic:#?}"); let basic_solve = self.dl_solve(basic.clone(), analyzer)?; if matches!(basic_solve.status, SolveStatus::Unsat) { return Ok(SolveStatus::Unsat); } + // println!("basic solve: {basic_solve:?}"); + let multi: Vec<_> = dl_solvable .iter() .filter_map(|c| if c.len() > 1 { Some(c.clone()) } else { None }) @@ -468,6 +496,7 @@ impl DLSolver { ); }); + if find_negative_cycle(&self.graph, root_node, analyzer).is_some() { return Ok(DLSolveResult { status: SolveStatus::Unsat, @@ -519,7 +548,6 @@ impl DLSolver { constraint: SolverAtom, analyzer: &mut impl GraphBackend, ) -> Vec> { - // println!("normalizing: {}", constraint.into_expr_elem()); let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); let false_part = AtomOrPart::Part(Elem::from(Concrete::from(false))); let true_part = AtomOrPart::Part(Elem::from(Concrete::from(true))); @@ -546,6 +574,104 @@ impl DLSolver { } _ => {} } + + // x <==> y + // x + x + y => AtomOrPart::Atom(Atom { lhs x, op: +, rhs: AtomOrPart::Atom(Atom { lhs: x, op: +, rhs: y})}) + let lhs_symbs = constraint.lhs.dependent_on(analyzer); + let rhs_symbs = constraint.rhs.dependent_on(analyzer); + let constraint = match (!lhs_symbs.is_empty(), !rhs_symbs.is_empty()) { + (true, true) => { + // TODO: in theory could have x x + y + // which should simplify to 0 y + constraint + } + (true, false) => { + // check for two vars on lhs + if lhs_symbs.len() > 1 { + // two or more + let lhs = constraint.lhs.expect_atom(); + match lhs.op { + RangeOp::Sub(_) => { + // x - y z ==> x z + y + SolverAtom { + ty: OpType::DL, + lhs: lhs.lhs, + op: constraint.op, + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Add(true), + rhs: lhs.rhs, + })), + } + } + RangeOp::Add(_) => { + // x + y z ==> x z - y + SolverAtom { + ty: OpType::DL, + lhs: lhs.lhs, + op: constraint.op, + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: lhs.rhs, + })), + } + } + _ => constraint + } + } else { + // good + constraint + } + } + (false, true) => { + // check for two vars on lhs + if rhs_symbs.len() > 1 { + // two or more + let rhs = constraint.rhs.expect_atom(); + match rhs.op { + RangeOp::Sub(_) => { + // z x - y ==> z + y x + SolverAtom { + ty: OpType::DL, + lhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Add(true), + rhs: rhs.rhs + })), + op: constraint.op, + rhs: rhs.lhs, + } + } + RangeOp::Add(_) => { + // z x + y ==> z - y x + SolverAtom { + ty: OpType::DL, + lhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Sub(true), + rhs: rhs.rhs + })), + op: constraint.op, + rhs: rhs.lhs, + } + } + _ => constraint + } + } else { + // good + constraint + } + } + _ => constraint + }; + + + println!("normalizing: {}", constraint.into_expr_elem()); match constraint.op { RangeOp::Eq => { // convert `x == y` into `x <= y - 0 || y <= x - 0` @@ -631,6 +757,8 @@ impl DLSolver { let rhs_symb = !constraint.rhs.dependent_on(analyzer).is_empty(); match (lhs_symb, rhs_symb) { (true, true) => { + // x < y + // ==> x - y <= -1 let new_lhs = AtomOrPart::Atom( constraint .lhs @@ -652,6 +780,8 @@ impl DLSolver { ) } (true, false) => { + // x < k + // ==> x - 0 <= k let new_lhs = AtomOrPart::Atom( constraint .lhs @@ -672,6 +802,9 @@ impl DLSolver { ) } (false, true) => { + // k < x ==> k < (x - y) + // k < x + // ==> 0 - x <= k let new_lhs = AtomOrPart::Atom( Elem::from(Concrete::from(U256::zero())) .wrapping_sub(constraint.rhs.into_elem()) @@ -687,6 +820,8 @@ impl DLSolver { }, analyzer, ) + // } + // } } _ => panic!("here"), } @@ -741,22 +876,44 @@ impl DLSolver { } } RangeOp::Add(_) => { - // (k + x <= y) || (x + k <= y) - // ==> (x <= y - k) - Self::dl_atom_normalize( - SolverAtom { - ty: constraint.ty, - lhs: lhs_atom.lhs, - op: constraint.op, - rhs: Rc::new(AtomOrPart::Atom(SolverAtom { + if lhs_atom.lhs == zero_part.clone().into() { + Self::dl_atom_normalize( + SolverAtom { ty: constraint.ty, - lhs: constraint.rhs, - op: RangeOp::Sub(true), - rhs: lhs_atom.rhs, - })), - }, - analyzer, - ) + lhs: lhs_atom.rhs, + op: constraint.op, + rhs: constraint.rhs, + }, + analyzer, + ) + } else if lhs_atom.rhs == zero_part.into() { + Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: lhs_atom.lhs, + op: constraint.op, + rhs: constraint.rhs, + }, + analyzer, + ) + } else { + // (k + x <= y) || (x + k <= y) + // ==> (x <= y - k) + Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: lhs_atom.lhs, + op: constraint.op, + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: lhs_atom.rhs, + })), + }, + analyzer, + ) + } } RangeOp::And => { let mut res = Self::dl_atom_normalize( diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index a0f6c475..a512e4ca 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -146,7 +146,7 @@ pub trait BinOp: AnalyzerBackend + Sized { rhs_cvar: ContextVarNode, ctx: ContextNode, op: RangeOp, - assign: bool, + mut assign: bool, ) -> Result { tracing::trace!( "binary op: {} {} {}, assign: {}", @@ -156,6 +156,35 @@ pub trait BinOp: AnalyzerBackend + Sized { assign ); + // if rhs_cvar.is_const(self).unwrap() { + // let int = rhs_cvar.evaled_range_max(self).unwrap().unwrap(); + // match collapse(&Elem::from(lhs_cvar), op, &int, self) { + // MaybeCollapsed::Collapsed(c) => { + // println!("collapsed: {c:?}"); + // } + // MaybeCollapsed::Concretes(_, _) => { + // println!("concretes"); + // } + // MaybeCollapsed::Not(..) => { + // println!("not collapsed"); + // } + // } + // } else if lhs_cvar.is_const(self).unwrap() { + // let int = lhs_cvar.evaled_range_max(self).unwrap().unwrap(); + // match collapse(&int, op, &Elem::from(rhs_cvar), self) { + // MaybeCollapsed::Collapsed(c) => { + // println!("collapsed: {c:?}"); + // } + // MaybeCollapsed::Concretes(_, _) => { + // println!("concretes"); + // } + // MaybeCollapsed::Not(..) => { + // println!("not collapsed"); + // } + // } + // } + + let unchecked = match op { RangeOp::Add(u) | RangeOp::Sub(u) | RangeOp::Mul(u) | RangeOp::Div(u) => u, _ => false, @@ -174,45 +203,22 @@ pub trait BinOp: AnalyzerBackend + Sized { new } else { - let mut new_lhs_underlying = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} {} {})", - ctx.new_tmp(self).into_expr_err(loc)?, - lhs_cvar.name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.name(self).into_expr_err(loc)? - ), - display_name: format!( - "({} {} {})", - lhs_cvar.display_name(self).into_expr_err(loc)?, - op.to_string(), - rhs_cvar.display_name(self).into_expr_err(loc)? - ), - storage: None, - is_tmp: true, - is_symbolic: lhs_cvar.is_symbolic(self).into_expr_err(loc)? - || rhs_cvar.is_symbolic(self).into_expr_err(loc)?, - is_return: false, - tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), - dep_on: { - let mut deps = lhs_cvar.dependent_on(self, true).into_expr_err(loc)?; - deps.extend(rhs_cvar.dependent_on(self, true).into_expr_err(loc)?); - Some(deps) - }, - ty: lhs_cvar.underlying(self).into_expr_err(loc)?.ty.clone(), - }; - - // will potentially mutate the ty from concrete to builtin with a concrete range - new_lhs_underlying - .ty - .concrete_to_builtin(self) - .into_expr_err(loc)?; + // TODO: simplify the expression such that we match an existing tmp if possible + let mut new_lhs_underlying = ContextVar::new_bin_op_tmp(lhs_cvar, op, rhs_cvar, ctx, loc, self).into_expr_err(loc)?; + if let Ok(Some(existing)) = self.get_unchanged_tmp_variable(&new_lhs_underlying.display_name, ctx) { + self.advance_var_in_ctx_forcible(existing, loc, ctx, true)? + } else { + // will potentially mutate the ty from concrete to builtin with a concrete range + new_lhs_underlying + .ty + .concrete_to_builtin(self) + .into_expr_err(loc)?; - let new_var = self.add_node(Node::ContextVar(new_lhs_underlying)); - ctx.add_var(new_var.into(), self).into_expr_err(loc)?; - self.add_edge(new_var, ctx, Edge::Context(ContextEdge::Variable)); - ContextVarNode::from(new_var) + let new_var = self.add_node(Node::ContextVar(new_lhs_underlying)); + ctx.add_var(new_var.into(), self).into_expr_err(loc)?; + self.add_edge(new_var, ctx, Edge::Context(ContextEdge::Variable)); + ContextVarNode::from(new_var) + } }; let mut new_rhs = rhs_cvar.latest_version(self); diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 656c8b80..8984b7f6 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -82,9 +82,11 @@ pub trait CondOp: AnalyzerBackend + Requir match (true_killed, false_killed) { (true, true) => { // both have been killed, delete the child and dont process the bodies + println!("BOTH KILLED"); ctx.delete_child(analyzer).into_expr_err(loc)?; } (true, false) => { + println!("TRUE KILLED"); // the true context has been killed, delete child, process the false fork expression // in the parent context and parse the false body ctx.delete_child(analyzer).into_expr_err(loc)?; @@ -97,6 +99,7 @@ pub trait CondOp: AnalyzerBackend + Requir } } (false, true) => { + println!("FALSE KILLED"); // the false context has been killed, delete child, process the true fork expression // in the parent context and parse the true body ctx.delete_child(analyzer).into_expr_err(loc)?; @@ -111,6 +114,7 @@ pub trait CondOp: AnalyzerBackend + Requir })?; } (false, false) => { + println!("NEITHER KILLED"); // both branches are reachable. process each body analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { analyzer.parse_ctx_statement( diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index bb63e629..1c0478c5 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -890,12 +890,13 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { tracing::trace!("checking unsat"); any_unsat |= new_var_range.unsat(self); + + ctx.add_ctx_dep(conditional_cvar, self).into_expr_err(loc)?; + if any_unsat || ctx.unreachable(self).into_expr_err(loc)? { ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); } - - ctx.add_ctx_dep(conditional_cvar, self).into_expr_err(loc)?; } tracing::trace!( diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 1dcd2f75..a7d16293 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -134,6 +134,61 @@ pub trait Variable: AnalyzerBackend + Size } } + fn get_tmp_variable( + &mut self, + name: &str, + ctx: ContextNode, + ) -> Option { + let cvar = ctx.tmp_var_by_name(self, &name)?; + Some(cvar.latest_version(self)) + } + + fn get_unchanged_tmp_variable( + &mut self, + name: &str, + ctx: ContextNode, + ) -> Result, GraphError> { + let Some(var) = self.get_tmp_variable(name, ctx) else { + return Ok(None) + }; + + if let Some(tmp) = var.tmp_of(self)? { + if tmp.lhs.latest_version(self) != tmp.lhs { + let latest = tmp.lhs.latest_version(self); + let newest_min = latest.evaled_range_min(self)?; + let curr_min = tmp.lhs.evaled_range_min(self)?; + if newest_min != curr_min { + return Ok(None) + } + let newest_max = latest.evaled_range_max(self)?; + let curr_max = tmp.lhs.evaled_range_max(self)?; + if newest_max != curr_max { + return Ok(None) + } + } + + if let Some(rhs) = tmp.rhs { + if rhs.latest_version(self) != rhs { + let latest = rhs.latest_version(self); + let newest_min = latest.evaled_range_min(self)?; + let curr_min = rhs.evaled_range_min(self)?; + if newest_min != curr_min { + return Ok(None) + } + let newest_max = latest.evaled_range_max(self)?; + let curr_max = rhs.evaled_range_max(self)?; + if newest_max != curr_max { + return Ok(None) + } + } + } + + Ok(Some(var)) + } else { + Ok(Some(var)) + } + } + /// Match on the [`ExprRet`]s of a variable definition and construct the variable fn match_var_def( &mut self, From ff7bb5f489e765815bc7e64f4271cab0cee90bfd Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Mar 2024 11:19:14 -0700 Subject: [PATCH 68/71] lint --- crates/graph/src/nodes/context/solving.rs | 24 +++++++++---------- .../graph/src/nodes/context/var/underlying.rs | 3 +-- .../graph/src/nodes/context/var/versioning.rs | 22 ++++++++++++----- crates/graph/src/nodes/context/variables.rs | 8 +++++-- crates/graph/src/solvers/atoms.rs | 2 +- crates/graph/src/solvers/dl.rs | 14 +++++------ crates/solc-expressions/src/bin_op.rs | 11 +++++---- crates/solc-expressions/src/variable.rs | 18 ++++++-------- 8 files changed, 56 insertions(+), 46 deletions(-) diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index 8e1fc2c8..c66aef3d 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,6 +1,4 @@ use crate::elem::Elem; -use crate::FlattenedRange; -use crate::SolcRange; use crate::{ as_dot_str, nodes::{ContextNode, ContextVarNode}, @@ -25,13 +23,11 @@ impl ContextNode { // println!("checking unreachable: {}", self.path(analyzer)); let mut solver = self.dl_solver(analyzer)?.clone(); match solver.solve_partial(analyzer)? { - SolveStatus::Unsat => { - Ok(true) - }, + SolveStatus::Unsat => Ok(true), e => { // println!("other: {e:?}"); Ok(false) - }, + } } } @@ -105,16 +101,20 @@ impl ContextNode { if let Some(atom) = Elem::Arena(r.min).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); let constraints = solver.add_constraints(vec![atom], analyzer); - constraints.into_iter().for_each(|(constraint, normalized)| { - solver.add_constraint(constraint, normalized); - }); + constraints + .into_iter() + .for_each(|(constraint, normalized)| { + solver.add_constraint(constraint, normalized); + }); self.underlying_mut(analyzer)?.dl_solver = solver; } else if let Some(atom) = Elem::Arena(r.max).atomize(analyzer) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); let constraints = solver.add_constraints(vec![atom], analyzer); - constraints.into_iter().for_each(|(constraint, normalized)| { - solver.add_constraint(constraint, normalized); - }); + constraints + .into_iter() + .for_each(|(constraint, normalized)| { + solver.add_constraint(constraint, normalized); + }); self.underlying_mut(analyzer)?.dl_solver = solver; } diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index a35c32be..ac799221 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -84,8 +84,7 @@ impl ContextVar { ), storage: None, is_tmp: true, - is_symbolic: lhs_cvar.is_symbolic(analyzer)? - || rhs_cvar.is_symbolic(analyzer)?, + is_symbolic: lhs_cvar.is_symbolic(analyzer)? || rhs_cvar.is_symbolic(analyzer)?, is_return: false, tmp_of: Some(TmpConstruction::new(lhs_cvar, op, Some(rhs_cvar))), dep_on: { diff --git a/crates/graph/src/nodes/context/var/versioning.rs b/crates/graph/src/nodes/context/var/versioning.rs index caf3d91e..594dfa90 100644 --- a/crates/graph/src/nodes/context/var/versioning.rs +++ b/crates/graph/src/nodes/context/var/versioning.rs @@ -64,14 +64,19 @@ impl ContextVarNode { .graph() .edges_directed(current_node.0.into(), Direction::Outgoing) .filter(|edge| { - matches!(edge.weight(), Edge::Context(ContextEdge::InheritedVariable) | Edge::Context(ContextEdge::InputVariable)) + matches!( + edge.weight(), + Edge::Context(ContextEdge::InheritedVariable) + | Edge::Context(ContextEdge::InputVariable) + ) }) .map(|edge| ContextVarNode::from(edge.target())) .take(1) - .next() { + .next() + { global_first = target_node.first_version(analyzer); stack.push(global_first); - pushed = true; + pushed = true; } if !pushed { @@ -125,13 +130,18 @@ impl ContextVarNode { .graph() .edges_directed(current_node.0.into(), Direction::Outgoing) .filter(|edge| { - matches!(edge.weight(), Edge::Context(ContextEdge::InheritedVariable) | Edge::Context(ContextEdge::InputVariable)) + matches!( + edge.weight(), + Edge::Context(ContextEdge::InheritedVariable) + | Edge::Context(ContextEdge::InputVariable) + ) }) .map(|edge| ContextVarNode::from(edge.target())) .take(1) - .next() { + .next() + { stack.push(target_node); - pushed = true; + pushed = true; } if !pushed { diff --git a/crates/graph/src/nodes/context/variables.rs b/crates/graph/src/nodes/context/variables.rs index 6061da17..20ccb24e 100644 --- a/crates/graph/src/nodes/context/variables.rs +++ b/crates/graph/src/nodes/context/variables.rs @@ -48,7 +48,7 @@ impl ContextNode { let name = var.name(analyzer)?; let vars = &mut self.underlying_mut(analyzer)?.cache.vars; vars.insert(name, var); - Ok(()) + Ok(()) } } @@ -71,7 +71,11 @@ impl ContextNode { .copied() } - pub fn tmp_var_by_name(&self, analyzer: &impl GraphBackend, name: &str) -> Option { + pub fn tmp_var_by_name( + &self, + analyzer: &impl GraphBackend, + name: &str, + ) -> Option { self.underlying(analyzer) .unwrap() .cache diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 87ab7eda..9fe1dd39 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -330,7 +330,7 @@ impl Atomize for Elem { } (AtomOrPart::Atom(l_atom), r @ AtomOrPart::Part(_)) => { // println!("atom part"); - + AtomOrPart::Atom(l_atom.add_rhs(expr.op, r)) } (l @ AtomOrPart::Part(_), AtomOrPart::Atom(r_atom)) => { diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 2b2b39b8..dcaf5978 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -496,7 +496,6 @@ impl DLSolver { ); }); - if find_negative_cycle(&self.graph, root_node, analyzer).is_some() { return Ok(DLSolveResult { status: SolveStatus::Unsat, @@ -619,7 +618,7 @@ impl DLSolver { })), } } - _ => constraint + _ => constraint, } } else { // good @@ -640,7 +639,7 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.lhs, op: RangeOp::Add(true), - rhs: rhs.rhs + rhs: rhs.rhs, })), op: constraint.op, rhs: rhs.lhs, @@ -654,23 +653,22 @@ impl DLSolver { ty: OpType::DL, lhs: constraint.lhs, op: RangeOp::Sub(true), - rhs: rhs.rhs + rhs: rhs.rhs, })), op: constraint.op, rhs: rhs.lhs, } } - _ => constraint + _ => constraint, } } else { // good constraint } } - _ => constraint + _ => constraint, }; - println!("normalizing: {}", constraint.into_expr_elem()); match constraint.op { RangeOp::Eq => { @@ -820,7 +818,7 @@ impl DLSolver { }, analyzer, ) - // } + // } // } } _ => panic!("here"), diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index a512e4ca..a9c45591 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -146,7 +146,7 @@ pub trait BinOp: AnalyzerBackend + Sized { rhs_cvar: ContextVarNode, ctx: ContextNode, op: RangeOp, - mut assign: bool, + assign: bool, ) -> Result { tracing::trace!( "binary op: {} {} {}, assign: {}", @@ -183,7 +183,6 @@ pub trait BinOp: AnalyzerBackend + Sized { // } // } // } - let unchecked = match op { RangeOp::Add(u) | RangeOp::Sub(u) | RangeOp::Mul(u) | RangeOp::Div(u) => u, @@ -204,8 +203,12 @@ pub trait BinOp: AnalyzerBackend + Sized { new } else { // TODO: simplify the expression such that we match an existing tmp if possible - let mut new_lhs_underlying = ContextVar::new_bin_op_tmp(lhs_cvar, op, rhs_cvar, ctx, loc, self).into_expr_err(loc)?; - if let Ok(Some(existing)) = self.get_unchanged_tmp_variable(&new_lhs_underlying.display_name, ctx) { + let mut new_lhs_underlying = + ContextVar::new_bin_op_tmp(lhs_cvar, op, rhs_cvar, ctx, loc, self) + .into_expr_err(loc)?; + if let Ok(Some(existing)) = + self.get_unchanged_tmp_variable(&new_lhs_underlying.display_name, ctx) + { self.advance_var_in_ctx_forcible(existing, loc, ctx, true)? } else { // will potentially mutate the ty from concrete to builtin with a concrete range diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index a7d16293..18d0956b 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -134,12 +134,8 @@ pub trait Variable: AnalyzerBackend + Size } } - fn get_tmp_variable( - &mut self, - name: &str, - ctx: ContextNode, - ) -> Option { - let cvar = ctx.tmp_var_by_name(self, &name)?; + fn get_tmp_variable(&mut self, name: &str, ctx: ContextNode) -> Option { + let cvar = ctx.tmp_var_by_name(self, name)?; Some(cvar.latest_version(self)) } @@ -149,7 +145,7 @@ pub trait Variable: AnalyzerBackend + Size ctx: ContextNode, ) -> Result, GraphError> { let Some(var) = self.get_tmp_variable(name, ctx) else { - return Ok(None) + return Ok(None); }; if let Some(tmp) = var.tmp_of(self)? { @@ -158,12 +154,12 @@ pub trait Variable: AnalyzerBackend + Size let newest_min = latest.evaled_range_min(self)?; let curr_min = tmp.lhs.evaled_range_min(self)?; if newest_min != curr_min { - return Ok(None) + return Ok(None); } let newest_max = latest.evaled_range_max(self)?; let curr_max = tmp.lhs.evaled_range_max(self)?; if newest_max != curr_max { - return Ok(None) + return Ok(None); } } @@ -173,12 +169,12 @@ pub trait Variable: AnalyzerBackend + Size let newest_min = latest.evaled_range_min(self)?; let curr_min = rhs.evaled_range_min(self)?; if newest_min != curr_min { - return Ok(None) + return Ok(None); } let newest_max = latest.evaled_range_max(self)?; let curr_max = rhs.evaled_range_max(self)?; if newest_max != curr_max { - return Ok(None) + return Ok(None); } } } From 6c5128347625ba9f1cf439a90264567d2cc7df6c Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Mar 2024 13:08:59 -0700 Subject: [PATCH 69/71] dl fix2 --- crates/graph/src/range/elem/expr.rs | 26 +++ crates/graph/src/solvers/atoms.rs | 18 +- crates/graph/src/solvers/dl.rs | 240 +++++++++++-------------- crates/solc-expressions/src/cond_op.rs | 8 +- 4 files changed, 150 insertions(+), 142 deletions(-) diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 4ce9abc6..6897a318 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -62,6 +62,32 @@ impl Hash for RangeExpr { } impl RangeExpr { + pub fn is_noop(&self) -> (bool, usize) { + let one = Elem::from(Concrete::from(U256::one())); + let zero = Elem::from(Concrete::from(U256::zero())); + match self.op { + RangeOp::Mul(_) | RangeOp::Div(_) => { + if *self.lhs == one { + (true, 0) + } else if *self.rhs == one { + (true, 1) + } else { + (false, 0) + } + } + RangeOp::Add(_) | RangeOp::Sub(_) => { + if *self.lhs == zero { + (true, 0) + } else if *self.rhs == zero { + (true, 1) + } else { + (false, 0) + } + } + _ => (false, 0), + } + } + pub fn inverse_if_boolean(&self) -> Option { if EQ_OPS.contains(&self.op) { if SINGLETON_EQ_OPS.contains(&self.op) { diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 9fe1dd39..23f7d8f9 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -1,3 +1,4 @@ +use crate::elem::{collapse, MaybeCollapsed}; use crate::range::exec_traits::ExecOp; use crate::{ nodes::{Concrete, ContextVarNode}, @@ -253,15 +254,26 @@ pub trait Atomize { impl Atomize for Elem { #[tracing::instrument(level = "trace", skip_all)] fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart { + match self { Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), - e @ Elem::Expr(expr) => { - // println!("atoms or part was expr: {e}"); + Elem::Expr(expr) => { + match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + MaybeCollapsed::Concretes(_l, _r) => { + let exec_res = expr.exec_op(true, analyzer).unwrap(); + return exec_res.atoms_or_part(analyzer); + } + MaybeCollapsed::Collapsed(elem) => { + return elem.atoms_or_part(analyzer); + } + MaybeCollapsed::Not(..) => {} + } + match ( expr.lhs.atoms_or_part(analyzer), - expr.rhs.atoms_or_part(analyzer), + expr.rhs.atoms_or_part(analyzer) ) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { // println!("part part"); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index dcaf5978..6a1abc5e 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -308,11 +308,26 @@ impl DLSolver { let dl_solvable = self.dl_solvable_constraints(); // println!("dl solvable: {dl_solvable:#?}"); - // constraints -> paths -> constraint - + // constraints -> variable -> paths + + // [ + // var1: [ + // constraint1: [path1, path2], + // constraint2: [path1], + // ] + // ] let basic: Vec = dl_solvable .iter() - .filter_map(|c| if c.len() == 1 { Some(c.clone()) } else { None }) + .filter_map(|var| { + let res: Vec<_> = var.iter().filter_map(|constraint| { + if constraint.len() == 1 { Some(constraint.clone()) } else { None } + }).collect(); + if res.len() == 1 { + Some(res) + } else { + None + } + }) .flatten() .flatten() .collect(); @@ -321,17 +336,28 @@ impl DLSolver { // so its truly unsat // println!("basic: {basic:#?}"); let basic_solve = self.dl_solve(basic.clone(), analyzer)?; - if matches!(basic_solve.status, SolveStatus::Unsat) { - return Ok(SolveStatus::Unsat); - } + // if matches!(basic_solve.status, SolveStatus::Unsat) { + // return Ok(SolveStatus::Unsat); + // } // println!("basic solve: {basic_solve:?}"); let multi: Vec<_> = dl_solvable .iter() - .filter_map(|c| if c.len() > 1 { Some(c.clone()) } else { None }) + .filter_map(|var| { + let res: Vec<_> = var.iter().filter_map(|constraint| { + if constraint.len() > 1 { Some(constraint.clone()) } else { None } + }).collect(); + if res.len() > 1 { + Some(res) + } else { + None + } + }) .collect(); + // println!("multi: {multi:?}"); + if multi.is_empty() { // we had no branches, just use the basic solve return match basic_solve.status { @@ -345,6 +371,7 @@ impl DLSolver { } }; } else if !basic.is_empty() { + // println!("was multi"); let mut cnt = 0; let mut unsat = 0; for permutation in multi.iter().multi_cartesian_product() { @@ -669,7 +696,7 @@ impl DLSolver { _ => constraint, }; - println!("normalizing: {}", constraint.into_expr_elem()); + // println!("normalizing: {}", constraint.into_expr_elem()); match constraint.op { RangeOp::Eq => { // convert `x == y` into `x <= y - 0 || y <= x - 0` @@ -751,78 +778,47 @@ impl DLSolver { res } RangeOp::Lt => { - let lhs_symb = !constraint.lhs.dependent_on(analyzer).is_empty(); - let rhs_symb = !constraint.rhs.dependent_on(analyzer).is_empty(); - match (lhs_symb, rhs_symb) { - (true, true) => { - // x < y - // ==> x - y <= -1 - let new_lhs = AtomOrPart::Atom( - constraint - .lhs - .into_elem() - .wrapping_sub(constraint.rhs.into_elem()) - .atomize(analyzer) - .expect("unable to atomize?"), - ); - Self::dl_atom_normalize( - SolverAtom { - ty: OpType::DL, - lhs: Rc::new(new_lhs), - op: RangeOp::Lte, - rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from( - I256::from(-1), - )))), - }, - analyzer, - ) - } - (true, false) => { - // x < k - // ==> x - 0 <= k - let new_lhs = AtomOrPart::Atom( - constraint - .lhs - .into_elem() - .wrapping_sub(Elem::from(Concrete::from(U256::zero()))) - .atomize(analyzer) - .expect("unable to atomize?"), - ); - - Self::dl_atom_normalize( - SolverAtom { - ty: OpType::DL, - lhs: Rc::new(new_lhs), - op: RangeOp::Lte, - rhs: constraint.rhs, - }, - analyzer, - ) - } - (false, true) => { - // k < x ==> k < (x - y) - // k < x - // ==> 0 - x <= k - let new_lhs = AtomOrPart::Atom( - Elem::from(Concrete::from(U256::zero())) - .wrapping_sub(constraint.rhs.into_elem()) - .atomize(analyzer) - .expect("unable to atomize?"), - ); - Self::dl_atom_normalize( - SolverAtom { - ty: OpType::DL, - lhs: Rc::new(new_lhs), - op: RangeOp::Lte, - rhs: constraint.lhs, - }, - analyzer, - ) - // } - // } - } - _ => panic!("here"), - } + // x < y + // x <= y - 1 + let new_rhs = constraint.rhs + .into_elem() + .wrapping_sub(Elem::from(Concrete::from(U256::one()))) + .atoms_or_part(analyzer); + Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.lhs, + op: RangeOp::Lte, + rhs: Rc::new(new_rhs), + }, + analyzer, + ) + } + RangeOp::Gte => Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lte, + rhs: constraint.lhs, + }, + analyzer, + ), + RangeOp::Gt => Self::dl_atom_normalize( + SolverAtom { + ty: OpType::DL, + lhs: constraint.rhs, + op: RangeOp::Lt, + rhs: constraint.lhs, + }, + analyzer, + ), + RangeOp::Or => { + let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); + res.extend(Self::dl_atom_normalize( + constraint.rhs.as_solver_atom(), + analyzer, + )); + res } RangeOp::Lte => { if constraint.lhs.is_atom() { @@ -953,37 +949,37 @@ impl DLSolver { } } // RangeOp::Eq => { - // // (atom.lhs == atom.rhs) <= rhs - // // try just swapping - // // rhs >= - // let new_lhs_atom = SolverAtom { - // ty: constraint.ty, - // lhs: lhs_atom.lhs, - // op: RangeOp::Sub(true), - // rhs: lhs_atom.rhs - // }; - // Self::dl_atom_normalize(SolverAtom { - // ty: constraint.ty, - // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), - // op: constraint.op, - // rhs: constraint.rhs.clone(), - // }) + // // (atom.lhs == atom.rhs) <= rhs + // // try just swapping + // // rhs >= + // let new_lhs_atom = SolverAtom { + // ty: constraint.ty, + // lhs: lhs_atom.lhs, + // op: RangeOp::Sub(true), + // rhs: lhs_atom.rhs + // }; + // Self::dl_atom_normalize(SolverAtom { + // ty: constraint.ty, + // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), + // op: constraint.op, + // rhs: constraint.rhs.clone(), + // }) // } // RangeOp::Neq => { - // // (atom.lhs != atom.rhs) <= rhs - // // (atom.lhs - atom.rhs) <= rhs - // let new_lhs_atom = SolverAtom { - // ty: constraint.ty, - // lhs: lhs_atom.lhs, - // op: RangeOp::Sub(true), - // rhs: lhs_atom.rhs - // }; - // Self::dl_atom_normalize(SolverAtom { - // ty: constraint.ty, - // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), - // op: constraint.op, - // rhs: constraint.rhs.clone(), - // }) + // // (atom.lhs != atom.rhs) <= rhs + // // (atom.lhs - atom.rhs) <= rhs + // let new_lhs_atom = SolverAtom { + // ty: constraint.ty, + // lhs: lhs_atom.lhs, + // op: RangeOp::Sub(true), + // rhs: lhs_atom.rhs + // }; + // Self::dl_atom_normalize(SolverAtom { + // ty: constraint.ty, + // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), + // op: constraint.op, + // rhs: constraint.rhs.clone(), + // }) // } other => panic!("other op: {}, {constraint:#?}", other.to_string()), } @@ -1008,32 +1004,6 @@ impl DLSolver { vec![vec![constraint]] } } - RangeOp::Gte => Self::dl_atom_normalize( - SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs, - op: RangeOp::Lte, - rhs: constraint.lhs, - }, - analyzer, - ), - RangeOp::Gt => Self::dl_atom_normalize( - SolverAtom { - ty: OpType::DL, - lhs: constraint.rhs, - op: RangeOp::Lt, - rhs: constraint.lhs, - }, - analyzer, - ), - RangeOp::Or => { - let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); - res.extend(Self::dl_atom_normalize( - constraint.rhs.as_solver_atom(), - analyzer, - )); - res - } _other => { // println!("other: {}, {}", other.to_string(), constraint.into_expr_elem()); Self::dl_atom_normalize(constraint, analyzer) diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 8984b7f6..95b06017 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -82,11 +82,11 @@ pub trait CondOp: AnalyzerBackend + Requir match (true_killed, false_killed) { (true, true) => { // both have been killed, delete the child and dont process the bodies - println!("BOTH KILLED"); + // println!("BOTH KILLED"); ctx.delete_child(analyzer).into_expr_err(loc)?; } (true, false) => { - println!("TRUE KILLED"); + // println!("TRUE KILLED"); // the true context has been killed, delete child, process the false fork expression // in the parent context and parse the false body ctx.delete_child(analyzer).into_expr_err(loc)?; @@ -99,7 +99,7 @@ pub trait CondOp: AnalyzerBackend + Requir } } (false, true) => { - println!("FALSE KILLED"); + // println!("FALSE KILLED"); // the false context has been killed, delete child, process the true fork expression // in the parent context and parse the true body ctx.delete_child(analyzer).into_expr_err(loc)?; @@ -114,7 +114,7 @@ pub trait CondOp: AnalyzerBackend + Requir })?; } (false, false) => { - println!("NEITHER KILLED"); + // println!("NEITHER KILLED"); // both branches are reachable. process each body analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { analyzer.parse_ctx_statement( From e6173b019a9a73558d61afcd112baedc76ddf5e3 Mon Sep 17 00:00:00 2001 From: brock elmore Date: Tue, 19 Mar 2024 13:09:38 -0700 Subject: [PATCH 70/71] lint --- crates/graph/src/range/elem/expr.rs | 2 +- crates/graph/src/solvers/atoms.rs | 3 +-- crates/graph/src/solvers/dl.rs | 29 ++++++++++++++++++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs index 6897a318..797a3ece 100644 --- a/crates/graph/src/range/elem/expr.rs +++ b/crates/graph/src/range/elem/expr.rs @@ -84,7 +84,7 @@ impl RangeExpr { (false, 0) } } - _ => (false, 0), + _ => (false, 0), } } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index 23f7d8f9..bdb1351f 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -254,7 +254,6 @@ pub trait Atomize { impl Atomize for Elem { #[tracing::instrument(level = "trace", skip_all)] fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart { - match self { Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), @@ -273,7 +272,7 @@ impl Atomize for Elem { match ( expr.lhs.atoms_or_part(analyzer), - expr.rhs.atoms_or_part(analyzer) + expr.rhs.atoms_or_part(analyzer), ) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { // println!("part part"); diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 6a1abc5e..56783a0e 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -319,9 +319,16 @@ impl DLSolver { let basic: Vec = dl_solvable .iter() .filter_map(|var| { - let res: Vec<_> = var.iter().filter_map(|constraint| { - if constraint.len() == 1 { Some(constraint.clone()) } else { None } - }).collect(); + let res: Vec<_> = var + .iter() + .filter_map(|constraint| { + if constraint.len() == 1 { + Some(constraint.clone()) + } else { + None + } + }) + .collect(); if res.len() == 1 { Some(res) } else { @@ -345,9 +352,16 @@ impl DLSolver { let multi: Vec<_> = dl_solvable .iter() .filter_map(|var| { - let res: Vec<_> = var.iter().filter_map(|constraint| { - if constraint.len() > 1 { Some(constraint.clone()) } else { None } - }).collect(); + let res: Vec<_> = var + .iter() + .filter_map(|constraint| { + if constraint.len() > 1 { + Some(constraint.clone()) + } else { + None + } + }) + .collect(); if res.len() > 1 { Some(res) } else { @@ -780,7 +794,8 @@ impl DLSolver { RangeOp::Lt => { // x < y // x <= y - 1 - let new_rhs = constraint.rhs + let new_rhs = constraint + .rhs .into_elem() .wrapping_sub(Elem::from(Concrete::from(U256::one()))) .atoms_or_part(analyzer); From a329c79441f1fd4a25d7548b1faac57d0a8f6efa Mon Sep 17 00:00:00 2001 From: brockelmore <31553173+brockelmore@users.noreply.github.com> Date: Fri, 21 Jun 2024 09:23:21 -0700 Subject: [PATCH 71/71] fix(ranges): Clean up range executions (#76) * idk * lint * begin range refactor * lint * add range exec tests * lint * more refactor * lint * refactor range execution * lint * further refactor of range exec * more range work * lint * more tests * lint * remove commented code * MOAR: mother of all refactors * lint * more improvements * lint --- Cargo.lock | 11 + Cargo.toml | 32 +- crates/analyzers/src/bounds.rs | 50 +- crates/analyzers/src/func_analyzer/mod.rs | 25 +- .../src/func_analyzer/report_display.rs | 49 +- crates/analyzers/src/lib.rs | 32 +- crates/analyzers/src/var_analyzer/mod.rs | 38 +- .../src/var_analyzer/report_display.rs | 46 +- crates/cli/src/main.rs | 58 +- crates/graph/Cargo.toml | 5 +- crates/graph/src/graph_elements.rs | 73 +- crates/graph/src/nodes/block.rs | 10 +- crates/graph/src/nodes/builtin.rs | 11 +- crates/graph/src/nodes/concrete.rs | 119 +- crates/graph/src/nodes/context/expr_ret.rs | 33 +- crates/graph/src/nodes/context/node.rs | 11 +- crates/graph/src/nodes/context/querying.rs | 14 +- crates/graph/src/nodes/context/solving.rs | 192 +- crates/graph/src/nodes/context/var/node.rs | 43 +- crates/graph/src/nodes/context/var/ranging.rs | 126 +- crates/graph/src/nodes/context/var/typing.rs | 110 +- .../graph/src/nodes/context/var/underlying.rs | 2 +- crates/graph/src/nodes/context/versioning.rs | 63 +- crates/graph/src/nodes/contract_ty.rs | 13 +- crates/graph/src/nodes/enum_ty.rs | 12 +- crates/graph/src/nodes/err_ty.rs | 15 +- crates/graph/src/nodes/func_ty.rs | 81 +- crates/graph/src/nodes/msg.rs | 9 +- crates/graph/src/nodes/source_unit.rs | 11 +- crates/graph/src/nodes/source_unit_part.rs | 11 +- crates/graph/src/nodes/struct_ty.rs | 26 +- crates/graph/src/nodes/ty_ty.rs | 23 +- crates/graph/src/nodes/var_ty.rs | 21 +- crates/graph/src/range/elem/concrete.rs | 142 +- crates/graph/src/range/elem/elem_enum.rs | 1391 ------------ .../graph/src/range/elem/elem_enum/arena.rs | 216 ++ .../graph/src/range/elem/elem_enum/impls.rs | 686 ++++++ crates/graph/src/range/elem/elem_enum/mod.rs | 28 + crates/graph/src/range/elem/elem_enum/ops.rs | 93 + .../src/range/elem/elem_enum/range_elem.rs | 617 ++++++ .../graph/src/range/elem/elem_enum/traits.rs | 114 + crates/graph/src/range/elem/elem_trait.rs | 97 +- crates/graph/src/range/elem/expr.rs | 1213 ----------- crates/graph/src/range/elem/expr/collapse.rs | 633 ++++++ crates/graph/src/range/elem/expr/mod.rs | 728 +++++++ .../graph/src/range/elem/expr/simplify/add.rs | 162 ++ .../graph/src/range/elem/expr/simplify/mod.rs | 55 + .../src/range/elem/expr/simplify/ords.rs | 122 ++ .../graph/src/range/elem/expr/simplify/sub.rs | 177 ++ crates/graph/src/range/elem/map_or_array.rs | 309 ++- crates/graph/src/range/elem/mod.rs | 54 +- crates/graph/src/range/elem/reference.rs | 195 +- crates/graph/src/range/exec/add.rs | 111 - crates/graph/src/range/exec/bitwise.rs | 780 ++++++- crates/graph/src/range/exec/cast.rs | 304 ++- crates/graph/src/range/exec/div.rs | 146 -- crates/graph/src/range/exec/exec_op.rs | 1868 +++-------------- crates/graph/src/range/exec/exp.rs | 85 - crates/graph/src/range/exec/logical.rs | 55 - crates/graph/src/range/exec/math_ops/add.rs | 569 +++++ crates/graph/src/range/exec/math_ops/div.rs | 494 +++++ crates/graph/src/range/exec/math_ops/exp.rs | 201 ++ crates/graph/src/range/exec/math_ops/mod.rs | 12 + .../graph/src/range/exec/math_ops/modulo.rs | 329 +++ crates/graph/src/range/exec/math_ops/mul.rs | 507 +++++ crates/graph/src/range/exec/math_ops/sub.rs | 567 +++++ crates/graph/src/range/exec/max.rs | 84 +- crates/graph/src/range/exec/mem_ops/concat.rs | 297 ++- .../graph/src/range/exec/mem_ops/mem_get.rs | 409 ++++ .../graph/src/range/exec/mem_ops/mem_set.rs | 405 +++- .../graph/src/range/exec/mem_ops/memcopy.rs | 25 + crates/graph/src/range/exec/mem_ops/mod.rs | 19 +- crates/graph/src/range/exec/min.rs | 84 +- crates/graph/src/range/exec/mod.rs | 34 +- crates/graph/src/range/exec/modulo.rs | 47 - crates/graph/src/range/exec/mul.rs | 111 - crates/graph/src/range/exec/ord.rs | 216 -- crates/graph/src/range/exec/shift.rs | 190 +- crates/graph/src/range/exec/sub.rs | 149 -- .../src/range/exec/truthy_ops/logical.rs | 145 ++ crates/graph/src/range/exec/truthy_ops/mod.rs | 5 + crates/graph/src/range/exec/truthy_ops/ord.rs | 333 +++ crates/graph/src/range/exec_traits.rs | 25 +- crates/graph/src/range/mod.rs | 11 + crates/graph/src/range/range_string.rs | 109 +- crates/graph/src/range/range_trait.rs | 57 +- crates/graph/src/range/solc_range.rs | 406 ++-- crates/graph/src/solvers/atoms.rs | 122 +- crates/graph/src/solvers/brute.rs | 285 ++- crates/graph/src/solvers/dl.rs | 272 ++- crates/graph/src/var_type.rs | 32 +- crates/pyrometer/benches/parse.rs | 37 +- crates/pyrometer/src/analyzer.rs | 137 +- crates/pyrometer/src/analyzer_backend.rs | 53 +- crates/pyrometer/src/graph_backend.rs | 217 +- crates/pyrometer/tests/helpers.rs | 37 +- crates/pyrometer/tests/no_killed_ctxs.rs | 3 +- crates/pyrometer/tests/test_data/bitwise.sol | 2 +- crates/pyrometer/tests/test_data/cast.sol | 2 +- .../pyrometer/tests/test_data/const_var.sol | 2 +- .../pyrometer/tests/test_data/intrinsics.sol | 2 +- crates/pyrometer/tests/test_data/math.sol | 40 +- crates/pyrometer/tests/test_data/storage.sol | 2 +- crates/shared/src/analyzer_like.rs | 11 +- crates/shared/src/graph_like.rs | 37 +- crates/solc-expressions/src/array.rs | 91 +- crates/solc-expressions/src/assign.rs | 62 +- crates/solc-expressions/src/bin_op.rs | 914 ++++---- crates/solc-expressions/src/cmp.rs | 142 +- crates/solc-expressions/src/cond_op.rs | 101 +- .../src/context_builder/expr.rs | 142 +- .../src/context_builder/fn_calls.rs | 53 +- .../src/context_builder/mod.rs | 83 +- .../src/context_builder/stmt.rs | 287 ++- crates/solc-expressions/src/env.rs | 6 +- .../src/func_call/func_caller.rs | 165 +- .../solc-expressions/src/func_call/helper.rs | 163 +- .../src/func_call/internal_call.rs | 38 +- .../src/func_call/intrinsic_call/abi.rs | 9 +- .../src/func_call/intrinsic_call/array.rs | 71 +- .../src/func_call/intrinsic_call/block.rs | 9 +- .../func_call/intrinsic_call/constructors.rs | 29 +- .../func_call/intrinsic_call/dyn_builtin.rs | 41 +- .../intrinsic_call/intrinsic_caller.rs | 60 +- .../func_call/intrinsic_call/precompile.rs | 18 +- .../src/func_call/intrinsic_call/solidity.rs | 29 +- .../src/func_call/intrinsic_call/types.rs | 53 +- crates/solc-expressions/src/func_call/join.rs | 608 +++--- .../src/func_call/modifier.rs | 184 +- .../src/func_call/namespaced_call.rs | 62 +- crates/solc-expressions/src/list.rs | 20 +- crates/solc-expressions/src/literal.rs | 8 +- crates/solc-expressions/src/loops.rs | 32 +- .../src/member_access/list_access.rs | 33 +- .../src/member_access/member_trait.rs | 16 +- .../src/pre_post_in_decrement.rs | 76 +- crates/solc-expressions/src/require.rs | 482 +++-- crates/solc-expressions/src/variable.rs | 90 +- .../solc-expressions/src/yul/yul_builder.rs | 131 +- .../solc-expressions/src/yul/yul_cond_op.rs | 109 +- crates/solc-expressions/src/yul/yul_funcs.rs | 101 +- 141 files changed, 14379 insertions(+), 9028 deletions(-) delete mode 100644 crates/graph/src/range/elem/elem_enum.rs create mode 100644 crates/graph/src/range/elem/elem_enum/arena.rs create mode 100644 crates/graph/src/range/elem/elem_enum/impls.rs create mode 100644 crates/graph/src/range/elem/elem_enum/mod.rs create mode 100644 crates/graph/src/range/elem/elem_enum/ops.rs create mode 100644 crates/graph/src/range/elem/elem_enum/range_elem.rs create mode 100644 crates/graph/src/range/elem/elem_enum/traits.rs delete mode 100644 crates/graph/src/range/elem/expr.rs create mode 100644 crates/graph/src/range/elem/expr/collapse.rs create mode 100644 crates/graph/src/range/elem/expr/mod.rs create mode 100644 crates/graph/src/range/elem/expr/simplify/add.rs create mode 100644 crates/graph/src/range/elem/expr/simplify/mod.rs create mode 100644 crates/graph/src/range/elem/expr/simplify/ords.rs create mode 100644 crates/graph/src/range/elem/expr/simplify/sub.rs delete mode 100644 crates/graph/src/range/exec/add.rs delete mode 100644 crates/graph/src/range/exec/div.rs delete mode 100644 crates/graph/src/range/exec/exp.rs delete mode 100644 crates/graph/src/range/exec/logical.rs create mode 100644 crates/graph/src/range/exec/math_ops/add.rs create mode 100644 crates/graph/src/range/exec/math_ops/div.rs create mode 100644 crates/graph/src/range/exec/math_ops/exp.rs create mode 100644 crates/graph/src/range/exec/math_ops/mod.rs create mode 100644 crates/graph/src/range/exec/math_ops/modulo.rs create mode 100644 crates/graph/src/range/exec/math_ops/mul.rs create mode 100644 crates/graph/src/range/exec/math_ops/sub.rs create mode 100644 crates/graph/src/range/exec/mem_ops/mem_get.rs create mode 100644 crates/graph/src/range/exec/mem_ops/memcopy.rs delete mode 100644 crates/graph/src/range/exec/modulo.rs delete mode 100644 crates/graph/src/range/exec/mul.rs delete mode 100644 crates/graph/src/range/exec/ord.rs delete mode 100644 crates/graph/src/range/exec/sub.rs create mode 100644 crates/graph/src/range/exec/truthy_ops/logical.rs create mode 100644 crates/graph/src/range/exec/truthy_ops/mod.rs create mode 100644 crates/graph/src/range/exec/truthy_ops/ord.rs diff --git a/Cargo.lock b/Cargo.lock index 0ce4871f..bd01078d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -755,6 +755,7 @@ dependencies = [ "itertools", "lazy_static", "petgraph", + "pretty_assertions", "shared", "solang-parser", "tracing", @@ -1328,6 +1329,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "primitive-types" version = "0.12.2" diff --git a/Cargo.toml b/Cargo.toml index c6fb748f..5bc8a535 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [workspace] members = [ - "crates/analyzers", - "crates/cli", - "crates/graph", - "crates/pyrometer", - "crates/queries", - "crates/shared", - "crates/solc-expressions", + "crates/analyzers", + "crates/cli", + "crates/graph", + "crates/pyrometer", + "crates/queries", + "crates/shared", + "crates/solc-expressions", ] resolver = "2" @@ -17,14 +17,18 @@ authors = ["Brock Elmore"] license = "MIT OR Apache-2.0" homepage = "https://github.com/nascentxyz/pyrometer" repository = "https://github.com/nascentxyz/pyrometer" -exclude = ["benches/", "tests/", "examples/"] # exclude the benches directory from the build +exclude = [ + "benches/", + "tests/", + "examples/", +] # exclude the benches directory from the build rust-version = "1.74" [profile.release] debug = true [profile.dev] -opt-level = 1 # Enable some optimizations like tail call +# opt-level = 1 # Enable some optimizations like tail call inline = true [profile.bench] @@ -40,7 +44,11 @@ solc-expressions = { path = "crates/solc-expressions" } solang-parser = { version = "0.2.4", features = ["pt-serde"] } tracing = { version = "0.1", features = ["attributes"] } -tracing-subscriber = { version = "0.3", features = ["registry", "env-filter", "fmt"] } +tracing-subscriber = { version = "0.3", features = [ + "registry", + "env-filter", + "fmt", +] } tracing-tree = "0.3.0" ethers-core = "*" hex = "0.4.3" @@ -55,7 +63,7 @@ ahash = "0.8.10" # we patch ariadne to allow for counting by bytes because solang uses byte locations not char locations [patch.crates-io] -ariadne = {git = "https://github.com/brockelmore/ariadne"} +ariadne = { git = "https://github.com/brockelmore/ariadne" } # ###################################### # # Benchmarks @@ -63,4 +71,4 @@ ariadne = {git = "https://github.com/brockelmore/ariadne"} # [[bench]] # name = "parse" -# harness = false \ No newline at end of file +# harness = false diff --git a/crates/analyzers/src/bounds.rs b/crates/analyzers/src/bounds.rs index a3877649..636147a9 100644 --- a/crates/analyzers/src/bounds.rs +++ b/crates/analyzers/src/bounds.rs @@ -1,9 +1,12 @@ use crate::{FunctionVarsBoundAnalysis, LocSpan, LocStrSpan, ReportConfig, VarBoundAnalysis}; use graph::{ - nodes::ContextNode, range_string::ToRangeString, GraphBackend, Range, RangeEval, SolcRange, + elem::Elem, + nodes::{Concrete, ContextNode}, + range_string::ToRangeString, + GraphBackend, Range, RangeEval, SolcRange, }; -use shared::StorageLocation; +use shared::{RangeArena, StorageLocation}; use ariadne::{Color, Fmt, Label, Span}; use std::collections::{BTreeMap, BTreeSet}; @@ -71,9 +74,13 @@ pub struct OrderedAnalysis { } impl OrderedAnalysis { - pub fn from_bound_analysis(ba: VarBoundAnalysis, analyzer: &impl GraphBackend) -> Self { + pub fn from_bound_analysis( + ba: VarBoundAnalysis, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Self { let mut analyses: BTreeMap> = Default::default(); - if let Some(init) = ba.init_item(analyzer) { + if let Some(init) = ba.init_item(analyzer, arena) { let source: usize = *LocSpan(init.loc.1).source(); let mut set = BTreeSet::new(); set.insert(init.into()); @@ -83,7 +90,8 @@ impl OrderedAnalysis { .iter() .enumerate() .for_each(|(_i, bound_change)| { - let (parts, unsat) = range_parts(analyzer, &ba.report_config, &bound_change.1); + let (parts, unsat) = + range_parts(analyzer, arena, &ba.report_config, &bound_change.1); let item = StrippedAnalysisItem { init: false, name: ba.var_display_name.clone(), @@ -91,7 +99,7 @@ impl OrderedAnalysis { order: (bound_change.0.end() - bound_change.0.start()) as i32, //i as i32, // storage: ba.storage.clone(), ctx: ba.ctx, - ctx_conditionals: ba.conditionals(analyzer), + ctx_conditionals: ba.conditionals(analyzer, arena), parts, unsat, }; @@ -107,11 +115,12 @@ impl OrderedAnalysis { pub fn from_func_analysis( fvba: FunctionVarsBoundAnalysis, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Self { let mut analyses = Self::default(); fvba.vars_by_ctx.iter().for_each(|(_ctx, bas)| { bas.iter().for_each(|ba| { - analyses.extend(Self::from_bound_analysis(ba.clone(), analyzer)); + analyses.extend(Self::from_bound_analysis(ba.clone(), analyzer, arena)); }) }); analyses @@ -254,39 +263,40 @@ impl ToString for RangePart { /// Creates an Vec<[RangePart]> from a range based on the current [ReportConfig] pub fn range_parts( analyzer: &impl GraphBackend, + arena: &mut RangeArena>, report_config: &ReportConfig, range: &SolcRange, ) -> (Vec, bool) { let mut parts = vec![]; let min = if report_config.eval_bounds { range - .evaled_range_min(analyzer) + .evaled_range_min(analyzer, arena) .unwrap() - .to_range_string(false, analyzer) + .to_range_string(false, analyzer, arena) .s } else if report_config.simplify_bounds { range - .simplified_range_min(analyzer) + .simplified_range_min(analyzer, arena) .unwrap() - .to_range_string(false, analyzer) + .to_range_string(false, analyzer, arena) .s } else { - range.range_min().to_range_string(false, analyzer).s + range.range_min().to_range_string(false, analyzer, arena).s }; let max = if report_config.eval_bounds { range - .evaled_range_max(analyzer) + .evaled_range_max(analyzer, arena) .unwrap() - .to_range_string(true, analyzer) + .to_range_string(true, analyzer, arena) .s } else if report_config.simplify_bounds { range - .simplified_range_max(analyzer) + .simplified_range_max(analyzer, arena) .unwrap() - .to_range_string(true, analyzer) + .to_range_string(true, analyzer, arena) .s } else { - range.range_max().to_range_string(true, analyzer).s + range.range_max().to_range_string(true, analyzer, arena).s }; if min == max { @@ -301,8 +311,8 @@ pub fn range_parts( let mut excls = range_excl .iter() .map(|range| { - let min = range.to_range_string(false, analyzer).s; - let max = range.to_range_string(true, analyzer).s; + let min = range.to_range_string(false, analyzer, arena).s; + let max = range.to_range_string(true, analyzer, arena).s; if min == max { RangePart::Equal(min) } else { @@ -314,6 +324,6 @@ pub fn range_parts( excls })); } - let unsat = range.unsat(analyzer); + let unsat = range.unsat(analyzer, arena); (parts, unsat) } diff --git a/crates/analyzers/src/func_analyzer/mod.rs b/crates/analyzers/src/func_analyzer/mod.rs index f41db5cd..dc3c5bcf 100644 --- a/crates/analyzers/src/func_analyzer/mod.rs +++ b/crates/analyzers/src/func_analyzer/mod.rs @@ -4,10 +4,11 @@ use crate::{ }; use graph::{ - nodes::{ContextNode, KilledKind}, + elem::Elem, + nodes::{Concrete, ContextNode, KilledKind}, AnalyzerBackend, GraphBackend, }; -use shared::Search; +use shared::{RangeArena, Search}; use ariadne::{Color, Config, Fmt, Label, Report, Span}; use solang_parser::pt::CodeLocation; @@ -46,6 +47,7 @@ impl<'a> FunctionVarsBoundAnalysis { &self, file_mapping: &'a BTreeMap, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Vec> { let mut handled_ctx_switches = BTreeSet::default(); let reports = self @@ -56,7 +58,7 @@ impl<'a> FunctionVarsBoundAnalysis { let deps = ctx.ctx_deps(analyzer).unwrap(); let deps = deps .iter() - .map(|var| (var.as_controllable_name(analyzer).unwrap(), var)) + .map(|var| (var.as_controllable_name(analyzer, arena).unwrap(), var)) .collect::>(); // create the bound strings // let atoms = ctx.dep_atoms(analyzer).unwrap(); @@ -64,7 +66,7 @@ impl<'a> FunctionVarsBoundAnalysis { // let mut handled_atom = vec![]; // let mut bounds_string: Vec = vec![]; // atoms.iter().enumerate().for_each(|(i, atom)| { - // let atom_str = atom.to_range_string(true, analyzer).s; + // let atom_str = atom.to_range_string(true, analyzer, arena).s; // if !handled_atom.contains(&atom_str) { // handled_atom.push(atom_str.clone()); // bounds_string.push(format!("{}. {}", i + 1, atom_str)) @@ -78,7 +80,8 @@ impl<'a> FunctionVarsBoundAnalysis { .filter_map(|(i, (name, cvar))| { let range = cvar.ref_range(analyzer).unwrap()?; - let (parts, _unsat) = range_parts(analyzer, &self.report_config, &range); + let (parts, _unsat) = + range_parts(analyzer, arena, &self.report_config, &range); let ret = parts.into_iter().fold( format!("{}. {name}", i + 1), |mut acc, _part| { @@ -119,7 +122,7 @@ impl<'a> FunctionVarsBoundAnalysis { let mut labels: Vec<_> = analyses .iter() .flat_map(|analysis| { - let mut labels = analysis.labels(analyzer); + let mut labels = analysis.labels(analyzer, arena); labels.extend( analysis .spanned_ctx_info @@ -197,6 +200,7 @@ impl<'a> FunctionVarsBoundAnalysis { let range = var.ref_range(analyzer).unwrap()?; let (parts, _unsat) = range_parts( analyzer, + arena, &self.report_config, &range, ); @@ -255,7 +259,7 @@ impl<'a> FunctionVarsBoundAnalysis { .filter_map(|(loc, var)| { let range = var.ref_range(analyzer).unwrap()?; let (parts, _unsat) = - range_parts(analyzer, &self.report_config, &range); + range_parts(analyzer, arena, &self.report_config, &range); Some( Label::new(LocStrSpan::new(file_mapping, loc)) .with_message( @@ -306,6 +310,7 @@ impl FunctionVarsBoundAnalyzer for T where T: VarBoundAnalyzer + Search + Ana pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerBackend + Sized { fn bounds_for_lineage<'a>( &'a self, + arena: &mut RangeArena>, file_mapping: &'a BTreeMap, ctx: ContextNode, edges: Vec, @@ -353,10 +358,11 @@ pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerBackend let is_ret = var.is_return_node_in_any(&parents, self); if is_ret | report_config.show_tmps - | (report_config.show_consts && var.is_const(self).unwrap()) + | (report_config.show_consts && var.is_const(self, arena).unwrap()) | (report_config.show_symbolics && var.is_symbolic(self).unwrap()) { Some(self.bounds_for_var_in_family_tree( + arena, file_mapping, parents.clone(), var.name(self).unwrap(), @@ -385,6 +391,7 @@ pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerBackend fn bounds_for_all<'a>( &'a self, + arena: &mut RangeArena>, file_mapping: &'a BTreeMap, ctx: ContextNode, report_config: ReportConfig, @@ -393,6 +400,6 @@ pub trait FunctionVarsBoundAnalyzer: VarBoundAnalyzer + Search + AnalyzerBackend if edges.is_empty() { edges.push(ctx); } - self.bounds_for_lineage(file_mapping, ctx, edges, report_config) + self.bounds_for_lineage(arena, file_mapping, ctx, edges, report_config) } } diff --git a/crates/analyzers/src/func_analyzer/report_display.rs b/crates/analyzers/src/func_analyzer/report_display.rs index 9bead892..be106ff4 100644 --- a/crates/analyzers/src/func_analyzer/report_display.rs +++ b/crates/analyzers/src/func_analyzer/report_display.rs @@ -1,6 +1,8 @@ use crate::{FunctionVarsBoundAnalysis, LocStrSpan, ReportDisplay, ReportKind}; -use graph::GraphBackend; +use graph::{elem::Elem, nodes::Concrete, GraphBackend}; + +use shared::RangeArena; use ariadne::{Cache, Color, Config, Fmt, Label, Report, Span}; @@ -27,7 +29,7 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { fn report_kind(&self) -> ReportKind { ReportKind::Custom("Bounds", Color::Cyan) } - fn msg(&self, analyzer: &impl GraphBackend) -> String { + fn msg(&self, analyzer: &impl GraphBackend, _arena: &mut RangeArena>) -> String { format!( "Bounds for function: {}", format!( @@ -41,17 +43,25 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { ) } - fn labels(&self, _analyzer: &impl GraphBackend) -> Vec> { + fn labels( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Vec> { vec![] } - fn reports(&self, analyzer: &impl GraphBackend) -> Vec> { + fn reports( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec> { let mut report = Report::build( self.report_kind(), self.func_var_bound_analysis.ctx_loc.source(), self.func_var_bound_analysis.ctx_loc.start(), ) - .with_message(self.msg(analyzer)) + .with_message(self.msg(analyzer, arena)) .with_config( Config::default() .with_cross_gap(false) @@ -59,7 +69,7 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { .with_tab_width(4), ); - report.add_labels(self.labels(analyzer)); + report.add_labels(self.labels(analyzer, arena)); if let Some((killed_span, kind)) = &self.func_var_bound_analysis.ctx_killed { report = report.with_label( Label::new(killed_span.clone()) @@ -70,23 +80,34 @@ impl<'a> ReportDisplay for CLIFunctionVarsBoundAnalysis<'a> { let mut reports = vec![report.finish()]; - reports.extend( - self.func_var_bound_analysis - .reports_for_forks(self.file_mapping, analyzer), - ); + reports.extend(self.func_var_bound_analysis.reports_for_forks( + self.file_mapping, + analyzer, + arena, + )); reports } - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { - let reports = &self.reports(analyzer); + fn print_reports( + &self, + mut src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) { + let reports = &self.reports(analyzer, arena); for report in reports.iter() { report.print(&mut src).unwrap(); } } - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { - let reports = &self.reports(analyzer); + fn eprint_reports( + &self, + mut src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) { + let reports = &self.reports(analyzer, arena); reports.iter().for_each(|report| { report.eprint(&mut src).unwrap(); }); diff --git a/crates/analyzers/src/lib.rs b/crates/analyzers/src/lib.rs index a2fbc7fe..f469f356 100644 --- a/crates/analyzers/src/lib.rs +++ b/crates/analyzers/src/lib.rs @@ -1,8 +1,8 @@ pub mod bounds; use ariadne::{Cache, Label, Report, ReportKind, Span}; -use graph::{AnalyzerBackend, GraphBackend}; -use shared::Search; +use graph::{elem::Elem, nodes::Concrete, AnalyzerBackend, GraphBackend}; +use shared::{RangeArena, Search}; use solang_parser::pt::Loc; use std::collections::BTreeMap; @@ -166,9 +166,27 @@ impl Default for ReportConfig { pub trait ReportDisplay { fn report_kind(&self) -> ReportKind; - fn msg(&self, analyzer: &impl GraphBackend) -> String; - fn labels(&self, analyzer: &impl GraphBackend) -> Vec>; - fn reports(&self, analyzer: &impl GraphBackend) -> Vec>; - fn print_reports(&self, src: &mut impl Cache, analyzer: &impl GraphBackend); - fn eprint_reports(&self, src: &mut impl Cache, analyzer: &impl GraphBackend); + fn msg(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena>) -> String; + fn labels( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec>; + fn reports( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec>; + fn print_reports( + &self, + src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ); + fn eprint_reports( + &self, + src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ); } diff --git a/crates/analyzers/src/var_analyzer/mod.rs b/crates/analyzers/src/var_analyzer/mod.rs index 9fac71ef..26399012 100644 --- a/crates/analyzers/src/var_analyzer/mod.rs +++ b/crates/analyzers/src/var_analyzer/mod.rs @@ -4,10 +4,11 @@ use crate::{ }; use graph::{ - nodes::{ContextNode, ContextVarNode, KilledKind}, + elem::Elem, + nodes::{Concrete, ContextNode, ContextVarNode, KilledKind}, AnalyzerBackend, GraphBackend, Range, SolcRange, }; -use shared::{Search, StorageLocation}; +use shared::{RangeArena, Search, StorageLocation}; use std::collections::BTreeSet; @@ -66,7 +67,11 @@ impl Default for VarBoundAnalysis { } impl VarBoundAnalysis { - pub fn conditionals(&self, analyzer: &impl GraphBackend) -> Vec<(String, Vec)> { + pub fn conditionals( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec<(String, Vec)> { let deps = self.ctx.ctx_deps(analyzer).unwrap(); let deps = deps .iter() @@ -77,18 +82,22 @@ impl VarBoundAnalysis { .enumerate() .filter_map(|(_i, (_name, cvar))| { let range = cvar.ref_range(analyzer).unwrap()?; - let parts = range_parts(analyzer, &self.report_config, &range).0; + let parts = range_parts(analyzer, arena, &self.report_config, &range).0; Some((cvar.display_name(analyzer).unwrap(), parts)) }) .collect() } /// Creates an [AnalysisItem] if there is a initial bound for a variable - pub fn init_item(&self, analyzer: &impl GraphBackend) -> Option { + pub fn init_item( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option { let mut parts = vec![]; let mut unsat = false; if let Some(init_range) = &self.var_def.1 { - (parts, unsat) = range_parts(analyzer, &self.report_config, init_range) + (parts, unsat) = range_parts(analyzer, arena, &self.report_config, init_range) } if parts.is_empty() { None @@ -100,7 +109,7 @@ impl VarBoundAnalysis { loc: self.var_def.0.clone(), storage: self.storage, ctx: self.ctx, - ctx_conditionals: self.conditionals(analyzer), + ctx_conditionals: self.conditionals(analyzer, arena), parts, unsat, }) @@ -114,6 +123,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { /// generate a bound analysis for a variable throughout the lineage fn bounds_for_var_in_family_tree( &self, + arena: &mut RangeArena>, file_mapping: &'_ BTreeMap, ordered_ctxs: Vec, var_name: String, @@ -125,6 +135,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { .filter_map(|ctx| Some((ctx, ctx.var_by_name(self, &var_name)?))) .for_each(|(_ctx, cvar)| { let analysis = self.bounds_for_var_node( + arena, &inherited, file_mapping, &var_name, @@ -140,6 +151,7 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { /// Analyzes the bounds for a variable up to the provided node fn bounds_for_var_node( &self, + arena: &mut RangeArena>, inherited: &Option, file_mapping: &'_ BTreeMap, var_name: &str, @@ -232,14 +244,14 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { }; if let Some(curr_range) = comparator.ref_range(self).unwrap() { - let mut cr_min = curr_range.evaled_range_min(self).unwrap(); - let mut cr_max = curr_range.evaled_range_max(self).unwrap(); + let mut cr_min = curr_range.evaled_range_min(self, arena).unwrap(); + let mut cr_max = curr_range.evaled_range_max(self, arena).unwrap(); let mut cr_excl = curr_range.range_exclusions(); if needs_curr { if let Some(next_range) = curr.ref_range(self).unwrap() { - let nr_min = next_range.evaled_range_min(self).unwrap(); - let nr_max = next_range.evaled_range_max(self).unwrap(); + let nr_min = next_range.evaled_range_min(self, arena).unwrap(); + let nr_max = next_range.evaled_range_max(self, arena).unwrap(); let nr_excl = &next_range.range_exclusions(); // check if there was a bound change @@ -264,8 +276,8 @@ pub trait VarBoundAnalyzer: Search + AnalyzerBackend + Sized { while let Some(next) = curr.next_version(self) { if let Some(next_range) = next.ref_range(self).unwrap() { - let nr_min = next_range.evaled_range_min(self).unwrap(); - let nr_max = next_range.evaled_range_max(self).unwrap(); + let nr_min = next_range.evaled_range_min(self, arena).unwrap(); + let nr_max = next_range.evaled_range_max(self, arena).unwrap(); let nr_excl = &next_range.range_exclusions(); // check if there was a bound change diff --git a/crates/analyzers/src/var_analyzer/report_display.rs b/crates/analyzers/src/var_analyzer/report_display.rs index 3f876c7d..a4b1e48a 100644 --- a/crates/analyzers/src/var_analyzer/report_display.rs +++ b/crates/analyzers/src/var_analyzer/report_display.rs @@ -3,7 +3,9 @@ use crate::{ LocStrSpan, ReportDisplay, ReportKind, VarBoundAnalysis, }; -use graph::GraphBackend; +use graph::{elem::Elem, nodes::Concrete, GraphBackend}; + +use shared::RangeArena; use ariadne::{Cache, Color, Config, Fmt, Label, Report, Span}; @@ -11,16 +13,20 @@ impl ReportDisplay for VarBoundAnalysis { fn report_kind(&self) -> ReportKind { ReportKind::Custom("Bounds", Color::Cyan) } - fn msg(&self, analyzer: &impl GraphBackend) -> String { + fn msg(&self, analyzer: &impl GraphBackend, _arena: &mut RangeArena>) -> String { format!( "Bounds for {} in {}:", self.var_display_name, self.ctx.underlying(analyzer).unwrap().path ) } - fn labels(&self, analyzer: &impl GraphBackend) -> Vec> { + fn labels( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec> { let mut labels = if self.report_config.show_initial_bounds { - if let Some(init_item) = self.init_item(analyzer) { + if let Some(init_item) = self.init_item(analyzer, arena) { vec![init_item.into()] } else { vec![] @@ -35,7 +41,7 @@ impl ReportDisplay for VarBoundAnalysis { .enumerate() .map(|(_i, bound_change)| { let (parts, unsat) = - range_parts(analyzer, &self.report_config, &bound_change.1); + range_parts(analyzer, arena, &self.report_config, &bound_change.1); AnalysisItem { init: false, name: self.var_display_name.clone(), @@ -43,7 +49,7 @@ impl ReportDisplay for VarBoundAnalysis { order: (bound_change.0.end() - bound_change.0.start()) as i32, storage: self.storage, ctx: self.ctx, - ctx_conditionals: self.conditionals(analyzer), + ctx_conditionals: self.conditionals(analyzer, arena), parts, unsat, } @@ -55,13 +61,17 @@ impl ReportDisplay for VarBoundAnalysis { labels } - fn reports(&self, analyzer: &impl GraphBackend) -> Vec> { + fn reports( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec> { let mut report = Report::build( self.report_kind(), self.var_def.0.source(), self.var_def.0.start(), ) - .with_message(self.msg(analyzer)) + .with_message(self.msg(analyzer, arena)) .with_config( Config::default() .with_cross_gap(false) @@ -69,7 +79,7 @@ impl ReportDisplay for VarBoundAnalysis { .with_tab_width(4), ); - report.add_labels(self.labels(analyzer)); + report.add_labels(self.labels(analyzer, arena)); if let Some((killed_span, kind)) = &self.ctx_killed { report = report.with_label( @@ -93,15 +103,25 @@ impl ReportDisplay for VarBoundAnalysis { reports } - fn print_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { - let reports = self.reports(analyzer); + fn print_reports( + &self, + mut src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) { + let reports = self.reports(analyzer, arena); reports.into_iter().for_each(|report| { report.print(&mut src).unwrap(); }); } - fn eprint_reports(&self, mut src: &mut impl Cache, analyzer: &impl GraphBackend) { - let reports = self.reports(analyzer); + fn eprint_reports( + &self, + mut src: &mut impl Cache, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) { + let reports = self.reports(analyzer, arena); reports.into_iter().for_each(|report| { report.eprint(&mut src).unwrap(); }); diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index a473dc7c..a55d8426 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -226,9 +226,11 @@ fn main() { show_nonreverts: args.show_nonreverts.unwrap_or(true), }, }; - let mut analyzer = Analyzer::default(); - analyzer.max_depth = args.max_stack_depth; - analyzer.root = Root::RemappingsDirectory(env::current_dir().unwrap()); + let mut analyzer = Analyzer { + max_depth: args.max_stack_depth, + root: Root::RemappingsDirectory(env::current_dir().unwrap()), + ..Default::default() + }; println!("debug panic: {}", args.debug_panic); analyzer.debug_panic = args.debug_panic; @@ -253,15 +255,17 @@ fn main() { panic!("Unsupported file type") }; + let mut arena_base = Default::default(); + let arena = &mut arena_base; let t0 = std::time::Instant::now(); - let maybe_entry = analyzer.parse(&sol, ¤t_path, true); + let maybe_entry = analyzer.parse(arena, &sol, ¤t_path, true); let t_end = t0.elapsed(); let parse_time = t_end.as_millis(); println!("DONE ANALYZING IN: {parse_time}ms. Writing to cli..."); if args.stats { - println!("{}", analyzer.stats(t_end)); + println!("{}", analyzer.stats(t_end, arena)); } // println!("Arena: {:#?}", analyzer.range_arena); @@ -290,19 +294,19 @@ fn main() { analyzer.print_errors(&file_mapping, &mut source_map); if args.open_dot { - analyzer.open_dot() + analyzer.open_dot(arena) } if args.dot { - println!("{}", analyzer.dot_str_no_tmps()); + println!("{}", analyzer.dot_str_no_tmps(arena)); } if args.mermaid { - println!("{}", analyzer.mermaid_str()); + println!("{}", analyzer.mermaid_str(arena)); } if args.open_mermaid { - analyzer.open_mermaid(); + analyzer.open_mermaid(arena); } // println!("{}", analyzer.range_arena.ranges.iter().map(|i| { @@ -375,7 +379,7 @@ fn main() { if !args.funcs.is_empty() { if args.funcs.iter().any(|analyze_for| { FunctionNode::from(func) - .name(&analyzer) + .name(&mut analyzer) .unwrap() .starts_with(analyze_for) }) { @@ -395,17 +399,17 @@ fn main() { if let Some(mut solver) = BruteBinSearchSolver::maybe_new( c.ctx_deps(&analyzer).unwrap(), &mut analyzer, + arena, ) .unwrap() { - println!("created solver"); - match solver.solve(&mut analyzer).unwrap() { + match solver.solve(&mut analyzer, arena).unwrap() { AtomicSolveStatus::Unsat => { println!("TRUE UNSAT: {}", c.path(&analyzer)); } AtomicSolveStatus::Sat(ranges) => { - println!("-----------------------"); - println!("sat for: {}", c.path(&analyzer)); + // println!("-----------------------"); + // println!("sat for: {}", c.path(&analyzer)); ranges.iter().for_each(|(atomic, conc)| { println!( "{}: {}", @@ -415,17 +419,17 @@ fn main() { }); } AtomicSolveStatus::Indeterminate => { - println!("-----------------------"); - println!("sat for: {}", c.path(&analyzer)); - println!("MAYBE UNSAT"); + // println!("-----------------------"); + // println!("sat for: {}", c.path(&analyzer)); + // println!("MAYBE UNSAT"); } } } - println!("-----------------------"); + // println!("-----------------------"); let analysis = analyzer - .bounds_for_lineage(&file_mapping, *c, vec![*c], config) + .bounds_for_lineage(arena, &file_mapping, *c, vec![*c], config) .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); + analysis.print_reports(&mut source_map, &analyzer, arena); // return; } }); @@ -433,9 +437,9 @@ fn main() { } } else if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) + .bounds_for_all(arena, &file_mapping, ctx, config) .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); + analysis.print_reports(&mut source_map, &analyzer, arena); } } } else { @@ -451,19 +455,19 @@ fn main() { let funcs = contract.funcs(&analyzer); for func in funcs.into_iter() { if !args.funcs.is_empty() { - if args.funcs.contains(&func.name(&analyzer).unwrap()) { + if args.funcs.contains(&func.name(&mut analyzer).unwrap()) { let ctx = func.body_ctx(&mut analyzer); let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) + .bounds_for_all(arena, &file_mapping, ctx, config) .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); + analysis.print_reports(&mut source_map, &analyzer, arena); } } else { let ctx = func.body_ctx(&mut analyzer); let analysis = analyzer - .bounds_for_all(&file_mapping, ctx, config) + .bounds_for_all(arena, &file_mapping, ctx, config) .as_cli_compat(&file_mapping); - analysis.print_reports(&mut source_map, &analyzer); + analysis.print_reports(&mut source_map, &analyzer, arena); } } }); diff --git a/crates/graph/Cargo.toml b/crates/graph/Cargo.toml index 6bc26f70..af3dff3a 100644 --- a/crates/graph/Cargo.toml +++ b/crates/graph/Cargo.toml @@ -21,4 +21,7 @@ tracing.workspace = true tracing-subscriber.workspace = true itertools = "0.10.5" -lazy_static = "1.4.0" \ No newline at end of file +lazy_static = "1.4.0" + +[dev-dependencies] +pretty_assertions = "1.4.0" diff --git a/crates/graph/src/graph_elements.rs b/crates/graph/src/graph_elements.rs index bc3bbf95..652d643d 100644 --- a/crates/graph/src/graph_elements.rs +++ b/crates/graph/src/graph_elements.rs @@ -1,10 +1,11 @@ use crate::elem::Elem; use crate::{nodes::*, VarType}; -use shared::{AnalyzerLike, GraphLike, Heirarchical, NodeIdx}; +use shared::{AnalyzerLike, GraphLike, Heirarchical, NodeIdx, RangeArena}; use lazy_static::lazy_static; -use solang_parser::pt::Identifier; +use petgraph::{Directed, Graph}; +use solang_parser::pt::{Identifier, Loc}; use std::collections::HashMap; @@ -20,10 +21,20 @@ pub trait AnalyzerBackend: Function = Function, > + GraphBackend { + fn add_concrete_var( + &mut self, + ctx: ContextNode, + concrete: Concrete, + loc: Loc, + ) -> Result; } pub trait AsDotStr { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String; + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String; } #[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd)] @@ -102,24 +113,28 @@ pub enum Node { Block(Block), } -pub fn as_dot_str(idx: NodeIdx, analyzer: &impl GraphBackend) -> String { +pub fn as_dot_str( + idx: NodeIdx, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> String { use crate::Node::*; match analyzer.node(idx) { - Context(_) => ContextNode::from(idx).as_dot_str(analyzer), - ContextVar(_) => ContextVarNode::from(idx).as_dot_str(analyzer), + Context(_) => ContextNode::from(idx).as_dot_str(analyzer, arena), + ContextVar(_) => ContextVarNode::from(idx).as_dot_str(analyzer, arena), ContextFork => "Context Fork".to_string(), FunctionCall => "Function Call".to_string(), Builtin(bi) => bi.as_string(analyzer).unwrap(), - VarType(v_ty) => v_ty.as_dot_str(analyzer), - Contract(_c) => ContractNode::from(idx).as_dot_str(analyzer), - Function(_f) => FunctionNode::from(idx).as_dot_str(analyzer), - FunctionParam(_fp) => FunctionParamNode::from(idx).as_dot_str(analyzer), - FunctionReturn(_fr) => FunctionReturnNode::from(idx).as_dot_str(analyzer), - Struct(_s) => StructNode::from(idx).as_dot_str(analyzer), - Enum(_e) => EnumNode::from(idx).as_dot_str(analyzer), - Field(_f) => FieldNode::from(idx).as_dot_str(analyzer), - Var(_v) => VarNode::from(idx).as_dot_str(analyzer), - Ty(_t) => TyNode::from(idx).as_dot_str(analyzer), + VarType(v_ty) => v_ty.as_string(analyzer).unwrap(), + Contract(_c) => ContractNode::from(idx).as_dot_str(analyzer, arena), + Function(_f) => FunctionNode::from(idx).as_dot_str(analyzer, arena), + FunctionParam(_fp) => FunctionParamNode::from(idx).as_dot_str(analyzer, arena), + FunctionReturn(_fr) => FunctionReturnNode::from(idx).as_dot_str(analyzer, arena), + Struct(_s) => StructNode::from(idx).as_dot_str(analyzer, arena), + Enum(_e) => EnumNode::from(idx).as_dot_str(analyzer, arena), + Field(_f) => FieldNode::from(idx).as_dot_str(analyzer, arena), + Var(_v) => VarNode::from(idx).as_dot_str(analyzer, arena), + Ty(_t) => TyNode::from(idx).as_dot_str(analyzer, arena), // Concrete(c) => c.as_human_string(), e => format!("{e:?}"), } @@ -380,3 +395,29 @@ pub enum ContextEdge { /// Unused Range, } + +#[derive(Default)] +pub(crate) struct DummyGraph { + pub range_arena: RangeArena>, +} + +impl GraphLike for DummyGraph { + type Node = Node; + type Edge = Edge; + type RangeElem = Elem; + fn graph_mut(&mut self) -> &mut Graph { + panic!("Dummy Graph") + } + + fn graph(&self) -> &Graph { + panic!("Dummy Graph") + } + fn range_arena(&self) -> &RangeArena> { + &self.range_arena + } + fn range_arena_mut(&mut self) -> &mut RangeArena> { + &mut self.range_arena + } +} + +impl GraphBackend for DummyGraph {} diff --git a/crates/graph/src/nodes/block.rs b/crates/graph/src/nodes/block.rs index ded6ebc3..4ac5bf6a 100644 --- a/crates/graph/src/nodes/block.rs +++ b/crates/graph/src/nodes/block.rs @@ -1,5 +1,5 @@ -use crate::{AsDotStr, GraphBackend, GraphError, Node}; -use shared::NodeIdx; +use crate::{nodes::Concrete, range::elem::Elem, AsDotStr, GraphBackend, GraphError, Node}; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::{Address, H256, U256}; @@ -24,7 +24,11 @@ impl BlockNode { } impl AsDotStr for BlockNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { format!("block {{ {:?} }}", self.underlying(analyzer).unwrap()) } } diff --git a/crates/graph/src/nodes/builtin.rs b/crates/graph/src/nodes/builtin.rs index c9feff60..757ca985 100644 --- a/crates/graph/src/nodes/builtin.rs +++ b/crates/graph/src/nodes/builtin.rs @@ -1,7 +1,7 @@ use crate::{nodes::Concrete, AnalyzerBackend, GraphBackend, GraphError, Node, SolcRange, VarType}; use crate::range::elem::*; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::{Expression, Loc, Type}; @@ -251,6 +251,7 @@ impl Builtin { pub fn try_from_ty( ty: Type, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Option { use Type::*; match ty { @@ -265,8 +266,8 @@ impl Builtin { Rational => Some(Builtin::Rational), DynamicBytes => Some(Builtin::DynamicBytes), Mapping { key, value, .. } => { - let key_idx = analyzer.parse_expr(&key, None); - let val_idx = analyzer.parse_expr(&value, None); + let key_idx = analyzer.parse_expr(arena, &key, None); + let val_idx = analyzer.parse_expr(arena, &value, None); let key_var_ty = VarType::try_from_idx(analyzer, key_idx)?; let val_var_ty = VarType::try_from_idx(analyzer, val_idx)?; Some(Builtin::Mapping(key_var_ty, val_var_ty)) @@ -279,7 +280,7 @@ impl Builtin { let inputs = params .iter() .filter_map(|(_, param)| param.as_ref()) - .map(|param| analyzer.parse_expr(¶m.ty, None)) + .map(|param| analyzer.parse_expr(arena, ¶m.ty, None)) .collect::>(); let inputs = inputs .iter() @@ -290,7 +291,7 @@ impl Builtin { let tmp_outputs = params .iter() .filter_map(|(_, param)| param.as_ref()) - .map(|param| analyzer.parse_expr(¶m.ty, None)) + .map(|param| analyzer.parse_expr(arena, ¶m.ty, None)) .collect::>(); outputs = tmp_outputs .iter() diff --git a/crates/graph/src/nodes/concrete.rs b/crates/graph/src/nodes/concrete.rs index bd1c5ef3..eeafe272 100644 --- a/crates/graph/src/nodes/concrete.rs +++ b/crates/graph/src/nodes/concrete.rs @@ -106,12 +106,6 @@ impl Default for Concrete { } } -// impl From for Concrete { -// fn from(u: usize) -> Self { -// Concrete::Uint(256, U256::from(u)) -// } -// } - impl From for Concrete { fn from(u: U256) -> Self { Concrete::Uint(256, u) @@ -130,6 +124,14 @@ impl From> for Concrete { } } +impl From for Concrete { + fn from(u: u8) -> Self { + let mut h = H256::default(); + h.0[0] = u; + Concrete::Bytes(1, h) + } +} + impl From for Concrete { fn from(u: H256) -> Self { Concrete::Bytes(32, u) @@ -163,13 +165,26 @@ impl From for Concrete { } } -impl> From> for Concrete { - fn from(u: Vec) -> Self { - Concrete::Array(u.into_iter().map(|t| t.into()).collect()) +impl From<&str> for Concrete { + fn from(u: &str) -> Self { + Concrete::String(u.to_string()) } } +// impl> From> for Concrete { +// fn from(u: Vec) -> Self { +// Concrete::Array(u.into_iter().map(|t| t.into()).collect()) +// } +// } + impl Concrete { + pub fn raw_bits_u256(&self) -> Option { + match self { + Concrete::Int(_, val) => Some(val.into_raw()), + _ => self.into_u256(), + } + } + pub fn set_indices(&mut self, other: &Self) { match (self, other) { (Concrete::DynBytes(s), Concrete::DynBytes(o)) => { @@ -308,8 +323,23 @@ impl Concrete { } } + pub fn is_zero(&self) -> bool { + self.into_u256() == Some(U256::zero()) + } + + pub fn is_one(&self) -> bool { + self.into_u256() == Some(U256::from(1)) + } + /// Cast from one concrete variant given another concrete variant pub fn cast_from(self, other: &Self) -> Option { + if let (Concrete::DynBytes(s), Concrete::DynBytes(o)) = (&self, other) { + if s.len() < o.len() { + let mut t = s.clone(); + t.resize(o.len(), 0); + return Some(Concrete::DynBytes(t)); + } + } self.cast(other.as_builtin()) } @@ -346,6 +376,13 @@ impl Concrete { matches!(self, Concrete::Int(_, _)) } + pub fn size_wrap(self) -> Self { + match self { + Concrete::Int(size, val) => Concrete::Int(256, val).cast(Builtin::Int(size)).unwrap(), + _ => self, + } + } + /// Performs a literal cast to another type pub fn literal_cast(self, builtin: Builtin) -> Option { match self { @@ -462,33 +499,39 @@ impl Concrete { bit_repr.cast(builtin) } Builtin::Int(size) => { - // no op - if r_size == size { - Some(self) - } else { - let mask = if size == 256 { - U256::MAX / 2 - } else { - U256::from(2).pow((size - 1).into()) - 1 - }; + match r_size.cmp(&size) { + std::cmp::Ordering::Less => { + // upcast + Some(Concrete::Int(size, val)) + } + std::cmp::Ordering::Equal => { + // noop + Some(self) + } + std::cmp::Ordering::Greater => { + // downcast + let mask = if size == 256 { + U256::MAX / 2 + } else { + U256::from(2).pow((size).into()) - 1 + }; - let (_sign, abs) = val.into_sign_and_abs(); + let raw = val.into_raw(); - if abs < mask { - Some(Concrete::Int(size, val)) - } else { - // check if the top bit for the new value is set on the existing value - // if it is, then the cast will result in a negative number - let top_mask = - if abs & (U256::from(1) << U256::from(size)) != U256::zero() { - // sign extension - ((U256::from(1) << U256::from(257 - size)) - U256::from(1)) - << U256::from(size - 1) - } else { - U256::from(0) - }; - - Some(Concrete::Int(size, I256::from_raw((abs & mask) | top_mask))) + if raw < mask / U256::from(2) { + Some(Concrete::Int(size, val)) + } else { + let base_value = raw & mask; + let res = + if base_value >> (size - 1) & U256::from(1) == U256::from(1) { + let top = U256::MAX << size; + base_value | top + } else { + base_value + }; + + Some(Concrete::Int(size, I256::from_raw(res))) + } } } } @@ -687,7 +730,7 @@ impl Concrete { } /// Gets the default max for a given concrete variant. - pub fn max(&self) -> Option { + pub fn max_of_type(&self) -> Option { match self { Concrete::Uint(size, _) => { let max = if *size == 256 { @@ -798,7 +841,7 @@ impl Concrete { } /// Gets the default min for a given concrete variant. - pub fn min(&self) -> Option { + pub fn min_of_type(&self) -> Option { match self { Concrete::Uint(size, _) => Some(Concrete::Uint(*size, 0.into())), Concrete::Int(size, _) => { @@ -851,6 +894,10 @@ impl Concrete { } } + pub fn is_negative(&self) -> bool { + matches!(self, Concrete::Int(_, val) if *val < I256::from(0)) + } + pub fn as_hex_string(&self) -> String { match self { Concrete::Uint(_, val) => { diff --git a/crates/graph/src/nodes/context/expr_ret.rs b/crates/graph/src/nodes/context/expr_ret.rs index b9b6b782..2195fef9 100644 --- a/crates/graph/src/nodes/context/expr_ret.rs +++ b/crates/graph/src/nodes/context/expr_ret.rs @@ -1,5 +1,9 @@ -use crate::{nodes::context::ContextVarNode, AsDotStr, GraphBackend, GraphError, Node, VarType}; -use shared::NodeIdx; +use crate::{ + nodes::{context::ContextVarNode, Concrete}, + range::elem::Elem, + AsDotStr, GraphBackend, GraphError, Node, VarType, +}; +use shared::{NodeIdx, RangeArena}; /// The reason a context was killed #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -47,8 +51,12 @@ impl ExprRet { pub fn debug_str(&self, analyzer: &impl GraphBackend) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => match analyzer.node(*inner) { - Node::ContextVar(_) => ContextVarNode::from(*inner).display_name(analyzer).unwrap(), - e => format!("{:?}", e), + Node::ContextVar(_) => format!( + "idx_{}: {}", + inner.index(), + ContextVarNode::from(*inner).display_name(analyzer).unwrap() + ), + e => format!("idx_{}: {:?}", inner.index(), e), }, ExprRet::Multi(inner) => { format!( @@ -198,14 +206,18 @@ impl ExprRet { } /// Try to convert to a solidity-like function input string, i.e. `(uint256, uint256, bytes32)` - pub fn try_as_func_input_str(&self, analyzer: &impl GraphBackend) -> String { + pub fn try_as_func_input_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { match self { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => { let idx = inner; match VarType::try_from_idx(analyzer, *idx) { Some(var_ty) => { if let Ok(ty) = var_ty.unresolved_as_resolved(analyzer) { - format!("({})", ty.as_dot_str(analyzer)) + format!("({})", ty.as_dot_str(analyzer, arena)) } else { "".to_string() } @@ -216,7 +228,10 @@ impl ExprRet { ExprRet::Multi(inner) => { let mut strs = vec![]; for ret in inner.iter() { - strs.push(ret.try_as_func_input_str(analyzer).replace(['(', ')'], "")); + strs.push( + ret.try_as_func_input_str(analyzer, arena) + .replace(['(', ')'], ""), + ); } format!("({})", strs.join(", ")) } @@ -276,4 +291,8 @@ impl ExprRet { ExprRet::Null => 0, } } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } } diff --git a/crates/graph/src/nodes/context/node.rs b/crates/graph/src/nodes/context/node.rs index 4a6fb6aa..6c4bb8d5 100644 --- a/crates/graph/src/nodes/context/node.rs +++ b/crates/graph/src/nodes/context/node.rs @@ -1,9 +1,10 @@ use crate::{ - nodes::{Context, ContextVarNode, KilledKind}, + nodes::{Concrete, Context, ContextVarNode, KilledKind}, + range::elem::Elem, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::Loc; @@ -12,7 +13,11 @@ use solang_parser::pt::Loc; pub struct ContextNode(pub usize); impl AsDotStr for ContextNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { format!("Context {{ {} }}", self.path(analyzer)) } } diff --git a/crates/graph/src/nodes/context/querying.rs b/crates/graph/src/nodes/context/querying.rs index 717289eb..16fd28a9 100644 --- a/crates/graph/src/nodes/context/querying.rs +++ b/crates/graph/src/nodes/context/querying.rs @@ -115,12 +115,14 @@ impl ContextNode { .map(|modifier_set| { let as_vec = modifier_set.iter().collect::>(); - if as_vec.len() > 2 { - panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") - } else if as_vec.len() == 2 { - as_vec[0].get_overriding(as_vec[1], analyzer) - } else { - Ok(*as_vec[0]) + match as_vec.len() { + 2 => { + as_vec[0].get_overriding(as_vec[1], analyzer) + } + 3.. => { + panic!("3+ visible functions with the same name. This is invalid solidity, {as_vec:#?}") + } + _ => Ok(*as_vec[0]) } }) .collect() diff --git a/crates/graph/src/nodes/context/solving.rs b/crates/graph/src/nodes/context/solving.rs index c66aef3d..af834be9 100644 --- a/crates/graph/src/nodes/context/solving.rs +++ b/crates/graph/src/nodes/context/solving.rs @@ -1,30 +1,35 @@ use crate::elem::Elem; + use crate::{ - as_dot_str, - nodes::{ContextNode, ContextVarNode}, - range::{elem::RangeOp, Range, RangeEval}, + nodes::{Concrete, ContextNode, ContextVarNode}, + range::Range, solvers::{ dl::{DLSolver, SolveStatus}, Atomize, SolverAtom, }, - AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, + AnalyzerBackend, GraphBackend, GraphError, }; use std::borrow::Cow; -use shared::NodeIdx; - -use petgraph::dot::Dot; +use shared::RangeArena; use std::collections::BTreeMap; impl ContextNode { /// Use a Difference Logic solver to see if it is unreachable - pub fn unreachable(&self, analyzer: &impl GraphBackend) -> Result { + pub fn unreachable( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { // println!("checking unreachable: {}", self.path(analyzer)); let mut solver = self.dl_solver(analyzer)?.clone(); - match solver.solve_partial(analyzer)? { - SolveStatus::Unsat => Ok(true), - e => { + match solver.solve_partial(analyzer, arena)? { + SolveStatus::Unsat => { + tracing::trace!("{} is unreachable via UNSAT", self.path(analyzer)); + Ok(true) + } + _e => { // println!("other: {e:?}"); Ok(false) } @@ -35,12 +40,13 @@ impl ContextNode { pub fn dep_atoms( &self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { let deps: Vec<_> = self.ctx_deps(analyzer)?; let mut ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { let mut range = dep.range(analyzer)?.unwrap(); - let r: Cow<'_, _> = range.flattened_range(analyzer)?; + let r: Cow<'_, _> = range.flattened_range(analyzer, arena)?; ranges.insert(*dep, r.into_owned()); Ok(()) })?; @@ -48,10 +54,10 @@ impl ContextNode { Ok(ranges .iter() .filter_map(|(_dep, range)| { - if let Some(atom) = Elem::Arena(range.min).atomize(analyzer) { + if let Some(atom) = Elem::Arena(range.min).atomize(analyzer, arena) { Some(atom) } else { - Elem::Arena(range.max).atomize(analyzer) + Elem::Arena(range.max).atomize(analyzer, arena) } }) .collect::>()) @@ -79,11 +85,27 @@ impl ContextNode { Ok(deps) } + pub fn debug_ctx_deps( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + let deps = self.ctx_deps(analyzer)?; + deps.iter().enumerate().for_each(|(i, var)| { + println!( + "{i}. {}", + var.as_controllable_name(analyzer, arena).unwrap() + ) + }); + Ok(()) + } + /// Adds a dependency for this context to exit successfully pub fn add_ctx_dep( &self, dep: ContextVarNode, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { tracing::trace!( "Adding ctx ({}) dependency: {}, is_controllable: {}", @@ -96,20 +118,31 @@ impl ContextNode { if !self.underlying(analyzer)?.ctx_deps.contains(&dep) { // dep.cache_flattened_range(analyzer)?; let mut range = dep.range(analyzer)?.unwrap(); - let r = range.flattened_range(analyzer)?.into_owned(); + + let min = range.simplified_range_min(analyzer, arena)?; + let max = range.simplified_range_max(analyzer, arena)?; + + let true_elem = Elem::from(true); + let trivial_sat = min == true_elem && max == true_elem; + if trivial_sat || min == Elem::Null || max == Elem::Null { + return Ok(()); + } + + let r = range.flattened_range(analyzer, arena)?.into_owned(); + // add the atomic constraint - if let Some(atom) = Elem::Arena(r.min).atomize(analyzer) { + if let Some(atom) = Elem::Arena(r.min).atomize(analyzer, arena) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); - let constraints = solver.add_constraints(vec![atom], analyzer); + let constraints = solver.add_constraints(vec![atom], analyzer, arena); constraints .into_iter() .for_each(|(constraint, normalized)| { solver.add_constraint(constraint, normalized); }); self.underlying_mut(analyzer)?.dl_solver = solver; - } else if let Some(atom) = Elem::Arena(r.max).atomize(analyzer) { + } else if let Some(atom) = Elem::Arena(r.max).atomize(analyzer, arena) { let mut solver = std::mem::take(&mut self.underlying_mut(analyzer)?.dl_solver); - let constraints = solver.add_constraints(vec![atom], analyzer); + let constraints = solver.add_constraints(vec![atom], analyzer, arena); constraints .into_iter() .for_each(|(constraint, normalized)| { @@ -124,125 +157,4 @@ impl ContextNode { } Ok(()) } - - /// Creates a DAG of the context dependencies and opens it with graphviz - pub fn deps_dag(&self, g: &impl GraphBackend) -> Result<(), GraphError> { - let deps = self.ctx_deps(g)?; - // #[derive(Debug, Copy, Clone)] - // pub enum DepEdge { - // Lhs, - // Rhs, - // } - - let mut gr: petgraph::Graph = - petgraph::Graph::default(); - - let mut contains: BTreeMap> = - BTreeMap::default(); - deps.iter().try_for_each(|dep| { - let mapping = dep.graph_dependent_on(g)?; - mapping.into_iter().for_each(|(_k, tmp)| { - if let Some(rhs) = tmp.rhs { - let lhs = if let Some(ver) = contains.keys().find(|other| { - other.ref_range(g).unwrap() == tmp.lhs.ref_range(g).unwrap() - && tmp.lhs.display_name(g).unwrap() == other.display_name(g).unwrap() - }) { - *contains.get(ver).unwrap() - } else { - let lhs = gr.add_node(tmp.lhs.into()); - contains.insert(tmp.lhs, lhs); - lhs - }; - - let new_rhs = if let Some(ver) = contains.keys().find(|other| { - other.range(g).unwrap() == rhs.range(g).unwrap() - && rhs.display_name(g).unwrap() == other.display_name(g).unwrap() - }) { - *contains.get(ver).unwrap() - } else { - let new_rhs = gr.add_node(rhs.into()); - contains.insert(rhs, new_rhs); - new_rhs - }; - gr.add_edge(lhs, new_rhs, tmp.op); - } - }); - Ok(()) - })?; - - let mut dot_str = Vec::new(); - let raw_start_str = r##"digraph G { - node [shape=box, style="filled, rounded", color="#565f89", fontcolor="#d5daf0", fontname="Helvetica", fillcolor="#24283b"]; - edge [color="#414868", fontcolor="#c0caf5", fontname="Helvetica"]; - bgcolor="#1a1b26";"##; - dot_str.push(raw_start_str.to_string()); - let nodes_and_edges_str = format!( - "{:?}", - Dot::with_attr_getters( - &gr, - &[ - petgraph::dot::Config::GraphContentOnly, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::EdgeNoLabel - ], - &|_graph, edge_ref| { - let e = edge_ref.weight(); - format!("label = \"{e:?}\"") - }, - &|_graph, (idx, node_ref)| { - let inner = match g.node(*node_ref) { - Node::ContextVar(cvar) => { - let range_str = if let Some(r) = cvar.ty.ref_range(g).unwrap() { - r.as_dot_str(g) - // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) - } else { - "".to_string() - }; - - format!( - "{} -- {} -- range: {}", - cvar.display_name, - cvar.ty.as_string(g).unwrap(), - range_str - ) - } - _ => as_dot_str(idx, g), - }; - format!( - "label = \"{}\", color = \"{}\"", - inner.replace('\"', "\'"), - g.node(*node_ref).dot_str_color() - ) - } - ) - ); - dot_str.push(nodes_and_edges_str); - let raw_end_str = r#"}"#; - dot_str.push(raw_end_str.to_string()); - let dot_str = dot_str.join("\n"); - - println!("{dot_str}"); - use std::env::temp_dir; - use std::fs; - use std::io::Write; - use std::process::Command; - let mut dir = temp_dir(); - let file_name = "dot.dot"; - dir.push(file_name); - - let mut file = fs::File::create(dir.clone()).unwrap(); - file.write_all(dot_str.as_bytes()).unwrap(); - Command::new("dot") - .arg("-Tsvg") - .arg(dir) - .arg("-o") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Command::new("open") - .arg("dot.svg") - .output() - .expect("failed to execute process"); - Ok(()) - } } diff --git a/crates/graph/src/nodes/context/var/node.rs b/crates/graph/src/nodes/context/var/node.rs index 4fcb102e..8d1df01f 100644 --- a/crates/graph/src/nodes/context/var/node.rs +++ b/crates/graph/src/nodes/context/var/node.rs @@ -1,10 +1,10 @@ use crate::{ - nodes::{ContextNode, ContextVar, TmpConstruction, VarNode}, - range::{elem::RangeElem, range_string::ToRangeString, Range}, + nodes::{Concrete, ContextNode, ContextVar, TmpConstruction, VarNode}, + range::{elem::*, range_string::ToRangeString, Range}, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, }; -use shared::{NodeIdx, Search, StorageLocation}; +use shared::{NodeIdx, RangeArena, Search, StorageLocation}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::Loc; @@ -15,19 +15,23 @@ use std::collections::BTreeMap; pub struct ContextVarNode(pub usize); impl AsDotStr for ContextVarNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); let range_str = if let Some(r) = underlying.ty.ref_range(analyzer).unwrap() { format!( "[{}, {}]", - r.evaled_range_min(analyzer) + r.evaled_range_min(analyzer, arena) .unwrap() - .to_range_string(false, analyzer) + .to_range_string(false, analyzer, arena) .s, - r.evaled_range_max(analyzer) + r.evaled_range_max(analyzer, arena) .unwrap() - .to_range_string(true, analyzer) + .to_range_string(true, analyzer, arena) .s ) } else { @@ -142,19 +146,22 @@ impl ContextVarNode { Ok(self.underlying(analyzer)?.name.clone()) } - pub fn as_controllable_name(&self, analyzer: &impl GraphBackend) -> Result { - if let Some(ref_range) = self.ref_range(analyzer)? { - let min_name = ref_range - .range_min() - .simplify_minimize(analyzer)? - .to_range_string(false, analyzer) - .s; - + pub fn as_controllable_name( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + if self.is_fundamental(analyzer)? { + self.display_name(analyzer) + } else if let Some(ref_range) = self.ref_range(analyzer)? { + let min_name = ref_range.range_min().simplify_minimize(analyzer, arena)?; + let min_name = min_name.to_range_string(false, analyzer, arena).s; let max_name = ref_range .range_max() - .simplify_maximize(analyzer)? - .to_range_string(true, analyzer) + .simplify_maximize(analyzer, arena)? + .to_range_string(true, analyzer, arena) .s; + if max_name == min_name { Ok(max_name) } else { diff --git a/crates/graph/src/nodes/context/var/ranging.rs b/crates/graph/src/nodes/context/var/ranging.rs index 4a8b20e3..8f0fbef1 100644 --- a/crates/graph/src/nodes/context/var/ranging.rs +++ b/crates/graph/src/nodes/context/var/ranging.rs @@ -1,10 +1,11 @@ +use crate::range::elem::*; use crate::{ nodes::{Concrete, ContextVarNode}, range::{range_string::ToRangeString, Range, RangeEval}, AnalyzerBackend, GraphBackend, GraphError, SolcRange, VarType, }; -use crate::range::elem::*; +use shared::RangeArena; use solang_parser::pt::Loc; @@ -13,17 +14,21 @@ impl ContextVarNode { self.underlying(analyzer)?.ty.range(analyzer) } - pub fn range_string(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn range_string( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { Ok(Some(format!( "[ {}, {} ]", range - .evaled_range_min(analyzer)? - .to_range_string(false, analyzer) + .evaled_range_min(analyzer, arena)? + .to_range_string(false, analyzer, arena) .s, range - .evaled_range_max(analyzer)? - .to_range_string(true, analyzer) + .evaled_range_max(analyzer, arena)? + .to_range_string(true, analyzer, arena) .s ))) } else { @@ -33,18 +38,19 @@ impl ContextVarNode { pub fn simplified_range_string( &self, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { Ok(Some(format!( "[ {}, {} ]", range - .simplified_range_min(analyzer)? - .to_range_string(false, analyzer) + .simplified_range_min(analyzer, arena)? + .to_range_string(false, analyzer, arena) .s, range - .simplified_range_max(analyzer)? - .to_range_string(true, analyzer) + .simplified_range_max(analyzer, arena)? + .to_range_string(true, analyzer, arena) .s ))) } else { @@ -84,9 +90,10 @@ impl ContextVarNode { pub fn evaled_range_min( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.evaled_range_min(analyzer)?)) + Ok(Some(r.evaled_range_min(analyzer, arena)?)) } else { Ok(None) } @@ -95,9 +102,10 @@ impl ContextVarNode { pub fn evaled_range_max( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result>, GraphError> { if let Some(r) = self.ref_range(analyzer)? { - Ok(Some(r.evaled_range_max(analyzer)?)) + Ok(Some(r.evaled_range_max(analyzer, arena)?)) } else { Ok(None) } @@ -117,10 +125,14 @@ impl ContextVarNode { } } - pub fn cache_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + pub fn cache_range( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { // range.cache_flatten(analyzer)?; - range.cache_eval(analyzer)?; + range.cache_eval(analyzer, arena)?; self.set_range(analyzer, range)?; } Ok(()) @@ -129,17 +141,22 @@ impl ContextVarNode { pub fn cache_flattened_range( &self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { - range.cache_flatten(analyzer)?; + range.cache_flatten(analyzer, arena)?; self.set_range(analyzer, range)?; } Ok(()) } - pub fn cache_eval_range(&self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + pub fn cache_eval_range( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { if let Some(mut range) = self.ty_mut(analyzer)?.take_range() { - range.cache_eval(analyzer)?; + range.cache_eval(analyzer, arena)?; self.set_range(analyzer, range)?; } Ok(()) @@ -178,9 +195,10 @@ impl ContextVarNode { &self, elem: Elem, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { if let Some(r) = self.ref_range(analyzer)? { - Ok(r.contains_elem(&elem, analyzer)) + Ok(r.contains_elem(&elem, analyzer, arena)) } else { Ok(false) } @@ -190,36 +208,44 @@ impl ContextVarNode { pub fn set_range_min( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, mut new_min: Elem, ) -> Result<(), GraphError> { assert!(self.latest_version(analyzer) == *self); - if new_min.recursive_dependent_on(analyzer)?.contains(self) { + if new_min + .recursive_dependent_on(analyzer, arena)? + .contains(self) + { if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into(), analyzer); + new_min.filter_recursion((*self).into(), prev.into(), analyzer, arena); } else { return Err(GraphError::UnbreakableRecursion(format!("The variable {}'s range is self-referential and we cannot break the recursion.", self.display_name(analyzer)?))); } } - new_min.arenaize(analyzer)?; + tracing::trace!("new min: {new_min}"); + new_min.arenaize(analyzer, arena)?; // new_min.cache_flatten(analyzer)?; // new_min.cache_minimize(analyzer)?; tracing::trace!( - "setting range minimum: {} (node idx: {}), current:{}, new_min:{}, deps: {:#?}", + "setting range minimum: {} (node idx: {}), current:{}, new_min:{} ({}), deps: {:#?}", self.display_name(analyzer)?, self.0, - self.range_min(analyzer)?.unwrap(), + self.range_min(analyzer) + .unwrap_or_default() + .unwrap_or_default(), + new_min.recurse_dearenaize(analyzer, arena), new_min, - new_min.recursive_dependent_on(analyzer)? + new_min.recursive_dependent_on(analyzer, arena)? ); if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; self.underlying_mut(analyzer)?.ty = new_ty; - self.set_range_min(analyzer, new_min)?; + self.set_range_min(analyzer, arena, new_min)?; } else { let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? @@ -229,7 +255,7 @@ impl ContextVarNode { self.underlying_mut(analyzer)? .set_range_min(new_min, fallback)?; } - self.cache_range(analyzer)?; + self.cache_range(analyzer, arena)?; Ok(()) } @@ -237,16 +263,20 @@ impl ContextVarNode { pub fn set_range_max( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, mut new_max: Elem, ) -> Result<(), GraphError> { assert!(self.latest_version(analyzer) == *self); - if new_max.recursive_dependent_on(analyzer)?.contains(self) { + if new_max + .recursive_dependent_on(analyzer, arena)? + .contains(self) + { if let Some(prev) = self.previous_or_inherited_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into(), analyzer); + new_max.filter_recursion((*self).into(), prev.into(), analyzer, arena); } } - new_max.arenaize(analyzer)?; + new_max.arenaize(analyzer, arena)?; tracing::trace!( "setting range maximum: {:?}, {}, current: {}, new: {}", @@ -260,7 +290,7 @@ impl ContextVarNode { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; self.underlying_mut(analyzer)?.ty = new_ty; - self.set_range_max(analyzer, new_max)?; + self.set_range_max(analyzer, arena, new_max)?; } else { let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? @@ -272,7 +302,7 @@ impl ContextVarNode { .set_range_max(new_max, fallback)?; } - self.cache_range(analyzer)?; + self.cache_range(analyzer, arena)?; Ok(()) } @@ -305,22 +335,26 @@ impl ContextVarNode { pub fn try_set_range_min( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, mut new_min: Elem, ) -> Result { assert!(self.latest_version(analyzer) == *self); - if new_min.recursive_dependent_on(analyzer)?.contains(self) { + if new_min + .recursive_dependent_on(analyzer, arena)? + .contains(self) + { if let Some(prev) = self.previous_version(analyzer) { - new_min.filter_recursion((*self).into(), prev.into(), analyzer); + new_min.filter_recursion((*self).into(), prev.into(), analyzer, arena); } } - new_min.arenaize(analyzer)?; + new_min.arenaize(analyzer, arena)?; if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; self.underlying_mut(analyzer)?.ty = new_ty; - self.try_set_range_min(analyzer, new_min) + self.try_set_range_min(analyzer, arena, new_min) } else { let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? @@ -336,22 +370,26 @@ impl ContextVarNode { pub fn try_set_range_max( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, mut new_max: Elem, ) -> Result { assert!(self.latest_version(analyzer) == *self); - if new_max.recursive_dependent_on(analyzer)?.contains(self) { + if new_max + .recursive_dependent_on(analyzer, arena)? + .contains(self) + { if let Some(prev) = self.previous_version(analyzer) { - new_max.filter_recursion((*self).into(), prev.into(), analyzer); + new_max.filter_recursion((*self).into(), prev.into(), analyzer, arena); } } - new_max.arenaize(analyzer)?; + new_max.arenaize(analyzer, arena)?; if self.is_concrete(analyzer)? { let mut new_ty = self.ty(analyzer)?.clone(); new_ty.concrete_to_builtin(analyzer)?; self.underlying_mut(analyzer)?.ty = new_ty; - self.try_set_range_max(analyzer, new_max) + self.try_set_range_max(analyzer, arena, new_max) } else { let fallback = if self.needs_fallback(analyzer)? { self.fallback_range(analyzer)? @@ -390,9 +428,13 @@ impl ContextVarNode { .try_set_range_exclusions(new_exclusions, fallback)) } - pub fn range_deps(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + pub fn range_deps( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(range) = self.ref_range(analyzer)? { - Ok(range.dependent_on(analyzer)) + Ok(range.dependent_on(analyzer, arena)) } else { Ok(vec![]) } diff --git a/crates/graph/src/nodes/context/var/typing.rs b/crates/graph/src/nodes/context/var/typing.rs index 5603b8b3..4ca75ccf 100644 --- a/crates/graph/src/nodes/context/var/typing.rs +++ b/crates/graph/src/nodes/context/var/typing.rs @@ -1,11 +1,14 @@ use crate::{ elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVarNode}, - range::{elem::RangeElem, RangeEval}, + range::{ + elem::{RangeElem, RangeExpr, RangeOp}, + RangeEval, + }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; -use shared::{Search, StorageLocation}; +use shared::{RangeArena, Search, StorageLocation}; use ethers_core::types::{I256, U256}; use petgraph::{visit::EdgeRef, Direction}; @@ -16,6 +19,42 @@ impl ContextVarNode { Ok(&self.underlying(analyzer)?.ty) } + pub fn ty_max_concrete( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + if let Ok(b) = self.underlying(analyzer)?.ty.as_builtin(analyzer) { + if let Some(zero) = b.zero_concrete() { + return Ok(Concrete::max_of_type(&zero)); + } + } + + Ok(None) + } + pub fn ty_min_concrete( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + if let Ok(b) = self.underlying(analyzer)?.ty.as_builtin(analyzer) { + if let Some(zero) = b.zero_concrete() { + return Ok(Concrete::min_of_type(&zero)); + } + } + + Ok(None) + } + + pub fn ty_zero_concrete( + &self, + analyzer: &impl GraphBackend, + ) -> Result, GraphError> { + if let Ok(b) = self.underlying(analyzer)?.ty.as_builtin(analyzer) { + return Ok(b.zero_concrete()); + } + + Ok(None) + } + pub fn ty_eq_ty( &self, other: &VarType, @@ -204,9 +243,13 @@ impl ContextVarNode { }) } - pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { + pub fn is_const( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { let underlying = self.underlying(analyzer)?; - underlying.ty.is_const(analyzer) + underlying.ty.is_const(analyzer, arena) } pub fn is_symbolic(&self, analyzer: &impl GraphBackend) -> Result { @@ -312,13 +355,34 @@ impl ContextVarNode { self.ty(analyzer)?.ty_eq(other.ty(analyzer)?, analyzer) } + /// Performs an in-place cast pub fn cast_from( &self, other: &Self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { - let to_ty = other.ty(analyzer)?.clone(); - self.cast_from_ty(to_ty, analyzer)?; + let other_ty = other.ty(analyzer)?.clone(); + if other_ty.ty_eq(&self.underlying(analyzer)?.ty, analyzer)? { + return Ok(()); + } + + let min_expr = Elem::Expr(RangeExpr::new( + self.range_min(analyzer)?.expect("Should have a minimum"), + RangeOp::Cast, + Elem::from(*other), + )); + + let max_expr = Elem::Expr(RangeExpr::new( + self.range_max(analyzer)?.expect("Should have a maximum"), + RangeOp::Cast, + Elem::from(*other), + )); + + self.underlying_mut(analyzer)?.ty = other_ty; + + self.set_range_min(analyzer, arena, min_expr)?; + self.set_range_max(analyzer, arena, max_expr)?; Ok(()) } @@ -366,6 +430,7 @@ impl ContextVarNode { &self, to_ty: VarType, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); if !from_ty.ty_eq(&to_ty, analyzer)? { @@ -376,8 +441,8 @@ impl ContextVarNode { if let (Some(mut r), Some(r2)) = (self.ty_mut(analyzer)?.take_range(), to_ty.range(analyzer)?) { - r.min.arenaize(analyzer)?; - r.max.arenaize(analyzer)?; + r.min.arenaize(analyzer, arena)?; + r.max.arenaize(analyzer, arena)?; let mut min_expr = r .min @@ -390,11 +455,11 @@ impl ContextVarNode { .cast(r2.min.clone()) .max(r.max.clone().cast(r2.min)); - min_expr.arenaize(analyzer)?; - max_expr.arenaize(analyzer)?; + min_expr.arenaize(analyzer, arena)?; + max_expr.arenaize(analyzer, arena)?; let zero = Elem::from(Concrete::from(U256::zero())); - if r.contains_elem(&zero, analyzer) { + if r.contains_elem(&zero, analyzer, arena) { min_expr = min_expr.min(zero.clone()); max_expr = max_expr.max(zero); } @@ -410,7 +475,7 @@ impl ContextVarNode { let int_min = int.min_concrete().unwrap(); let bit_repr = int_min.bit_representation().unwrap(); let bit_repr = bit_repr.into(); - if r.contains_elem(&bit_repr, analyzer) { + if r.contains_elem(&bit_repr, analyzer, arena) { min_expr = min_expr.min(int_min.clone().into()); max_expr = max_expr.max(int_min.into()); } @@ -420,7 +485,7 @@ impl ContextVarNode { // from ty is int, to ty is uint if let Some(r) = self.ref_range(analyzer)? { let neg1 = Concrete::from(I256::from(-1i32)); - if r.contains_elem(&neg1.clone().into(), analyzer) { + if r.contains_elem(&neg1.clone().into(), analyzer, arena) { max_expr = max_expr.max(neg1.bit_representation().unwrap().into()); } @@ -431,8 +496,8 @@ impl ContextVarNode { } r.min = min_expr; r.max = max_expr; - r.min.arenaize(analyzer)?; - r.max.arenaize(analyzer)?; + r.min.arenaize(analyzer, arena)?; + r.max.arenaize(analyzer, arena)?; self.set_range(analyzer, r)?; } } @@ -466,9 +531,13 @@ impl ContextVarNode { Ok(()) } - pub fn try_increase_size(&self, analyzer: &mut impl AnalyzerBackend) -> Result<(), GraphError> { + pub fn try_increase_size( + &self, + analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { let from_ty = self.ty(analyzer)?.clone(); - self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer)?; + self.cast_from_ty(from_ty.max_size(analyzer)?, analyzer, arena)?; Ok(()) } @@ -480,6 +549,7 @@ impl ContextVarNode { &self, to_ty: &VarType, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result, Elem)>, GraphError> { if let Some(to_range) = to_ty.range(analyzer)? { let mut min_expr = (*self) @@ -500,7 +570,7 @@ impl ContextVarNode { if let Some(r) = self.ref_range(analyzer)? { let zero = Elem::from(Concrete::from(U256::zero())); - if r.contains_elem(&zero, analyzer) { + if r.contains_elem(&zero, analyzer, arena) { min_expr = min_expr.min(zero.clone()); max_expr = max_expr.max(zero); } @@ -517,7 +587,7 @@ impl ContextVarNode { let int_min = int.min_concrete().unwrap(); let bit_repr = int_min.bit_representation().unwrap(); let bit_repr = bit_repr.into(); - if r.contains_elem(&bit_repr, analyzer) { + if r.contains_elem(&bit_repr, analyzer, arena) { min_expr = min_expr.min(int_min.clone().into()); max_expr = max_expr.max(int_min.into()); } @@ -527,7 +597,7 @@ impl ContextVarNode { // from ty is int, to ty is uint if let Some(r) = self.ref_range(analyzer)? { let neg1 = Concrete::from(I256::from(-1i32)); - if r.contains_elem(&neg1.clone().into(), analyzer) { + if r.contains_elem(&neg1.clone().into(), analyzer, arena) { max_expr = max_expr.max(neg1.bit_representation().unwrap().into()); } } diff --git a/crates/graph/src/nodes/context/var/underlying.rs b/crates/graph/src/nodes/context/var/underlying.rs index ac799221..ff31d6fb 100644 --- a/crates/graph/src/nodes/context/var/underlying.rs +++ b/crates/graph/src/nodes/context/var/underlying.rs @@ -228,7 +228,7 @@ impl ContextVar { pub fn new_from_builtin( loc: Loc, bn_node: BuiltInNode, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, ) -> Result { Ok(ContextVar { loc: Some(loc), diff --git a/crates/graph/src/nodes/context/versioning.rs b/crates/graph/src/nodes/context/versioning.rs index 714bc308..0af39443 100644 --- a/crates/graph/src/nodes/context/versioning.rs +++ b/crates/graph/src/nodes/context/versioning.rs @@ -1,3 +1,4 @@ +use crate::nodes::Context; use crate::ContextEdge; use crate::Edge; use crate::{ @@ -299,7 +300,7 @@ impl ContextNode { Some(CallFork::Call(call)) => format!("call {{ {} }}", call.path(analyzer)), None => unreachable!(), }; - Err(GraphError::ChildRedefinition(format!( + Err(GraphError::ChildRedefinition(panic!( "This is a bug. Tried to redefine a child context, parent:\n{}, current child:\n{},\nnew child: Fork({}, {})", self.path(analyzer), child_str, @@ -311,6 +312,64 @@ impl ContextNode { } } + pub fn set_join_forks( + &self, + loc: Loc, + end_worlds: Vec, + analyzer: &mut impl AnalyzerBackend, + ) -> Result, GraphError> { + // if we have 4 worlds we need to represent + // we need to construct a tree like this + // a + // | + // |----------| + // a1 a2 + // | | + // |------| |------| + // a3 a4 a5 a6 + // + // each fork adds 1 world + + let _edges = self.all_edges(analyzer)?; + let mut stack = std::collections::VecDeque::new(); + stack.push_front(*self); + + for _ in 0..end_worlds.len().saturating_sub(1) { + let curr = stack.pop_front().unwrap(); + + let left_ctx = Context::new_subctx( + curr, + None, + loc, + Some("join_left"), + None, + false, + analyzer, + None, + )?; + let left_subctx = ContextNode::from(analyzer.add_node(Node::Context(left_ctx))); + let right_ctx = Context::new_subctx( + curr, + None, + loc, + Some("join_right"), + None, + false, + analyzer, + None, + )?; + let right_subctx = ContextNode::from(analyzer.add_node(Node::Context(right_ctx))); + curr.set_child_fork(left_subctx, right_subctx, analyzer)?; + left_subctx.set_continuation_ctx(analyzer, curr, "join_left")?; + right_subctx.set_continuation_ctx(analyzer, curr, "join_right")?; + + stack.push_back(left_subctx); + stack.push_back(right_subctx); + } + + self.all_edges(analyzer) + } + /// Adds a child to the context pub fn set_child_call( &self, @@ -329,7 +388,7 @@ impl ContextNode { None => unreachable!(), }; tracing::trace!("Error setting child as a call"); - Err(GraphError::ChildRedefinition(format!( + Err(GraphError::ChildRedefinition(panic!( "This is a bug. Tried to redefine a child context, parent: {}, current child: {}, new child: {}", self.path(analyzer), child_str, diff --git a/crates/graph/src/nodes/contract_ty.rs b/crates/graph/src/nodes/contract_ty.rs index 85cdda7b..fc9ebb78 100644 --- a/crates/graph/src/nodes/contract_ty.rs +++ b/crates/graph/src/nodes/contract_ty.rs @@ -1,8 +1,9 @@ use crate::{ - nodes::{FunctionNode, SourceUnitNode, SourceUnitPartNode, StructNode, VarNode}, + nodes::{Concrete, FunctionNode, SourceUnitNode, SourceUnitPartNode, StructNode, VarNode}, + range::elem::Elem, AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, }; -use shared::{NodeIdx, Search}; +use shared::{NodeIdx, RangeArena, Search}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{ContractDefinition, ContractTy, Identifier, Loc}; @@ -14,7 +15,11 @@ use std::collections::BTreeMap; pub struct ContractNode(pub usize); impl AsDotStr for ContractNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", @@ -180,7 +185,7 @@ impl ContractNode { pub fn funcs_mapping( &self, - analyzer: &(impl Search + AnalyzerBackend), + analyzer: &mut (impl Search + AnalyzerBackend), ) -> BTreeMap { analyzer .search_children_depth(self.0.into(), &Edge::Func, 1, 0) diff --git a/crates/graph/src/nodes/enum_ty.rs b/crates/graph/src/nodes/enum_ty.rs index dbd835ff..e02b0cdb 100644 --- a/crates/graph/src/nodes/enum_ty.rs +++ b/crates/graph/src/nodes/enum_ty.rs @@ -1,6 +1,8 @@ -use crate::{nodes::Concrete, AsDotStr, GraphBackend, GraphError, Node, SolcRange}; +use crate::{ + nodes::Concrete, range::elem::Elem, AsDotStr, GraphBackend, GraphError, Node, SolcRange, +}; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::U256; use solang_parser::pt::{EnumDefinition, Identifier, Loc}; @@ -10,7 +12,11 @@ use solang_parser::pt::{EnumDefinition, Identifier, Loc}; pub struct EnumNode(pub usize); impl AsDotStr for EnumNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "enum {} {{ {} }}", diff --git a/crates/graph/src/nodes/err_ty.rs b/crates/graph/src/nodes/err_ty.rs index 30007db0..4ecd30e6 100644 --- a/crates/graph/src/nodes/err_ty.rs +++ b/crates/graph/src/nodes/err_ty.rs @@ -1,6 +1,8 @@ -use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node}; +use crate::{ + nodes::Concrete, range::elem::Elem, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, +}; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{ErrorDefinition, ErrorParameter, Expression, Identifier, Loc}; #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -20,7 +22,11 @@ impl ErrorNode { } } impl AsDotStr for ErrorNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "error {}", @@ -97,11 +103,12 @@ impl From for Node { impl ErrorParam { pub fn new( analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, param: ErrorParameter, ) -> Self { ErrorParam { loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), + ty: analyzer.parse_expr(arena, ¶m.ty, None), name: param.name, } } diff --git a/crates/graph/src/nodes/func_ty.rs b/crates/graph/src/nodes/func_ty.rs index 0fb4f98f..cf60328b 100644 --- a/crates/graph/src/nodes/func_ty.rs +++ b/crates/graph/src/nodes/func_ty.rs @@ -1,10 +1,12 @@ use crate::{ + nodes::Concrete, nodes::{ContextNode, ContractNode, SourceUnitNode, SourceUnitPartNode}, + range::elem::Elem, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, SolcRange, VarType, }; -use shared::{NodeIdx, Search, StorageLocation}; +use shared::{NodeIdx, RangeArena, Search, StorageLocation}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ @@ -377,6 +379,7 @@ impl FunctionNode { pub fn set_params_and_ret( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { let underlying = self.underlying(analyzer)?.clone(); let mut params_strs = vec![]; @@ -386,7 +389,7 @@ impl FunctionNode { .enumerate() .filter_map(|(i, (_loc, input))| { if let Some(input) = input { - let param = FunctionParam::new(analyzer, input, i); + let param = FunctionParam::new(analyzer, arena, input, i); let input_node = analyzer.add_node(param); params_strs.push( FunctionParamNode::from(input_node) @@ -405,7 +408,7 @@ impl FunctionNode { .into_iter() .filter_map(|(_loc, output)| { if let Some(output) = output { - let ret = FunctionReturn::new(analyzer, output); + let ret = FunctionReturn::new(analyzer, arena, output); let output_node = analyzer.add_node(ret); analyzer.add_edge(output_node, *self, Edge::FunctionReturn); Some(output_node.into()) @@ -439,13 +442,34 @@ impl FunctionNode { // // } // } - pub fn returns<'a>(&self, analyzer: &'a impl GraphBackend) -> &'a [FunctionReturnNode] { - self.underlying(analyzer) - .unwrap() - .cache - .returns - .as_ref() - .unwrap() + pub fn returns( + &self, + arena: &mut RangeArena>, + analyzer: &mut impl AnalyzerBackend, + ) -> Vec { + if let Some(cached) = self.underlying(analyzer).unwrap().cache.returns.as_ref() { + cached.to_vec() + } else { + let underlying = self.underlying(analyzer).unwrap().clone(); + let rets = underlying + .returns + .into_iter() + .filter_map(|(_loc, output)| { + if let Some(output) = output { + let ret = FunctionReturn::new(analyzer, arena, output); + let output_node = analyzer.add_node(ret); + analyzer.add_edge(output_node, *self, Edge::FunctionReturn); + Some(output_node.into()) + } else { + None + } + }) + .collect::>(); + + let underlying_mut = self.underlying_mut(analyzer).unwrap(); + underlying_mut.cache.returns = Some(rets.clone()); + rets + } } pub fn is_public_or_ext(&self, analyzer: &impl GraphBackend) -> Result { @@ -512,11 +536,15 @@ impl FunctionNode { } impl AsDotStr for FunctionNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let inputs = self .params(analyzer) .iter() - .map(|param_node: &FunctionParamNode| param_node.as_dot_str(analyzer)) + .map(|param_node: &FunctionParamNode| param_node.as_dot_str(analyzer, arena)) .collect::>() .join(", "); @@ -769,12 +797,16 @@ impl From for Function { pub struct FunctionParamNode(pub usize); impl AsDotStr for FunctionParamNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) .expect("Non-typeable as type"); format!( "{}{}{}", - var_ty.as_dot_str(analyzer), + var_ty.as_dot_str(analyzer, arena), if let Some(stor) = &self.underlying(analyzer).unwrap().storage { format!(" {stor} ") } else { @@ -840,7 +872,7 @@ impl FunctionParamNode { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer)?.ty).ok_or( GraphError::NodeConfusion("Non-typeable as type".to_string()), )?; - Ok(var_ty.as_dot_str(analyzer)) + var_ty.as_string(analyzer) } pub fn ty(&self, analyzer: &impl GraphBackend) -> Result { @@ -878,12 +910,13 @@ impl From for Node { impl FunctionParam { pub fn new( analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, param: Parameter, order: usize, ) -> Self { FunctionParam { loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), + ty: analyzer.parse_expr(arena, ¶m.ty, None), order, storage: param.storage.map(|s| s.into()), name: param.name, @@ -895,12 +928,16 @@ impl FunctionParam { pub struct FunctionReturnNode(pub usize); impl AsDotStr for FunctionReturnNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let var_ty = VarType::try_from_idx(analyzer, self.underlying(analyzer).unwrap().ty) .expect("Non-typeable as type"); format!( "{}{}{}", - var_ty.as_dot_str(analyzer), + var_ty.as_dot_str(analyzer, arena), if let Some(stor) = &self.underlying(analyzer).unwrap().storage { format!(" {stor} ") } else { @@ -976,10 +1013,14 @@ pub struct FunctionReturn { } impl FunctionReturn { - pub fn new(analyzer: &mut impl AnalyzerBackend, param: Parameter) -> Self { + pub fn new( + analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, + param: Parameter, + ) -> Self { FunctionReturn { loc: param.loc, - ty: analyzer.parse_expr(¶m.ty, None), + ty: analyzer.parse_expr(arena, ¶m.ty, None), storage: param.storage.map(|s| s.into()), name: param.name, } diff --git a/crates/graph/src/nodes/msg.rs b/crates/graph/src/nodes/msg.rs index e882503c..c7f71544 100644 --- a/crates/graph/src/nodes/msg.rs +++ b/crates/graph/src/nodes/msg.rs @@ -1,9 +1,10 @@ use crate::{ nodes::{Builtin, Concrete, ContextNode, ContextVar}, + range::elem::Elem, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::{Address, U256}; use solang_parser::pt::Loc; @@ -27,7 +28,11 @@ impl MsgNode { } impl AsDotStr for MsgNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { format!("msg {{ {:?} }}", self.underlying(analyzer).unwrap()) } } diff --git a/crates/graph/src/nodes/source_unit.rs b/crates/graph/src/nodes/source_unit.rs index aabc2db9..dce79147 100644 --- a/crates/graph/src/nodes/source_unit.rs +++ b/crates/graph/src/nodes/source_unit.rs @@ -1,9 +1,10 @@ use crate::{ - nodes::{ContractNode, FunctionNode, SourceUnitPartNode, StructNode, VarNode}, + nodes::{Concrete, ContractNode, FunctionNode, SourceUnitPartNode, StructNode, VarNode}, + range::elem::Elem, AsDotStr, GraphBackend, GraphError, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; #[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct SourceUnit { @@ -36,7 +37,11 @@ impl From for SourceUnitNode { } impl AsDotStr for SourceUnitNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!("SourceUnit({})", underlying.file) } diff --git a/crates/graph/src/nodes/source_unit_part.rs b/crates/graph/src/nodes/source_unit_part.rs index 22791787..34c2e183 100644 --- a/crates/graph/src/nodes/source_unit_part.rs +++ b/crates/graph/src/nodes/source_unit_part.rs @@ -1,9 +1,10 @@ use crate::{ - nodes::{ContractNode, FunctionNode, StructNode, VarNode}, + nodes::{Concrete, ContractNode, FunctionNode, StructNode, VarNode}, + range::elem::Elem, AsDotStr, GraphBackend, GraphError, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; #[derive(Default, Clone, Debug, PartialOrd, PartialEq, Ord, Eq)] pub struct SourceUnitPart { @@ -41,7 +42,11 @@ impl From for SourceUnitPartNode { } impl AsDotStr for SourceUnitPartNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!("SourceUnitPart({}, {})", underlying.file, underlying.part) } diff --git a/crates/graph/src/nodes/struct_ty.rs b/crates/graph/src/nodes/struct_ty.rs index 4eef093b..18ba87e9 100644 --- a/crates/graph/src/nodes/struct_ty.rs +++ b/crates/graph/src/nodes/struct_ty.rs @@ -1,6 +1,9 @@ -use crate::{AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, Node, VarType}; +use crate::{ + nodes::Concrete, range::elem::Elem, AnalyzerBackend, AsDotStr, Edge, GraphBackend, GraphError, + Node, VarType, +}; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{Expression, Identifier, Loc, StructDefinition, VariableDeclaration}; @@ -64,7 +67,11 @@ impl StructNode { } impl AsDotStr for StructNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "struct {} {{ {} }}", @@ -75,7 +82,7 @@ impl AsDotStr for StructNode { }, self.fields(analyzer) .iter() - .map(|field_node| { field_node.as_dot_str(analyzer) }) + .map(|field_node| { field_node.as_dot_str(analyzer, arena) }) .collect::>() .join("; ") ) @@ -152,12 +159,16 @@ impl FieldNode { } impl AsDotStr for FieldNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) + var_ty.as_dot_str(analyzer, arena) } else { "".to_string() }, @@ -198,9 +209,10 @@ impl From for Node { impl Field { pub fn new( analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, var_def: VariableDeclaration, ) -> Field { - let ty_idx = analyzer.parse_expr(&var_def.ty, None); + let ty_idx = analyzer.parse_expr(arena, &var_def.ty, None); Field { loc: var_def.loc, ty: ty_idx, diff --git a/crates/graph/src/nodes/ty_ty.rs b/crates/graph/src/nodes/ty_ty.rs index af658539..b3d4e42d 100644 --- a/crates/graph/src/nodes/ty_ty.rs +++ b/crates/graph/src/nodes/ty_ty.rs @@ -1,6 +1,9 @@ -use crate::{AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, VarType}; +use crate::{ + nodes::Concrete, range::elem::Elem, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, + VarType, +}; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Identifier, Loc, TypeDefinition}; @@ -38,12 +41,16 @@ impl From for TyNode { } impl AsDotStr for TyNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{} {}", if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) + var_ty.as_dot_str(analyzer, arena) } else { "".to_string() }, @@ -66,10 +73,14 @@ impl From for Node { } impl Ty { - pub fn new(analyzer: &mut impl AnalyzerBackend, ty: TypeDefinition) -> Ty { + pub fn new( + analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, + ty: TypeDefinition, + ) -> Ty { Ty { loc: ty.loc, - ty: analyzer.parse_expr(&ty.ty, None), + ty: analyzer.parse_expr(arena, &ty.ty, None), name: ty.name, } } diff --git a/crates/graph/src/nodes/var_ty.rs b/crates/graph/src/nodes/var_ty.rs index 4391952c..802315cc 100644 --- a/crates/graph/src/nodes/var_ty.rs +++ b/crates/graph/src/nodes/var_ty.rs @@ -1,9 +1,12 @@ use crate::{ - nodes::{ContextVar, ContextVarNode, ContractNode, SourceUnitNode, SourceUnitPartNode}, + nodes::{ + Concrete, ContextVar, ContextVarNode, ContractNode, SourceUnitNode, SourceUnitPartNode, + }, + range::elem::Elem, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, GraphError, Node, VarType, }; -use shared::{NodeIdx, Search}; +use shared::{NodeIdx, RangeArena, Search}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::pt::{ @@ -46,11 +49,12 @@ impl VarNode { pub fn parse_initializer( &self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, parent: NodeIdx, ) -> Result<(), GraphError> { if let Some(expr) = self.underlying(analyzer)?.initializer_expr.clone() { tracing::trace!("Parsing variable initializer"); - let init = analyzer.parse_expr(&expr, Some(parent)); + let init = analyzer.parse_expr(arena, &expr, Some(parent)); let underlying = self.underlying(analyzer)?.clone(); let mut set = false; if let Some(ty) = VarType::try_from_idx(analyzer, underlying.ty) { @@ -174,12 +178,16 @@ impl VarNode { } impl AsDotStr for VarNode { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { let underlying = self.underlying(analyzer).unwrap(); format!( "{}{} {}", if let Some(var_ty) = VarType::try_from_idx(analyzer, underlying.ty) { - var_ty.as_dot_str(analyzer) + var_ty.as_dot_str(analyzer, arena) } else { "".to_string() }, @@ -237,11 +245,12 @@ impl From for Node { impl Var { pub fn new( analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, var: VariableDefinition, in_contract: bool, ) -> Var { tracing::trace!("Parsing Var type"); - let ty = analyzer.parse_expr(&var.ty, None); + let ty = analyzer.parse_expr(arena, &var.ty, None); Var { loc: var.loc, ty, diff --git a/crates/graph/src/range/elem/concrete.rs b/crates/graph/src/range/elem/concrete.rs index 21fa678d..8ee3f789 100644 --- a/crates/graph/src/range/elem/concrete.rs +++ b/crates/graph/src/range/elem/concrete.rs @@ -1,22 +1,54 @@ use crate::{ nodes::{Concrete, ContextVarNode}, - range::elem::{Elem, RangeElem}, + range::elem::{Elem, RangeArenaLike, RangeElem}, GraphBackend, GraphError, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use std::hash::{Hash, Hasher}; +use ethers_core::types::{I256, U256}; use solang_parser::pt::Loc; /// A concrete value for a range element #[derive(Default, Clone, Debug, Ord, PartialOrd)] pub struct RangeConcrete { + /// The value of the concrete pub val: T, + /// The source code location pub loc: Loc, } +pub fn rc_uint_sized(n: u128) -> RangeConcrete { + let size: u16 = ((32 - ((n.leading_zeros() + 128) / 8)) * 8).max(8) as u16; + RangeConcrete::new(Concrete::Uint(size, U256::from(n)), Loc::Implicit) +} + +pub fn rc_uint256(n: u128) -> RangeConcrete { + RangeConcrete::new(Concrete::Uint(256, U256::from(n)), Loc::Implicit) +} + +pub fn rc_int_sized(n: i128) -> RangeConcrete { + let size: u16 = ((32 - ((n.abs().leading_zeros() + 128) / 8)) * 8).max(8) as u16; + RangeConcrete::new(Concrete::Int(size, I256::from(n)), Loc::Implicit) +} + +pub fn rc_i256_sized(n: I256) -> RangeConcrete { + let size: u16 = ((32 - ((n.abs().leading_zeros()) / 8)) * 8).max(8) as u16; + RangeConcrete::new(Concrete::Int(size, n), Loc::Implicit) +} + +pub fn rc_int256(n: i128) -> RangeConcrete { + RangeConcrete::new(Concrete::Int(256, I256::from(n)), Loc::Implicit) +} + +impl RangeConcrete { + pub fn new(val: T, loc: Loc) -> Self { + Self { val, loc } + } +} + impl PartialEq for RangeConcrete { fn eq(&self, other: &Self) -> bool { self.val == other.val @@ -24,7 +56,7 @@ impl PartialEq for RangeConcrete { } impl Eq for RangeConcrete {} -impl Hash for RangeConcrete { +impl Hash for RangeConcrete { fn hash(&self, state: &mut H) { self.val.hash(state); } @@ -40,15 +72,24 @@ impl From for RangeConcrete { } impl RangeConcrete { - pub fn as_bytes(&self, _analyzer: &impl GraphBackend, _maximize: bool) -> Option> { + pub fn as_bytes( + &self, + _analyzer: &impl GraphBackend, + _maximize: bool, + _arena: &mut RangeArena>, + ) -> Option> { Some(self.val.as_bytes()) } } impl RangeElem for RangeConcrete { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - let _ = analyzer.range_arena_idx_or_upsert(Elem::Concrete(self.clone())); + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + let _ = arena.idx_or_upsert(Elem::Concrete(self.clone()), analyzer); Ok(()) } @@ -56,15 +97,17 @@ impl RangeElem for RangeConcrete { &self, _seen: &mut Vec, _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result { Ok(false) } fn depends_on( &self, - var: ContextVarNode, - seen: &mut Vec, - analyzer: &impl GraphBackend, + _var: ContextVarNode, + _seen: &mut Vec, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result { Ok(false) } @@ -73,23 +116,36 @@ impl RangeElem for RangeConcrete { &self, _maximize: bool, _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> bool { true } - fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + fn is_min_max_cached( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> (bool, bool) { (true, true) } - fn cache_flatten(&mut self, _: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten( + &mut self, + _: &mut impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Result<(), GraphError> { Ok(()) } - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + fn range_eq(&self, other: &Self, arena: &mut RangeArena>) -> bool { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => self_val == other_val, _ => match (&self.val, &other.val) { @@ -101,17 +157,11 @@ impl RangeElem for RangeConcrete { (Concrete::Array(a), Concrete::Array(b)) => { if a.len() == b.len() { a.iter().zip(b.iter()).all(|(a, b)| { - let a = RangeConcrete { - val: a.clone(), - loc: self.loc, - }; + let a = RangeConcrete::new(a.clone(), self.loc); - let b = RangeConcrete { - val: b.clone(), - loc: other.loc, - }; + let b = RangeConcrete::new(b.clone(), other.loc); - a.range_eq(&b, analyzer) + a.range_eq(&b, arena) }) } else { false @@ -122,7 +172,11 @@ impl RangeElem for RangeConcrete { } } - fn range_ord(&self, other: &Self, _analyzer: &impl GraphBackend) -> Option { + fn range_ord( + &self, + other: &Self, + _arena: &mut RangeArena>, + ) -> Option { match (self.val.into_u256(), other.val.into_u256()) { (Some(self_val), Some(other_val)) => Some(self_val.cmp(&other_val)), (Some(_), _) => { @@ -156,37 +210,66 @@ impl RangeElem for RangeConcrete { } } - fn dependent_on(&self, _analyzer: &impl GraphBackend) -> Vec { + fn dependent_on( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Vec { vec![] } - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &mut impl GraphBackend) {} + fn filter_recursion( + &mut self, + _: NodeIdx, + _: NodeIdx, + _analyzer: &mut impl GraphBackend, + _arena: &mut RangeArena>, + ) { + } - fn maximize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { + fn maximize( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn minimize(&self, _analyzer: &impl GraphBackend) -> Result, GraphError> { + fn minimize( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_maximize( &self, _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } fn simplify_minimize( &self, _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result, GraphError> { Ok(Elem::Concrete(self.clone())) } - fn cache_maximize(&mut self, _g: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize( + &mut self, + _g: &mut impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Result<(), GraphError> { Ok(()) } - fn cache_minimize(&mut self, _g: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize( + &mut self, + _g: &mut impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Result<(), GraphError> { Ok(()) } fn uncache(&mut self) {} @@ -194,6 +277,7 @@ impl RangeElem for RangeConcrete { fn recursive_dependent_on( &self, _: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result, GraphError> { Ok(vec![]) } diff --git a/crates/graph/src/range/elem/elem_enum.rs b/crates/graph/src/range/elem/elem_enum.rs deleted file mode 100644 index 3252a4c0..00000000 --- a/crates/graph/src/range/elem/elem_enum.rs +++ /dev/null @@ -1,1391 +0,0 @@ -use crate::elem::MinMaxed; -use crate::{ - nodes::{Concrete, ContextVarNode}, - range::elem::{ - collapse, MaybeCollapsed, RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference, - }, - GraphBackend, GraphError, -}; -use solang_parser::pt::Loc; -use std::cell::RefCell; -use std::rc::Rc; - -use shared::{NodeIdx, RangeArenaIdx}; - -use ethers_core::types::I256; -use tracing::instrument; - -use std::{ - collections::BTreeMap, - hash::{Hash, Hasher}, - ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}, -}; - -/// A core range element. -#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] -pub enum Elem { - /// A range element that is a reference to another node - Reference(Reference), - /// A concrete range element of type `T`. e.g.: some number like `10` - ConcreteDyn(RangeDyn), - /// A concrete range element of type `T`. e.g.: some number like `10` - Concrete(RangeConcrete), - /// A range element that is an expression composed of other range elements - Expr(RangeExpr), - /// A range element that is a pointer to another expression in an arena - Arena(RangeArenaIdx), - /// A null range element useful in range expressions that dont have a rhs - #[default] - Null, -} - -impl Hash for Elem { - fn hash(&self, state: &mut H) { - match self { - Elem::Reference(r) => r.hash(state), - Elem::Concrete(c) => c.hash(state), - Elem::Expr(expr) => expr.hash(state), - Elem::ConcreteDyn(d) => d.hash(state), - Elem::Null => (-1i32).hash(state), - Elem::Arena(idx) => idx.hash(state), - } - } -} - -impl Elem { - pub fn node_idx(&self) -> Option { - match self { - Self::Reference(Reference { idx, .. }) => Some(*idx), - _ => None, - } - } - - pub fn concrete(&self) -> Option { - match self { - Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), - _ => None, - } - } - - pub fn maybe_concrete(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } - } - - pub fn maybe_concrete_value(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(a.clone()), - _ => None, - } - } - - pub fn maybe_range_dyn(&self) -> Option> { - match self { - Elem::ConcreteDyn(a) => Some(a.clone()), - _ => None, - } - } - - pub fn is_conc(&self) -> bool { - match self { - Elem::Concrete(_a) => true, - Elem::ConcreteDyn(a) => { - a.len.maybe_concrete().is_some() - && a.val - .iter() - .all(|(key, (val, _))| key.is_conc() && val.is_conc()) - } - Elem::Expr(expr) => expr.lhs.is_conc() && expr.rhs.is_conc(), - _ => false, - } - } -} - -impl Elem { - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - match self { - Self::Reference(d) => d.idx == node_idx, - Self::Concrete(_) => false, - Self::Expr(expr) => expr.contains_node(node_idx), - Self::ConcreteDyn(d) => d.contains_node(node_idx), - Self::Null => false, - Elem::Arena(_) => todo!(), - } - } - - pub fn expect_into_expr(self) -> RangeExpr { - match self { - Self::Expr(expr) => expr, - _ => panic!("Not expression"), - } - } - - pub fn dyn_map(&self) -> Option<&BTreeMap> { - match self { - Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), - _ => None, - } - } - - pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { - match self { - Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), - _ => None, - } - } - - /// Creates a new range element that is a cast from one type to another - pub fn cast(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Cast, other); - Elem::Expr(expr) - } - - pub fn concat(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Concat, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the minimum of two range elements - pub fn min(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Min, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is the maximum of two range elements - pub fn max(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Max, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of equality of two range elements - pub fn eq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Eq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a boolean of inequality of two range elements - pub fn neq(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Neq, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is one range element to the power of another - pub fn pow(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Exp, other); - Elem::Expr(expr) - } - - /// Creates a new range element that is a memcopy of another - pub fn memcopy(self) -> Self { - let expr = RangeExpr::new(self, RangeOp::Memcopy, Elem::Null); - Elem::Expr(expr) - } - - /// Creates a new range element that applies a setting of indices of a memory object - pub fn set_indices(self, other: RangeDyn) -> Self { - let expr = RangeExpr::new(self, RangeOp::SetIndices, Elem::ConcreteDyn(other)); - Elem::Expr(expr) - } - - /// Creates a new range element that sets the length of a memory object - pub fn set_length(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::SetLength, other); - Elem::Expr(expr) - } - - /// Gets the length of a memory object - pub fn get_length(self) -> Self { - let expr = RangeExpr::new(self, RangeOp::GetLength, Elem::Null); - Elem::Expr(expr) - } - - /// Gets the length of a memory object - pub fn get_index(self, other: Self) -> Self { - let expr = RangeExpr::new(self, RangeOp::GetIndex, other); - Elem::Expr(expr) - } -} - -impl From> for Elem { - fn from(dy: Reference) -> Self { - Elem::Reference(dy) - } -} - -impl From> for Elem { - fn from(c: RangeConcrete) -> Self { - Elem::Concrete(c) - } -} - -impl Add for Elem { - type Output = Self; - - fn add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(false), other); - Self::Expr(expr) - } -} - -impl Sub for Elem { - type Output = Self; - - fn sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(false), other); - Self::Expr(expr) - } -} - -impl Mul for Elem { - type Output = Self; - - fn mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(false), other); - Self::Expr(expr) - } -} - -impl Div for Elem { - type Output = Self; - - fn div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(false), other); - Self::Expr(expr) - } -} - -impl Shl for Elem { - type Output = Self; - - fn shl(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shl, other); - Self::Expr(expr) - } -} - -impl Shr for Elem { - type Output = Self; - - fn shr(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Shr, other); - Self::Expr(expr) - } -} - -impl Rem for Elem { - type Output = Self; - - fn rem(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mod, other); - Self::Expr(expr) - } -} - -impl BitAnd for Elem { - type Output = Self; - - fn bitand(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitAnd, other); - Self::Expr(expr) - } -} - -impl BitOr for Elem { - type Output = Self; - - fn bitor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitOr, other); - Self::Expr(expr) - } -} - -impl BitXor for Elem { - type Output = Self; - - fn bitxor(self, other: Self) -> Self::Output { - let expr = RangeExpr::new(self, RangeOp::BitXor, other); - Self::Expr(expr) - } -} - -impl From for Elem { - fn from(idx: NodeIdx) -> Self { - Elem::Reference(Reference::new(idx)) - } -} - -impl Elem { - pub fn replace_dep( - &mut self, - to_replace: NodeIdx, - replacement: Self, - analyzer: &mut impl GraphBackend, - ) { - match self { - Elem::Reference(Reference { idx, .. }) => { - if *idx == to_replace { - *self = replacement; - } - } - Elem::Concrete(_) => {} - Elem::Expr(expr) => { - expr.lhs - .replace_dep(to_replace, replacement.clone(), analyzer); - expr.rhs.replace_dep(to_replace, replacement, analyzer); - expr.maximized = None; - expr.minimized = None; - } - Elem::ConcreteDyn(d) => { - d.len.replace_dep(to_replace, replacement.clone(), analyzer); - let vals = std::mem::take(&mut d.val); - d.val = vals - .into_iter() - .map(|(mut k, (mut v, op))| { - k.replace_dep(to_replace, replacement.clone(), analyzer); - v.replace_dep(to_replace, replacement.clone(), analyzer); - (k, (v, op)) - }) - .collect(); - } - Elem::Null => {} - Elem::Arena(_) => { - let mut s = self.dearenaize(analyzer).borrow().clone(); - s.replace_dep(to_replace, replacement, analyzer); - *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(s)); - } - } - } - - pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Self { - match self { - Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx] - .borrow() - .clone() - .recurse_dearenaize(analyzer), - Self::Expr(expr) => expr.recurse_dearenaize(analyzer), - e => e.clone(), - } - } - - pub fn dearenaize(&self, analyzer: &impl GraphBackend) -> Rc> { - match self { - Self::Arena(arena_idx) => analyzer.range_arena().ranges[*arena_idx].clone(), - _ => unreachable!(), - } - } - - pub fn arena_eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::Arena(a), Self::Arena(b)) => a == b, - (Self::Concrete(a), Self::Concrete(b)) => a == b, - (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => { - a.len == b.len - && a.val.len() == b.val.len() - && a.val - .iter() - .zip(b.val.iter()) - .all(|((a, op_a), (b, op_b))| a.arena_eq(b) && op_a == op_b) - } - (Self::Reference(a), Self::Reference(b)) => a == b, - (Self::Expr(a), Self::Expr(b)) => { - a.lhs.arena_eq(&b.lhs) && a.rhs.arena_eq(&b.rhs) && a.op == b.op - } - (Elem::Null, Elem::Null) => true, - _ => false, - } - } - pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { - let evaled = if maximize { - self.maximize(analyzer).ok()? - } else { - self.minimize(analyzer).ok()? - }; - - match evaled { - Elem::Concrete(c) => c.as_bytes(analyzer, maximize), - Elem::ConcreteDyn(c) => c.as_bytes(analyzer, maximize), - _ => None, - } - } - - pub fn overlaps( - &self, - other: &Self, - eval: bool, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match (self, other) { - (Elem::Concrete(s), Elem::Concrete(o)) => Ok(Some(o.val == s.val)), - (Elem::Reference(s), Elem::Reference(o)) => { - if eval { - let lhs_min = s.minimize(analyzer)?; - let rhs_max = o.maximize(analyzer)?; - - match lhs_min.range_ord(&rhs_max, analyzer) { - Some(std::cmp::Ordering::Less) => { - // we know our min is less than the other max - // check that the max is greater than or eq their min - let lhs_max = s.maximize(analyzer)?; - let rhs_min = o.minimize(analyzer)?; - Ok(Some(matches!( - lhs_max.range_ord(&rhs_min, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ))) - } - Some(std::cmp::Ordering::Equal) => Ok(Some(true)), - _ => Ok(Some(false)), - } - } else if s == o { - Ok(Some(true)) - } else { - Ok(None) - } - } - (Elem::Reference(s), c @ Elem::Concrete(_)) => { - if eval { - let lhs_min = s.minimize(analyzer)?; - - match lhs_min.range_ord(c, analyzer) { - Some(std::cmp::Ordering::Less) => { - // we know our min is less than the other max - // check that the max is greater than or eq their min - let lhs_max = s.maximize(analyzer)?; - Ok(Some(matches!( - lhs_max.range_ord(c, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ))) - } - Some(std::cmp::Ordering::Equal) => Ok(Some(true)), - _ => Ok(Some(false)), - } - } else { - Ok(None) - } - } - (Elem::Concrete(_), Elem::Reference(_)) => other.overlaps(self, eval, analyzer), - _ => Ok(None), - } - } - pub fn overlaps_dual( - &self, - rhs_min: &Self, - rhs_max: &Self, - eval: bool, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match self { - Self::Reference(d) => { - if eval { - let lhs_min = d.minimize(analyzer)?; - let rhs_max = rhs_max.maximize(analyzer)?; - - match lhs_min.range_ord(&rhs_max, analyzer) { - Some(std::cmp::Ordering::Less) => { - // we know our min is less than the other max - // check that the max is greater than or eq their min - let lhs_max = d.maximize(analyzer)?; - let rhs_min = rhs_min.minimize(analyzer)?; - Ok(Some(matches!( - lhs_max.range_ord(&rhs_min, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ))) - } - Some(std::cmp::Ordering::Equal) => Ok(Some(true)), - _ => Ok(Some(false)), - } - } else if self == rhs_min || self == rhs_max { - Ok(Some(true)) - } else { - Ok(None) - } - } - Self::Concrete(_) => match rhs_min.range_ord(self, analyzer) { - Some(std::cmp::Ordering::Less) => Ok(Some(matches!( - rhs_max.range_ord(self, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ))), - Some(std::cmp::Ordering::Equal) => Ok(Some(true)), - _ => Ok(Some(false)), - }, - _ => Ok(None), - } - } - pub fn is_negative( - &self, - maximize: bool, - analyzer: &impl GraphBackend, - ) -> Result { - let res = match self { - Elem::Concrete(RangeConcrete { - val: Concrete::Int(_, val), - .. - }) if val < &I256::zero() => true, - Elem::Reference(dy) => { - if maximize { - dy.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - dy.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - Elem::Expr(expr) => { - if maximize { - expr.maximize(analyzer)?.is_negative(maximize, analyzer)? - } else { - expr.minimize(analyzer)?.is_negative(maximize, analyzer)? - } - } - _ => false, - }; - Ok(res) - } - - pub fn pre_evaled_is_negative(&self) -> bool { - matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) - } - - pub fn inverse_if_boolean(&self) -> Option { - match self { - Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( - self.clone(), - RangeOp::Not, - Elem::Null, - ))), - Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), - Self::ConcreteDyn(_d) => None, - Self::Null => None, - Self::Arena(_) => todo!(), - } - } - - pub fn arenaized_flattened( - &self, - max: bool, - analyzer: &impl GraphBackend, - ) -> Option>> { - if let Some(idx) = analyzer.range_arena_idx(self) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { - match &*t { - Elem::Expr(ref arenaized) => { - if max { - arenaized.flattened_max.clone() - } else { - arenaized.flattened_min.clone() - } - } - Elem::Reference(ref arenaized) => { - if max { - arenaized.flattened_max.clone() - } else { - arenaized.flattened_min.clone() - } - } - Elem::ConcreteDyn(ref arenaized) => { - if max { - arenaized.flattened_max.clone() - } else { - arenaized.flattened_min.clone() - } - } - c @ Elem::Concrete(_) => Some(Box::new(c.clone())), - c @ Elem::Null => Some(Box::new(c.clone())), - a @ Elem::Arena(_) => a.arenaized_flattened(max, analyzer), - } - } else { - None - } - } else { - None - } - } - - pub fn set_arenaized_flattened( - &self, - max: bool, - elem: &Elem, - analyzer: &impl GraphBackend, - ) { - if let Some(idx) = analyzer.range_arena_idx(self) { - if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { - match &mut *t { - Elem::Expr(ref mut arenaized) => { - if max { - arenaized.flattened_max = Some(Box::new(elem.clone())); - } else { - arenaized.flattened_min = Some(Box::new(elem.clone())); - } - } - Elem::Reference(ref mut arenaized) => { - if max { - arenaized.flattened_max = Some(Box::new(elem.clone())); - } else { - arenaized.flattened_min = Some(Box::new(elem.clone())); - } - } - Elem::ConcreteDyn(ref mut arenaized) => { - if max { - arenaized.flattened_max = Some(Box::new(elem.clone())); - } else { - arenaized.flattened_min = Some(Box::new(elem.clone())); - } - } - _ => {} - } - } - } - } - - pub fn set_arenaized_cache( - &self, - max: bool, - elem: &Elem, - analyzer: &impl GraphBackend, - ) { - if let Some(idx) = analyzer.range_arena_idx(self) { - if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { - match &mut *t { - Elem::Expr(ref mut arenaized) => { - if max { - arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); - } else { - arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); - } - } - Elem::Reference(ref mut arenaized) => { - if max { - arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); - } else { - arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); - } - } - Elem::ConcreteDyn(ref mut arenaized) => { - if max { - arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); - } else { - arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); - } - } - _ => {} - } - } - } - } -} - -impl From for Elem { - fn from(c: Concrete) -> Self { - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }) - } -} - -impl From for Elem { - fn from(c: ContextVarNode) -> Self { - Elem::Reference(Reference::new(c.into())) - } -} - -impl std::fmt::Display for Elem { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), - Elem::ConcreteDyn(d) => { - write!(f, "{{len: {}, values: {{", d.len)?; - d.val - .iter() - .try_for_each(|(key, (val, op))| write!(f, " {key}: ({val}, {op}),"))?; - write!(f, "}}}}") - } - Elem::Concrete(RangeConcrete { val, .. }) => { - write!(f, "{}", val.as_string()) - } - Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { - RangeOp::Min | RangeOp::Max => { - write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) - } - RangeOp::Cast => match &**rhs { - Elem::Concrete(RangeConcrete { val, .. }) => { - write!( - f, - "{}({}, {})", - op.to_string(), - lhs, - val.as_builtin().basic_as_string() - ) - } - _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), - }, - RangeOp::BitNot => { - write!(f, "~{}", lhs) - } - _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), - }, - Elem::Arena(idx) => write!(f, "arena_idx_{idx}"), - Elem::Null => write!(f, ""), - } - } -} - -impl RangeElem for Elem { - type GraphError = GraphError; - - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - match self { - Self::Arena(_) => return Ok(()), - Self::Reference(d) => d.arenaize(analyzer)?, - Self::ConcreteDyn(d) => d.arenaize(analyzer)?, - Self::Expr(expr) => { - expr.arenaize(analyzer)?; - } - Self::Concrete(c) => c.arenaize(analyzer)?, - Self::Null => {} - } - - let self_take = std::mem::take(self); - *self = Elem::Arena(analyzer.range_arena_idx_or_upsert(self_take)); - Ok(()) - } - - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { - match (self, other) { - (Self::Arena(a), Self::Arena(b)) => a == b, - (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b, analyzer), - (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b, analyzer), - (Self::Reference(a), Self::Reference(b)) => a.idx == b.idx, - _ => false, - } - } - - fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { - match (self, other) { - (Self::Arena(a), Self::Arena(b)) => { - if a == b { - Some(std::cmp::Ordering::Equal) - } else { - self.dearenaize(analyzer) - .borrow() - .range_ord(&other.dearenaize(analyzer).borrow(), analyzer) - } - } - (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, analyzer), - (Self::Reference(a), Self::Reference(b)) => a.range_ord(b, analyzer), - (Elem::Null, Elem::Null) => None, - (_a, Elem::Null) => Some(std::cmp::Ordering::Greater), - (Elem::Null, _a) => Some(std::cmp::Ordering::Less), - _ => None, - } - } - - #[instrument(level = "trace", skip_all)] - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match self { - Self::Reference(d) => d.flatten(maximize, analyzer), - Self::Concrete(c) => c.flatten(maximize, analyzer), - Self::Expr(expr) => expr.flatten(maximize, analyzer), - Self::ConcreteDyn(d) => d.flatten(maximize, analyzer), - Self::Null => Ok(Elem::Null), - Self::Arena(_) => { - let de = self.dearenaize(analyzer); - let res = de.borrow().flatten(maximize, analyzer)?; - // match &mut *de.borrow_mut() { - // Self::Reference(ref mut d) => { - // if maximize { - // d.flattened_max = Some(Box::new(res)); - // } else { - // d.flattened_min = Some(Box::new(res)); - // } - // } - // Self::Expr(ref mut expr) => { - // if maximize { - // expr.flattened_max = Some(Box::new(res)); - // } else { - // expr.flattened_min = Some(Box::new(res)); - // } - // } - // Self::ConcreteDyn(ref mut d) => { - // if maximize { - // d.flattened_max = Some(Box::new(res)); - // } else { - // d.flattened_min = Some(Box::new(res)); - // } - // } - // _ => {} - // } - Ok(res) - } - } - } - - #[instrument(level = "trace", skip_all)] - fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - if self.is_flatten_cached(analyzer) { - return Ok(()); - } - - match self { - Self::Reference(d) => d.cache_flatten(analyzer), - Self::Concrete(c) => c.cache_flatten(analyzer), - Self::Expr(expr) => expr.cache_flatten(analyzer), - Self::ConcreteDyn(d) => d.cache_flatten(analyzer), - Self::Null => Ok(()), - Self::Arena(idx) => { - tracing::trace!("flattening for arena idx: {idx}"); - let dearenaized = self.dearenaize(analyzer); - let (min, max) = { - let Ok(t) = dearenaized.try_borrow() else { - return Ok(()); - }; - - let min = t.flatten(false, analyzer)?; - let max = t.flatten(true, analyzer)?; - (min, max) - }; - - match &mut *dearenaized.borrow_mut() { - Self::Reference(ref mut d) => { - d.flattened_min = Some(Box::new(min)); - d.flattened_max = Some(Box::new(max)); - } - Self::Expr(ref mut expr) => { - expr.flattened_min = Some(Box::new(min)); - expr.flattened_max = Some(Box::new(max)); - } - Self::ConcreteDyn(ref mut d) => { - d.flattened_min = Some(Box::new(min)); - d.flattened_max = Some(Box::new(max)); - } - _ => {} - } - // let mut dearenaized = self.dearenaize(analyzer).borrow().clone(); - // dearenaized.cache_flatten(analyzer)?; - // *self.dearenaize(analyzer).borrow_mut() = dearenaized; - Ok(()) - } - } - } - - #[instrument(level = "trace", skip_all)] - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { - match self { - Self::Reference(d) => d.is_flatten_cached(analyzer), - Self::Concrete(c) => c.is_flatten_cached(analyzer), - Self::Expr(expr) => expr.is_flatten_cached(analyzer), - Self::ConcreteDyn(d) => d.is_flatten_cached(analyzer), - Self::Null => true, - Self::Arena(_idx) => { - if let Ok(t) = self.dearenaize(analyzer).try_borrow() { - t.is_flatten_cached(analyzer) - } else { - false - } - } - } - } - - fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { - match self { - Self::Reference(d) => d.is_min_max_cached(analyzer), - Self::Concrete(_c) => (true, true), - Self::Expr(expr) => expr.is_min_max_cached(analyzer), - Self::ConcreteDyn(d) => d.is_min_max_cached(analyzer), - Self::Null => (true, true), - Self::Arena(_) => { - if let Ok(t) = self.dearenaize(analyzer).try_borrow() { - t.is_min_max_cached(analyzer) - } else { - (false, false) - } - } - } - } - - fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { - match self { - Self::Reference(d) => d.dependent_on(analyzer), - Self::Concrete(_) => vec![], - Self::Expr(expr) => expr.dependent_on(analyzer), - Self::ConcreteDyn(d) => d.dependent_on(analyzer), - Self::Null => vec![], - Self::Arena(_) => { - if let Ok(t) = self.dearenaize(analyzer).try_borrow() { - t.dependent_on(analyzer) - } else { - vec![] - } - } - } - } - - fn recursive_dependent_on( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match self { - Self::Reference(d) => d.recursive_dependent_on(analyzer), - Self::Concrete(_) => Ok(vec![]), - Self::Expr(expr) => expr.recursive_dependent_on(analyzer), - Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer), - Self::Null => Ok(vec![]), - Self::Arena(_) => self - .dearenaize(analyzer) - .borrow() - .recursive_dependent_on(analyzer), - } - } - - fn has_cycle( - &self, - seen: &mut Vec, - analyzer: &impl GraphBackend, - ) -> Result { - match self { - Self::Reference(d) => d.has_cycle(seen, analyzer), - Self::Concrete(_) => Ok(false), - Self::Expr(expr) => expr.has_cycle(seen, analyzer), - Self::ConcreteDyn(d) => d.has_cycle(seen, analyzer), - Self::Null => Ok(false), - Self::Arena(_) => self.dearenaize(analyzer).borrow().has_cycle(seen, analyzer), - } - } - - fn depends_on( - &self, - var: ContextVarNode, - seen: &mut Vec, - analyzer: &impl GraphBackend, - ) -> Result { - match self { - Self::Reference(d) => d.depends_on(var, seen, analyzer), - Self::Concrete(_) => Ok(false), - Self::Expr(expr) => expr.depends_on(var, seen, analyzer), - Self::ConcreteDyn(d) => d.depends_on(var, seen, analyzer), - Self::Null => Ok(false), - Self::Arena(_) => self - .dearenaize(analyzer) - .borrow() - .depends_on(var, seen, analyzer), - } - } - - fn filter_recursion( - &mut self, - node_idx: NodeIdx, - new_idx: NodeIdx, - analyzer: &mut impl GraphBackend, - ) { - match self { - Self::Reference(ref mut d) => { - if d.idx == node_idx { - d.idx = new_idx - } - } - Self::Concrete(_) => {} - Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx, analyzer), - Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx, analyzer), - Self::Null => {} - Self::Arena(_idx) => { - let dearenaized = self.dearenaize(analyzer); - dearenaized - .borrow_mut() - .filter_recursion(node_idx, new_idx, analyzer); - } - } - } - - fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - if let Some(idx) = analyzer.range_arena_idx(self) { - let (_min, max) = Elem::Arena(idx).is_min_max_cached(analyzer); - if max { - tracing::trace!("maximize cache hit"); - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => return dy.maximize(analyzer), - Concrete(inner) => return inner.maximize(analyzer), - ConcreteDyn(inner) => return inner.maximize(analyzer), - Expr(expr) => return expr.maximize(analyzer), - Null => return Ok(Elem::Null), - _ => {} - } - } - } - - use Elem::*; - let res = match self { - Reference(dy) => dy.maximize(analyzer)?, - Concrete(inner) => inner.maximize(analyzer)?, - ConcreteDyn(inner) => inner.maximize(analyzer)?, - Expr(expr) => expr.maximize(analyzer)?, - Null => Elem::Null, - Arena(_) => { - let dearenaized = self.dearenaize(analyzer); - let res = { - let Ok(t) = dearenaized.try_borrow() else { - return Ok(self.clone()); - }; - t.maximize(analyzer)? - }; - - match &mut *dearenaized.borrow_mut() { - Self::Reference(ref mut d) => { - tracing::trace!("maximize cache MISS: {self}"); - d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); - } - Self::Expr(ref mut expr) => { - tracing::trace!("maximize cache MISS: {self}"); - expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); - } - Self::ConcreteDyn(ref mut d) => { - tracing::trace!("maximize cache MISS: {self}"); - d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); - } - _ => {} - } - - let (_min, max) = self.is_min_max_cached(analyzer); - assert!(max, "????"); - - res - } - }; - Ok(res) - } - - fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - use Elem::*; - - if let Some(idx) = analyzer.range_arena_idx(self) { - let (min, _max) = Elem::Arena(idx).is_min_max_cached(analyzer); - if min { - tracing::trace!("minimize cache hit"); - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => return dy.minimize(analyzer), - Concrete(inner) => return inner.minimize(analyzer), - ConcreteDyn(inner) => return inner.minimize(analyzer), - Expr(expr) => return expr.minimize(analyzer), - Null => return Ok(Elem::Null), - _ => {} - } - } - } - - let res = match self { - Reference(dy) => dy.minimize(analyzer)?, - Concrete(inner) => inner.minimize(analyzer)?, - ConcreteDyn(inner) => inner.minimize(analyzer)?, - Expr(expr) => expr.minimize(analyzer)?, - Null => Elem::Null, - Arena(_) => { - let dearenaized = self.dearenaize(analyzer); - let res = { - let Ok(t) = dearenaized.try_borrow() else { - return Ok(self.clone()); - }; - t.minimize(analyzer)? - }; - - match &mut *dearenaized.borrow_mut() { - Self::Reference(ref mut d) => { - tracing::trace!("minimize cache MISS: {self}"); - d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); - } - Self::Expr(ref mut expr) => { - tracing::trace!("minimize cache MISS: {self}"); - expr.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); - } - Self::ConcreteDyn(ref mut d) => { - tracing::trace!("minimize cache MISS: {self}"); - d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); - } - _ => {} - } - - let (min, _max) = self.is_min_max_cached(analyzer); - assert!(min, "????"); - res - } - }; - Ok(res) - } - - fn simplify_maximize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - use Elem::*; - - if let Some(idx) = analyzer.range_arena_idx(self) { - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => { - if let Some(max) = &dy.flattened_max { - return Ok(*max.clone()); - } - } - c @ Concrete(_) => return Ok(c.clone()), - ConcreteDyn(inner) => { - if let Some(max) = &inner.flattened_max { - return Ok(*max.clone()); - } - } - Expr(expr) => { - if let Some(max) = &expr.flattened_max { - return Ok(*max.clone()); - } - } - Null => return Ok(Elem::Null), - _ => {} - } - } - - match self { - Reference(dy) => dy.simplify_maximize(analyzer), - Concrete(inner) => inner.simplify_maximize(analyzer), - ConcreteDyn(inner) => inner.simplify_maximize(analyzer), - Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Collapsed(collapsed) => { - let res = collapsed.simplify_maximize(analyzer)?; - collapsed.set_arenaized_flattened(true, &res, analyzer); - Ok(res) - } - _ => { - let res = expr.simplify_maximize(analyzer)?; - expr.set_arenaized_flattened(true, res.clone(), analyzer); - Ok(res) - } - }, - Null => Ok(Elem::Null), - Arena(_) => { - let dearenaized = self.dearenaize(analyzer); - let flat = dearenaized.borrow().flatten(true, analyzer)?; - let max = flat.simplify_maximize(analyzer)?; - // let min = flat.simplify_minimize(analyzer)?; - match &mut *dearenaized.borrow_mut() { - Self::Reference(ref mut d) => { - tracing::trace!("simplify maximize cache MISS: {self}"); - d.flattened_max = Some(Box::new(max.clone())); - // d.flattened_min = Some(Box::new(min.clone())); - } - Self::Expr(ref mut expr) => { - tracing::trace!("simplify maximize cache MISS: {self}"); - expr.flattened_max = Some(Box::new(max.clone())); - // expr.flattened_min = Some(Box::new(min.clone())); - } - Self::ConcreteDyn(ref mut d) => { - tracing::trace!("simplify maximize cache MISS: {self}"); - d.flattened_max = Some(Box::new(max.clone())); - // d.flattened_min = Some(Box::new(min.clone())); - } - _ => {} - } - - // assert!(self.is_flatten_cached(analyzer), "????"); - Ok(max) - } - } - } - - fn simplify_minimize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - use Elem::*; - - if let Some(idx) = analyzer.range_arena_idx(self) { - match &*analyzer.range_arena().ranges[idx].borrow() { - Reference(dy) => { - if let Some(min) = &dy.flattened_min { - return Ok(*min.clone()); - } - } - c @ Concrete(_) => return Ok(c.clone()), - ConcreteDyn(inner) => { - if let Some(min) = &inner.flattened_min { - return Ok(*min.clone()); - } - } - Expr(expr) => { - if let Some(min) = &expr.flattened_min { - return Ok(*min.clone()); - } - } - Null => return Ok(Elem::Null), - _ => {} - } - } - - let res = match self { - Reference(dy) => dy.simplify_minimize(analyzer), - Concrete(inner) => inner.simplify_minimize(analyzer), - ConcreteDyn(inner) => inner.simplify_minimize(analyzer), - Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Collapsed(collapsed) => { - let res = collapsed.simplify_minimize(analyzer)?; - collapsed.set_arenaized_flattened(false, &res, analyzer); - Ok(res) - } - _ => { - let res = expr.simplify_minimize(analyzer)?; - expr.set_arenaized_flattened(false, res.clone(), analyzer); - Ok(res) - } - }, - Null => Ok(Elem::Null), - Arena(_) => { - let dearenaized = self.dearenaize(analyzer); - let flat = dearenaized.borrow().flatten(false, analyzer)?; - let min = flat.simplify_minimize(analyzer)?; - match &mut *dearenaized.borrow_mut() { - Self::Reference(ref mut d) => { - tracing::trace!("simplify minimize cache MISS: {self}"); - d.flattened_min = Some(Box::new(min.clone())); - } - Self::Expr(ref mut expr) => { - tracing::trace!("simplify minimize cache MISS: {self}"); - expr.flattened_min = Some(Box::new(min.clone())); - } - Self::ConcreteDyn(ref mut d) => { - tracing::trace!("simplify minimize cache MISS: {self}"); - d.flattened_min = Some(Box::new(min.clone())); - } - _ => {} - } - - Ok(min) - } - }?; - - Ok(res) - } - - fn cache_maximize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.cache_maximize(analyzer), - Concrete(inner) => inner.cache_maximize(analyzer), - ConcreteDyn(inner) => inner.cache_maximize(analyzer), - Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Collapsed(mut collapsed) => { - collapsed.cache_maximize(analyzer)?; - let max = collapsed.maximize(analyzer)?; - self.set_arenaized_flattened(true, &max, analyzer); - *self = collapsed; - Ok(()) - } - _ => { - expr.cache_maximize(analyzer)?; - let max = expr.maximize(analyzer)?; - self.set_arenaized_flattened(true, &max, analyzer); - Ok(()) - } - }, - Null => Ok(()), - Arena(_idx) => { - let dearenaized = self.dearenaize(analyzer); - if let Ok(mut t) = dearenaized.try_borrow_mut() { - t.cache_maximize(analyzer)?; - } - - Ok(()) - } - } - } - - fn cache_minimize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - use Elem::*; - match self { - Reference(dy) => dy.cache_minimize(analyzer), - Concrete(inner) => inner.cache_minimize(analyzer), - ConcreteDyn(inner) => inner.cache_minimize(analyzer), - Expr(expr) => match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Collapsed(mut collapsed) => { - collapsed.cache_minimize(analyzer)?; - let min = collapsed.minimize(analyzer)?; - self.set_arenaized_flattened(false, &min, analyzer); - *self = collapsed; - Ok(()) - } - _ => { - expr.cache_minimize(analyzer)?; - let min = expr.minimize(analyzer)?; - self.set_arenaized_flattened(false, &min, analyzer); - Ok(()) - } - }, - Null => Ok(()), - Arena(_idx) => { - let dearenaized = self.dearenaize(analyzer); - if let Ok(mut t) = dearenaized.try_borrow_mut() { - t.cache_minimize(analyzer)?; - } - - Ok(()) - } - } - } - fn uncache(&mut self) { - use Elem::*; - match self { - Reference(dy) => dy.uncache(), - Concrete(inner) => inner.uncache(), - ConcreteDyn(inner) => inner.uncache(), - Expr(expr) => expr.uncache(), - Null => {} - Arena(_idx) => {} - } - } -} - -impl Elem { - pub fn wrapping_add(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Add(true), other); - Self::Expr(expr) - } - pub fn wrapping_sub(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Sub(true), other); - Self::Expr(expr) - } - pub fn wrapping_mul(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Mul(true), other); - Self::Expr(expr) - } - pub fn wrapping_div(self, other: Elem) -> Self { - let expr = RangeExpr::new(self, RangeOp::Div(true), other); - Self::Expr(expr) - } - - /// Creates a logical AND of two range elements - pub fn and(self, other: Self) -> Self { - let expr = RangeExpr::::new(self, RangeOp::And, other); - Self::Expr(expr) - } - - /// Creates a logical OR of two range elements - pub fn or(self, other: Self) -> Self { - let expr = RangeExpr::::new(self, RangeOp::Or, other); - Self::Expr(expr) - } - - pub fn maybe_elem_min(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::min(val)?)), - _ => None, - } - } - - pub fn maybe_elem_max(&self) -> Option { - match self { - Elem::Concrete(RangeConcrete { val, .. }) => Some(Elem::from(Concrete::max(val)?)), - _ => None, - } - } -} diff --git a/crates/graph/src/range/elem/elem_enum/arena.rs b/crates/graph/src/range/elem/elem_enum/arena.rs new file mode 100644 index 00000000..49582f96 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/arena.rs @@ -0,0 +1,216 @@ +use crate::GraphBackend; +use crate::{ + nodes::Concrete, + range::elem::{Elem, RangeElem}, +}; +use shared::RangeArena; + +pub trait RangeArenaLike { + fn debug_str(&self, analyzer: &impl GraphBackend) -> String; + fn ranges(&self) -> &Vec; + fn ranges_mut(&mut self) -> &mut Vec; + fn idx_or_upsert(&mut self, elem: T, analyzer: &impl GraphBackend) -> usize; + fn take_nonnull(&mut self, idx: usize) -> Option; + fn idx(&self, elem: &T) -> Option; + fn to_graph( + &mut self, + analyzer: &impl GraphBackend, + ) -> Result, usize, petgraph::Directed, usize>, crate::GraphError>; +} + +impl RangeArenaLike> for RangeArena> { + fn debug_str(&self, analyzer: &impl GraphBackend) -> String { + self.ranges + .iter() + .enumerate() + .map(|(i, elem)| { + fn fmt(elem: &Elem, analyzer: &impl GraphBackend) -> String { + match elem { + Elem::Reference(reference) => { + format!( + "node_{} -- {}", + reference.idx.index(), + crate::nodes::ContextVarNode::from(reference.idx) + .display_name(analyzer) + .unwrap() + ) + } + Elem::Expr(expr) => { + format!( + "{} {} {}", + fmt(&expr.lhs, analyzer), + expr.op.to_string(), + fmt(&expr.rhs, analyzer) + ) + } + _ => format!("{elem}"), + } + }; + + format!("{i}: {}", fmt(elem, analyzer)) + }) + .collect::>() + .join("\n\t") + } + + fn to_graph( + &mut self, + analyzer: &impl GraphBackend, + ) -> Result, usize, petgraph::Directed, usize>, crate::GraphError> + { + let mut graph = petgraph::Graph::default(); + let mut added = vec![]; + let mut ids = vec![]; + + fn get_children( + elem: &Elem, + analyzer: &impl GraphBackend, + ) -> Result>, crate::GraphError> { + match elem { + Elem::Reference(r) => { + let cvar = crate::nodes::ContextVarNode::from(r.idx); + let range = cvar.ref_range(analyzer)?.unwrap(); + let min = range.min.clone(); + let max = range.max.clone(); + Ok(vec![min, max]) + } + _c @ Elem::Concrete(_) => Ok(vec![]), + Elem::ConcreteDyn(d) => { + let mut v = vec![(*d.len).clone()]; + v.extend(d.val.values().map(|(v, _)| v.clone()).collect::>()); + v.extend(d.val.keys().cloned().collect::>()); + Ok(v) + } + Elem::Expr(expr) => Ok(vec![(*expr.lhs).clone(), (*expr.rhs).clone()]), + Elem::Null => Ok(vec![]), + Elem::Arena(_) => Ok(vec![]), + } + } + + fn add_elem_and_children( + graph: &mut petgraph::Graph, usize, petgraph::Directed, usize>, + added: &mut Vec>, + ids: &mut Vec, + elem: &Elem, + analyzer: &impl GraphBackend, + ) -> Result<(), crate::GraphError> { + assert!(added.len() == ids.len()); + + if !added.contains(elem) { + let new_elems: Vec> = get_children(elem, analyzer)?; + let id = graph.add_node(elem.clone()); + added.push(elem.clone()); + ids.push(id.index()); + + new_elems.into_iter().try_for_each(|elem| { + add_elem_and_children(graph, added, ids, &elem, analyzer)?; + let to_id = added.iter().position(|i| i == &elem).unwrap(); + graph.add_edge(id, to_id.into(), 0); + Ok(()) + })?; + } + + Ok(()) + } + + self.ranges.iter().try_for_each(|elem: &Elem| { + add_elem_and_children(&mut graph, &mut added, &mut ids, elem, analyzer) + })?; + Ok(graph) + } + + fn idx_or_upsert(&mut self, elem: Elem, analyzer: &impl GraphBackend) -> usize { + if self.ranges.is_empty() { + self.ranges.push(Elem::Null); + self.map.insert(Elem::Null, 0); + } + + let nulls = self.ranges.iter().fold(0, |mut acc, e| { + if matches!(e, Elem::Null) { + acc += 1; + } + acc + }); + + // println!( + // "{}\nhad cycle:\n{:?}", + // self.debug_str(analyzer), + // petgraph::dot::Dot::new(&self.to_graph(analyzer).unwrap()) // petgraph::algo::toposort(&self.to_graph(analyzer).unwrap(), None).is_err() + // ); + match elem { + Elem::Arena(idx) => return idx, + Elem::Null => return 0, + _ => {} + } + + if let Some(idx) = self.idx(&elem) { + let Some(existing) = self.take_nonnull(idx) else { + self.ranges_mut()[idx] = elem; + return idx; + }; + + let (min_cached, max_cached) = existing.is_min_max_cached(analyzer, self); + let mut existing_count = 0; + if min_cached { + existing_count += 1; + } + if max_cached { + existing_count += 1; + } + if existing.is_flatten_cached(analyzer, self) { + existing_count += 1; + } + + let (min_cached, max_cached) = elem.is_min_max_cached(analyzer, self); + let mut new_count = 0; + if min_cached { + new_count += 1; + } + if max_cached { + new_count += 1; + } + if elem.is_flatten_cached(analyzer, self) { + new_count += 1; + } + + if new_count >= existing_count { + self.ranges_mut()[idx] = elem; + } else { + self.ranges_mut()[idx] = existing; + } + + idx + } else { + let idx = self.ranges.len(); + self.ranges.push(elem.clone()); + self.map.insert(elem, idx); + idx + } + } + + fn ranges(&self) -> &Vec> { + &self.ranges + } + fn ranges_mut(&mut self) -> &mut Vec> { + &mut self.ranges + } + + fn take_nonnull(&mut self, idx: usize) -> Option> { + if let Some(t) = self.ranges.get_mut(idx) { + match t { + Elem::Null => None, + _ => Some(std::mem::take(t)), + } + } else { + None + } + } + + fn idx(&self, elem: &Elem) -> Option { + if let Elem::Arena(idx) = elem { + Some(*idx) + } else { + self.map.get(elem).copied() + } + } +} diff --git a/crates/graph/src/range/elem/elem_enum/impls.rs b/crates/graph/src/range/elem/elem_enum/impls.rs new file mode 100644 index 00000000..f9aa87d8 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/impls.rs @@ -0,0 +1,686 @@ +use crate::elem::{MinMaxed, RangeArenaLike}; +use crate::{ + nodes::Concrete, + range::elem::{Elem, RangeConcrete, RangeDyn, RangeElem, RangeExpr, RangeOp, Reference}, + GraphBackend, GraphError, +}; +use shared::{NodeIdx, RangeArena}; + +use ethers_core::types::I256; + +use std::collections::BTreeMap; + +impl Elem { + pub fn wrapping_add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(true), other); + Self::Expr(expr) + } + pub fn wrapping_sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(true), other); + Self::Expr(expr) + } + pub fn wrapping_mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(true), other); + Self::Expr(expr) + } + pub fn wrapping_div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(true), other); + Self::Expr(expr) + } + + /// Creates a logical AND of two range elements + pub fn and(self, other: Self) -> Self { + let expr = RangeExpr::::new(self, RangeOp::And, other); + Self::Expr(expr) + } + + /// Creates a logical OR of two range elements + pub fn or(self, other: Self) -> Self { + let expr = RangeExpr::::new(self, RangeOp::Or, other); + Self::Expr(expr) + } + + pub fn maybe_elem_min(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => { + Some(Elem::from(Concrete::min_of_type(val)?)) + } + _ => None, + } + } + + pub fn maybe_elem_max(&self) -> Option { + match self { + Elem::Concrete(RangeConcrete { val, .. }) => { + Some(Elem::from(Concrete::max_of_type(val)?)) + } + _ => None, + } + } +} + +impl Elem { + pub fn node_idx(&self) -> Option { + match self { + Self::Reference(Reference { idx, .. }) => Some(*idx), + _ => None, + } + } + + pub fn concrete(&self) -> Option { + match self { + Self::Concrete(RangeConcrete { val: c, .. }) => Some(c.clone()), + _ => None, + } + } + + pub fn maybe_concrete(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + + pub fn maybe_concrete_value(&self) -> Option> { + match self { + Elem::Concrete(a) => Some(a.clone()), + _ => None, + } + } + + pub fn maybe_range_dyn(&self) -> Option> { + match self { + Elem::ConcreteDyn(a) => Some(a.clone()), + _ => None, + } + } + + pub fn is_conc(&self) -> bool { + match self { + Elem::Concrete(_a) => true, + Elem::ConcreteDyn(a) => { + a.len.maybe_concrete().is_some() + && a.val + .iter() + .all(|(key, (val, _))| key.is_conc() && val.is_conc()) + } + Elem::Expr(expr) => expr.lhs.is_conc() && expr.rhs.is_conc(), + _ => false, + } + } +} + +impl Elem { + pub fn assert_nonnull(&self) { + match self { + Elem::Expr(expr) => { + expr.lhs.assert_nonnull(); + expr.rhs.assert_nonnull(); + } + Elem::Null => panic!("was null"), + _ => {} + } + } + + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + match self { + Self::Reference(d) => d.idx == node_idx, + Self::Concrete(_) => false, + Self::Expr(expr) => expr.contains_node(node_idx), + Self::ConcreteDyn(d) => d.contains_node(node_idx), + Self::Null => false, + Elem::Arena(_) => todo!(), + } + } + + pub fn expect_into_expr(self) -> RangeExpr { + match self { + Self::Expr(expr) => expr, + _ => panic!("Not expression"), + } + } + + pub fn dyn_map(&self) -> Option<&BTreeMap> { + match self { + Self::ConcreteDyn(dyn_range) => Some(&dyn_range.val), + _ => None, + } + } + + pub fn dyn_map_mut(&mut self) -> Option<&mut BTreeMap> { + match self { + Self::ConcreteDyn(ref mut dyn_range) => Some(&mut dyn_range.val), + _ => None, + } + } + + /// Creates a new range element that is a cast from one type to another + pub fn cast(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Cast, other); + Elem::Expr(expr) + } + + pub fn concat(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Concat, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the minimum of two range elements + pub fn min(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Min, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is the maximum of two range elements + pub fn max(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Max, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of equality of two range elements + pub fn eq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Eq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a boolean of inequality of two range elements + pub fn neq(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Neq, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is one range element to the power of another + pub fn pow(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Exp, other); + Elem::Expr(expr) + } + + /// Creates a new range element that is a memcopy of another + pub fn memcopy(self) -> Self { + let expr = RangeExpr::new(self, RangeOp::Memcopy, Elem::Null); + Elem::Expr(expr) + } + + /// Creates a new range element that applies a setting of indices of a memory object + pub fn set_indices(self, other: RangeDyn) -> Self { + let expr = RangeExpr::new(self, RangeOp::SetIndices, Elem::ConcreteDyn(other)); + Elem::Expr(expr) + } + + /// Creates a new range element that sets the length of a memory object + pub fn set_length(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::SetLength, other); + Elem::Expr(expr) + } + + /// Gets the length of a memory object + pub fn get_length(self) -> Self { + let expr = RangeExpr::new(self, RangeOp::GetLength, Elem::Null); + Elem::Expr(expr) + } + + /// Gets the length of a memory object + pub fn get_index(self, other: Self) -> Self { + let expr = RangeExpr::new(self, RangeOp::GetIndex, other); + Elem::Expr(expr) + } +} + +impl Elem { + pub fn replace_dep( + &mut self, + to_replace: NodeIdx, + replacement: Self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, + ) { + match self { + Elem::Reference(Reference { idx, .. }) => { + if *idx == to_replace { + *self = replacement; + } + } + Elem::Concrete(_) => {} + Elem::Expr(expr) => { + expr.lhs + .replace_dep(to_replace, replacement.clone(), analyzer, arena); + expr.rhs + .replace_dep(to_replace, replacement, analyzer, arena); + expr.maximized = None; + expr.minimized = None; + } + Elem::ConcreteDyn(d) => { + d.len + .replace_dep(to_replace, replacement.clone(), analyzer, arena); + let vals = std::mem::take(&mut d.val); + d.val = vals + .into_iter() + .map(|(mut k, (mut v, op))| { + k.replace_dep(to_replace, replacement.clone(), analyzer, arena); + v.replace_dep(to_replace, replacement.clone(), analyzer, arena); + (k, (v, op)) + }) + .collect(); + } + Elem::Null => {} + Elem::Arena(_) => { + let mut cloned = self.dearenaize_clone(arena); + cloned.replace_dep(to_replace, replacement, analyzer, arena); + cloned.arenaize(analyzer, arena).unwrap(); + *self = cloned; + } + } + } + + pub fn recurse_dearenaize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena, + ) -> Self { + match self { + Self::Arena(arena_idx) => arena + .ranges + .get(*arena_idx) + .unwrap() + .clone() + .recurse_dearenaize(analyzer, arena), + Self::Expr(expr) => expr.recurse_dearenaize(analyzer, arena), + e => e.clone(), + } + } + + pub fn dearenaize_clone(&self, arena: &mut RangeArena) -> Self { + match self { + Self::Arena(arena_idx) => arena.ranges.get(*arena_idx).cloned().unwrap_or_default(), + _ => unreachable!(), + } + } + + pub fn dearenaize(&self, arena: &mut RangeArena) -> (Self, usize) { + match self { + Self::Arena(arena_idx) => { + ( + arena.take_nonnull(*arena_idx).unwrap_or_default(), + // arena.ranges.get(*arena_idx).cloned().unwrap_or_default(), + *arena_idx, + ) + } + _ => unreachable!(), + } + } + + pub fn rearenaize(&self, elem: Self, idx: usize, arena: &mut RangeArena) { + if !matches!(elem, Elem::Null) { + if let Some(t) = arena.ranges.get_mut(idx) { + *t = elem; + } + } + } + + pub fn arena_eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Arena(a), Self::Arena(b)) => a == b, + (Self::Concrete(a), Self::Concrete(b)) => a == b, + (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => { + a.len == b.len + && a.val.len() == b.val.len() + && a.val + .iter() + .zip(b.val.iter()) + .all(|((a, op_a), (b, op_b))| a.arena_eq(b) && op_a == op_b) + } + (Self::Reference(a), Self::Reference(b)) => a == b, + (Self::Expr(a), Self::Expr(b)) => { + a.lhs.arena_eq(&b.lhs) && a.rhs.arena_eq(&b.rhs) && a.op == b.op + } + (Elem::Null, Elem::Null) => true, + _ => false, + } + } + pub fn as_bytes( + &self, + analyzer: &impl GraphBackend, + maximize: bool, + arena: &mut RangeArena>, + ) -> Option> { + let evaled = if maximize { + self.maximize(analyzer, arena).ok()? + } else { + self.minimize(analyzer, arena).ok()? + }; + + match evaled { + Elem::Concrete(c) => c.as_bytes(analyzer, maximize, arena), + Elem::ConcreteDyn(c) => c.as_bytes(analyzer, maximize, arena), + _ => None, + } + } + + pub fn overlaps( + &self, + other: &Self, + eval: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + match (self, other) { + (Elem::Concrete(s), Elem::Concrete(o)) => Ok(Some(o.val == s.val)), + (Elem::Reference(s), Elem::Reference(o)) => { + if s == o { + Ok(Some(true)) + } else if eval { + let lhs_min = s.minimize(analyzer, arena)?; + let rhs_max = o.maximize(analyzer, arena)?; + + match lhs_min.range_ord(&rhs_max, arena) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = s.maximize(analyzer, arena)?; + let rhs_min = o.minimize(analyzer, arena)?; + Ok(Some(matches!( + lhs_max.range_ord(&rhs_min, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else { + Ok(None) + } + } + (Elem::Reference(s), c @ Elem::Concrete(_)) => { + if eval { + let lhs_min = s.minimize(analyzer, arena)?; + + match lhs_min.range_ord(c, arena) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = s.maximize(analyzer, arena)?; + Ok(Some(matches!( + lhs_max.range_ord(c, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else { + Ok(None) + } + } + (Elem::Concrete(_), Elem::Reference(_)) => other.overlaps(self, eval, analyzer, arena), + _ => Ok(None), + } + } + + /// Given an element and a min and max, checks if the element could be equal to the RHS + pub fn overlaps_dual( + &self, + rhs_min: &Self, + rhs_max: &Self, + eval: bool, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + match self { + Self::Reference(d) => { + if eval { + let lhs_min = d.minimize(analyzer, arena)?; + let rhs_max = rhs_max.maximize(analyzer, arena)?; + + match lhs_min.range_ord(&rhs_max, arena) { + Some(std::cmp::Ordering::Less) => { + // we know our min is less than the other max + // check that the max is greater than or eq their min + let lhs_max = d.maximize(analyzer, arena)?; + let rhs_min = rhs_min.minimize(analyzer, arena)?; + Ok(Some(matches!( + lhs_max.range_ord(&rhs_min, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))) + } + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } else if self == rhs_min || self == rhs_max { + Ok(Some(true)) + } else { + Ok(None) + } + } + Self::Concrete(_) => { + let (min, max) = if eval { + ( + rhs_min.minimize(analyzer, arena)?, + rhs_max.maximize(analyzer, arena)?, + ) + } else { + (rhs_min.clone(), rhs_max.clone()) + }; + + match min.range_ord(self, arena) { + Some(std::cmp::Ordering::Less) => Ok(Some(matches!( + max.range_ord(self, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ))), + Some(std::cmp::Ordering::Equal) => Ok(Some(true)), + _ => Ok(Some(false)), + } + } + _ => Ok(None), + } + } + pub fn is_negative( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + let res = match self { + Elem::Concrete(RangeConcrete { + val: Concrete::Int(_, val), + .. + }) if val < &I256::zero() => true, + Elem::Reference(dy) => { + if maximize { + dy.maximize(analyzer, arena)? + .is_negative(maximize, analyzer, arena)? + } else { + dy.minimize(analyzer, arena)? + .is_negative(maximize, analyzer, arena)? + } + } + Elem::Expr(expr) => { + if maximize { + expr.maximize(analyzer, arena)? + .is_negative(maximize, analyzer, arena)? + } else { + expr.minimize(analyzer, arena)? + .is_negative(maximize, analyzer, arena)? + } + } + _ => false, + }; + Ok(res) + } + + pub fn pre_evaled_is_negative(&self) -> bool { + matches!(self, Elem::Concrete(RangeConcrete { val: Concrete::Int(_, val), ..}) if val < &I256::zero()) + } + + pub fn inverse_if_boolean(&self) -> Option { + match self { + Self::Reference(Reference { idx: _, .. }) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Concrete(_) => Some(Elem::Expr(RangeExpr::new( + self.clone(), + RangeOp::Not, + Elem::Null, + ))), + Self::Expr(expr) => Some(Elem::Expr(expr.inverse_if_boolean()?)), + Self::ConcreteDyn(_d) => None, + Self::Null => None, + Self::Arena(_) => todo!(), + } + } + + pub fn arenaized_flattened( + &self, + max: bool, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option>> { + if let Some(idx) = arena.idx(self) { + if let Some(t) = arena.ranges.get(idx) { + match t { + Elem::Expr(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + Elem::Reference(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + Elem::ConcreteDyn(ref arenaized) => { + if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + } + } + c @ Elem::Concrete(_) => Some(Box::new(c.clone())), + c @ Elem::Null => Some(Box::new(c.clone())), + Elem::Arena(idx) => Elem::Arena(*idx).arenaized_flattened(max, analyzer, arena), + } + } else { + None + } + } else { + None + } + } + + pub fn set_arenaized_flattened( + &self, + max: bool, + elem: &Elem, + arena: &mut RangeArena>, + ) { + if let Some(idx) = arena.idx(self) { + if let Some(ref mut t) = arena.ranges.get_mut(idx) { + match &mut *t { + Elem::Expr(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + Elem::Reference(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + Elem::ConcreteDyn(ref mut arenaized) => { + if max { + arenaized.flattened_max = Some(Box::new(elem.clone())); + } else { + arenaized.flattened_min = Some(Box::new(elem.clone())); + } + } + _ => {} + } + } + } + } + + pub fn set_arenaized_cache( + &self, + max: bool, + elem: &Elem, + arena: &mut RangeArena>, + ) { + if let Some(idx) = arena.idx(self) { + if let Some(t) = arena.ranges.get_mut(idx) { + match &mut *t { + Elem::Expr(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + Elem::Reference(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + Elem::ConcreteDyn(ref mut arenaized) => { + if max { + arenaized.maximized = Some(MinMaxed::Maximized(Box::new(elem.clone()))); + } else { + arenaized.minimized = Some(MinMaxed::Minimized(Box::new(elem.clone()))); + } + } + _ => {} + } + } + } + } + + pub fn is_bytes(&self) -> bool { + matches!( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::Bytes(..), + .. + }) + ) + } + + pub fn is_string(&self) -> bool { + matches!( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::String(..), + .. + }) + ) + } + + pub fn is_uint(&self) -> bool { + matches!( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::Uint(..), + .. + }) + ) + } + + pub fn is_int(&self) -> bool { + matches!( + self, + Elem::Concrete(RangeConcrete { + val: Concrete::Int(..), + .. + }) + ) + } +} diff --git a/crates/graph/src/range/elem/elem_enum/mod.rs b/crates/graph/src/range/elem/elem_enum/mod.rs new file mode 100644 index 00000000..4c9bb429 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/mod.rs @@ -0,0 +1,28 @@ +mod arena; +mod impls; +mod ops; +mod range_elem; +mod traits; + +use crate::range::elem::{RangeConcrete, RangeDyn, RangeExpr, Reference}; +use shared::RangeArenaIdx; + +pub use arena::RangeArenaLike; + +/// A core range element. +#[derive(Default, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)] +pub enum Elem { + /// A range element that is a reference to another node + Reference(Reference), + /// A concrete range element of type `T`. e.g.: some number like `10` + ConcreteDyn(RangeDyn), + /// A concrete range element of type `T`. e.g.: some number like `10` + Concrete(RangeConcrete), + /// A range element that is an expression composed of other range elements + Expr(RangeExpr), + /// A range element that is a pointer to another expression in an arena + Arena(RangeArenaIdx), + /// A null range element useful in range expressions that dont have a rhs + #[default] + Null, +} diff --git a/crates/graph/src/range/elem/elem_enum/ops.rs b/crates/graph/src/range/elem/elem_enum/ops.rs new file mode 100644 index 00000000..52e17fa1 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/ops.rs @@ -0,0 +1,93 @@ +use crate::range::elem::{Elem, RangeExpr, RangeOp}; + +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub}; + +impl Add for Elem { + type Output = Self; + + fn add(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Add(false), other); + Self::Expr(expr) + } +} + +impl Sub for Elem { + type Output = Self; + + fn sub(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Sub(false), other); + Self::Expr(expr) + } +} + +impl Mul for Elem { + type Output = Self; + + fn mul(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mul(false), other); + Self::Expr(expr) + } +} + +impl Div for Elem { + type Output = Self; + + fn div(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Div(false), other); + Self::Expr(expr) + } +} + +impl Shl for Elem { + type Output = Self; + + fn shl(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shl, other); + Self::Expr(expr) + } +} + +impl Shr for Elem { + type Output = Self; + + fn shr(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Shr, other); + Self::Expr(expr) + } +} + +impl Rem for Elem { + type Output = Self; + + fn rem(self, other: Elem) -> Self { + let expr = RangeExpr::new(self, RangeOp::Mod, other); + Self::Expr(expr) + } +} + +impl BitAnd for Elem { + type Output = Self; + + fn bitand(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitAnd, other); + Self::Expr(expr) + } +} + +impl BitOr for Elem { + type Output = Self; + + fn bitor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitOr, other); + Self::Expr(expr) + } +} + +impl BitXor for Elem { + type Output = Self; + + fn bitxor(self, other: Self) -> Self::Output { + let expr = RangeExpr::new(self, RangeOp::BitXor, other); + Self::Expr(expr) + } +} diff --git a/crates/graph/src/range/elem/elem_enum/range_elem.rs b/crates/graph/src/range/elem/elem_enum/range_elem.rs new file mode 100644 index 00000000..dc9898f3 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/range_elem.rs @@ -0,0 +1,617 @@ +use crate::elem::{MinMaxed, RangeArenaLike}; +use crate::{ + nodes::{Concrete, ContextVarNode}, + range::elem::{collapse, Elem, MaybeCollapsed, RangeElem}, + GraphBackend, GraphError, +}; + +use shared::{NodeIdx, RangeArena}; + +impl RangeElem for Elem { + type GraphError = GraphError; + + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + match self { + Self::Arena(_) => return Ok(()), + Self::Reference(d) => d.arenaize(analyzer, arena)?, + Self::ConcreteDyn(d) => d.arenaize(analyzer, arena)?, + Self::Expr(expr) => { + expr.arenaize(analyzer, arena)?; + } + Self::Concrete(c) => c.arenaize(analyzer, arena)?, + Self::Null => {} + } + + let self_take = std::mem::take(self); + *self = Elem::Arena(arena.idx_or_upsert(self_take, analyzer)); + Ok(()) + } + + fn range_eq(&self, other: &Self, arena: &mut RangeArena>) -> bool { + match (self, other) { + (Self::Arena(a), Self::Arena(b)) => a == b, + (Self::Concrete(a), Self::Concrete(b)) => a.range_eq(b, arena), + (Self::ConcreteDyn(a), Self::ConcreteDyn(b)) => a.range_eq(b, arena), + (Self::Reference(a), Self::Reference(b)) => a.idx == b.idx, + _ => false, + } + } + + fn range_ord( + &self, + other: &Self, + arena: &mut RangeArena>, + ) -> Option { + match (self, other) { + (Self::Arena(a), Self::Arena(b)) => { + if a == b { + Some(std::cmp::Ordering::Equal) + } else { + let (l, a) = self.dearenaize(arena); + let (r, b) = other.dearenaize(arena); + let res = l.range_ord(&r, arena); + self.rearenaize(l, a, arena); + self.rearenaize(r, b, arena); + res + } + } + (Self::Concrete(a), Self::Concrete(b)) => a.range_ord(b, arena), + (c @ Self::Concrete(_), Self::Reference(r)) => { + if let (Some(MinMaxed::Minimized(min)), Some(MinMaxed::Maximized(max))) = + (&r.minimized, &r.maximized) + { + let min_ord = c.range_ord(min, arena)?; + let max_ord = c.range_ord(max, arena)?; + if min_ord == max_ord { + Some(min_ord) + } else { + None + } + } else { + None + } + } + (Self::Reference(r), c @ Self::Concrete(_)) => { + if let (Some(MinMaxed::Minimized(min)), Some(MinMaxed::Maximized(max))) = + (&r.minimized, &r.maximized) + { + let min_ord = min.range_ord(c, arena)?; + let max_ord = max.range_ord(c, arena)?; + if min_ord == max_ord { + Some(min_ord) + } else { + None + } + } else { + None + } + } + (Self::Reference(a), Self::Reference(b)) => a.range_ord(b, arena), + (Elem::Null, Elem::Null) => None, + (_a, Elem::Null) => Some(std::cmp::Ordering::Greater), + (Elem::Null, _a) => Some(std::cmp::Ordering::Less), + _ => None, + } + } + + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + match self { + Self::Reference(d) => d.flatten(maximize, analyzer, arena), + Self::Concrete(c) => c.flatten(maximize, analyzer, arena), + Self::Expr(expr) => expr.flatten(maximize, analyzer, arena), + Self::ConcreteDyn(d) => d.flatten(maximize, analyzer, arena), + Self::Null => Ok(Elem::Null), + Self::Arena(_) => { + let (de, idx) = self.dearenaize(arena); + let res = de.flatten(maximize, analyzer, arena)?; + self.rearenaize(de, idx, arena); + Ok(res) + } + } + } + + fn cache_flatten( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + if self.is_flatten_cached(analyzer, arena) { + return Ok(()); + } + + match self { + Self::Reference(d) => d.cache_flatten(analyzer, arena), + Self::Concrete(c) => c.cache_flatten(analyzer, arena), + Self::Expr(expr) => expr.cache_flatten(analyzer, arena), + Self::ConcreteDyn(d) => d.cache_flatten(analyzer, arena), + Self::Null => Ok(()), + Self::Arena(idx) => { + tracing::trace!("flattening for arena idx: {idx}"); + let (mut dearenaized, idx) = self.dearenaize(arena); + dearenaized.cache_flatten(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + Ok(()) + } + } + } + + fn is_flatten_cached( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { + match self { + Self::Reference(d) => d.is_flatten_cached(analyzer, arena), + Self::Concrete(c) => c.is_flatten_cached(analyzer, arena), + Self::Expr(expr) => expr.is_flatten_cached(analyzer, arena), + Self::ConcreteDyn(d) => d.is_flatten_cached(analyzer, arena), + Self::Null => true, + Self::Arena(_) => { + let (t, idx) = self.dearenaize(arena); + let res = t.is_flatten_cached(analyzer, arena); + self.rearenaize(t, idx, arena); + res + } + } + } + + fn is_min_max_cached( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> (bool, bool) { + match self { + Self::Reference(d) => d.is_min_max_cached(analyzer, arena), + Self::Concrete(_c) => (true, true), + Self::Expr(expr) => expr.is_min_max_cached(analyzer, arena), + Self::ConcreteDyn(d) => d.is_min_max_cached(analyzer, arena), + Self::Null => (true, true), + Self::Arena(_) => { + let (t, idx) = self.dearenaize(arena); + let res = t.is_min_max_cached(analyzer, arena); + self.rearenaize(t, idx, arena); + res + } + } + } + + fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { + match self { + Self::Reference(d) => d.dependent_on(analyzer, arena), + Self::Concrete(_) => vec![], + Self::Expr(expr) => expr.dependent_on(analyzer, arena), + Self::ConcreteDyn(d) => d.dependent_on(analyzer, arena), + Self::Null => vec![], + Self::Arena(_) => { + let (t, idx) = self.dearenaize(arena); + let res = t.dependent_on(analyzer, arena); + self.rearenaize(t, idx, arena); + res + } + } + } + + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + match self { + Self::Reference(d) => d.recursive_dependent_on(analyzer, arena), + Self::Concrete(_) => Ok(vec![]), + Self::Expr(expr) => expr.recursive_dependent_on(analyzer, arena), + Self::ConcreteDyn(d) => d.recursive_dependent_on(analyzer, arena), + Self::Null => Ok(vec![]), + Self::Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let res = dearenaized.recursive_dependent_on(analyzer, arena); + self.rearenaize(dearenaized, idx, arena); + res + } + } + } + + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + match self { + Self::Reference(d) => d.has_cycle(seen, analyzer, arena), + Self::Concrete(_) => Ok(false), + Self::Expr(expr) => expr.has_cycle(seen, analyzer, arena), + Self::ConcreteDyn(d) => d.has_cycle(seen, analyzer, arena), + Self::Null => Ok(false), + Self::Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let res = dearenaized.has_cycle(seen, analyzer, arena); + self.rearenaize(dearenaized, idx, arena); + res + } + } + } + + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + match self { + Self::Reference(d) => d.depends_on(var, seen, analyzer, arena), + Self::Concrete(_) => Ok(false), + Self::Expr(expr) => expr.depends_on(var, seen, analyzer, arena), + Self::ConcreteDyn(d) => d.depends_on(var, seen, analyzer, arena), + Self::Null => Ok(false), + Self::Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let res = dearenaized.depends_on(var, seen, analyzer, arena); + self.rearenaize(dearenaized, idx, arena); + res + } + } + } + + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) { + match self { + Self::Reference(ref mut d) => { + if d.idx == node_idx { + d.idx = new_idx + } + } + Self::Concrete(_) => {} + Self::Expr(expr) => expr.filter_recursion(node_idx, new_idx, analyzer, arena), + Self::ConcreteDyn(d) => d.filter_recursion(node_idx, new_idx, analyzer, arena), + Self::Null => {} + Self::Arena(_) => { + let (mut dearenaized, idx) = self.dearenaize(arena); + dearenaized.filter_recursion(node_idx, new_idx, analyzer, arena); + self.rearenaize(dearenaized, idx, arena); + } + } + } + + fn maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.maximize(analyzer, arena)?, + Concrete(inner) => inner.maximize(analyzer, arena)?, + ConcreteDyn(inner) => inner.maximize(analyzer, arena)?, + Expr(expr) => expr.maximize(analyzer, arena)?, + Null => Elem::Null, + Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let res = dearenaized.maximize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + + match arena.ranges.get_mut(idx) { + Some(Self::Reference(ref mut d)) => { + if d.maximized.is_none() { + d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + } + Some(Self::Expr(ref mut expr)) => { + if expr.maximized.is_none() { + expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + } + Some(Self::ConcreteDyn(ref mut d)) => { + if d.maximized.is_none() { + d.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); + } + } + _ => {} + } + + let (_min, max) = self.is_min_max_cached(analyzer, arena); + assert!(max, "????"); + + res + } + }; + Ok(res) + } + + fn minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + use Elem::*; + let res = match self { + Reference(dy) => dy.minimize(analyzer, arena)?, + Concrete(inner) => inner.minimize(analyzer, arena)?, + ConcreteDyn(inner) => inner.minimize(analyzer, arena)?, + Expr(expr) => expr.minimize(analyzer, arena)?, + Null => Elem::Null, + Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let res = dearenaized.minimize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + + match arena.ranges.get_mut(idx) { + Some(Self::Reference(ref mut d)) => { + if d.minimized.is_none() { + d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + } + Some(Self::Expr(ref mut expr)) => { + if expr.minimized.is_none() { + expr.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + } + Some(Self::ConcreteDyn(ref mut d)) => { + if d.minimized.is_none() { + d.minimized = Some(MinMaxed::Minimized(Box::new(res.clone()))); + } + } + _ => {} + } + + let (min, _max) = self.is_min_max_cached(analyzer, arena); + assert!(min, "????"); + res + } + }; + Ok(res) + } + + fn simplify_maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + use Elem::*; + + if let Some(idx) = arena.idx(self) { + if let Some(t) = arena.ranges.get(idx) { + match t { + Reference(dy) => { + if let Some(max) = &dy.flattened_max { + return Ok(*max.clone()); + } + } + c @ Concrete(_) => return Ok(c.clone()), + ConcreteDyn(inner) => { + if let Some(max) = &inner.flattened_max { + return Ok(*max.clone()); + } + } + Expr(expr) => { + if let Some(max) = &expr.flattened_max { + return Ok(*max.clone()); + } + } + _ => {} + } + } + } + + match self { + Reference(dy) => dy.simplify_maximize(analyzer, arena), + Concrete(inner) => inner.simplify_maximize(analyzer, arena), + ConcreteDyn(inner) => inner.simplify_maximize(analyzer, arena), + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), arena) { + MaybeCollapsed::Collapsed(collapsed) => { + let res = collapsed.simplify_maximize(analyzer, arena)?; + collapsed.set_arenaized_flattened(true, &res, arena); + Ok(res) + } + _ => { + let res = expr.simplify_maximize(analyzer, arena)?; + expr.set_arenaized_flattened(true, res.clone(), arena); + Ok(res) + } + }, + Null => Ok(Elem::Null), + Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let flat = dearenaized.flatten(true, analyzer, arena)?; + let max = flat.simplify_maximize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + + match arena.ranges.get_mut(idx) { + Some(Self::Reference(ref mut d)) => { + tracing::trace!("simplify maximize cache MISS: {self}"); + d.flattened_max = Some(Box::new(max.clone())); + } + Some(Self::Expr(ref mut expr)) => { + tracing::trace!("simplify maximize cache MISS: {self}"); + expr.flattened_max = Some(Box::new(max.clone())); + } + Some(Self::ConcreteDyn(ref mut d)) => { + tracing::trace!("simplify maximize cache MISS: {self}"); + d.flattened_max = Some(Box::new(max.clone())); + } + _ => {} + } + + Ok(max) + } + } + } + + fn simplify_minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + use Elem::*; + + if let Some(idx) = arena.idx(self) { + if let Some(t) = arena.ranges.get(idx) { + match t { + Reference(dy) => { + if let Some(min) = &dy.flattened_min { + return Ok(*min.clone()); + } + } + c @ Concrete(_) => return Ok(c.clone()), + ConcreteDyn(inner) => { + if let Some(min) = &inner.flattened_min { + return Ok(*min.clone()); + } + } + Expr(expr) => { + if let Some(min) = &expr.flattened_min { + return Ok(*min.clone()); + } + } + Null => return Ok(Elem::Null), + _ => {} + } + } + } + + let res = match self { + Reference(dy) => dy.simplify_minimize(analyzer, arena), + Concrete(inner) => inner.simplify_minimize(analyzer, arena), + ConcreteDyn(inner) => inner.simplify_minimize(analyzer, arena), + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), arena) { + MaybeCollapsed::Collapsed(collapsed) => { + let res = collapsed.simplify_minimize(analyzer, arena)?; + collapsed.set_arenaized_flattened(false, &res, arena); + Ok(res) + } + _ => { + let res = expr.simplify_minimize(analyzer, arena)?; + expr.set_arenaized_flattened(false, res.clone(), arena); + Ok(res) + } + }, + Null => Ok(Elem::Null), + Arena(_) => { + let (dearenaized, idx) = self.dearenaize(arena); + let flat = dearenaized.flatten(false, analyzer, arena)?; + let min = flat.simplify_minimize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + + match arena.ranges.get_mut(idx) { + Some(Self::Reference(ref mut d)) => { + tracing::trace!("simplify minimize cache MISS: {self}"); + d.flattened_min = Some(Box::new(min.clone())); + } + Some(Self::Expr(ref mut expr)) => { + tracing::trace!("simplify minimize cache MISS: {self}"); + expr.flattened_min = Some(Box::new(min.clone())); + } + Some(Self::ConcreteDyn(ref mut d)) => { + tracing::trace!("simplify minimize cache MISS: {self}"); + d.flattened_min = Some(Box::new(min.clone())); + } + _ => {} + } + + Ok(min) + } + }?; + + Ok(res) + } + + fn cache_maximize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_maximize(analyzer, arena), + Concrete(inner) => inner.cache_maximize(analyzer, arena), + ConcreteDyn(inner) => inner.cache_maximize(analyzer, arena), + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), arena) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_maximize(analyzer, arena)?; + let max = collapsed.maximize(analyzer, arena)?; + self.set_arenaized_flattened(true, &max, arena); + *self = collapsed; + Ok(()) + } + _ => { + expr.cache_maximize(analyzer, arena)?; + let max = expr.maximize(analyzer, arena)?; + self.set_arenaized_flattened(true, &max, arena); + Ok(()) + } + }, + Null => Ok(()), + Arena(_) => { + let (mut dearenaized, idx) = self.dearenaize(arena); + dearenaized.cache_maximize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + Ok(()) + } + } + } + + fn cache_minimize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + use Elem::*; + match self { + Reference(dy) => dy.cache_minimize(analyzer, arena), + Concrete(inner) => inner.cache_minimize(analyzer, arena), + ConcreteDyn(inner) => inner.cache_minimize(analyzer, arena), + Expr(expr) => match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), arena) { + MaybeCollapsed::Collapsed(mut collapsed) => { + collapsed.cache_minimize(analyzer, arena)?; + let min = collapsed.minimize(analyzer, arena)?; + self.set_arenaized_flattened(false, &min, arena); + *self = collapsed; + Ok(()) + } + _ => { + expr.cache_minimize(analyzer, arena)?; + let min = expr.minimize(analyzer, arena)?; + self.set_arenaized_flattened(false, &min, arena); + Ok(()) + } + }, + Null => Ok(()), + Arena(_) => { + let (mut dearenaized, idx) = self.dearenaize(arena); + dearenaized.cache_minimize(analyzer, arena)?; + self.rearenaize(dearenaized, idx, arena); + Ok(()) + } + } + } + fn uncache(&mut self) { + use Elem::*; + match self { + Reference(dy) => dy.uncache(), + Concrete(inner) => inner.uncache(), + ConcreteDyn(inner) => inner.uncache(), + Expr(expr) => expr.uncache(), + Null => {} + Arena(_idx) => {} + } + } +} diff --git a/crates/graph/src/range/elem/elem_enum/traits.rs b/crates/graph/src/range/elem/elem_enum/traits.rs new file mode 100644 index 00000000..a2faced0 --- /dev/null +++ b/crates/graph/src/range/elem/elem_enum/traits.rs @@ -0,0 +1,114 @@ +use crate::{ + nodes::{Concrete, ContextVarNode}, + range::elem::{Elem, RangeConcrete, RangeExpr, RangeOp, Reference}, +}; +use shared::NodeIdx; + +use solang_parser::pt::Loc; + +use std::{ + borrow::Cow, + hash::{Hash, Hasher}, +}; + +impl Hash for Elem { + fn hash(&self, state: &mut H) { + match self { + Elem::Reference(r) => r.hash(state), + Elem::Concrete(c) => c.hash(state), + Elem::Expr(expr) => expr.hash(state), + Elem::ConcreteDyn(d) => d.hash(state), + Elem::Null => (-1i32).hash(state), + Elem::Arena(idx) => idx.hash(state), + } + } +} + +impl<'a> From<&'a Elem> for Cow<'a, Elem> { + fn from(val: &'a Elem) -> Self { + Cow::Borrowed(val) + } +} + +impl<'a> From> for Cow<'a, Elem> { + fn from(val: Elem) -> Self { + Cow::Owned(val) + } +} + +impl From for Elem { + fn from(c: bool) -> Self { + Elem::Concrete(RangeConcrete::new(Concrete::from(c), Loc::Implicit)) + } +} + +impl From> for Elem { + fn from(dy: Reference) -> Self { + Elem::Reference(dy) + } +} + +impl From> for Elem { + fn from(c: RangeConcrete) -> Self { + Elem::Concrete(c) + } +} + +impl From for Elem { + fn from(idx: NodeIdx) -> Self { + Elem::Reference(Reference::new(idx)) + } +} + +impl From for Elem { + fn from(c: Concrete) -> Self { + Elem::Concrete(RangeConcrete::new(c, Loc::Implicit)) + } +} + +impl From for Elem { + fn from(c: ContextVarNode) -> Self { + Elem::Reference(Reference::new(c.into())) + } +} + +impl std::fmt::Display for Elem { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Elem::Reference(Reference { idx, .. }) => write!(f, "idx_{}", idx.index()), + Elem::ConcreteDyn(d) => { + write!(f, "{{len: {}, values: {{", d.len)?; + d.val + .iter() + .try_for_each(|(key, (val, op))| write!(f, " {key}: ({val}, {op}),"))?; + write!(f, "}}}}") + } + Elem::Concrete(RangeConcrete { val, .. }) => { + write!(f, "{}", val.as_string()) + } + Elem::Expr(RangeExpr { lhs, op, rhs, .. }) => match op { + RangeOp::Min | RangeOp::Max => { + write!(f, "{}{{{}, {}}}", op.to_string(), lhs, rhs) + } + RangeOp::Cast => match &**rhs { + Elem::Concrete(RangeConcrete { val, .. }) => { + write!( + f, + "{}({}, {})", + op.to_string(), + lhs, + val.as_builtin().basic_as_string() + ) + } + _ => write!(f, "{}({}, {})", op.to_string(), lhs, rhs), + }, + RangeOp::BitNot => { + write!(f, "~{}", lhs) + } + _ => write!(f, "({} {} {})", lhs, op.to_string(), rhs), + }, + Elem::Arena(idx) => write!(f, "arena_idx_{idx}"), + Elem::Null => write!(f, ""), + } + } +} diff --git a/crates/graph/src/range/elem/elem_trait.rs b/crates/graph/src/range/elem/elem_trait.rs index 7f5c13b3..c4bfcd28 100644 --- a/crates/graph/src/range/elem/elem_trait.rs +++ b/crates/graph/src/range/elem/elem_trait.rs @@ -1,62 +1,99 @@ -use crate::{ - nodes::ContextVarNode, - range::elem::{Elem, RangeExpr, RangeOp}, - GraphBackend, GraphError, -}; +use crate::{nodes::ContextVarNode, range::elem::Elem, GraphBackend, GraphError}; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; +use std::hash::Hash; -pub trait RangeElem { +pub trait RangeElem: Hash { type GraphError; /// Flattens an element into an expression or concrete based purely on inputs, calldata, storage, or environment data variables fn flatten( &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError>; /// Returns whether `cache_flatten` has been called - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool; - fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool); + fn is_flatten_cached( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool; + fn is_min_max_cached( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> (bool, bool); /// Flattens an element and caches the result - fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_flatten( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its maximum value - fn maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, Self::GraphError>; /// Maximizes the element and caches the result for quicker use later - fn cache_maximize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_maximize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), Self::GraphError>; /// Tries to evaluate a range element down to a concrete or maximally simplified expression to its minimum value - fn minimize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, Self::GraphError>; /// Minimizes the element and caches the result for quicker use later - fn cache_minimize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_minimize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), Self::GraphError>; /// Uncaches the minimum and maximum fn uncache(&mut self); /// Tries to simplify to maximum(i.e.: leaves symbolic/dynamic values as they are) - fn simplify_maximize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn simplify_maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, Self::GraphError>; /// Tries to simplify to minimum (i.e.: leaves symbolic/dynamic values as they are) - fn simplify_minimize(&self, analyzer: &impl GraphBackend) -> Result, Self::GraphError>; + fn simplify_minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, Self::GraphError>; /// Checks if two range elements are equal - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; + fn range_eq(&self, other: &Self, arena: &mut RangeArena>) -> bool; /// Tries to compare the ordering of two range elements - fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option; - /// Constructs a range `Elem::Expr` given a lhs, rhs, and operation ([`RangeOp`]). - fn range_op(lhs: Elem, rhs: Elem, op: RangeOp, _analyzer: &impl GraphBackend) -> Elem - where - Self: Sized, - { - Elem::Expr(RangeExpr::new(lhs, op, rhs)) - } + fn range_ord( + &self, + other: &Self, + arena: &mut RangeArena>, + ) -> Option; /// Traverses the range expression and finds all nodes that are dynamically pointed to /// and returns it in a vector. - fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec; + fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec; fn recursive_dependent_on( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError>; fn has_cycle( &self, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result; fn depends_on( @@ -64,6 +101,7 @@ pub trait RangeElem { var: ContextVarNode, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result; /// Attempts to replace range elements that form a cyclic dependency by replacing /// it with a new node. Ideally no cyclic dependencies occur in ranges as of now @@ -77,7 +115,12 @@ pub trait RangeElem { node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ); - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError>; + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError>; } diff --git a/crates/graph/src/range/elem/expr.rs b/crates/graph/src/range/elem/expr.rs deleted file mode 100644 index 797a3ece..00000000 --- a/crates/graph/src/range/elem/expr.rs +++ /dev/null @@ -1,1213 +0,0 @@ -use crate::{ - nodes::{Concrete, ContextVarNode}, - range::{ - elem::{Elem, MinMaxed, RangeElem, RangeOp}, - exec_traits::*, - }, - GraphBackend, GraphError, -}; -use std::hash::Hash; -use std::hash::Hasher; - -use ethers_core::types::U256; -use shared::NodeIdx; - -pub static SINGLETON_EQ_OPS: &[RangeOp] = &[ - RangeOp::Eq, - RangeOp::Neq, - RangeOp::Lt, - RangeOp::Lte, - RangeOp::Gt, - RangeOp::Gte, -]; - -pub static EQ_OPS: &[RangeOp] = &[ - RangeOp::Eq, - RangeOp::Neq, - RangeOp::Lt, - RangeOp::Lte, - RangeOp::Gt, - RangeOp::Gte, - RangeOp::And, - RangeOp::Or, -]; - -pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; - -/// A range expression composed of other range [`Elem`] -#[derive(Clone, Debug, Ord, PartialOrd)] -pub struct RangeExpr { - pub maximized: Option>, - pub minimized: Option>, - pub flattened_min: Option>>, - pub flattened_max: Option>>, - pub lhs: Box>, - pub op: RangeOp, - pub rhs: Box>, -} - -impl PartialEq for RangeExpr { - fn eq(&self, other: &Self) -> bool { - self.lhs == other.lhs && self.rhs == other.rhs && self.op == other.op - } -} -impl Eq for RangeExpr {} - -impl Hash for RangeExpr { - fn hash(&self, state: &mut H) { - (*self.lhs).hash(state); - self.op.hash(state); - (*self.rhs).hash(state); - } -} - -impl RangeExpr { - pub fn is_noop(&self) -> (bool, usize) { - let one = Elem::from(Concrete::from(U256::one())); - let zero = Elem::from(Concrete::from(U256::zero())); - match self.op { - RangeOp::Mul(_) | RangeOp::Div(_) => { - if *self.lhs == one { - (true, 0) - } else if *self.rhs == one { - (true, 1) - } else { - (false, 0) - } - } - RangeOp::Add(_) | RangeOp::Sub(_) => { - if *self.lhs == zero { - (true, 0) - } else if *self.rhs == zero { - (true, 1) - } else { - (false, 0) - } - } - _ => (false, 0), - } - } - - pub fn inverse_if_boolean(&self) -> Option { - if EQ_OPS.contains(&self.op) { - if SINGLETON_EQ_OPS.contains(&self.op) { - let mut new_self = self.clone(); - new_self.uncache(); - new_self.op = new_self.op.logical_inverse()?; - Some(new_self) - } else { - // non-singleton, i.e. AND or OR - let mut new_self = self.clone(); - new_self.uncache(); - new_self.op = new_self.op.inverse()?; - if let Some(new_lhs) = new_self.inverse_if_boolean() { - *new_self.lhs = Elem::Expr(new_lhs); - } - if let Some(new_rhs) = new_self.inverse_if_boolean() { - *new_self.rhs = Elem::Expr(new_rhs); - } - Some(new_self) - } - } else { - None - } - } - - pub fn recurse_dearenaize(&self, analyzer: &impl GraphBackend) -> Elem { - Elem::Expr(Self::new( - self.lhs.recurse_dearenaize(analyzer).clone(), - self.op, - self.rhs.recurse_dearenaize(analyzer).clone(), - )) - } - - pub fn arena_idx(&self, analyzer: &impl GraphBackend) -> Option { - let expr = Elem::Expr(RangeExpr::new( - Elem::Arena(analyzer.range_arena_idx(&self.lhs)?), - self.op, - Elem::Arena(analyzer.range_arena_idx(&self.rhs)?), - )); - analyzer.range_arena_idx(&expr) - } - - pub fn arenaized_cache( - &self, - max: bool, - analyzer: &impl GraphBackend, - ) -> Option> { - if let Some(idx) = self.arena_idx(analyzer) { - let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { - return None; - }; - let Elem::Expr(ref arenaized) = *t else { - return None; - }; - return if max { - arenaized.maximized.clone() - } else { - arenaized.minimized.clone() - }; - } - None - } - - pub fn arenaized_flat_cache( - &self, - max: bool, - analyzer: &impl GraphBackend, - ) -> Option>> { - if let Some(idx) = self.arena_idx(analyzer) { - let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() else { - return None; - }; - let Elem::Expr(ref arenaized) = *t else { - return None; - }; - return if max { - arenaized.flattened_max.clone() - } else { - arenaized.flattened_min.clone() - }; - } - None - } - - pub fn set_arenaized_flattened( - &self, - max: bool, - elem: Elem, - analyzer: &impl GraphBackend, - ) { - if let Some(idx) = self.arena_idx(analyzer) { - if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { - let Elem::Expr(arenaized) = &mut *t else { - return; - }; - - if max { - arenaized.flattened_max = Some(Box::new(elem)); - } else { - arenaized.flattened_min = Some(Box::new(elem)); - } - } - } - } -} - -impl RangeExpr { - /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. - pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { - RangeExpr { - maximized: None, - minimized: None, - flattened_max: None, - flattened_min: None, - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - } - } - - pub fn contains_node(&self, node_idx: NodeIdx) -> bool { - self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) - } -} - -impl RangeElem for RangeExpr { - type GraphError = GraphError; - - #[tracing::instrument(level = "trace", skip_all)] - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - // self.lhs.clone().arenaize(analyzer)?; - // self.rhs.clone().arenaize(analyzer)?; - if self.arena_idx(analyzer).is_none() { - let lhs = std::mem::take(&mut self.lhs); - let rhs = std::mem::take(&mut self.rhs); - self.lhs = Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*lhs))); - self.rhs = Box::new(Elem::Arena(analyzer.range_arena_idx_or_upsert(*rhs))); - let _ = analyzer.range_arena_idx_or_upsert(Elem::Expr(self.clone())); - } - Ok(()) - } - - fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { - false - } - - #[tracing::instrument(level = "trace", skip_all)] - fn flatten( - &self, - maximize: bool, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match (maximize, &self.flattened_min, &self.flattened_max) { - (true, _, Some(flat)) | (false, Some(flat), _) => { - return Ok(*flat.clone()); - } - _ => {} - } - - if let Some(arenaized) = self.arenaized_flat_cache(maximize, analyzer) { - return Ok(*arenaized); - } - - Ok(Elem::Expr(RangeExpr::new( - self.lhs.flatten(maximize, analyzer)?, - self.op, - self.rhs.flatten(maximize, analyzer)?, - ))) - } - - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { - self.flattened_min.is_some() && self.flattened_max.is_some() || { - if let Some(idx) = self.arena_idx(analyzer) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { - if let Elem::Expr(ref arenaized) = *t { - arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() - } else { - false - } - } else { - false - } - } else { - false - } - } - } - - fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { - let (arena_cached_min, arena_cached_max) = { - if let Some(idx) = self.arena_idx(analyzer) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { - if let Elem::Expr(ref arenaized) = *t { - (arenaized.minimized.is_some(), arenaized.maximized.is_some()) - } else { - (false, false) - } - } else { - (false, false) - } - } else { - (false, false) - } - }; - ( - self.minimized.is_some() || arena_cached_min, - self.maximized.is_some() || arena_cached_max, - ) - } - - fn range_ord( - &self, - _other: &Self, - _analyzer: &impl GraphBackend, - ) -> Option { - todo!() - } - - fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { - let mut deps = self.lhs.dependent_on(analyzer); - deps.extend(self.rhs.dependent_on(analyzer)); - deps - } - - #[tracing::instrument(level = "trace", skip_all)] - fn recursive_dependent_on( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - let mut deps = self.lhs.recursive_dependent_on(analyzer)?; - deps.extend(self.rhs.recursive_dependent_on(analyzer)?); - Ok(deps) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn has_cycle( - &self, - seen: &mut Vec, - analyzer: &impl GraphBackend, - ) -> Result { - let lhs_has_cycle = self.lhs.has_cycle(seen, analyzer)?; - let rhs_has_cycle = self.rhs.has_cycle(seen, analyzer)?; - Ok(lhs_has_cycle || rhs_has_cycle) - } - - fn depends_on( - &self, - var: ContextVarNode, - seen: &mut Vec, - analyzer: &impl GraphBackend, - ) -> Result { - let lhs_deps_on = self.lhs.depends_on(var, seen, analyzer)?; - let rhs_deps_on = self.rhs.depends_on(var, seen, analyzer)?; - Ok(lhs_deps_on || rhs_deps_on) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn filter_recursion( - &mut self, - node_idx: NodeIdx, - new_idx: NodeIdx, - analyzer: &mut impl GraphBackend, - ) { - let _ = self.arenaize(analyzer); - self.lhs.filter_recursion(node_idx, new_idx, analyzer); - self.rhs.filter_recursion(node_idx, new_idx, analyzer); - } - - #[tracing::instrument(level = "trace", skip_all)] - fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { - Ok(*cached) - } else if let Some(MinMaxed::Maximized(cached)) = self.arenaized_cache(true, analyzer) { - Ok(*cached) - } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(true, analyzer) - } else { - self.exec_op(true, analyzer) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { - if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { - Ok(*cached) - } else if let Some(MinMaxed::Minimized(cached)) = self.arenaized_cache(false, analyzer) { - Ok(*cached) - } else if self.op == RangeOp::SetIndices { - self.simplify_exec_op(false, analyzer) - } else { - self.exec_op(false, analyzer) - } - } - - #[tracing::instrument(level = "trace", skip_all)] - fn simplify_maximize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - if let Some(simp_max) = &self.flattened_max { - return Ok(*simp_max.clone()); - } - - if let Some(arenaized) = self.arenaized_flat_cache(true, analyzer) { - return Ok(*arenaized); - } - - let l = self.lhs.simplify_maximize(analyzer)?; - let r = self.rhs.simplify_maximize(analyzer)?; - let collapsed = collapse(&l, self.op, &r, analyzer); - let res = match collapsed { - MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(true, analyzer), - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(..) => { - // Ok(Elem::Expr(RangeExpr::new(l, self.op, r)))//.simplify_exec_op(false, &mut vec![], analyzer) - let res = RangeExpr::new(l, self.op, r).simplify_exec_op(true, analyzer)?; - match res { - Elem::Expr(expr) => { - match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => return expr.exec_op(true, analyzer), - MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), - _ => {} - } - Ok(Elem::Expr(expr)) - } - other => Ok(other), - } - } - }?; - self.set_arenaized_flattened(true, res.clone(), analyzer); - Ok(res) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn simplify_minimize( - &self, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - if let Some(simp_min) = &self.flattened_min { - return Ok(*simp_min.clone()); - } - - if let Some(arenaized) = self.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized); - } - - let l = self.lhs.simplify_minimize(analyzer)?; - self.lhs.set_arenaized_flattened(false, &l, analyzer); - let r = self.rhs.simplify_minimize(analyzer)?; - self.rhs.set_arenaized_flattened(false, &r, analyzer); - - let collapsed = collapse(&l, self.op, &r, analyzer); - let res = match collapsed { - MaybeCollapsed::Concretes(..) => RangeExpr::new(l, self.op, r).exec_op(false, analyzer), - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(..) => { - let res = RangeExpr::new(l, self.op, r).simplify_exec_op(false, analyzer)?; - match res { - Elem::Expr(expr) => { - match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => return expr.exec_op(false, analyzer), - MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), - _ => {} - } - Ok(Elem::Expr(expr)) - } - other => Ok(other), - } - } - }?; - - self.set_arenaized_flattened(false, res.clone(), analyzer); - Ok(res) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - self.arenaize(g)?; - - fn simplify_minimize( - mut this: Elem, - analyzer: &mut impl GraphBackend, - ) -> Result, GraphError> { - let Elem::Expr(this) = this else { - this.cache_flatten(analyzer)?; - if let Some(t) = this.arenaized_flattened(false, analyzer) { - return Ok(*t); - } else { - return Ok(this.clone()); - } - }; - - if let Some(simp_min) = &this.flattened_min { - return Ok(*simp_min.clone()); - } - - if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized); - } - - let l = this.lhs.simplify_minimize(analyzer)?; - let r = this.rhs.simplify_minimize(analyzer)?; - let collapsed = collapse(&l, this.op, &r, analyzer); - let res = match collapsed { - MaybeCollapsed::Concretes(..) => { - RangeExpr::new(l, this.op, r).exec_op(false, analyzer) - } - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(..) => { - let res = RangeExpr::new(l, this.op, r).simplify_exec_op(false, analyzer)?; - - let idx = analyzer.range_arena_idx_or_upsert(res.clone()); - match res { - Elem::Expr(expr) => { - match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => { - let exec_res = expr.exec_op(false, analyzer)?; - Elem::Arena(idx) - .set_arenaized_flattened(false, &exec_res, analyzer); - return Ok(exec_res); - } - MaybeCollapsed::Collapsed(collapsed) => { - Elem::Arena(idx) - .set_arenaized_flattened(false, &collapsed, analyzer); - return Ok(collapsed); - } - _ => {} - } - Ok(Elem::Expr(expr)) - } - other => Ok(other), - } - } - }?; - - this.set_arenaized_flattened(false, res.clone(), analyzer); - Ok(res) - } - - fn simplify_maximize( - mut this: Elem, - analyzer: &mut impl GraphBackend, - ) -> Result, GraphError> { - let Elem::Expr(this) = this else { - this.cache_flatten(analyzer)?; - if let Some(t) = this.arenaized_flattened(true, analyzer) { - return Ok(*t); - } else { - return Ok(this.clone()); - } - }; - - if let Some(simp_min) = &this.flattened_max { - return Ok(*simp_min.clone()); - } - - if let Some(arenaized) = this.arenaized_flat_cache(false, analyzer) { - return Ok(*arenaized); - } - - let l = this.lhs.simplify_maximize(analyzer)?; - let r = this.rhs.simplify_maximize(analyzer)?; - let collapsed = collapse(&l, this.op, &r, analyzer); - let res = match collapsed { - MaybeCollapsed::Concretes(..) => { - RangeExpr::new(l, this.op, r).exec_op(true, analyzer) - } - MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), - MaybeCollapsed::Not(..) => { - let res = RangeExpr::new(l, this.op, r).simplify_exec_op(true, analyzer)?; - - let idx = analyzer.range_arena_idx_or_upsert(res.clone()); - match res { - Elem::Expr(expr) => { - match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { - MaybeCollapsed::Concretes(..) => { - let exec_res = expr.exec_op(true, analyzer)?; - Elem::Arena(idx) - .set_arenaized_flattened(true, &exec_res, analyzer); - return Ok(exec_res); - } - MaybeCollapsed::Collapsed(collapsed) => { - Elem::Arena(idx) - .set_arenaized_flattened(true, &collapsed, analyzer); - return Ok(collapsed); - } - _ => {} - } - Ok(Elem::Expr(expr)) - } - other => Ok(other), - } - } - }?; - - this.set_arenaized_flattened(false, res.clone(), analyzer); - Ok(res) - } - - if self.flattened_max.is_none() { - if let Some(idx) = self.arena_idx(g) { - if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { - if arenaized.flattened_max.is_some() { - return Ok(()); - } - }; - } else { - self.arenaize(g)?; - } - - self.lhs.cache_flatten(g)?; - self.rhs.cache_flatten(g)?; - // self.arenaize(g)?; - let flat_max = self.flatten(true, g)?; - let simplified_flat_max = simplify_maximize(flat_max, g)?; - simplified_flat_max.clone().arenaize(g)?; - self.flattened_max = Some(Box::new(simplified_flat_max)); - } - - if self.flattened_min.is_none() { - if let Some(idx) = self.arena_idx(g) { - if let Elem::Expr(ref arenaized) = *g.range_arena().ranges[idx].borrow() { - if arenaized.flattened_min.is_some() { - return Ok(()); - } - }; - } else { - self.arenaize(g)?; - } - - self.lhs.cache_flatten(g)?; - self.rhs.cache_flatten(g)?; - // self.arenaize(g)?; - let flat_min = self.flatten(false, g)?; - let simplified_flat_min = simplify_minimize(flat_min, g)?; - simplified_flat_min.clone().arenaize(g)?; - self.flattened_min = Some(Box::new(simplified_flat_min)); - } - Ok(()) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - tracing::trace!("cache maximizing: {}", Elem::Expr(self.clone())); - self.arenaize(g)?; - if self.maximized.is_none() { - self.lhs.cache_maximize(g)?; - self.rhs.cache_maximize(g)?; - self.cache_exec_op(true, g)?; - } - Ok(()) - } - - #[tracing::instrument(level = "trace", skip_all)] - fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - tracing::trace!("cache minimizing: {}", Elem::Expr(self.clone())); - self.arenaize(g)?; - if self.minimized.is_none() { - self.lhs.cache_minimize(g)?; - self.rhs.cache_minimize(g)?; - self.cache_exec_op(false, g)?; - } - Ok(()) - } - - fn uncache(&mut self) { - self.uncache_exec(); - } -} - -pub enum MaybeCollapsed<'a, 'b> { - Concretes(&'a Elem, &'b Elem), - Collapsed(Elem), - Not(&'a Elem, &'b Elem), -} - -pub fn collapse<'a, 'b, 'c: 'a + 'b>( - l: &'a Elem, - op: RangeOp, - r: &'b Elem, - analyzer: &'c impl GraphBackend, -) -> MaybeCollapsed<'a, 'b> { - let zero = Elem::from(Concrete::from(U256::zero())); - let one = Elem::from(Concrete::from(U256::one())); - match (l, r) { - (Elem::Arena(_), r) => { - if let Ok(t) = l.dearenaize(analyzer).try_borrow() { - match collapse(&t, op, r, analyzer) { - MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), - MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (l, Elem::Arena(_)) => { - if let Ok(t) = r.dearenaize(analyzer).try_borrow() { - match collapse(l, op, &t, analyzer) { - MaybeCollapsed::Not(..) => MaybeCollapsed::Not(l, r), - MaybeCollapsed::Concretes(..) => MaybeCollapsed::Concretes(l, r), - MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (Elem::Concrete(_), Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), - (Elem::Expr(expr), d @ Elem::Reference(_)) => { - // try to collapse the expression - let x = &*expr.lhs; - let y = &*expr.rhs; - let z = d; - - let x_ord_z = x.range_ord(z, analyzer); - let x_eq_z = matches!(x_ord_z, Some(std::cmp::Ordering::Equal)); - - let y_ord_z = y.range_ord(z, analyzer); - let y_eq_z = matches!(y_ord_z, Some(std::cmp::Ordering::Equal)); - - let y_eq_zero = matches!( - y.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) | None - ); - let x_eq_zero = matches!( - x.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) | None - ); - let y_eq_one = matches!( - y.range_ord(&one, analyzer), - Some(std::cmp::Ordering::Equal) | None - ); - let x_eq_one = matches!( - x.range_ord(&one, analyzer), - Some(std::cmp::Ordering::Equal) | None - ); - match (expr.op, op) { - (RangeOp::Sub(_), RangeOp::Eq) | (RangeOp::Div(_), RangeOp::Eq) => { - if x_eq_z && !y_eq_zero { - // (x -|/ k) == x ==> false - MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(_), RangeOp::Eq) => { - if (x_eq_z && !y_eq_zero) || (y_eq_z && !x_eq_zero) { - // (x +|* k) == x ==> false - MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Mul(_), RangeOp::Eq) => { - if (x_eq_z && !y_eq_one) || (y_eq_z && !x_eq_one) { - // (x +|* k) == x ==> false - MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) - } else { - MaybeCollapsed::Not(l, r) - } - } - _ => MaybeCollapsed::Not(l, r), - } - } - // if we have an expression, it fundamentally must have a dynamic in it - (Elem::Expr(expr), c @ Elem::Concrete(_)) => { - // potentially collapsible - let x = &*expr.lhs; - let y = &*expr.rhs; - let z = c; - - match (expr.op, op) { - (RangeOp::Sub(false), RangeOp::Min) => { - // min{x - y, z} - // if x <= z, then x - y will be the minimum if y >= 0 - if matches!( - x.range_ord(z, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Less) - ) && matches!( - y.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) - ) { - MaybeCollapsed::Collapsed(l.clone()) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(false), RangeOp::Max) => { - // max{x + y, z} - // if x >= z, then x + y will be the maximum if y >= 0 - // or if y >= z, then x + y will be the maximum if x >= 0 - if (matches!( - x.range_ord(z, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) - ) && matches!( - y.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) - )) || (matches!( - y.range_ord(z, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) - ) && matches!( - x.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) - )) { - MaybeCollapsed::Collapsed(l.clone()) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Eq, RangeOp::Eq) => { - // ((x == y) == z) - // can skip if x and z eq - if let Some(std::cmp::Ordering::Equal) = x.range_ord(z, analyzer) { - MaybeCollapsed::Collapsed(l.clone()) - } else if let Some(std::cmp::Ordering::Equal) = y.range_ord(z, analyzer) { - MaybeCollapsed::Collapsed(l.clone()) - } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { - MaybeCollapsed::Collapsed(l.clone()) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(l_op), RangeOp::Add(r_op)) => { - // ((x + y) + z) - let op_fn = if l_op && r_op { - // unchecked - RangeAdd::range_wrapping_add - } else { - // checked - as RangeAdd>::range_add - }; - if let Some(new) = op_fn(x, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) - } else if let Some(new) = op_fn(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { - // ((x + y) - z) => k - y || x + k - if l_op == r_op { - match y.range_ord(z, analyzer) { - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { - // y and z are concrete && y >= z ==> x + (y - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(y, z) { - let new_expr = - Elem::Expr(RangeExpr::new(x.clone(), expr.op, new)); - MaybeCollapsed::Collapsed(new_expr) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // y and z are concrete && y < z ==> x - (z - y) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(z, y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - RangeOp::Sub(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => { - // x and z are concrete, if x >= z, just do (x - z) + y - // else do (y - (z - x)) - match x.range_ord(z, analyzer) { - Some(std::cmp::Ordering::Equal) - | Some(std::cmp::Ordering::Greater) => { - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - expr.op, - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // (y - (z - x)) because z > x, therefore its (-k + y) ==> (y - k) where k = (x - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(z, x) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - y.clone(), - RangeOp::Sub(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => MaybeCollapsed::Not(l, r), - } - } - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { - // ((x - y) + z) => k - y || x + k - if l_op == r_op { - match y.range_ord(z, analyzer) { - Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { - // y and z are concrete && z <= y ==> x - (y - z) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - expr.op, - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - Some(std::cmp::Ordering::Less) => { - // y and z are concrete && y < z ==> x + (z - y) - let op_fn = if l_op { - // unchecked - RangeSub::range_wrapping_sub - } else { - // checked - as RangeSub>::range_sub - }; - if let Some(new) = op_fn(z, y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - RangeOp::Add(l_op), - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - None => { - // x and z are concrete, just add them ==> (x + z) - y - let op_fn = if l_op { - // unchecked - RangeAdd::range_wrapping_add - } else { - // checked - as RangeAdd>::range_add - }; - if let Some(new) = op_fn(x, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - new, - expr.op, - y.clone(), - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Mul(l_op), RangeOp::Mul(r_op)) => { - // ((x * y) * z) - if l_op == r_op { - let op_fn = if l_op { - // unchecked - RangeMul::range_wrapping_mul - } else { - // checked - as RangeMul>::range_mul - }; - if let Some(new) = op_fn(x, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - y.clone(), - op, - new, - ))) - } else if let Some(new) = op_fn(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - op, - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Add(wrapping), op) if EQ_OPS.contains(&op) => { - let const_op = if wrapping { - RangeSub::range_wrapping_sub - } else { - RangeSub::range_sub - }; - // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) - // .. - // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) - if let Some(new) = const_op(z, y) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) - } else if let Some(new) = const_op(z, x) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Sub(wrapping), op) if EQ_OPS.contains(&op) => { - let op_y = if wrapping { - as RangeAdd>::range_wrapping_add - } else { - as RangeAdd>::range_add - }; - let op_x = if wrapping { - as RangeSub>::range_wrapping_sub - } else { - as RangeSub>::range_sub - }; - // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) - // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) - if let Some(new) = op_x(x, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) - } else if let Some(new) = op_y(y, z) { - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Mul(wrapping), op) if EQ_OPS.contains(&op) => { - let div_op = if wrapping { - RangeDiv::range_wrapping_div - } else { - RangeDiv::range_div - }; - // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) - // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) - if let Some(new) = div_op(z, x) { - let new_op = if matches!( - x.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) - ) && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - y.clone(), - new_op, - new, - ))) - } else if let Some(new) = div_op(z, y) { - let new_op = if matches!( - y.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) - ) && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - new_op, - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } - (RangeOp::Div(wrapping), op) if EQ_OPS.contains(&op) => { - let mul_op = if wrapping { - as RangeMul>::range_wrapping_mul - } else { - as RangeMul>::range_mul - }; - let div_op = if wrapping { - as RangeDiv>::range_wrapping_div - } else { - as RangeDiv>::range_div - }; - - // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) - // .. - // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) - if let Some(new) = mul_op(z, y) { - let new_op = if matches!( - y.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) - ) && FLIP_INEQ_OPS.contains(&op) - { - op.inverse().unwrap() - } else { - op - }; - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - x.clone(), - new_op, - new, - ))) - } else if !FLIP_INEQ_OPS.contains(&op) { - if let Some(new) = div_op(x, z) { - // y is the dynamic element - // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially - // but we dont know if y was negative. so we limit to just eq & neq - MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( - y.clone(), - op, - new, - ))) - } else { - MaybeCollapsed::Not(l, r) - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (_, RangeOp::Eq) => { - // (x _ y) == z ==> (x _ y if z == true) - if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { - MaybeCollapsed::Collapsed(l.clone()) - } else if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { - // (!x && !y) - match ( - x.inverse_if_boolean(), - y.inverse_if_boolean(), - expr.op.logical_inverse(), - ) { - (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( - Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), - ), - _ => MaybeCollapsed::Not(l, r), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - (_, RangeOp::Neq) => { - // (x _ y) != z ==> (x _ y if z != false) - if z.range_eq(&Elem::from(Concrete::from(false)), analyzer) { - // != false is == true - MaybeCollapsed::Collapsed(l.clone()) - } else if z.range_eq(&Elem::from(Concrete::from(true)), analyzer) { - // != true is == false, to make it == true, inverse everything - match ( - x.inverse_if_boolean(), - y.inverse_if_boolean(), - expr.op.logical_inverse(), - ) { - (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( - Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), - ), - _ => MaybeCollapsed::Not(l, r), - } - } else { - MaybeCollapsed::Not(l, r) - } - } - _ => MaybeCollapsed::Not(l, r), - } - } - (Elem::Concrete(_c), Elem::Expr(_expr)) => match collapse(r, op, l, analyzer) { - MaybeCollapsed::Collapsed(inner) => MaybeCollapsed::Collapsed(inner.clone()), - MaybeCollapsed::Not(_, _) => MaybeCollapsed::Not(l, r), - MaybeCollapsed::Concretes(_, _) => unreachable!(), - }, - (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => match op { - RangeOp::Sub(_) | RangeOp::Add(_) => { - if matches!( - c.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Equal) - ) { - MaybeCollapsed::Collapsed(le.clone()) - } else { - MaybeCollapsed::Not(l, r) - } - } - RangeOp::Mul(_) | RangeOp::Div(_) => { - if matches!(c.range_ord(&one, analyzer), Some(std::cmp::Ordering::Equal)) { - MaybeCollapsed::Collapsed(le.clone()) - } else { - MaybeCollapsed::Not(l, r) - } - } - _ => MaybeCollapsed::Not(l, r), - }, - _ => MaybeCollapsed::Not(l, r), - } -} diff --git a/crates/graph/src/range/elem/expr/collapse.rs b/crates/graph/src/range/elem/expr/collapse.rs new file mode 100644 index 00000000..d043005b --- /dev/null +++ b/crates/graph/src/range/elem/expr/collapse.rs @@ -0,0 +1,633 @@ +use crate::elem::expr::simplify::*; + +use crate::{ + nodes::Concrete, + range::{ + elem::{Elem, RangeConcrete, RangeElem, RangeExpr, RangeOp}, + exec_traits::*, + }, +}; + +use ethers_core::types::U256; +use shared::RangeArena; + +pub static ORD_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::Min, + RangeOp::Max, +]; + +pub static EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, + RangeOp::And, + RangeOp::Or, +]; + +pub static SINGLETON_EQ_OPS: &[RangeOp] = &[ + RangeOp::Eq, + RangeOp::Neq, + RangeOp::Lt, + RangeOp::Lte, + RangeOp::Gt, + RangeOp::Gte, +]; + +pub static FLIP_INEQ_OPS: &[RangeOp] = &[RangeOp::Lt, RangeOp::Lte, RangeOp::Gt, RangeOp::Gte]; + +#[derive(Debug)] +pub enum MaybeCollapsed { + Concretes(Elem, Elem), + Collapsed(Elem), + Not(Elem, Elem), +} + +pub fn collapse( + l: Elem, + op: RangeOp, + r: Elem, + arena: &mut RangeArena>, +) -> MaybeCollapsed { + let l = if let Elem::Expr(e) = l { + match collapse(*e.lhs, e.op, *e.rhs, arena) { + MaybeCollapsed::Not(l, r) => Elem::Expr(RangeExpr::new(l, e.op, r)), + MaybeCollapsed::Concretes(l, r) => Elem::Expr(RangeExpr::new(l, e.op, r)), + MaybeCollapsed::Collapsed(e) => e, + } + } else { + l + }; + + let r = if let Elem::Expr(e) = r { + match collapse(*e.lhs, e.op, *e.rhs, arena) { + MaybeCollapsed::Not(l, r) => Elem::Expr(RangeExpr::new(l, e.op, r)), + MaybeCollapsed::Concretes(l, r) => Elem::Expr(RangeExpr::new(l, e.op, r)), + MaybeCollapsed::Collapsed(e) => e, + } + } else { + r + }; + + if let Some(e) = ident_rules(&l, op, &r, arena) { + return MaybeCollapsed::Collapsed(e); + } + + let res = match (l, r) { + (l @ Elem::Arena(_), r) => { + let t = l.dearenaize_clone(arena); + match collapse(t, op, r, arena) { + MaybeCollapsed::Not(l, r) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(l, r) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), + } + } + (l, r @ Elem::Arena(_)) => { + let t = r.dearenaize_clone(arena); + match collapse(l, op, t, arena) { + MaybeCollapsed::Not(l, r) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(l, r) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Collapsed(e) => MaybeCollapsed::Collapsed(e), + } + } + (l @ Elem::Concrete(_), r @ Elem::Concrete(_)) => MaybeCollapsed::Concretes(l, r), + (Elem::Expr(expr), d @ Elem::Reference(_)) => { + // try to collapse the expression + let x = &*expr.lhs; + let y = &*expr.rhs; + let z = d; + + let ords = Ords::new(x, y, &z, arena); + + match (expr.op, op) { + (RangeOp::Sub(false), _) if ORD_OPS.contains(&op) => { + if let Some(res) = sub_ord_rules(x, y, op, &z, ords, arena) { + MaybeCollapsed::Collapsed(res) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Div(_), RangeOp::Eq) => { + if ords.x_eq_z() && !ords.y_eq_one() { + // (x -|/ y) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Add(_), RangeOp::Eq) => { + if (ords.x_eq_z() && !ords.y_eq_zero()) || (ords.y_eq_z() && !ords.x_eq_zero()) + { + // (x +|* k) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Mul(_), RangeOp::Eq) => { + if (ords.x_eq_z() && !ords.y_eq_one()) || (ords.y_eq_z() && !ords.x_eq_one()) { + // (x +|* k) == x ==> false + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(false))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Max, RangeOp::Gte) => { + if ords.x_eq_z() || ords.y_eq_z() { + // max{ x, y } >= + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(true))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Min, RangeOp::Lte) => { + if ords.x_eq_z() || ords.y_eq_z() { + // min{ x, y } <= + MaybeCollapsed::Collapsed(Elem::from(Concrete::from(true))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + _ => MaybeCollapsed::Not(Elem::Expr(expr), z), + } + } + // if we have an expression, it fundamentally must have a dynamic in it + (Elem::Expr(expr), c @ Elem::Concrete(_)) => { + // potentially collapsible + let x = &*expr.lhs; + let y = &*expr.rhs; + let z = c; + + let ords = Ords::new(x, y, &z, arena); + + match (expr.op, op) { + (RangeOp::Sub(false), _) if ORD_OPS.contains(&op) => { + if let Some(res) = sub_ord_rules(x, y, op, &z, ords, arena) { + MaybeCollapsed::Collapsed(res) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Add(false), _) if ORD_OPS.contains(&op) => { + if let Some(res) = add_ord_rules(x, y, op, &z, ords, arena) { + MaybeCollapsed::Collapsed(res) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Eq, RangeOp::Eq) => { + // ((x == y) == z) + // can skip if x and z eq + if ords.x_eq_z() || ords.y_eq_z() { + MaybeCollapsed::Collapsed(Elem::Expr(expr)) + } else if z.range_eq(&Elem::from(Concrete::from(true)), arena) { + MaybeCollapsed::Collapsed(Elem::Expr(expr)) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Add(l_op), RangeOp::Add(r_op)) => { + // ((x + y) + z) + let op_fn = if l_op && r_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = op_fn(y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Add(l_op), RangeOp::Sub(r_op)) => { + // ((x + y) - z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z, arena) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && y >= z ==> x + (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(y, &z) { + let new_expr = + Elem::Expr(RangeExpr::new(x.clone(), expr.op, new)); + MaybeCollapsed::Collapsed(new_expr) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x - (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + None => { + // x and z are concrete, if x >= z, just do (x - z) + y + // else do (y - (z - x)) + match x.range_ord(&z, arena) { + Some(std::cmp::Ordering::Equal) + | Some(std::cmp::Ordering::Greater) => { + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + expr.op, + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + Some(std::cmp::Ordering::Less) => { + // (y - (z - x)) because z > x, therefore its (-k + y) ==> (y - k) where k = (x - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + RangeOp::Sub(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + None => MaybeCollapsed::Not(Elem::Expr(expr), z), + } + } + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Sub(l_op), RangeOp::Add(r_op)) => { + // ((x - y) + z) => k - y || x + k + if l_op == r_op { + match y.range_ord(&z, arena) { + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) => { + // y and z are concrete && z <= y ==> x - (y - z) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + expr.op, + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + Some(std::cmp::Ordering::Less) => { + // y and z are concrete && y < z ==> x + (z - y) + let op_fn = if l_op { + // unchecked + RangeSub::range_wrapping_sub + } else { + // checked + as RangeSub>::range_sub + }; + if let Some(new) = op_fn(&z, y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Add(l_op), + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + None => { + // x and z are concrete, just add them ==> (x + z) - y + let op_fn = if l_op { + // unchecked + RangeAdd::range_wrapping_add + } else { + // checked + as RangeAdd>::range_add + }; + if let Some(new) = op_fn(x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + new, + expr.op, + y.clone(), + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Mul(l_op), RangeOp::Mul(r_op)) => { + // ((x * y) * z) + if l_op == r_op { + let op_fn = if l_op { + // unchecked + RangeMul::range_wrapping_mul + } else { + // checked + as RangeMul>::range_mul + }; + if let Some(new) = op_fn(x, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + op, + new, + ))) + } else if let Some(new) = op_fn(y, &z) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + op, + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Add(wrapping), op) if EQ_OPS.contains(&op) => { + let const_op = if wrapping { + RangeSub::range_wrapping_sub + } else { + RangeSub::range_sub + }; + // ((x + y) == z) => (x == (z - y)) || (y == (z - x)) + // .. + // ((x + y) != z) => (x != (z - y)) || (y != (z - x)) + if let Some(new) = const_op(&z, y) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(y.clone(), op, new))) + } else if let Some(new) = const_op(&z, x) { + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new(x.clone(), op, new))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Sub(wrapping), op) if EQ_OPS.contains(&op) => { + let op_y = if wrapping { + as RangeAdd>::range_wrapping_add + } else { + as RangeAdd>::range_add + }; + let op_x = if wrapping { + as RangeSub>::range_wrapping_sub + } else { + as RangeSub>::range_sub + }; + // ((x - y) == z) => (x == (z + y)) || (y == (x - z)) + // ((x - y) != z) => (x != (z + y)) || (y != (x - z)) + if let Some(new) = op_y(y, &z) { + let new_expr = RangeExpr::new(x.clone(), op, new); + MaybeCollapsed::Collapsed(Elem::Expr(new_expr)) + } else if let Some(new) = op_x(x, &z) { + let new_expr = RangeExpr::new(y.clone(), op, new); + MaybeCollapsed::Collapsed(Elem::Expr(new_expr)) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Mul(wrapping), op) if EQ_OPS.contains(&op) => { + let div_op = if wrapping { + RangeDiv::range_wrapping_div + } else { + RangeDiv::range_div + }; + // ((x * y) == z) => (x == (z / y)) || (y == (z / x)) + // ((x * y) != z) => (x != (z / y)) || (y != (z / x)) + if let Some(new) = div_op(&z, x) { + let new_op = if ords.x_lt_zero() && FLIP_INEQ_OPS.contains(&op) { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + new_op, + new, + ))) + } else if let Some(new) = div_op(&z, y) { + let new_op = if ords.y_lt_zero() && FLIP_INEQ_OPS.contains(&op) { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + new_op, + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (RangeOp::Div(wrapping), op) if EQ_OPS.contains(&op) => { + let mul_op = if wrapping { + as RangeMul>::range_wrapping_mul + } else { + as RangeMul>::range_mul + }; + let div_op = if wrapping { + as RangeDiv>::range_wrapping_div + } else { + as RangeDiv>::range_div + }; + + // ((x / y) == z) => (x == (z * y)) || (y == (x / z)) + // .. + // ((x / y) != z) => (x != (z / y)) || (y != (x / z)) + if let Some(new) = mul_op(&z, y) { + let new_op = if ords.y_lt_zero() && FLIP_INEQ_OPS.contains(&op) { + op.inverse().unwrap() + } else { + op + }; + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + x.clone(), + new_op, + new, + ))) + } else if !FLIP_INEQ_OPS.contains(&op) { + if let Some(new) = div_op(x, &z) { + // y is the dynamic element + // we cant do flip ops here because we do (x / y) * y >= z * y which is a flip potentially + // but we dont know if y was negative. so we limit to just eq & neq + MaybeCollapsed::Collapsed(Elem::Expr(RangeExpr::new( + y.clone(), + op, + new, + ))) + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (_, RangeOp::Eq) => { + // (x _ y) == z ==> (x _ y if z == true) + if z.range_eq(&Elem::from(Concrete::from(true)), arena) { + MaybeCollapsed::Collapsed(Elem::Expr(expr)) + } else if z.range_eq(&Elem::from(Concrete::from(false)), arena) { + // (!x && !y) + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(Elem::Expr(expr), z), + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + (_, RangeOp::Neq) => { + // (x _ y) != z ==> (x _ y if z != false) + if z.range_eq(&Elem::from(Concrete::from(false)), arena) { + // != false is == true + MaybeCollapsed::Collapsed(Elem::Expr(expr)) + } else if z.range_eq(&Elem::from(Concrete::from(true)), arena) { + // != true is == false, to make it == true, inverse everything + match ( + x.inverse_if_boolean(), + y.inverse_if_boolean(), + expr.op.logical_inverse(), + ) { + (Some(new_x), Some(new_y), Some(new_op)) => MaybeCollapsed::Collapsed( + Elem::Expr(RangeExpr::new(new_x, new_op, new_y)), + ), + _ => MaybeCollapsed::Not(Elem::Expr(expr), z), + } + } else { + MaybeCollapsed::Not(Elem::Expr(expr), z) + } + } + _ => MaybeCollapsed::Not(Elem::Expr(expr), z), + } + } + (l @ Elem::Concrete(_), r @ Elem::Expr(_)) => { + if op.commutative() { + match collapse(r, op, l, arena) { + MaybeCollapsed::Collapsed(inner) => MaybeCollapsed::Collapsed(inner.clone()), + MaybeCollapsed::Not(r, l) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(r, l) => MaybeCollapsed::Concretes(l, r), + } + } else if let Some(inv) = op.non_commutative_logical_inverse() { + match collapse(r, inv, l, arena) { + MaybeCollapsed::Collapsed(inner) => MaybeCollapsed::Collapsed(inner.clone()), + MaybeCollapsed::Not(r, l) => MaybeCollapsed::Not(l, r), + MaybeCollapsed::Concretes(r, l) => MaybeCollapsed::Concretes(l, r), + } + } else { + MaybeCollapsed::Not(l, r) + } + } + (le @ Elem::Reference(_), c @ Elem::Concrete(_)) => { + let zero = Elem::from(Concrete::from(U256::zero())); + let one = Elem::from(Concrete::from(U256::one())); + match op { + RangeOp::Sub(_) | RangeOp::Add(_) => { + if matches!(c.range_ord(&zero, arena), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le.clone()) + } else { + MaybeCollapsed::Not(le, c) + } + } + RangeOp::Mul(_) | RangeOp::Div(_) => { + if matches!(c.range_ord(&one, arena), Some(std::cmp::Ordering::Equal)) { + MaybeCollapsed::Collapsed(le.clone()) + } else { + MaybeCollapsed::Not(le, c) + } + } + _ => MaybeCollapsed::Not(le, c), + } + } + (Elem::Null, real) => match op { + RangeOp::Max | RangeOp::Min => MaybeCollapsed::Collapsed(real.clone()), + RangeOp::Not => match real { + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(c), + loc, + }) => MaybeCollapsed::Collapsed(Elem::Concrete(RangeConcrete::new( + Concrete::from(!c), + loc, + ))), + _ => MaybeCollapsed::Not(Elem::Null, real), + }, + _ => MaybeCollapsed::Not(Elem::Null, real), + }, + (real, Elem::Null) => match op { + RangeOp::Max | RangeOp::Min => MaybeCollapsed::Collapsed(real.clone()), + RangeOp::Not => match real { + Elem::Concrete(RangeConcrete { + val: Concrete::Bool(c), + loc, + }) => MaybeCollapsed::Collapsed(Elem::Concrete(RangeConcrete::new( + Concrete::from(!c), + loc, + ))), + _ => MaybeCollapsed::Not(real, Elem::Null), + }, + _ => MaybeCollapsed::Not(real, Elem::Null), + }, + (l, r) => return MaybeCollapsed::Not(l, r), + }; + + match res { + MaybeCollapsed::Collapsed(Elem::Expr(e)) => collapse(*e.lhs, e.op, *e.rhs, arena), + other => other, + } +} diff --git a/crates/graph/src/range/elem/expr/mod.rs b/crates/graph/src/range/elem/expr/mod.rs new file mode 100644 index 00000000..f69aaeb3 --- /dev/null +++ b/crates/graph/src/range/elem/expr/mod.rs @@ -0,0 +1,728 @@ +mod collapse; +pub use collapse::*; + +mod simplify; + +use crate::{ + nodes::{Concrete, ContextVarNode}, + range::{ + elem::{Elem, MinMaxed, RangeArenaLike, RangeConcrete, RangeElem, RangeOp}, + exec_traits::*, + }, + GraphBackend, GraphError, +}; +use std::hash::Hash; +use std::hash::Hasher; + +use ethers_core::types::U256; +use shared::{NodeIdx, RangeArena}; + +/// A range expression composed of other range [`Elem`] +#[derive(Clone, Debug, Ord, PartialOrd)] +pub struct RangeExpr { + pub maximized: Option>, + pub minimized: Option>, + pub flattened_min: Option>>, + pub flattened_max: Option>>, + pub lhs: Box>, + pub op: RangeOp, + pub rhs: Box>, +} + +impl std::fmt::Display for RangeExpr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.op { + RangeOp::Min | RangeOp::Max => { + write!(f, "{}{{{}, {}}}", self.op.to_string(), self.lhs, self.rhs) + } + RangeOp::Cast => match &*self.rhs { + Elem::Concrete(RangeConcrete { val, .. }) => { + write!( + f, + "{}({}, {})", + self.op.to_string(), + self.lhs, + val.as_builtin().basic_as_string() + ) + } + _ => write!(f, "{}({}, {})", self.op.to_string(), self.lhs, self.rhs), + }, + RangeOp::BitNot => { + write!(f, "~{}", self.lhs) + } + _ => write!(f, "({} {} {})", self.lhs, self.op.to_string(), self.rhs), + } + } +} + +impl PartialEq for RangeExpr { + fn eq(&self, other: &Self) -> bool { + self.op == other.op && self.lhs == other.lhs && self.rhs == other.rhs + } +} +impl Eq for RangeExpr {} + +impl Hash for RangeExpr { + fn hash(&self, state: &mut H) { + (*self.lhs).hash(state); + self.op.hash(state); + (*self.rhs).hash(state); + } +} + +impl RangeExpr { + pub fn is_noop(&self) -> (bool, usize) { + let one = Elem::from(Concrete::from(U256::one())); + let zero = Elem::from(Concrete::from(U256::zero())); + match self.op { + RangeOp::Mul(_) | RangeOp::Div(_) => { + if *self.lhs == one { + (true, 0) + } else if *self.rhs == one { + (true, 1) + } else { + (false, 0) + } + } + RangeOp::Add(_) | RangeOp::Sub(_) => { + if *self.lhs == zero { + (true, 0) + } else if *self.rhs == zero { + (true, 1) + } else { + (false, 0) + } + } + _ => (false, 0), + } + } + + pub fn inverse_if_boolean(&self) -> Option { + if EQ_OPS.contains(&self.op) { + if SINGLETON_EQ_OPS.contains(&self.op) { + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.logical_inverse()?; + Some(new_self) + } else { + // non-singleton, i.e. AND or OR + let mut new_self = self.clone(); + new_self.uncache(); + new_self.op = new_self.op.inverse()?; + if let Some(new_lhs) = new_self.inverse_if_boolean() { + *new_self.lhs = Elem::Expr(new_lhs); + } + if let Some(new_rhs) = new_self.inverse_if_boolean() { + *new_self.rhs = Elem::Expr(new_rhs); + } + Some(new_self) + } + } else { + None + } + } + + pub fn recurse_dearenaize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Elem { + Elem::Expr(Self::new( + self.lhs.recurse_dearenaize(analyzer, arena).clone(), + self.op, + self.rhs.recurse_dearenaize(analyzer, arena).clone(), + )) + } + + pub fn arena_idx(&self, arena: &RangeArena>) -> Option { + let expr = Elem::Expr(RangeExpr::new( + Elem::Arena(arena.idx(&self.lhs)?), + self.op, + Elem::Arena(arena.idx(&self.rhs)?), + )); + arena.idx(&expr) + } + + pub fn arenaized_cache( + &self, + max: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option> { + if let Some(idx) = self.arena_idx(arena) { + let Some(ref mut t) = arena.ranges.get_mut(idx) else { + return None; + }; + let Elem::Expr(ref mut arenaized) = *t else { + return None; + }; + return if max { + arenaized.maximized.clone() + } else { + arenaized.minimized.clone() + }; + } + None + } + + pub fn arenaized_flat_cache( + &self, + max: bool, + arena: &mut RangeArena>, + ) -> Option>> { + if let Some(idx) = self.arena_idx(arena) { + let Some(ref mut t) = arena.ranges.get_mut(idx) else { + return None; + }; + let Elem::Expr(ref mut arenaized) = *t else { + return None; + }; + return if max { + arenaized.flattened_max.clone() + } else { + arenaized.flattened_min.clone() + }; + } + None + } + + pub fn set_arenaized_flattened( + &self, + max: bool, + elem: Elem, + arena: &mut RangeArena>, + ) { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get_mut(idx) { + let Elem::Expr(arenaized) = &mut *t else { + return; + }; + + if max { + arenaized.flattened_max = Some(Box::new(elem)); + } else { + arenaized.flattened_min = Some(Box::new(elem)); + } + } + } + } +} + +impl RangeExpr { + /// Creates a new range expression given a left hand side range [`Elem`], a [`RangeOp`], and a a right hand side range [`Elem`]. + pub fn new(lhs: Elem, op: RangeOp, rhs: Elem) -> RangeExpr { + RangeExpr { + maximized: None, + minimized: None, + flattened_max: None, + flattened_min: None, + lhs: Box::new(lhs), + op, + rhs: Box::new(rhs), + } + } + + pub fn contains_node(&self, node_idx: NodeIdx) -> bool { + self.lhs.contains_node(node_idx) || self.rhs.contains_node(node_idx) + } +} + +impl RangeElem for RangeExpr { + type GraphError = GraphError; + + // #[tracing::instrument(level = "trace", skip_all)] + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + if self.arena_idx(arena).is_none() { + let lhs = std::mem::take(&mut self.lhs); + let rhs = std::mem::take(&mut self.rhs); + self.lhs = Box::new(Elem::Arena(arena.idx_or_upsert(*lhs, analyzer))); + self.rhs = Box::new(Elem::Arena(arena.idx_or_upsert(*rhs, analyzer))); + let _ = arena.idx_or_upsert(Elem::Expr(self.clone()), analyzer); + } + Ok(()) + } + + fn range_eq(&self, _other: &Self, _arena: &mut RangeArena>) -> bool { + false + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn flatten( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + match (maximize, &self.flattened_min, &self.flattened_max) { + (true, _, Some(flat)) | (false, Some(flat), _) => { + return Ok(*flat.clone()); + } + _ => {} + } + + if let Some(arenaized) = self.arenaized_flat_cache(maximize, arena) { + return Ok(*arenaized); + } + + Ok(Elem::Expr(RangeExpr::new( + self.lhs.flatten(maximize, analyzer, arena)?, + self.op, + self.rhs.flatten(maximize, analyzer, arena)?, + ))) + } + + fn is_flatten_cached( + &self, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { + self.flattened_min.is_some() && self.flattened_max.is_some() || { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get(idx) { + if let Elem::Expr(ref arenaized) = *t { + arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() + } else { + false + } + } else { + false + } + } else { + false + } + } + } + + fn is_min_max_cached( + &self, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> (bool, bool) { + let (arena_cached_min, arena_cached_max) = { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get(idx) { + if let Elem::Expr(ref arenaized) = *t { + (arenaized.minimized.is_some(), arenaized.maximized.is_some()) + } else { + (false, false) + } + } else { + (false, false) + } + } else { + (false, false) + } + }; + ( + self.minimized.is_some() || arena_cached_min, + self.maximized.is_some() || arena_cached_max, + ) + } + + fn range_ord( + &self, + _other: &Self, + _arena: &mut RangeArena>, + ) -> Option { + todo!() + } + + fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { + let mut deps = self.lhs.dependent_on(analyzer, arena); + deps.extend(self.rhs.dependent_on(analyzer, arena)); + deps + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn recursive_dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + let mut deps = self.lhs.recursive_dependent_on(analyzer, arena)?; + deps.extend(self.rhs.recursive_dependent_on(analyzer, arena)?); + Ok(deps) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn has_cycle( + &self, + seen: &mut Vec, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + let lhs_has_cycle = self.lhs.has_cycle(seen, analyzer, arena)?; + let rhs_has_cycle = self.rhs.has_cycle(seen, analyzer, arena)?; + Ok(lhs_has_cycle || rhs_has_cycle) + } + + fn depends_on( + &self, + var: ContextVarNode, + seen: &mut Vec, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + let lhs_deps_on = self.lhs.depends_on(var, seen, analyzer, arena)?; + let rhs_deps_on = self.rhs.depends_on(var, seen, analyzer, arena)?; + Ok(lhs_deps_on || rhs_deps_on) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn filter_recursion( + &mut self, + node_idx: NodeIdx, + new_idx: NodeIdx, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) { + let _ = self.arenaize(analyzer, arena); + self.lhs + .filter_recursion(node_idx, new_idx, analyzer, arena); + self.rhs + .filter_recursion(node_idx, new_idx, analyzer, arena); + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { + Ok(*cached) + } else if let Some(MinMaxed::Maximized(cached)) = + self.arenaized_cache(true, analyzer, arena) + { + Ok(*cached) + } else if self.op == RangeOp::SetIndices { + self.simplify_exec_op(true, analyzer, arena) + } else { + self.exec_op(true, analyzer, arena) + } + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { + Ok(*cached) + } else if let Some(MinMaxed::Minimized(cached)) = + self.arenaized_cache(false, analyzer, arena) + { + Ok(*cached) + } else if self.op == RangeOp::SetIndices { + self.simplify_exec_op(false, analyzer, arena) + } else { + self.exec_op(false, analyzer, arena) + } + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn simplify_maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + if let Some(simp_max) = &self.flattened_max { + return Ok(*simp_max.clone()); + } + + if let Some(arenaized) = self.arenaized_flat_cache(true, arena) { + return Ok(*arenaized); + } + + let l = self.lhs.simplify_maximize(analyzer, arena)?; + let r = self.rhs.simplify_maximize(analyzer, arena)?; + let collapsed = collapse(l, self.op, r, arena); + let res = match collapsed { + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, self.op, r).exec_op(true, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(true, analyzer, arena)?; + match res { + Elem::Expr(expr) => match collapse(*expr.lhs, expr.op, *expr.rhs, arena) { + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, expr.op, r).exec_op(true, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, expr.op, r))), + }, + other => Ok(other), + } + } + }?; + self.set_arenaized_flattened(true, res.clone(), arena); + Ok(res) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn simplify_minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + if let Some(simp_min) = &self.flattened_min { + return Ok(*simp_min.clone()); + } + + if let Some(arenaized) = self.arenaized_flat_cache(false, arena) { + return Ok(*arenaized); + } + + let l = self.lhs.simplify_minimize(analyzer, arena)?; + self.lhs.set_arenaized_flattened(false, &l, arena); + let r = self.rhs.simplify_minimize(analyzer, arena)?; + self.rhs.set_arenaized_flattened(false, &r, arena); + + let collapsed = collapse(l, self.op, r, arena); + let res = match collapsed { + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, self.op, r).exec_op(false, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + let res = RangeExpr::new(l, self.op, r).simplify_exec_op(false, analyzer, arena)?; + match res { + Elem::Expr(expr) => match collapse(*expr.lhs, expr.op, *expr.rhs, arena) { + MaybeCollapsed::Concretes(l, r) => { + return RangeExpr::new(l, self.op, r).exec_op(false, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => return Ok(collapsed), + MaybeCollapsed::Not(l, r) => Ok(Elem::Expr(RangeExpr::new(l, expr.op, r))), + }, + other => Ok(other), + } + } + }?; + + self.set_arenaized_flattened(false, res.clone(), arena); + Ok(res) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn cache_flatten( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + self.arenaize(g, arena)?; + + fn simp_minimize( + this: &mut Elem, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + let Elem::Expr(this) = this else { + this.cache_flatten(analyzer, arena)?; + if let Some(t) = this.arenaized_flattened(false, analyzer, arena) { + return Ok(*t); + } else { + return Ok(this.clone()); + } + }; + + if let Some(simp_min) = &this.flattened_min { + return Ok(*simp_min.clone()); + } + + if let Some(arenaized) = this.arenaized_flat_cache(false, arena) { + return Ok(*arenaized); + } + + let l = simp_minimize(&mut this.lhs, analyzer, arena)?; + let r = simp_minimize(&mut this.rhs, analyzer, arena)?; + let collapsed = collapse(l, this.op, r, arena); + let res = match collapsed { + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, this.op, r).exec_op(false, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + let res = + RangeExpr::new(l, this.op, r).simplify_exec_op(false, analyzer, arena)?; + + let idx = arena.idx_or_upsert(res.clone(), analyzer); + match res { + Elem::Expr(expr) => match collapse(*expr.lhs, expr.op, *expr.rhs, arena) { + MaybeCollapsed::Concretes(l, r) => { + let exec_res = RangeExpr::new(l, expr.op, r) + .exec_op(false, analyzer, arena)?; + Elem::Arena(idx).set_arenaized_flattened(false, &exec_res, arena); + Ok(exec_res) + } + MaybeCollapsed::Collapsed(collapsed) => { + Elem::Arena(idx).set_arenaized_flattened(false, &collapsed, arena); + Ok(collapsed) + } + MaybeCollapsed::Not(l, r) => { + Ok(Elem::Expr(RangeExpr::new(l, expr.op, r))) + } + }, + other => Ok(other), + } + } + }?; + + this.set_arenaized_flattened(false, res.clone(), arena); + Ok(res) + } + + fn simp_maximize( + this: &mut Elem, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { + let Elem::Expr(this) = this else { + this.cache_flatten(analyzer, arena)?; + if let Some(t) = this.arenaized_flattened(true, analyzer, arena) { + return Ok(*t); + } else { + return Ok(this.clone()); + } + }; + + if let Some(simp_min) = &this.flattened_max { + return Ok(*simp_min.clone()); + } + + if let Some(arenaized) = this.arenaized_flat_cache(false, arena) { + return Ok(*arenaized); + } + + let l = simp_maximize(&mut this.lhs, analyzer, arena)?; + let r = simp_maximize(&mut this.rhs, analyzer, arena)?; + let collapsed = collapse(l, this.op, r, arena); + let res = match collapsed { + MaybeCollapsed::Concretes(l, r) => { + RangeExpr::new(l, this.op, r).exec_op(true, analyzer, arena) + } + MaybeCollapsed::Collapsed(collapsed) => Ok(collapsed), + MaybeCollapsed::Not(l, r) => { + let res = + RangeExpr::new(l, this.op, r).simplify_exec_op(true, analyzer, arena)?; + + let idx = arena.idx_or_upsert(res.clone(), analyzer); + match res { + Elem::Expr(expr) => match collapse(*expr.lhs, expr.op, *expr.rhs, arena) { + MaybeCollapsed::Concretes(l, r) => { + let exec_res = + RangeExpr::new(l, expr.op, r).exec_op(true, analyzer, arena)?; + Elem::Arena(idx).set_arenaized_flattened(true, &exec_res, arena); + Ok(exec_res) + } + MaybeCollapsed::Collapsed(collapsed) => { + Elem::Arena(idx).set_arenaized_flattened(true, &collapsed, arena); + Ok(collapsed) + } + MaybeCollapsed::Not(l, r) => { + Ok(Elem::Expr(RangeExpr::new(l, expr.op, r))) + } + }, + other => Ok(other), + } + } + }?; + + this.set_arenaized_flattened(false, res.clone(), arena); + Ok(res) + } + + if self.flattened_max.is_none() { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get(idx) { + if let Elem::Expr(ref arenaized) = *t { + if arenaized.flattened_max.is_some() { + return Ok(()); + } + } + }; + } else { + self.arenaize(g, arena)?; + } + + self.lhs.cache_flatten(g, arena)?; + self.rhs.cache_flatten(g, arena)?; + + let mut flat_max = self.flatten(true, g, arena)?; + let simplified_flat_max = simp_maximize(&mut flat_max, g, arena)?; + simplified_flat_max.clone().arenaize(g, arena)?; + self.flattened_max = Some(Box::new(simplified_flat_max)); + } + + if self.flattened_min.is_none() { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get(idx) { + if let Elem::Expr(ref arenaized) = *t { + if arenaized.flattened_min.is_some() { + return Ok(()); + } + } + }; + } else { + self.arenaize(g, arena)?; + } + + self.lhs.cache_flatten(g, arena)?; + self.rhs.cache_flatten(g, arena)?; + + let mut flat_min = self.flatten(false, g, arena)?; + let simplified_flat_min = simp_minimize(&mut flat_min, g, arena)?; + simplified_flat_min.clone().arenaize(g, arena)?; + self.flattened_min = Some(Box::new(simplified_flat_min)); + } + Ok(()) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn cache_maximize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + tracing::trace!("cache maximizing: {}", Elem::Expr(self.clone())); + self.arenaize(g, arena)?; + if self.maximized.is_none() { + self.lhs.cache_maximize(g, arena)?; + self.rhs.cache_maximize(g, arena)?; + self.cache_exec_op(true, g, arena)?; + } + Ok(()) + } + + // #[tracing::instrument(level = "trace", skip_all)] + fn cache_minimize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + tracing::trace!("cache minimizing: {}", Elem::Expr(self.clone())); + self.arenaize(g, arena)?; + if self.minimized.is_none() { + tracing::trace!("cache minimize lhs"); + self.lhs.cache_minimize(g, arena)?; + tracing::trace!("cache minimize rhs"); + self.rhs.cache_minimize(g, arena)?; + tracing::trace!("minimizing expr"); + self.cache_exec_op(false, g, arena)?; + } + Ok(()) + } + + fn uncache(&mut self) { + self.uncache_exec(); + } +} diff --git a/crates/graph/src/range/elem/expr/simplify/add.rs b/crates/graph/src/range/elem/expr/simplify/add.rs new file mode 100644 index 00000000..463d0885 --- /dev/null +++ b/crates/graph/src/range/elem/expr/simplify/add.rs @@ -0,0 +1,162 @@ +use crate::{ + nodes::Concrete, + range::{ + elem::expr::simplify::Ords, + elem::{Elem, RangeConcrete, RangeExpr, RangeOp}, + }, +}; + +use shared::RangeArena; + +pub fn add_ord_rules( + x: &Elem, + y: &Elem, + ord_op: RangeOp, + z: &Elem, + ords: Ords, + arena: &mut RangeArena>, +) -> Option> { + match ord_op { + RangeOp::Eq => { + if !ords.x_eq_z() { + return None; + } + // x + y == x + // ==> true iff y == 0, false otherwise + let res = if ords.y_eq_zero() { + Elem::from(true) + } else { + Elem::from(false) + }; + Some(res) + } + RangeOp::Neq => { + if !ords.x_eq_z() { + return None; + } + // x + y != x + // ==> true iff y != 0, false otherwise + let res = if ords.y_eq_zero() { + Elem::from(false) + } else { + Elem::from(true) + }; + Some(res) + } + RangeOp::Lt => { + // x + y < z + // ==> true if: + // x < z && y <= 0 + // ==> false if + // x >= z && y > 0 + if ords.x_lt_z() && ords.y_lte_zero() { + Some(Elem::from(true)) + } else if ords.x_gte_z() && ords.y_gt_zero() { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Gt => { + // x + y > z + // ==> true if: + // x >= z && y > 0 || x > z && y >= 0 + let true_lhs = ords.x_gte_z() && ords.y_gt_zero(); + let true_rhs = ords.x_gt_z() && ords.y_gte_zero(); + // ==> false if + // x <= z && y < 0 + let false_cond = ords.x_lte_z() && ords.y_lt_zero(); + + if true_lhs || true_rhs { + Some(Elem::from(true)) + } else if false_cond { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Lte => { + // x + y <= z + + // ==> true if: + // x <= z && y <= 0 + let true_cond = ords.x_lte_z() && ords.y_lte_zero(); + + // ==> false if: + // x > z && y >= 0 || x >= z && y > 0 + let false_lhs = ords.x_gt_z() && ords.y_gte_zero(); + let false_rhs = ords.x_gte_z() && ords.y_gt_zero(); + + if true_cond { + Some(Elem::from(true)) + } else if false_lhs || false_rhs { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Gte => { + // x + y >= z + + // ==> true if: + // x >= z && y >= 0 + let true_cond = ords.x_gte_z() && ords.y_gte_zero(); + + // ==> false if: + // x < z && y <= 0 || x <= z && y < 0 + let false_lhs = ords.x_lt_z() && ords.y_lte_zero(); + let false_rhs = ords.x_lte_z() && ords.y_lt_zero(); + + if true_cond { + Some(Elem::from(true)) + } else if false_lhs || false_rhs { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Max => { + // max{x + y, z} + // same as gt but return lhs or rhs instead + match add_ord_rules(x, y, RangeOp::Gt, z, ords, arena) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(b), + .. + })) => { + if b { + Some(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Add(false), + y.clone(), + ))) + } else { + Some(z.clone()) + } + } + _ => None, + } + } + RangeOp::Min => { + // min{x - y, z} + // same as lt but return lhs or rhs instead + match add_ord_rules(x, y, RangeOp::Lt, z, ords, arena) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(b), + .. + })) => { + if b { + Some(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Add(false), + y.clone(), + ))) + } else { + Some(z.clone()) + } + } + _ => None, + } + } + _ => None, + } +} diff --git a/crates/graph/src/range/elem/expr/simplify/mod.rs b/crates/graph/src/range/elem/expr/simplify/mod.rs new file mode 100644 index 00000000..efd55aff --- /dev/null +++ b/crates/graph/src/range/elem/expr/simplify/mod.rs @@ -0,0 +1,55 @@ +mod add; +mod ords; +mod sub; + +pub use add::*; +pub use ords::*; +pub use sub::*; + +use crate::{ + nodes::Concrete, + range::elem::{Elem, RangeElem, RangeOp}, +}; + +use ethers_core::types::U256; +use shared::RangeArena; + +pub(crate) fn ident_rules( + l: &Elem, + exec_op: RangeOp, + r: &Elem, + arena: &mut RangeArena>, +) -> Option> { + let zero = Elem::from(Concrete::from(U256::zero())); + let one = Elem::from(Concrete::from(U256::one())); + match exec_op { + RangeOp::Add(_) | RangeOp::Sub(_) => { + let lhs_zero = matches!(l.range_ord(&zero, arena), Some(std::cmp::Ordering::Equal)); + let rhs_zero = matches!(r.range_ord(&zero, arena), Some(std::cmp::Ordering::Equal)); + match (lhs_zero, rhs_zero) { + (true, true) => Some(Elem::from(Concrete::from(U256::zero()))), + (true, false) => Some((*r).clone()), + (false, true) => Some((*l).clone()), + _ => None, + } + } + RangeOp::Mul(_) | RangeOp::Div(_) => { + let lhs_one = matches!(l.range_ord(&one, arena), Some(std::cmp::Ordering::Equal)); + let rhs_one = matches!(r.range_ord(&one, arena), Some(std::cmp::Ordering::Equal)); + match (lhs_one, rhs_one) { + (true, true) => Some(Elem::from(Concrete::from(U256::one()))), + (true, false) => Some((*r).clone()), + (false, true) => Some((*l).clone()), + _ => None, + } + } + RangeOp::Exp => { + if matches!(r.range_ord(&zero, arena), Some(std::cmp::Ordering::Equal)) { + Some(Elem::from(Concrete::from(U256::one()))) + } else { + None + } + } + _ => None, + } +} diff --git a/crates/graph/src/range/elem/expr/simplify/ords.rs b/crates/graph/src/range/elem/expr/simplify/ords.rs new file mode 100644 index 00000000..f140a5db --- /dev/null +++ b/crates/graph/src/range/elem/expr/simplify/ords.rs @@ -0,0 +1,122 @@ +use crate::{ + nodes::Concrete, + range::elem::{Elem, RangeElem}, +}; + +use ethers_core::types::U256; +use shared::RangeArena; + +pub struct Ords { + pub x_ord_z: Option, + pub y_ord_z: Option, + pub y_ord_zero: Option, + pub x_ord_zero: Option, + pub y_ord_one: Option, + pub x_ord_one: Option, +} + +impl Ords { + pub fn new( + x: &Elem, + y: &Elem, + z: &Elem, + arena: &mut RangeArena>, + ) -> Self { + let zero = Elem::from(Concrete::from(U256::zero())); + let one = Elem::from(Concrete::from(U256::one())); + Self { + x_ord_z: x.range_ord(z, arena), + y_ord_z: y.range_ord(z, arena), + y_ord_zero: y.range_ord(&zero, arena), + x_ord_zero: x.range_ord(&zero, arena), + y_ord_one: y.range_ord(&one, arena), + x_ord_one: x.range_ord(&one, arena), + } + } + + pub fn x_gte_z(&self) -> bool { + self.x_gt_z() || self.x_eq_z() + } + pub fn y_gte_z(&self) -> bool { + self.y_gt_z() || self.y_eq_z() + } + + pub fn x_lte_z(&self) -> bool { + self.x_lt_z() || self.x_eq_z() + } + pub fn y_lte_z(&self) -> bool { + self.y_lt_z() || self.y_eq_z() + } + + pub fn x_gt_z(&self) -> bool { + matches!(self.x_ord_z, Some(std::cmp::Ordering::Greater)) + } + + pub fn y_gt_z(&self) -> bool { + matches!(self.x_ord_z, Some(std::cmp::Ordering::Greater)) + } + + pub fn x_lt_z(&self) -> bool { + matches!(self.x_ord_z, Some(std::cmp::Ordering::Less)) + } + + pub fn y_lt_z(&self) -> bool { + matches!(self.x_ord_z, Some(std::cmp::Ordering::Less)) + } + + pub fn x_eq_z(&self) -> bool { + matches!(self.x_ord_z, Some(std::cmp::Ordering::Equal)) + } + + pub fn y_eq_z(&self) -> bool { + matches!(self.y_ord_z, Some(std::cmp::Ordering::Equal)) + } + + pub fn x_lt_zero(&self) -> bool { + matches!(self.x_ord_zero, Some(std::cmp::Ordering::Less)) + } + + pub fn y_lt_zero(&self) -> bool { + matches!(self.y_ord_zero, Some(std::cmp::Ordering::Less)) + } + + pub fn x_eq_zero(&self) -> bool { + matches!(self.x_ord_zero, Some(std::cmp::Ordering::Equal)) + } + + pub fn x_gt_zero(&self) -> bool { + matches!(self.x_ord_zero, Some(std::cmp::Ordering::Greater)) + } + + pub fn y_gt_zero(&self) -> bool { + matches!(self.y_ord_zero, Some(std::cmp::Ordering::Greater)) + } + + pub fn y_eq_zero(&self) -> bool { + matches!(self.y_ord_zero, Some(std::cmp::Ordering::Equal)) + } + + pub fn x_gte_zero(&self) -> bool { + self.x_gt_zero() || self.x_eq_zero() + } + + pub fn y_gte_zero(&self) -> bool { + self.y_gt_zero() || self.y_eq_zero() + } + + pub fn x_lte_zero(&self) -> bool { + self.x_lt_zero() || self.x_eq_zero() + } + + pub fn y_lte_zero(&self) -> bool { + self.y_lt_zero() || self.y_eq_zero() + } + + pub fn x_eq_one(&self) -> bool { + matches!(self.x_ord_one, Some(std::cmp::Ordering::Equal)) + } + + pub fn y_eq_one(&self) -> bool { + matches!(self.y_ord_one, Some(std::cmp::Ordering::Equal)) + } +} diff --git a/crates/graph/src/range/elem/expr/simplify/sub.rs b/crates/graph/src/range/elem/expr/simplify/sub.rs new file mode 100644 index 00000000..d99f2d85 --- /dev/null +++ b/crates/graph/src/range/elem/expr/simplify/sub.rs @@ -0,0 +1,177 @@ +use crate::{ + nodes::Concrete, + range::{ + elem::expr::simplify::Ords, + elem::{Elem, RangeConcrete, RangeExpr, RangeOp}, + }, +}; + +use shared::RangeArena; + +pub fn sub_ord_rules( + x: &Elem, + y: &Elem, + ord_op: RangeOp, + z: &Elem, + ords: Ords, + arena: &mut RangeArena>, +) -> Option> { + match ord_op { + RangeOp::Eq => { + if !ords.x_eq_z() { + return None; + } + // x - y == x + // ==> true iff y == 0, false otherwise + let res = if ords.y_eq_zero() { + Elem::from(true) + } else { + Elem::from(false) + }; + Some(res) + } + RangeOp::Neq => { + if !ords.x_eq_z() { + return None; + } + // x - y != x + // ==> true iff y != 0, false otherwise + let res = if ords.y_eq_zero() { + Elem::from(false) + } else { + Elem::from(true) + }; + Some(res) + } + RangeOp::Lt => { + // x - y < z + // ==> true if: + // x <= z && y > 0 + // ==> false if + // x == z && y < 0 + let x_lte_z = ords.x_eq_z() || ords.x_lt_z(); + if x_lte_z && ords.y_gt_zero() { + Some(Elem::from(true)) + } else if ords.x_eq_z() && ords.y_lt_zero() { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Gt => { + // x - y > z + // ==> true if: + // x > z && y <= 0 || x >= z && y < 0 + // ==> false if + // x <= z && y > 0 + let true_lhs = ords.x_gt_z() && (ords.y_lt_zero() || ords.y_eq_zero()); + let true_rhs = (ords.x_gt_z() || ords.x_eq_z()) && ords.y_lt_zero(); + let x_lte_z = ords.x_eq_z() || ords.x_lt_z(); + + if true_lhs || true_rhs { + Some(Elem::from(true)) + } else if x_lte_z && ords.y_gt_zero() { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Lte => { + // x - y <= z + + // ==> true if: + // x <= z && y >= 0 + let x_lte_z = ords.x_eq_z() || ords.x_lt_z(); + let y_gte_zero = ords.y_gt_zero() || ords.y_eq_zero(); + + // ==> false if: + // x > z && y <= 0 || x >= z && y < 0 + let x_gt_z = ords.x_gt_z(); + let y_lte_zero = ords.y_lt_zero() || ords.y_eq_zero(); + let lhs = x_gt_z && y_lte_zero; + + let x_gte_z = ords.x_gt_z() || ords.x_eq_z(); + let y_lt_zero = ords.y_lt_zero(); + let rhs = x_gte_z && y_lt_zero; + let false_cond = lhs || rhs; + + if x_lte_z && y_gte_zero { + Some(Elem::from(true)) + } else if false_cond { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Gte => { + // x - y >= z + + // ==> true if: + // x >= z && y <= 0 + let x_gte_z = ords.x_eq_z() || ords.x_gt_z(); + let y_lte_zero = ords.y_lt_zero() || ords.y_eq_zero(); + + // ==> false if: + // x < z && y >= 0 || x <= z && y > 0 + let x_lt_z = ords.x_lt_z(); + let y_gte_zero = ords.y_gt_zero() || ords.y_eq_zero(); + let lhs = x_lt_z && y_gte_zero; + + let x_lte_z = ords.x_lt_z() || ords.x_eq_z(); + let y_gt_zero = ords.y_gt_zero(); + let rhs = x_lte_z && y_gt_zero; + let false_cond = lhs || rhs; + + if x_lte_z && y_gte_zero { + Some(Elem::from(true)) + } else if false_cond { + Some(Elem::from(false)) + } else { + None + } + } + RangeOp::Max => { + // max{x - y, z} + // same as gt but return lhs or rhs instead + match sub_ord_rules(x, y, RangeOp::Gt, z, ords, arena) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(b), + .. + })) => { + if b { + Some(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Sub(false), + y.clone(), + ))) + } else { + Some(z.clone()) + } + } + _ => None, + } + } + RangeOp::Min => { + // min{x - y, z} + // same as lt but return lhs or rhs instead + match sub_ord_rules(x, y, RangeOp::Lt, z, ords, arena) { + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(b), + .. + })) => { + if b { + Some(Elem::Expr(RangeExpr::new( + x.clone(), + RangeOp::Sub(false), + y.clone(), + ))) + } else { + Some(z.clone()) + } + } + _ => None, + } + } + _ => None, + } +} diff --git a/crates/graph/src/range/elem/map_or_array.rs b/crates/graph/src/range/elem/map_or_array.rs index b0aa3763..2f1f0e08 100644 --- a/crates/graph/src/range/elem/map_or_array.rs +++ b/crates/graph/src/range/elem/map_or_array.rs @@ -1,16 +1,22 @@ use crate::{ - nodes::{Concrete, ContextVarNode}, - range::elem::{Elem, MinMaxed, RangeElem}, + nodes::{Builtin, Concrete, ContextVarNode}, + range::{ + elem::{Elem, MinMaxed, RangeConcrete, RangeElem}, + exec_traits::{RangeCast, RangeMemLen}, + }, GraphBackend, GraphError, }; -use std::hash::Hash; -use std::hash::Hasher; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; +use ethers_core::types::{H256, U256}; use solang_parser::pt::Loc; use std::collections::BTreeMap; +use std::hash::Hash; +use std::hash::Hasher; + +use super::rc_uint256; /// A concrete value for a range element #[derive(Clone, Debug, Ord, PartialOrd)] @@ -40,7 +46,7 @@ impl PartialEq for RangeDyn { } impl Eq for RangeDyn {} -impl Hash for RangeDyn { +impl Hash for RangeDyn { fn hash(&self, state: &mut H) { (*self.len).hash(state); self.val.hash(state); @@ -108,7 +114,7 @@ impl RangeDyn { flattened_max: None, len: Box::new(Elem::Null), val, - op_num, + op_num: op_num - 1, loc, } } @@ -126,17 +132,46 @@ impl RangeDyn { } impl RangeDyn { - pub fn as_bytes(&self, analyzer: &impl GraphBackend, maximize: bool) -> Option> { + pub fn as_sized_bytes(&self) -> Option> { + let len = self.range_get_length()?; + let uint_val = len.maybe_concrete()?.val.uint_val()?; + if uint_val <= 32.into() { + let v = vec![0u8; uint_val.as_usize()]; + let conc = Concrete::from(v) + .cast(Builtin::Bytes(uint_val.as_usize() as u8)) + .unwrap(); + let to_cast = RangeConcrete::new(conc, Loc::Implicit); + self.range_cast(&to_cast) + } else { + None + } + } + pub fn as_bytes( + &self, + analyzer: &impl GraphBackend, + maximize: bool, + arena: &mut RangeArena>, + ) -> Option> { let len = if maximize { - let as_u256 = self.len.maximize(analyzer).ok()?.concrete()?.into_u256()?; + let as_u256 = self + .len + .maximize(analyzer, arena) + .ok()? + .concrete()? + .into_u256()?; if as_u256 > usize::MAX.into() { usize::MAX } else { as_u256.as_usize() } } else { - let mut as_u256 = self.len.minimize(analyzer).ok()?.concrete()?.into_u256()?; - if let Some(max_key) = self.evaled_max_key(analyzer) { + let mut as_u256 = self + .len + .minimize(analyzer, arena) + .ok()? + .concrete()? + .into_u256()?; + if let Some(max_key) = self.evaled_max_key(analyzer, arena) { if let Some(max_key) = max_key.into_u256() { as_u256 = as_u256.max(max_key); } @@ -152,7 +187,7 @@ impl RangeDyn { Some( self.val .values() - .map(|v| v.0.as_bytes(analyzer, maximize)) + .map(|v| v.0.as_bytes(analyzer, maximize, arena)) .collect::>>>()? .into_iter() .flatten() @@ -161,49 +196,117 @@ impl RangeDyn { ) } - pub fn evaled_max_key(&self, analyzer: &impl GraphBackend) -> Option { + pub fn evaled_max_key( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option { let mut evaled = self .val .keys() - .filter_map(|key| key.maximize(analyzer).ok()) + .filter_map(|key| key.maximize(analyzer, arena).ok()) .collect::>(); - evaled.sort_by(|a, b| a.range_ord(b, analyzer).unwrap_or(std::cmp::Ordering::Less)); + evaled.sort_by(|a, b| a.range_ord(b, arena).unwrap_or(std::cmp::Ordering::Less)); evaled.iter().take(1).next()?.concrete() } + + pub fn from_concrete(concrete: Concrete, loc: Loc) -> Option { + let (vals, len) = match concrete { + Concrete::Bytes(size, b) => ( + Some( + b.0.into_iter() + .take((size).into()) + .enumerate() + .map(|(i, b)| { + let mut h = H256::default(); + h.0[0] = b; + ( + rc_uint256(i as u128).into(), + RangeConcrete::new(Concrete::Bytes(1, h), Loc::Implicit).into(), + ) + }) + .collect::>(), + ), + Concrete::Uint(256, U256::from(size)), + ), + Concrete::DynBytes(b) => ( + Some( + b.iter() + .enumerate() + .map(|(i, by)| { + let mut h = H256::default(); + h.0[0] = *by; + ( + rc_uint256(i as u128).into(), + RangeConcrete::new(Concrete::Bytes(1, h), Loc::Implicit).into(), + ) + }) + .collect::>(), + ), + Concrete::Uint(256, U256::from(b.len())), + ), + Concrete::String(s) => ( + Some( + s.chars() + .enumerate() + .map(|(i, b): (usize, char)| { + let mut h = H256::default(); + h.0[0] = b as u8; + ( + rc_uint256(i as u128).into(), + RangeConcrete::new(Concrete::Bytes(1, h), Loc::Implicit).into(), + ) + }) + .collect::>(), + ), + Concrete::Uint(256, U256::from(s.len())), + ), + _ => (None, Concrete::Uint(256, 0.into())), + }; + + let mut s = Self::new_for_indices(vals?, loc); + s.len = Box::new(RangeConcrete::new(len, loc).into()); + Some(s) + } } impl RangeElem for RangeDyn { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - // self.cache_flatten(analyzer)?; - // self.cache_minimize(analyzer)?; - // self.cache_maximize(analyzer)?; - self.len.arenaize(analyzer)?; + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + self.len.arenaize(analyzer, arena)?; self.val = self .val .iter_mut() .map(|(k, (v, op))| { let mut new_k = k.clone(); let mut new_v = v.clone(); - new_k.arenaize(analyzer); - new_v.arenaize(analyzer); + new_k.arenaize(analyzer, arena); + new_v.arenaize(analyzer, arena); (new_k, (new_v, *op)) }) .collect(); Ok(()) } - fn range_eq(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + fn range_eq(&self, other: &Self, arena: &mut RangeArena>) -> bool { matches!( - self.range_ord(other, analyzer), + self.range_ord(other, arena), Some(std::cmp::Ordering::Equal) ) } - fn range_ord(&self, other: &Self, analyzer: &impl GraphBackend) -> Option { - match self.len.range_ord(&other.len, analyzer) { + fn range_ord( + &self, + other: &Self, + arena: &mut RangeArena>, + ) -> Option { + match self.len.range_ord(&other.len, arena) { Some(std::cmp::Ordering::Equal) => { let mut eq = 0; let mut self_lt = 0; @@ -211,9 +314,9 @@ impl RangeElem for RangeDyn { self.val.iter().zip(other.val.iter()).for_each( |((self_key, self_val), (other_key, other_val))| { if let Some(std::cmp::Ordering::Equal) = - self_key.clone().range_ord(other_key, analyzer) + self_key.clone().range_ord(other_key, arena) { - match self_val.0.clone().range_ord(&other_val.0, analyzer) { + match self_val.0.clone().range_ord(&other_val.0, arena) { Some(std::cmp::Ordering::Equal) => eq += 1, Some(std::cmp::Ordering::Less) => self_lt += 1, Some(std::cmp::Ordering::Greater) => self_gt += 1, @@ -237,12 +340,16 @@ impl RangeElem for RangeDyn { } } - fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { - let mut deps: Vec = self.len.dependent_on(analyzer); + fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { + let mut deps: Vec = self.len.dependent_on(analyzer, arena); deps.extend( self.val .iter() - .flat_map(|(_, val)| val.0.dependent_on(analyzer)) + .flat_map(|(_, val)| val.0.dependent_on(analyzer, arena)) .collect::>(), ); deps @@ -251,12 +358,13 @@ impl RangeElem for RangeDyn { fn recursive_dependent_on( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { - let mut deps: Vec = self.len.recursive_dependent_on(analyzer)?; + let mut deps: Vec = self.len.recursive_dependent_on(analyzer, arena)?; deps.extend( self.val .values() - .map(|val| val.0.recursive_dependent_on(analyzer)) + .map(|val| val.0.recursive_dependent_on(analyzer, arena)) .collect::>, _>>()? .iter() .flatten() @@ -265,7 +373,7 @@ impl RangeElem for RangeDyn { deps.extend( self.val .keys() - .map(|key| key.recursive_dependent_on(analyzer)) + .map(|key| key.recursive_dependent_on(analyzer, arena)) .collect::>, _>>()? .iter() .flatten() @@ -278,11 +386,12 @@ impl RangeElem for RangeDyn { &self, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { let mut has_cycle = false; - has_cycle = has_cycle || self.len.has_cycle(seen, analyzer)?; + has_cycle = has_cycle || self.len.has_cycle(seen, analyzer, arena)?; self.val.iter().try_for_each(|(_, val)| { - has_cycle = has_cycle || val.0.has_cycle(seen, analyzer)?; + has_cycle = has_cycle || val.0.has_cycle(seen, analyzer, arena)?; Ok(()) })?; Ok(has_cycle) @@ -293,11 +402,12 @@ impl RangeElem for RangeDyn { var: ContextVarNode, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { let mut deps_on = false; - deps_on |= self.len.depends_on(var, seen, analyzer)?; + deps_on |= self.len.depends_on(var, seen, analyzer, arena)?; self.val.iter().try_for_each(|(_, val)| { - deps_on |= val.0.depends_on(var, seen, analyzer)?; + deps_on |= val.0.depends_on(var, seen, analyzer, arena)?; Ok(()) })?; Ok(deps_on) @@ -307,6 +417,7 @@ impl RangeElem for RangeDyn { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { (true, _, Some(flat)) | (false, Some(flat), _) => return Ok(*flat.clone()), @@ -317,13 +428,13 @@ impl RangeElem for RangeDyn { maximized: None, flattened_min: None, flattened_max: None, - len: Box::new(self.len.flatten(maximize, analyzer)?), + len: Box::new(self.len.flatten(maximize, analyzer, arena)?), val: { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { map.insert( - idx.flatten(maximize, analyzer)?, - (val.0.flatten(maximize, analyzer)?, val.1), + idx.flatten(maximize, analyzer, arena)?, + (val.0.flatten(maximize, analyzer, arena)?, val.1), ); } map @@ -333,45 +444,57 @@ impl RangeElem for RangeDyn { })) } - fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_flatten( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { if self.flattened_max.is_none() { - self.len.cache_flatten(analyzer)?; + self.len.cache_flatten(analyzer, arena)?; let mapping = std::mem::take(&mut self.val); self.val = mapping .into_iter() .map(|(mut idx, mut val)| { - idx.cache_flatten(analyzer).unwrap(); - val.0.cache_flatten(analyzer).unwrap(); + idx.cache_flatten(analyzer, arena).unwrap(); + val.0.cache_flatten(analyzer, arena).unwrap(); (idx, val) }) .collect(); - let flat_max = self.flatten(true, analyzer)?; - let simplified_flat_max = flat_max.simplify_maximize(analyzer)?; + let flat_max = self.flatten(true, analyzer, arena)?; + let simplified_flat_max = flat_max.simplify_maximize(analyzer, arena)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { - self.len.cache_flatten(analyzer)?; + self.len.cache_flatten(analyzer, arena)?; let mapping = std::mem::take(&mut self.val); self.val = mapping .into_iter() .map(|(mut idx, mut val)| { - idx.cache_flatten(analyzer).unwrap(); - val.0.cache_flatten(analyzer).unwrap(); + idx.cache_flatten(analyzer, arena).unwrap(); + val.0.cache_flatten(analyzer, arena).unwrap(); (idx, val) }) .collect(); - let flat_min = self.flatten(false, analyzer)?; - let simplified_flat_min = flat_min.simplify_minimize(analyzer)?; + let flat_min = self.flatten(false, analyzer, arena)?; + let simplified_flat_min = flat_min.simplify_minimize(analyzer, arena)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) } - fn is_flatten_cached(&self, _analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() } - fn is_min_max_cached(&self, _analyzer: &impl GraphBackend) -> (bool, bool) { + fn is_min_max_cached( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> (bool, bool) { (self.minimized.is_some(), self.maximized.is_some()) } @@ -380,64 +503,68 @@ impl RangeElem for RangeDyn { node_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) { - self.len.filter_recursion(node_idx, new_idx, analyzer); + self.len + .filter_recursion(node_idx, new_idx, analyzer, arena); self.val = self .val .clone() .into_iter() .map(|(mut k, mut v)| { - k.filter_recursion(node_idx, new_idx, analyzer); - v.0.filter_recursion(node_idx, new_idx, analyzer); + k.filter_recursion(node_idx, new_idx, analyzer, arena); + v.0.filter_recursion(node_idx, new_idx, analyzer, arena); (k, v) }) .collect(); } - fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { return Ok(*cached); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.maximize(analyzer)?, + self.len.maximize(analyzer, arena)?, { let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont maximize the key so that any subsequent // `get_index` can find potential values - let maximized = val.0.maximize(analyzer)?; - map.insert(idx.simplify_maximize(analyzer)?, (maximized, val.1)); + let maximized = val.0.maximize(analyzer, arena)?; + map.insert(idx.simplify_maximize(analyzer, arena)?, (maximized, val.1)); } - // map.into_iter().filter(|(k, (v, op))| { - // *v != Elem::Null - // }).collect() map }, self.loc, ))) } - fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { return Ok(*cached); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.minimize(analyzer)?, + self.len.minimize(analyzer, arena)?, { let mut map: BTreeMap<_, (Elem, usize)> = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let minimized = val.0.minimize(analyzer)?; - map.insert(idx.simplify_minimize(analyzer)?, (minimized, val.1)); + let minimized = val.0.minimize(analyzer, arena)?; + map.insert(idx.simplify_minimize(analyzer, arena)?, (minimized, val.1)); } - // map.into_iter().filter(|(k, (v, op))| { - // *v != Elem::Null - // }).collect() map }, self.loc, @@ -447,18 +574,19 @@ impl RangeElem for RangeDyn { fn simplify_maximize( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if let Some(max) = &self.flattened_max { return Ok(*max.clone()); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_maximize(analyzer)?, + self.len.simplify_maximize(analyzer, arena)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_maximize(analyzer)?; + let simplified = val.0.simplify_maximize(analyzer, arena)?; map.insert(idx, (simplified, val.1)); } map @@ -469,19 +597,20 @@ impl RangeElem for RangeDyn { fn simplify_minimize( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if let Some(min) = &self.flattened_min { return Ok(*min.clone()); } Ok(Elem::ConcreteDyn(Self::new_w_op_nums( - self.len.simplify_minimize(analyzer)?, + self.len.simplify_minimize(analyzer, arena)?, { let mut map = BTreeMap::default(); for (idx, val) in self.val.clone().into_iter() { // We dont minimize the key so that any subsequent // `get_index` can find potential values - let simplified = val.0.simplify_minimize(analyzer)?; + let simplified = val.0.simplify_minimize(analyzer, arena)?; map.insert(idx, (simplified, val.1)); } map @@ -490,36 +619,44 @@ impl RangeElem for RangeDyn { ))) } - fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_maximize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { if self.maximized.is_none() { - self.len.cache_maximize(g)?; + self.len.cache_maximize(g, arena)?; let mapping = std::mem::take(&mut self.val); self.val = mapping .into_iter() .map(|(mut idx, mut val)| { - idx.cache_maximize(g).unwrap(); - val.0.cache_maximize(g).unwrap(); + idx.cache_maximize(g, arena).unwrap(); + val.0.cache_maximize(g, arena).unwrap(); (idx, val) }) .collect(); - self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g)?))); + self.maximized = Some(MinMaxed::Maximized(Box::new(self.maximize(g, arena)?))); } Ok(()) } - fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_minimize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { if self.minimized.is_none() { - self.len.cache_minimize(g)?; + self.len.cache_minimize(g, arena)?; let mapping = std::mem::take(&mut self.val); self.val = mapping .into_iter() .map(|(mut idx, mut val)| { - idx.cache_minimize(g).unwrap(); - val.0.cache_minimize(g).unwrap(); + idx.cache_minimize(g, arena).unwrap(); + val.0.cache_minimize(g, arena).unwrap(); (idx, val) }) .collect(); - self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g)?))); + self.minimized = Some(MinMaxed::Minimized(Box::new(self.minimize(g, arena)?))); } Ok(()) } @@ -527,7 +664,5 @@ impl RangeElem for RangeDyn { fn uncache(&mut self) { self.minimized = None; self.maximized = None; - // self.flattened_min = None; - // self.flattened_max = None; } } diff --git a/crates/graph/src/range/elem/mod.rs b/crates/graph/src/range/elem/mod.rs index cfb54157..dd1c7401 100644 --- a/crates/graph/src/range/elem/mod.rs +++ b/crates/graph/src/range/elem/mod.rs @@ -73,8 +73,6 @@ pub enum RangeOp { And, /// Logical OR Or, - /// Catch-all requirement statement - Where, /// Cast from one type to another Cast, /// Bitwise AND @@ -102,6 +100,57 @@ pub enum RangeOp { } impl RangeOp { + pub fn commutative(&self) -> bool { + use RangeOp::*; + match self { + Add(_i) => true, + Mul(_i) => true, + Sub(_i) => false, + Div(_i) => false, + Mod => false, + Exp => false, + Min => true, + Max => true, + + Eq => true, + Neq => true, + Lt => false, + Lte => false, + Gt => false, + Gte => false, + And => true, + Or => true, + Not => false, + + BitNot => false, + BitAnd => false, + BitXor => false, + BitOr => false, + Shl => false, + Shr => false, + + Cast => false, + + SetLength => false, + Memcopy => false, + GetLength => false, + SetIndices => false, + GetIndex => false, + Concat => false, + } + } + + pub fn non_commutative_logical_inverse(&self) -> Option { + use RangeOp::*; + match self { + Lt => Some(Gt), + Lte => Some(Gte), + Gt => Some(Lt), + Gte => Some(Lte), + _ => None, + } + } + /// Attempts to return the inverse range operation (e.g.: `RangeOp::Add => RangeOp::Sub`) pub fn inverse(self) -> Option { use RangeOp::*; @@ -176,7 +225,6 @@ impl ToString for RangeOp { Not => "!".to_string(), And => "&&".to_string(), Or => "||".to_string(), - Where => "where".to_string(), Cast => "cast".to_string(), BitAnd => "&".to_string(), BitOr => "|".to_string(), diff --git a/crates/graph/src/range/elem/reference.rs b/crates/graph/src/range/elem/reference.rs index 0ac79c12..84af8ef5 100644 --- a/crates/graph/src/range/elem/reference.rs +++ b/crates/graph/src/range/elem/reference.rs @@ -1,7 +1,7 @@ use crate::{ nodes::{Concrete, ContextVarNode}, range::{ - elem::{Elem, MinMaxed, RangeConcrete, RangeElem}, + elem::{Elem, MinMaxed, RangeArenaLike, RangeConcrete, RangeElem}, Range, }, GraphBackend, GraphError, TypeNode, VarType, @@ -9,7 +9,7 @@ use crate::{ use std::hash::Hash; use std::hash::Hasher; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::Loc; @@ -28,7 +28,7 @@ pub struct Reference { pub flattened_max: Option>>, } -impl Hash for Reference { +impl Hash for Reference { fn hash(&self, state: &mut H) { self.idx.hash(state); } @@ -56,19 +56,27 @@ impl Reference { impl RangeElem for Reference { type GraphError = GraphError; - fn arenaize(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { - let smol = Elem::Reference(Reference::new(self.idx)); - if analyzer.range_arena_idx(&smol).is_none() { - let _ = analyzer.range_arena_idx_or_upsert(Elem::Reference(self.clone())); - } + fn arenaize( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + // let smol = Elem::Reference(Reference::new(self.idx)); + // if analyzer.range_arena_idx(&smol).is_none() { + let _ = arena.idx_or_upsert(Elem::Reference(self.clone()), analyzer); + // } Ok(()) } - fn range_eq(&self, _other: &Self, _analyzer: &impl GraphBackend) -> bool { + fn range_eq(&self, _other: &Self, _arena: &mut RangeArena>) -> bool { false } - fn range_ord(&self, other: &Self, _analyzer: &impl GraphBackend) -> Option { + fn range_ord( + &self, + other: &Self, + _arena: &mut RangeArena>, + ) -> Option { if self.idx == other.idx { Some(std::cmp::Ordering::Equal) } else { @@ -76,13 +84,18 @@ impl RangeElem for Reference { } } - fn dependent_on(&self, _analyzer: &impl GraphBackend) -> Vec { + fn dependent_on( + &self, + _analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> Vec { vec![self.idx.into()] } fn recursive_dependent_on( &self, analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, ) -> Result, GraphError> { let mut deps = ContextVarNode(self.idx.index()).dependent_on(analyzer, true)?; deps.push(ContextVarNode(self.idx.index())); @@ -93,6 +106,7 @@ impl RangeElem for Reference { &self, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { let cvar = ContextVarNode::from(self.idx); let mut has_cycle = false; @@ -101,8 +115,8 @@ impl RangeElem for Reference { } else { seen.push(cvar); if let Some(range) = cvar.ref_range(analyzer)? { - has_cycle = has_cycle || range.min.has_cycle(seen, analyzer)?; - has_cycle = has_cycle || range.max.has_cycle(seen, analyzer)?; + has_cycle = has_cycle || range.min.has_cycle(seen, analyzer, arena)?; + has_cycle = has_cycle || range.max.has_cycle(seen, analyzer, arena)?; Ok(has_cycle) } else { Ok(false) @@ -115,6 +129,7 @@ impl RangeElem for Reference { var: ContextVarNode, seen: &mut Vec, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { let cvar = ContextVarNode::from(self.idx); if seen.contains(&cvar) { @@ -125,8 +140,8 @@ impl RangeElem for Reference { Ok(true) } else if let Some(range) = cvar.ref_range(analyzer)? { seen.push(cvar); - let mut deps_on = range.min.depends_on(var, seen, analyzer)?; - deps_on |= range.max.depends_on(var, seen, analyzer)?; + let mut deps_on = range.min.depends_on(var, seen, analyzer, arena)?; + deps_on |= range.max.depends_on(var, seen, analyzer, arena)?; Ok(deps_on) } else { Ok(false) @@ -137,6 +152,7 @@ impl RangeElem for Reference { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { match (maximize, &self.flattened_min, &self.flattened_max) { (true, _, Some(flat)) | (false, Some(flat), _) => { @@ -154,21 +170,24 @@ impl RangeElem for Reference { if maximize { cvar.range_max(analyzer)? .unwrap_or(Elem::Null) - .flatten(maximize, analyzer) + .flatten(maximize, analyzer, arena) } else { let flattened = cvar .range_min(analyzer)? .unwrap_or(Elem::Null) - .flatten(maximize, analyzer)?; + .flatten(maximize, analyzer, arena)?; Ok(flattened) } } - fn is_flatten_cached(&self, analyzer: &impl GraphBackend) -> bool { + fn is_flatten_cached( + &self, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { self.flattened_min.is_some() && self.flattened_max.is_some() || { - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) - { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { arenaized.flattened_min.is_some() && arenaized.flattened_max.is_some() } else { @@ -183,11 +202,14 @@ impl RangeElem for Reference { } } - fn is_min_max_cached(&self, analyzer: &impl GraphBackend) -> (bool, bool) { + fn is_min_max_cached( + &self, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> (bool, bool) { let (arena_cached_min, arena_cached_max) = { - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) - { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { (arenaized.minimized.is_some(), arenaized.maximized.is_some()) } else { @@ -206,12 +228,16 @@ impl RangeElem for Reference { ) } - fn cache_flatten(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - self.arenaize(g)?; + fn cache_flatten( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + self.arenaize(g, arena)?; if self.flattened_max.is_none() { - if let Some(idx) = g.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = g.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_max.is_some() { tracing::trace!("reference cache flatten hit"); @@ -222,14 +248,14 @@ impl RangeElem for Reference { } let cvar = ContextVarNode::from(self.idx); - cvar.cache_flattened_range(g)?; - let flat_max = self.flatten(true, g)?; - let simplified_flat_max = flat_max.simplify_maximize(g)?; + cvar.cache_flattened_range(g, arena)?; + let flat_max = self.flatten(true, g, arena)?; + let simplified_flat_max = flat_max.simplify_maximize(g, arena)?; self.flattened_max = Some(Box::new(simplified_flat_max)); } if self.flattened_min.is_none() { - if let Some(idx) = g.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = g.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_min.is_some() { tracing::trace!("reference cache flatten hit"); @@ -239,23 +265,34 @@ impl RangeElem for Reference { } } let cvar = ContextVarNode::from(self.idx); - cvar.cache_flattened_range(g)?; - let flat_min = self.flatten(false, g)?; - let simplified_flat_min = flat_min.simplify_minimize(g)?; + cvar.cache_flattened_range(g, arena)?; + let flat_min = self.flatten(false, g, arena)?; + let simplified_flat_min = flat_min.simplify_minimize(g, arena)?; self.flattened_min = Some(Box::new(simplified_flat_min)); } Ok(()) } - fn filter_recursion(&mut self, _: NodeIdx, _: NodeIdx, _analyzer: &mut impl GraphBackend) {} + fn filter_recursion( + &mut self, + _: NodeIdx, + _: NodeIdx, + _analyzer: &mut impl GraphBackend, + _arena: &mut RangeArena>, + ) { + } - fn maximize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn maximize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(MinMaxed::Maximized(cached)) = self.maximized.clone() { return Ok(*cached); } - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { tracing::trace!("reference maximize cache hit"); if let Some(MinMaxed::Maximized(cached)) = arenaized.maximized.clone() { @@ -272,26 +309,30 @@ impl RangeElem for Reference { | VarType::User(TypeNode::Ty(_), maybe_range) | VarType::BuiltIn(_, maybe_range) => { if let Some(range) = maybe_range { - range.evaled_range_max(analyzer) + range.evaled_range_max(analyzer, arena) } else { Ok(Elem::Reference(self.clone())) } } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete::new( + concrete_node.underlying(analyzer)?.clone(), + cvar.loc.unwrap_or(Loc::Implicit), + ))), _e => Ok(Elem::Reference(self.clone())), } } - fn minimize(&self, analyzer: &impl GraphBackend) -> Result, GraphError> { + fn minimize( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result, GraphError> { if let Some(MinMaxed::Minimized(cached)) = self.minimized.clone() { return Ok(*cached); } - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { if let Some(MinMaxed::Minimized(cached)) = arenaized.minimized.clone() { tracing::trace!("reference minimize cache hit"); @@ -308,15 +349,15 @@ impl RangeElem for Reference { | VarType::User(TypeNode::Ty(_), maybe_range) | VarType::BuiltIn(_, maybe_range) => { if let Some(range) = maybe_range { - range.evaled_range_min(analyzer) + range.evaled_range_min(analyzer, arena) } else { Ok(Elem::Reference(self.clone())) } } - VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete { - val: concrete_node.underlying(analyzer)?.clone(), - loc: cvar.loc.unwrap_or(Loc::Implicit), - })), + VarType::Concrete(concrete_node) => Ok(Elem::Concrete(RangeConcrete::new( + concrete_node.underlying(analyzer)?.clone(), + cvar.loc.unwrap_or(Loc::Implicit), + ))), _e => Ok(Elem::Reference(self.clone())), } } @@ -324,13 +365,14 @@ impl RangeElem for Reference { fn simplify_maximize( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if let Some(simp_max) = &self.flattened_max { return Ok(*simp_max.clone()); } - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_max.is_some() { tracing::trace!("reference simplify maximize cache hit"); @@ -348,20 +390,23 @@ impl RangeElem for Reference { cvar.global_first_version(analyzer).into(), ))) } else { - self.flatten(true, analyzer)?.simplify_maximize(analyzer) + self.flatten(true, analyzer, arena)? + .simplify_maximize(analyzer, arena) } } fn simplify_minimize( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { + let cvar = ContextVarNode::from(self.idx); if let Some(simp_min) = &self.flattened_min { return Ok(*simp_min.clone()); } - if let Some(idx) = analyzer.range_arena_idx(&Elem::Reference(Reference::new(self.idx))) { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { + if let Some(idx) = arena.idx(&Elem::Reference(Reference::new(self.idx))) { + if let Some(t) = arena.ranges.get(idx) { if let Elem::Reference(ref arenaized) = *t { if arenaized.flattened_min.is_some() { tracing::trace!("reference simplify minimize cache hit"); @@ -371,35 +416,43 @@ impl RangeElem for Reference { } } - let cvar = ContextVarNode::from(self.idx); if cvar.is_fundamental(analyzer)? { Ok(Elem::Reference(Reference::new( cvar.global_first_version(analyzer).into(), ))) } else { - self.flatten(false, analyzer)?.simplify_minimize(analyzer) + self.flatten(false, analyzer, arena)? + .simplify_minimize(analyzer, arena) } } - fn cache_maximize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - self.arenaize(g)?; + fn cache_maximize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + self.arenaize(g, arena)?; if self.maximized.is_none() { let cvar = ContextVarNode::from(self.idx); - cvar.cache_eval_range(g)?; - let max = self.maximize(g)?; - Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(true, &max, g); + cvar.cache_eval_range(g, arena)?; + let max = self.maximize(g, arena)?; + Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(true, &max, arena); self.maximized = Some(MinMaxed::Maximized(Box::new(max))); } Ok(()) } - fn cache_minimize(&mut self, g: &mut impl GraphBackend) -> Result<(), GraphError> { - self.arenaize(g)?; + fn cache_minimize( + &mut self, + g: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { + self.arenaize(g, arena)?; if self.minimized.is_none() { let cvar = ContextVarNode::from(self.idx); - cvar.cache_eval_range(g)?; - let min = self.minimize(g)?; - Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(false, &min, g); + cvar.cache_eval_range(g, arena)?; + let min = self.minimize(g, arena)?; + Elem::Reference(Reference::new(self.idx)).set_arenaized_cache(false, &min, arena); self.minimized = Some(MinMaxed::Minimized(Box::new(min))); } diff --git a/crates/graph/src/range/exec/add.rs b/crates/graph/src/range/exec/add.rs deleted file mode 100644 index 0e1bc7b3..00000000 --- a/crates/graph/src/range/exec/add.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -use ethers_core::types::{I256, U256}; - -impl RangeAdd for RangeConcrete { - fn range_add(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - let max_uint = max.into_u256().unwrap(); - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(lhs_val.saturating_add(rhs_val).min(max_uint)), - loc: self.loc, - })) - } - _ => { - match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - // neg_v guaranteed to be negative here - if neg_v.into_raw() > *val { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_add(I256::from_raw(*val)), - ), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.saturating_sub(neg_v.into_raw())), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_add(*r).max(min)), - loc: self.loc, - })) - } - _ => None, - } - } - } - } - fn range_wrapping_add(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(lhs_val.overflowing_add(rhs_val).0), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(neg_v.into_raw().overflowing_add(*val).0), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_add(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeAdd for Elem { - fn range_add(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), - _ => None, - } - } - fn range_wrapping_add(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/bitwise.rs b/crates/graph/src/range/exec/bitwise.rs index a980fb7b..087f8165 100644 --- a/crates/graph/src/range/exec/bitwise.rs +++ b/crates/graph/src/range/exec/bitwise.rs @@ -1,101 +1,162 @@ -use crate::nodes::Concrete; +use crate::nodes::{Builtin, Concrete}; use crate::range::{elem::*, exec_traits::*}; -use ethers_core::types::{H256, U256}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{H256, I256, U256}; impl RangeBitwise for RangeConcrete { fn range_bit_and(&self, other: &Self) -> Option> { match (&self.val, &other.val) { (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let op_res = *a & *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a & *b), - loc: self.loc, - })) + let val = Concrete::Uint(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let op_res = *a & *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a & *b), - loc: self.loc, - })) + let val = Concrete::Int(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Uint(s, u), Concrete::Int(s2, i)) | (Concrete::Int(s, i), Concrete::Uint(s2, u)) => { + let op_res = *u & i.into_raw(); let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *u & i.into_raw()), - loc: self.loc, - })) + let val = Concrete::Uint(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let op_res = a & b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a & b), - loc: self.loc, - })) + let val = Concrete::Bytes(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::DynBytes(v), _) if v.len() <= 32 => RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + ) + .range_bit_and(other), + (_, Concrete::DynBytes(v)) if v.len() <= 32 => self.range_bit_and(&RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + )), + _ => { + if let (Some(l), Some(r)) = (self.val.into_u256(), other.val.into_u256()) { + let op_res = l & r; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + None + } } - _ => None, } } fn range_bit_or(&self, other: &Self) -> Option> { match (&self.val, &other.val) { (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let op_res = *a | *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a | *b), - loc: self.loc, - })) + let val = Concrete::Uint(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let op_res = *a | *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a | *b), - loc: self.loc, - })) + let val = Concrete::Int(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let op_res = a | b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a | b), - loc: self.loc, - })) + let val = Concrete::Bytes(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::DynBytes(v), _) if v.len() <= 32 => RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + ) + .range_bit_or(other), + (_, Concrete::DynBytes(v)) if v.len() <= 32 => self.range_bit_or(&RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + )), + _ => { + if let (Some(l), Some(r)) = (self.val.into_u256(), other.val.into_u256()) { + let op_res = l | r; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + None + } } - _ => None, } } fn range_bit_xor(&self, other: &Self) -> Option> { match (&self.val, &other.val) { (Concrete::Uint(s, a), Concrete::Uint(s2, b)) => { + let op_res = *a ^ *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, *a ^ *b), - loc: self.loc, - })) + let val = Concrete::Uint(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Int(s, a), Concrete::Int(s2, b)) => { + let op_res = *a ^ *b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, *a ^ *b), - loc: self.loc, - })) + let val = Concrete::Int(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Bytes(s, a), Concrete::Bytes(s2, b)) => { + let op_res = a ^ b; let size = if s > s2 { s } else { s2 }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, a ^ b), - loc: self.loc, - })) + let val = Concrete::Bytes(*size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::DynBytes(v), _) if v.len() <= 32 => RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + ) + .range_bit_xor(other), + (_, Concrete::DynBytes(v)) if v.len() <= 32 => self.range_bit_xor(&RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + )), + _ => { + if let (Some(l), Some(r)) = (self.val.into_u256(), other.val.into_u256()) { + let op_res = l ^ r; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + None + } } - _ => None, } } fn range_bit_not(&self) -> Option> { match &self.val { Concrete::Uint(size, a) => { - let max = Concrete::max(&self.val).unwrap().uint_val().unwrap(); + let max = Concrete::max_of_type(&self.val) + .unwrap() + .uint_val() + .unwrap(); let val = U256( a.0.into_iter() .map(|i| !i) @@ -103,29 +164,29 @@ impl RangeBitwise for RangeConcrete { .try_into() .unwrap(), ); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, val & max), - loc: self.loc, - })) + let op_res = val & max; + let rc = RangeConcrete::new(Concrete::Uint(*size, op_res), self.loc); + Some(rc.into()) } Concrete::Int(size, a) => { - let (val, _) = a.overflowing_neg(); - let (val, _) = val.overflowing_sub(1.into()); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, val), - loc: self.loc, - })) + let (op_res, _) = a.overflowing_neg(); + let (op_res, _) = op_res.overflowing_sub(1.into()); + let rc = RangeConcrete::new(Concrete::Int(*size, op_res), self.loc); + Some(rc.into()) } Concrete::Bytes(s, a) => { - let mut h = H256::default(); + let mut op_res = H256::default(); (0..*s).for_each(|i| { - h.0[i as usize] = !a.0[i as usize]; + op_res.0[i as usize] = !a.0[i as usize]; }); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*s, h), - loc: self.loc, - })) + let rc = RangeConcrete::new(Concrete::Bytes(*s, op_res), self.loc); + Some(rc.into()) } + Concrete::DynBytes(v) if v.len() <= 32 => RangeConcrete::new( + Concrete::DynBytes(v.clone()).cast(Builtin::Bytes(v.len() as u8))?, + self.loc, + ) + .range_bit_not(), _ => None, } } @@ -158,3 +219,598 @@ impl RangeBitwise for Elem { } } } + +/// Executes a bitwise `and` given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked div` operation: +/// +/// `todo!()` +/// +/// Truth table for `wrapping div` operation: +/// +/// `todo!()` +/// +pub fn exec_bit_and( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + match (lhs_min, lhs_max, rhs_min, rhs_max) { + (Elem::ConcreteDyn(d), _, _, _) => { + return exec_bit_and( + &d.as_sized_bytes()?, + lhs_max, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, Elem::ConcreteDyn(d), _, _) => { + return exec_bit_and( + lhs_min, + &d.as_sized_bytes()?, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, Elem::ConcreteDyn(d), _) => { + return exec_bit_and( + lhs_min, + lhs_max, + &d.as_sized_bytes()?, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, _, Elem::ConcreteDyn(d)) => { + return exec_bit_and( + lhs_min, + lhs_max, + rhs_min, + &d.as_sized_bytes()?, + maximize, + analyzer, + arena, + ); + } + _ => {} + } + + let mut candidates = vec![]; + let bit_and = |lhs: &Elem<_>, rhs: &Elem<_>, candidates: &mut Vec>| { + if let Some(c) = lhs.range_bit_and(rhs) { + candidates.push(c); + } + }; + + // the max is the min of the maxes + match lhs_max.range_ord(rhs_max, arena) { + Some(std::cmp::Ordering::Less) => { + candidates.push(lhs_max.clone()); + } + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) => { + candidates.push(rhs_max.clone()); + } + _ => {} + } + + bit_and(lhs_min, rhs_min, &mut candidates); + bit_and(lhs_min, rhs_max, &mut candidates); + bit_and(lhs_max, rhs_min, &mut candidates); + bit_and(lhs_max, rhs_max, &mut candidates); + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(zero); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.clone()); + candidates.push(lhs_max.clone()); + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +/// Executes a bitwise `or` given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked div` operation: +/// +/// `todo!()` +/// +/// Truth table for `wrapping div` operation: +/// +/// `todo!()` +/// +pub fn exec_bit_or( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + match (lhs_min, lhs_max, rhs_min, rhs_max) { + (Elem::ConcreteDyn(d), _, _, _) => { + return exec_bit_or( + &d.as_sized_bytes()?, + lhs_max, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, Elem::ConcreteDyn(d), _, _) => { + return exec_bit_or( + lhs_min, + &d.as_sized_bytes()?, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, Elem::ConcreteDyn(d), _) => { + return exec_bit_or( + lhs_min, + lhs_max, + &d.as_sized_bytes()?, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, _, Elem::ConcreteDyn(d)) => { + return exec_bit_or( + lhs_min, + lhs_max, + rhs_min, + &d.as_sized_bytes()?, + maximize, + analyzer, + arena, + ); + } + _ => {} + } + + let mut candidates = vec![]; + let bit_or = |lhs: &Elem<_>, rhs: &Elem<_>, candidates: &mut Vec>| { + if let Some(c) = lhs.range_bit_or(rhs) { + candidates.push(c); + } + }; + + bit_or(lhs_min, rhs_min, &mut candidates); + bit_or(lhs_min, rhs_max, &mut candidates); + bit_or(lhs_max, rhs_min, &mut candidates); + bit_or(lhs_max, rhs_max, &mut candidates); + + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(negative_one.clone()); + candidates.push(negative_one.clone()); + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +/// Executes a bitwise `xor` given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked div` operation: +/// +/// `todo!()` +/// +/// Truth table for `wrapping div` operation: +/// +/// `todo!()` +/// +pub fn exec_bit_xor( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + match (lhs_min, lhs_max, rhs_min, rhs_max) { + (Elem::ConcreteDyn(d), _, _, _) => { + return exec_bit_xor( + &d.as_sized_bytes()?, + lhs_max, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, Elem::ConcreteDyn(d), _, _) => { + return exec_bit_xor( + lhs_min, + &d.as_sized_bytes()?, + rhs_min, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, Elem::ConcreteDyn(d), _) => { + return exec_bit_xor( + lhs_min, + lhs_max, + &d.as_sized_bytes()?, + rhs_max, + maximize, + analyzer, + arena, + ); + } + (_, _, _, Elem::ConcreteDyn(d)) => { + return exec_bit_xor( + lhs_min, + lhs_max, + rhs_min, + &d.as_sized_bytes()?, + maximize, + analyzer, + arena, + ); + } + _ => {} + } + + let mut candidates = vec![ + lhs_min.range_bit_xor(rhs_min), + lhs_min.range_bit_xor(rhs_max), + lhs_max.range_bit_xor(rhs_min), + lhs_max.range_bit_xor(rhs_max), + ]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&zero, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&zero, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + // if the rhs contains zero, in xor, thats just itself + candidates.push(lhs_max.range_bit_xor(&zero)); + } + + let min_contains = matches!( + rhs_min.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + candidates.push(lhs_min.range_bit_xor(&negative_one)); + candidates.push(lhs_max.range_bit_xor(&negative_one)); + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +/// Executes a bitwise `not` given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked div` operation: +/// +/// `todo!()` +/// +/// Truth table for `wrapping div` operation: +/// +/// `todo!()` +/// +pub fn exec_bit_not( + lhs_min: &Elem, + lhs_max: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + match (lhs_min, lhs_max) { + (Elem::ConcreteDyn(d), _) => { + return exec_bit_not(&d.as_sized_bytes()?, lhs_max, maximize, analyzer, arena); + } + (_, Elem::ConcreteDyn(d)) => { + return exec_bit_not(lhs_min, &d.as_sized_bytes()?, maximize, analyzer, arena); + } + _ => {} + } + let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; + + let zero = Elem::from(Concrete::from(U256::from(0))); + + let min_contains = matches!( + lhs_min.range_ord(&zero, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + lhs_max.range_ord(&zero, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains && max_contains { + match lhs_min { + Elem::Concrete( + ref r @ RangeConcrete { + val: Concrete::Uint(..), + .. + }, + ) => candidates.push(Some(Concrete::max_of_type(&r.val).unwrap().into())), + Elem::Concrete( + ref r @ RangeConcrete { + val: Concrete::Int(..), + .. + }, + ) => candidates.push(Some(Concrete::min_of_type(&r.val).unwrap().into())), + _ => {} + } + } + + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ethers_core::types::{I256, U256}; + use solang_parser::pt::Loc; + + #[test] + fn and_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_bit_and(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(5))); + } + + #[test] + fn and_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_bit_and(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-15))); + } + + #[test] + fn and_bytes_bytes() { + let mut h: [u8; 32] = [0; 32]; + h[0..4].copy_from_slice(&[1, 1, 1, 1][..]); + let mut h2: [u8; 32] = [0; 32]; + h2[0..4].copy_from_slice(&[0, 1, 0, 1][..]); + let x = RangeConcrete::new(Concrete::from(h), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from(h2), Loc::Implicit); + let result = x.range_bit_and(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::from(h2)); + } + + #[test] + fn or_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_bit_or(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(15))); + } + + #[test] + fn or_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_bit_or(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-5))); + } + + #[test] + fn or_bytes_bytes() { + let mut h: [u8; 32] = [0; 32]; + h[0..4].copy_from_slice(&[1, 1, 1, 1][..]); + let mut h2: [u8; 32] = [0; 32]; + h2[0..4].copy_from_slice(&[0, 1, 0, 1][..]); + let x = RangeConcrete::new(Concrete::from(h), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from(h2), Loc::Implicit); + let result = x.range_bit_or(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::from(h)); + } + + #[test] + fn xor_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_bit_xor(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(10))); + } + + #[test] + fn xor_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_bit_xor(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(10))); + } + + #[test] + fn xor_bytes_bytes() { + let mut h: [u8; 32] = [0; 32]; + h[0..4].copy_from_slice(&[1, 1, 1, 1][..]); + let mut h2: [u8; 32] = [0; 32]; + h2[0..4].copy_from_slice(&[0, 1, 0, 1][..]); + let x = RangeConcrete::new(Concrete::from(h), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from(h2), Loc::Implicit); + let result = x.range_bit_xor(&y).unwrap().maybe_concrete_value().unwrap(); + + let mut expected: [u8; 32] = [0; 32]; + expected[0..3].copy_from_slice(&[1, 0, 1][..]); + assert_eq!(result.val, Concrete::from(expected)); + } + + #[test] + fn not_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let result = x.range_bit_not().unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::MAX << 4)); + } + + #[test] + fn not_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_bit_not().unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(14))); + } + + #[test] + fn not_bytes() { + let mut h: [u8; 32] = [0; 32]; + h[0..4].copy_from_slice(&[1; 4][..]); + let x = RangeConcrete::new(Concrete::from(h), Loc::Implicit); + let result = x.range_bit_not().unwrap().maybe_concrete_value().unwrap(); + + let mut expected: [u8; 32] = [255; 32]; + expected[0..4].copy_from_slice(&[254, 254, 254, 254][..]); + assert_eq!(result.val, Concrete::from(expected)); + } +} diff --git a/crates/graph/src/range/exec/cast.rs b/crates/graph/src/range/exec/cast.rs index cf3033cb..0c02d5a9 100644 --- a/crates/graph/src/range/exec/cast.rs +++ b/crates/graph/src/range/exec/cast.rs @@ -1,36 +1,35 @@ -use crate::nodes::Concrete; +use crate::nodes::{Builtin, Concrete}; use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; use ethers_core::types::{H256, U256}; use std::collections::BTreeMap; impl RangeCast for RangeConcrete { fn range_cast(&self, other: &Self) -> Option> { - Some(Elem::Concrete(RangeConcrete { - val: self.val.clone().cast_from(&other.val)?, - loc: self.loc, - })) + Some(Elem::Concrete(RangeConcrete::new( + self.val.clone().cast_from(&other.val)?, + self.loc, + ))) } } impl RangeCast> for RangeConcrete { fn range_cast(&self, other: &RangeDyn) -> Option> { - match (self.val.clone(), other.val.iter().take(1).next()) { - ( - Concrete::Bytes(size, val), - Some(( - _, - ( - Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) - | (Concrete::Bytes(size, val), None) => { - // let mut existing = other.val.clone(); + match ( + self.val.clone(), + other.val.values().take(1).next().map(|(a, _)| a), + ) { + (Concrete::Uint(size, val), o) if o.is_none() || o.unwrap().is_bytes() => { + RangeConcrete::new( + Concrete::Uint(size, val).cast(Builtin::Bytes((size / 8) as u8))?, + self.loc, + ) + .range_cast(other) + } + (Concrete::Bytes(size, val), o) if o.is_none() || o.unwrap().is_bytes() => { let new = val .0 .iter() @@ -43,28 +42,13 @@ impl RangeCast> for RangeConcrete { (idx, v) }) .collect::>(); - // existing.extend(new); Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(size))), new, other.loc, ))) } - ( - Concrete::DynBytes(val), - Some(( - _, - ( - Elem::Concrete(Self { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) - | (Concrete::DynBytes(val), None) => { - // let mut existing = other.val.clone(); + (Concrete::DynBytes(val), o) if o.is_none() || o.unwrap().is_bytes() => { let new = val .iter() .enumerate() @@ -76,28 +60,13 @@ impl RangeCast> for RangeConcrete { (idx, v) }) .collect::>(); - // existing.extend(new); Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(val.len()))), new, other.loc, ))) } - ( - Concrete::String(val), - Some(( - _, - ( - Elem::Concrete(Self { - val: Concrete::String(..), - .. - }), - _, - ), - )), - ) - | (Concrete::String(val), None) => { - // let mut existing = other.val.clone(); + (Concrete::String(val), o) if o.is_none() || o.unwrap().is_string() => { let new = val .chars() .enumerate() @@ -109,7 +78,6 @@ impl RangeCast> for RangeConcrete { (idx, v) }) .collect::>(); - // existing.extend(new); Some(Elem::ConcreteDyn(RangeDyn::new( Elem::from(Concrete::from(U256::from(val.len()))), new, @@ -123,125 +91,31 @@ impl RangeCast> for RangeConcrete { impl RangeCast> for RangeDyn { fn range_cast(&self, other: &Self) -> Option> { - let val: Option<(_, &(Elem, usize))> = self.val.iter().take(1).next(); - let o_val: Option<(_, &(Elem, usize))> = other.val.iter().take(1).next(); + let val: Option<&Elem> = self.val.values().take(1).next().map(|(a, _)| a); + let o_val: Option<&Elem> = other.val.values().take(1).next().map(|(a, _)| a); + match (val, o_val) { - ( - Some(( - _, - &( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - Some(( - _, - &( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) - | ( - Some(( - _, - &( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - None, - ) => Some(Elem::ConcreteDyn(self.clone())), - ( - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - _, - ), - )), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - _, - ), - )), - ) - | ( - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(..), - .. - }), - _, - ), - )), - None, - ) => Some(Elem::ConcreteDyn(self.clone())), - ( - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - _, - ), - )), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - _, - ), - )), - ) - | ( - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(..), - .. - }), - _, - ), - )), - None, - ) => Some(Elem::ConcreteDyn(self.clone())), - (Some((_, (l @ Elem::Reference(_), _))), None) => Some(l.clone()), - (None, Some((_, (r @ Elem::Reference(_), _)))) => Some(r.clone()), + (Some(elem), Some(o_elem)) + if elem.is_bytes() && o_elem.is_bytes() + || elem.is_uint() && o_elem.is_uint() + || elem.is_int() && o_elem.is_int() => + { + Some(Elem::ConcreteDyn(self.clone())) + } + (Some(elem), None) if elem.is_bytes() || elem.is_uint() || elem.is_int() => { + Some(Elem::ConcreteDyn(self.clone())) + } + (Some(Elem::Reference(_)), None) => Some(Elem::ConcreteDyn(self.clone())), + (None, Some(Elem::Reference(_))) => Some(Elem::ConcreteDyn(self.clone())), (None, None) => Some(Elem::ConcreteDyn(self.clone())), - _e => None, + _ => None, } } } impl RangeCast> for RangeDyn { fn range_cast(&self, other: &RangeConcrete) -> Option> { - let (_k, (val, _op)): (_, &(Elem, _)) = self.val.iter().take(1).next()?; + let val: &Elem<_> = self.val.values().take(1).next().map(|(a, _)| a)?; let o_val = &other.val; match (val, o_val) { ( @@ -252,7 +126,7 @@ impl RangeCast> for RangeDyn { Concrete::Bytes(size, _), ) => { let mut h = H256::default(); - for (i, (_, val)) in self.val.iter().take(*size as usize).enumerate() { + for (i, val) in self.val.values().take(*size as usize).enumerate() { match val { ( Elem::Concrete(RangeConcrete { @@ -288,3 +162,101 @@ impl RangeCast for Elem { } } } + +pub fn exec_cast( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // the weird thing about cast is that we really dont know until after the cast due to sizing things + // so we should just try them all then compare + let candidates = vec![ + lhs_min.range_cast(rhs_min), + lhs_min.range_cast(rhs_max), + lhs_max.range_cast(rhs_min), + lhs_max.range_cast(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ethers_core::types::I256; + use solang_parser::pt::Loc; + + #[test] + fn int_downcast() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-1500)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(0)), Loc::Implicit); + let result = x.range_cast(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(36))); + } + + #[test] + fn uint_downcast() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(1500)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(0)), Loc::Implicit); + let result = x.range_cast(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(220))); + } + + #[test] + fn int_weirdness() { + // type(int64).max + let v = Concrete::max_of_type(&Concrete::Int(64, I256::from(0i32))) + .unwrap() + .int_val() + .unwrap(); + // int128(type(int64).max) + let x = RangeConcrete::new(Concrete::Int(128, v), Loc::Implicit); + // int128(type(int64).max) + 1 + let x = x + .range_add(&RangeConcrete::new( + Concrete::Int(256, I256::from(1)), + Loc::Implicit, + )) + .unwrap() + .maybe_concrete_value() + .unwrap(); + let expected = x.val.int_val().unwrap() * I256::from(-1i32); + let y = RangeConcrete::new(Concrete::Int(64, I256::from(0)), Loc::Implicit); + // int64(int128(type(int64).max) + 1) + let result = x.range_cast(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(64, expected)); + } + + #[test] + fn int_upcast() { + let x = rc_int_sized(-101); + let y = rc_int256(-101); + let result = x.range_cast(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-101))); + } + + #[test] + fn bytes_upcast() { + let x = RangeConcrete::new(Concrete::from(vec![19, 55]), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from(vec![0, 0, 0, 0]), Loc::Implicit); + let result = x.range_cast(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::from(vec![19, 55, 0, 0])); + } +} diff --git a/crates/graph/src/range/exec/div.rs b/crates/graph/src/range/exec/div.rs deleted file mode 100644 index 62476206..00000000 --- a/crates/graph/src/range/exec/div.rs +++ /dev/null @@ -1,146 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -use ethers_core::types::{I256, U256}; - -impl RangeDiv for RangeConcrete { - fn range_div(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val == 0.into() { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val / rhs_val), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - if neg_v == &I256::from(0) { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), - ), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::from(0) { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - if r == &I256::from(0) { - None - } else { - let (val, overflow) = l.overflowing_div(*r); - if overflow { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, val), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } - - fn range_wrapping_div(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if rhs_val == 0.into() { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val / rhs_val), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - if neg_v == &I256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(val / neg_v.into_raw()) * I256::from(-1i32), - ), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - if val == &U256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v / I256::from_raw(*val)), - loc: self.loc, - })) - } - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - if r == &I256::from(0) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(0i32)), - loc: self.loc, - })) - } else { - let (val, overflow) = l.overflowing_div(*r); - if overflow { - None - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, val), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } -} - -impl RangeDiv for Elem { - fn range_div(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), - _ => None, - } - } - - fn range_wrapping_div(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/exec_op.rs b/crates/graph/src/range/exec/exec_op.rs index 8de2986d..8f774fbe 100644 --- a/crates/graph/src/range/exec/exec_op.rs +++ b/crates/graph/src/range/exec/exec_op.rs @@ -1,11 +1,9 @@ use crate::{ nodes::Concrete, - range::{elem::*, exec_traits::*}, + range::{elem::*, exec::*, exec_traits::*}, GraphBackend, GraphError, }; - -use ethers_core::types::{I256, U256}; -use solang_parser::pt::Loc; +use shared::RangeArena; impl ExecOp for RangeExpr { type GraphError = GraphError; @@ -15,11 +13,13 @@ impl ExecOp for RangeExpr { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError> { - let idx = self.arena_idx(analyzer); + let idx = self.arena_idx(arena); if let Some(idx) = idx { - if let Ok(t) = analyzer.range_arena().ranges[idx].try_borrow() { - if let Elem::Expr(expr) = &*t { + if let Some(t) = arena.ranges.get(idx) { + if let Elem::Expr(expr) = t { + tracing::trace!("hitting cache"); if maximize { if let Some(MinMaxed::Maximized(max)) = &expr.maximized { return Ok(*max.clone()); @@ -31,11 +31,12 @@ impl ExecOp for RangeExpr { } } - let res = self.exec(self.spread(analyzer)?, maximize, analyzer)?; + let res = self.exec(self.spread(analyzer, arena)?, maximize, analyzer, arena)?; if let Some(idx) = idx { - if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + if let Some(t) = arena.ranges.get_mut(idx) { if let Elem::Expr(expr) = &mut *t { + tracing::trace!("setting cache"); if maximize { expr.maximized = Some(MinMaxed::Maximized(Box::new(res.clone()))); } else { @@ -53,20 +54,28 @@ impl ExecOp for RangeExpr { &mut self, maximize: bool, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(), GraphError> { - self.lhs.cache_minimize(analyzer)?; - self.lhs.cache_maximize(analyzer)?; - self.rhs.cache_minimize(analyzer)?; - self.rhs.cache_maximize(analyzer)?; - let res = self.exec_op(maximize, analyzer)?; + tracing::trace!("minimize lhs"); + self.lhs.cache_minimize(analyzer, arena)?; + tracing::trace!("maximize lhs"); + self.lhs.cache_maximize(analyzer, arena)?; + tracing::trace!("minimize rhs"); + self.rhs.cache_minimize(analyzer, arena)?; + tracing::trace!("maximize rhs"); + self.rhs.cache_maximize(analyzer, arena)?; + tracing::trace!("exec"); + + let res = self.exec_op(maximize, analyzer, arena)?; + if maximize { self.maximized = Some(MinMaxed::Maximized(Box::new(res))); } else { self.minimized = Some(MinMaxed::Minimized(Box::new(res))); } - if let Some(idx) = self.arena_idx(analyzer) { - if let Ok(mut t) = analyzer.range_arena().ranges[idx].try_borrow_mut() { + if let Some(idx) = self.arena_idx(arena) { + if let Some(t) = arena.ranges.get_mut(idx) { if let Elem::Expr(expr) = &mut *t { if maximize { expr.maximized.clone_from(&self.maximized); @@ -90,6 +99,7 @@ impl ExecOp for RangeExpr { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if maximize { if let Some(v) = &self.flattened_max { @@ -99,11 +109,11 @@ impl ExecOp for RangeExpr { return Ok(*v.clone()); } - if let Some(v) = self.arenaized_flat_cache(maximize, analyzer) { + if let Some(v) = self.arenaized_flat_cache(maximize, arena) { return Ok(*v); } - let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(analyzer)?; + let (lhs_min, lhs_max, rhs_min, rhs_max) = self.simplify_spread(analyzer, arena)?; tracing::trace!( "simplifying op: {} {} {}, lhs_min: {}, lhs_max: {}, rhs_min: {}, rhs_max: {}", self.lhs, @@ -117,144 +127,144 @@ impl ExecOp for RangeExpr { let lhs_is_conc = lhs_min.is_conc() && lhs_max.is_conc(); let rhs_is_conc = rhs_min.is_conc() && rhs_max.is_conc(); - let mut finished = false; + let finished = false; let mut ret = Ok(Elem::Null); - if self.op == RangeOp::Cast { - // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete - if lhs_is_conc { - ret = self.exec_op(maximize, analyzer); - finished = true; - } else { - // we can drop the cast if the max of the dynamic lhs is less than the cast - let concretized_lhs = self.lhs.maximize(analyzer)?; - if matches!( - concretized_lhs.range_ord(&self.rhs, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ) { - ret = Ok(*self.lhs.clone()); - finished = true; - } - } - } else if matches!(self.op, RangeOp::Concat | RangeOp::Memcopy) { - // we can always execute a concat or memcopy - ret = self.exec_op(maximize, analyzer); - finished = true; - } else if matches!( - self.op, - RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex - ) { - match self.op { - RangeOp::GetLength => { - ret = if maximize { - Ok(lhs_max - .range_get_length() - .unwrap_or_else(|| Elem::Expr(self.clone()))) - } else { - Ok(lhs_min - .range_get_length() - .unwrap_or_else(|| Elem::Expr(self.clone()))) - }; - finished = true; - } - RangeOp::SetLength => { - ret = if maximize { - Ok(lhs_max - .range_set_length(&rhs_max) - .unwrap_or_else(|| Elem::Expr(self.clone()))) - } else { - Ok(lhs_min - .range_set_length(&rhs_min) - .unwrap_or_else(|| Elem::Expr(self.clone()))) - }; - finished = true; - } - RangeOp::GetIndex => { - if maximize { - let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val - .iter() - .try_fold( - None, - |mut acc: Option>, (key, (val, _))| { - if matches!( - key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, - Some(true) - ) { - if acc.is_none() - || matches!( - acc.clone().unwrap().range_ord(val, analyzer), - Some(std::cmp::Ordering::Greater) - ) - { - acc = Some(val.clone()); - Ok(acc) - } else { - Ok(acc) - } - } else { - Ok(acc) - } - }, - )? - .unwrap_or_else(|| Elem::Null), - _ => Elem::Expr(self.clone()), - }; - ret = Ok(res); - finished = true; - } else { - let res = match lhs_max { - Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val - .iter() - .try_fold( - None, - |mut acc: Option>, (key, (val, _))| { - if matches!( - key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, - Some(true) - ) { - if acc.is_none() - || matches!( - acc.clone().unwrap().range_ord(val, analyzer), - Some(std::cmp::Ordering::Less) - ) - { - acc = Some(val.clone()); - Ok(acc) - } else { - Ok(acc) - } - } else { - Ok(acc) - } - }, - )? - .unwrap_or_else(|| Elem::Null), - _ => Elem::Expr(self.clone()), - }; - ret = Ok(res); - finished = true; - } - } - RangeOp::SetIndices => { - ret = if maximize { - Ok(lhs_max - .range_set_indices(&rhs_max) - .unwrap_or_else(|| Elem::Expr(self.clone()))) - } else { - Ok(lhs_min - .range_set_indices(&rhs_min) - .unwrap_or_else(|| Elem::Expr(self.clone()))) - }; - finished = true; - } - _ => unreachable!(), - } - } + // if self.op == RangeOp::Cast { + // // for a cast we can *actually* evaluate dynamic elem if lhs side is concrete + // if lhs_is_conc { + // ret = self.exec_op(maximize, analyzer); + // finished = true; + // } else { + // // we can drop the cast if the max of the dynamic lhs is less than the cast + // let concretized_lhs = self.lhs.maximize(analyzer, arena)?; + // if matches!( + // concretized_lhs.range_ord(&self.rhs, analyzer), + // Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + // ) { + // ret = Ok(*self.lhs.clone()); + // finished = true; + // } + // } + // } else if matches!(self.op, RangeOp::Concat | RangeOp::Memcopy) { + // // we can always execute a concat or memcopy + // ret = self.exec_op(maximize, analyzer); + // finished = true; + // } else if matches!( + // self.op, + // RangeOp::SetIndices | RangeOp::SetLength | RangeOp::GetLength | RangeOp::GetIndex + // ) { + // match self.op { + // RangeOp::GetLength => { + // ret = if maximize { + // Ok(lhs_max + // .range_get_length() + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // } else { + // Ok(lhs_min + // .range_get_length() + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // }; + // finished = true; + // } + // RangeOp::SetLength => { + // ret = if maximize { + // Ok(lhs_max + // .range_set_length(&rhs_max) + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // } else { + // Ok(lhs_min + // .range_set_length(&rhs_min) + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // }; + // finished = true; + // } + // RangeOp::GetIndex => { + // if maximize { + // let res = match lhs_max { + // Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val + // .iter() + // .try_fold( + // None, + // |mut acc: Option>, (key, (val, _))| { + // if matches!( + // key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + // Some(true) + // ) { + // if acc.is_none() + // || matches!( + // acc.clone().unwrap().range_ord(val, arena), + // Some(std::cmp::Ordering::Greater) + // ) + // { + // acc = Some(val.clone()); + // Ok(acc) + // } else { + // Ok(acc) + // } + // } else { + // Ok(acc) + // } + // }, + // )? + // .unwrap_or_else(|| Elem::Null), + // _ => Elem::Expr(self.clone()), + // }; + // ret = Ok(res); + // finished = true; + // } else { + // let res = match lhs_max { + // Elem::ConcreteDyn(RangeDyn { ref val, .. }) => val + // .iter() + // .try_fold( + // None, + // |mut acc: Option>, (key, (val, _))| { + // if matches!( + // key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, + // Some(true) + // ) { + // if acc.is_none() + // || matches!( + // acc.clone().unwrap().range_ord(val, arena), + // Some(std::cmp::Ordering::Less) + // ) + // { + // acc = Some(val.clone()); + // Ok(acc) + // } else { + // Ok(acc) + // } + // } else { + // Ok(acc) + // } + // }, + // )? + // .unwrap_or_else(|| Elem::Null), + // _ => Elem::Expr(self.clone()), + // }; + // ret = Ok(res); + // finished = true; + // } + // } + // RangeOp::SetIndices => { + // ret = if maximize { + // Ok(lhs_max + // .range_set_indices(&rhs_max) + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // } else { + // Ok(lhs_min + // .range_set_indices(&rhs_min) + // .unwrap_or_else(|| Elem::Expr(self.clone()))) + // }; + // finished = true; + // } + // _ => unreachable!(), + // } + // } let parts = (lhs_min, lhs_max, rhs_min, rhs_max); match (lhs_is_conc, rhs_is_conc, finished) { (true, true, false) => { - ret = self.exec(parts, maximize, analyzer); + ret = self.exec(parts, maximize, analyzer, arena); } (_, _, false) => { ret = Ok(Elem::Expr(self.clone())); @@ -262,8 +272,8 @@ impl ExecOp for RangeExpr { _ => {} } - if let Some(_idx) = self.arena_idx(analyzer) { - self.set_arenaized_flattened(maximize, ret.clone()?, analyzer); + if let Some(_idx) = self.arena_idx(arena) { + self.set_arenaized_flattened(maximize, ret.clone()?, arena); } ret } @@ -271,6 +281,7 @@ impl ExecOp for RangeExpr { fn spread( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result< ( Elem, @@ -280,17 +291,17 @@ impl ExecOp for RangeExpr { ), GraphError, > { - let lhs_min = self.lhs.minimize(analyzer)?; - self.lhs.set_arenaized_cache(false, &lhs_min, analyzer); + let lhs_min = self.lhs.minimize(analyzer, arena)?; + self.lhs.set_arenaized_cache(false, &lhs_min, arena); - let lhs_max = self.lhs.maximize(analyzer)?; - self.lhs.set_arenaized_cache(true, &lhs_max, analyzer); + let lhs_max = self.lhs.maximize(analyzer, arena)?; + self.lhs.set_arenaized_cache(true, &lhs_max, arena); - let rhs_min = self.rhs.minimize(analyzer)?; - self.rhs.set_arenaized_cache(false, &rhs_min, analyzer); + let rhs_min = self.rhs.minimize(analyzer, arena)?; + self.rhs.set_arenaized_cache(false, &rhs_min, arena); - let rhs_max = self.rhs.maximize(analyzer)?; - self.rhs.set_arenaized_cache(true, &rhs_max, analyzer); + let rhs_max = self.rhs.maximize(analyzer, arena)?; + self.rhs.set_arenaized_cache(true, &rhs_max, arena); Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } @@ -298,6 +309,7 @@ impl ExecOp for RangeExpr { fn simplify_spread( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result< ( Elem, @@ -307,17 +319,17 @@ impl ExecOp for RangeExpr { ), GraphError, > { - let lhs_min = self.lhs.simplify_minimize(analyzer)?; - self.lhs.set_arenaized_flattened(false, &lhs_min, analyzer); + let lhs_min = self.lhs.simplify_minimize(analyzer, arena)?; + self.lhs.set_arenaized_flattened(false, &lhs_min, arena); - let lhs_max = self.lhs.simplify_maximize(analyzer)?; - self.lhs.set_arenaized_flattened(true, &lhs_max, analyzer); + let lhs_max = self.lhs.simplify_maximize(analyzer, arena)?; + self.lhs.set_arenaized_flattened(true, &lhs_max, arena); - let rhs_min = self.rhs.simplify_minimize(analyzer)?; - self.rhs.set_arenaized_flattened(false, &rhs_min, analyzer); + let rhs_min = self.rhs.simplify_minimize(analyzer, arena)?; + self.rhs.set_arenaized_flattened(false, &rhs_min, arena); - let rhs_max = self.rhs.simplify_maximize(analyzer)?; - self.rhs.set_arenaized_flattened(true, &rhs_max, analyzer); + let rhs_max = self.rhs.simplify_maximize(analyzer, arena)?; + self.rhs.set_arenaized_flattened(true, &rhs_max, arena); Ok((lhs_min, lhs_max, rhs_min, rhs_max)) } @@ -333,16 +345,17 @@ impl ExecOp for RangeExpr { ), maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { if maximize { - if let Some(MinMaxed::Maximized(v)) = self.arenaized_cache(maximize, analyzer) { + if let Some(MinMaxed::Maximized(v)) = self.arenaized_cache(maximize, analyzer, arena) { tracing::trace!("avoided execing via cache"); return Ok(*v); } } if !maximize { - if let Some(MinMaxed::Minimized(v)) = self.arenaized_cache(maximize, analyzer) { + if let Some(MinMaxed::Minimized(v)) = self.arenaized_cache(maximize, analyzer, arena) { tracing::trace!("avoided execing via cache"); return Ok(*v); } @@ -360,1449 +373,82 @@ impl ExecOp for RangeExpr { rhs_max ); - let lhs_min_neg = lhs_min.pre_evaled_is_negative(); - let lhs_max_neg = lhs_max.pre_evaled_is_negative(); - let rhs_min_neg = rhs_min.pre_evaled_is_negative(); - let rhs_max_neg = rhs_max.pre_evaled_is_negative(); - - let consts = ( - matches!( - lhs_min.range_ord(&lhs_max, analyzer), - Some(std::cmp::Ordering::Equal) + let res = match self.op { + RangeOp::GetLength => exec_get_length(&lhs_min, &lhs_max, maximize, analyzer, arena), + RangeOp::GetIndex => exec_get_index(&self.lhs, &self.rhs, maximize, analyzer, arena), + RangeOp::SetLength => exec_set_length(&lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize), + RangeOp::SetIndices => exec_set_indices( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, &self.rhs, maximize, analyzer, arena, ), - matches!( - rhs_min.range_ord(&rhs_max, analyzer), - Some(std::cmp::Ordering::Equal) + RangeOp::Memcopy => exec_memcopy(&lhs_min, &lhs_max, maximize), + RangeOp::Concat => exec_concat( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Add(unchecked) => exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, unchecked, analyzer, arena, + ), + RangeOp::Sub(unchecked) => exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, unchecked, analyzer, arena, + ), + RangeOp::Mul(unchecked) => exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, unchecked, analyzer, arena, + ), + RangeOp::Div(unchecked) => exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, unchecked, analyzer, arena, + ), + RangeOp::Mod => exec_mod( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Exp => exec_exp( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Min => exec_min( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Max => exec_max( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Gt => exec_gt(&lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize), + RangeOp::Lt => exec_lt(&lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize), + RangeOp::Gte => exec_gte(&lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize), + RangeOp::Lte => exec_lte(&lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize), + RangeOp::Eq => exec_eq_neq( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, true, analyzer, arena, + ), + RangeOp::Neq => exec_eq_neq( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, false, analyzer, arena, + ), + RangeOp::And => exec_and( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Or => exec_or( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Not => exec_not( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::BitAnd => exec_bit_and( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::BitOr => exec_bit_or( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::BitXor => exec_bit_xor( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::BitNot => exec_bit_not(&lhs_min, &lhs_max, maximize, analyzer, arena), + RangeOp::Shl => exec_shl( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Shr => exec_shr( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, + ), + RangeOp::Cast => exec_cast( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, maximize, analyzer, arena, ), - ); - - fn fallback( - this: &RangeExpr, - lhs: Elem, - rhs: Elem, - consts: (bool, bool), - ) -> Elem { - match consts { - (true, true) => Elem::Expr(RangeExpr::new(lhs, this.op, rhs)), - (false, true) => Elem::Expr(RangeExpr::new(*this.lhs.clone(), this.op, rhs)), - (true, false) => Elem::Expr(RangeExpr::new(lhs, this.op, *this.rhs.clone())), - (false, false) => Elem::Expr(this.clone()), - } } - - let res = match self.op { - RangeOp::GetLength => { - if maximize { - let new = lhs_max.clone(); - let new_max = new.simplify_maximize(analyzer)?; - let res = new_max.range_get_length(); - res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - let new_min = lhs_min.simplify_minimize(analyzer)?; - let res = new_min.range_get_length(); - res.unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::SetLength => { - if maximize { - lhs_max - .range_set_length(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_set_length(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::GetIndex => { - if maximize { - fn match_ty_max( - lhs_max: Elem, - rhs_min: Elem, - rhs_max: Elem, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match lhs_max { - Elem::ConcreteDyn(RangeDyn { val, .. }) => Ok(val - .iter() - .try_fold( - None, - |mut acc: Option>, (key, (val, _))| { - if matches!( - key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, - Some(true) - ) { - if acc.is_none() - || matches!( - acc.clone().unwrap().range_ord(val, analyzer), - Some(std::cmp::Ordering::Greater) - ) - { - acc = Some(val.clone()); - Ok(acc) - } else { - Ok(acc) - } - } else { - Ok(acc) - } - }, - )? - .unwrap_or_else(|| Elem::Null)), - Elem::Reference(_) => { - let new_max = lhs_max.simplify_maximize(analyzer)?; - if new_max == lhs_max { - Ok(Elem::Null) - } else { - match_ty_max(new_max, rhs_min, rhs_max, analyzer) - } - } - _ => Ok(Elem::Null), - } - } - match_ty_max(lhs_max.clone(), rhs_min, rhs_max.clone(), analyzer) - .unwrap_or_else(|_| fallback(self, lhs_max, rhs_max, consts)) - } else { - fn match_ty_min( - lhs_min: Elem, - rhs_min: Elem, - rhs_max: Elem, - analyzer: &impl GraphBackend, - ) -> Result, GraphError> { - match lhs_min { - Elem::ConcreteDyn(RangeDyn { val, .. }) => Ok(val - .iter() - .try_fold( - None, - |mut acc: Option>, (key, (val, _))| { - if matches!( - key.overlaps_dual(&rhs_min, &rhs_max, true, analyzer)?, - Some(true) - ) { - if acc.is_none() - || matches!( - acc.clone().unwrap().range_ord(val, analyzer), - Some(std::cmp::Ordering::Less) - ) - { - acc = Some(val.clone()); - Ok(acc) - } else { - Ok(acc) - } - } else { - Ok(acc) - } - }, - )? - .unwrap_or_else(|| Elem::Null)), - Elem::Reference(ref _r) => { - let new_min = lhs_min.simplify_minimize(analyzer)?; - if new_min == lhs_min { - Ok(Elem::Null) - } else { - match_ty_min(new_min, rhs_min, rhs_max, analyzer) - } - } - _ => Ok(Elem::Null), - } - } - match_ty_min(lhs_min.clone(), rhs_min.clone(), rhs_max, analyzer) - .unwrap_or_else(|_| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::SetIndices => { - if maximize { - let max = self.rhs.simplify_maximize(analyzer)?; - - lhs_max.range_set_indices(&rhs_max).unwrap_or_else(|| { - lhs_max - .range_set_indices(&max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - }) - } else { - let min = self.rhs.simplify_minimize(analyzer)?; - lhs_min.range_set_indices(&rhs_min).unwrap_or_else(|| { - lhs_min - .range_set_indices(&min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - }) - } - } - RangeOp::Memcopy => { - if maximize { - lhs_max.clone() - } else { - lhs_min.clone() - } - } - RangeOp::Add(unchecked) => { - if unchecked { - let mut candidates = vec![ - lhs_min.range_wrapping_add(&rhs_min), - lhs_min.range_wrapping_add(&rhs_max), - lhs_max.range_wrapping_add(&rhs_min), - lhs_max.range_wrapping_add(&rhs_max), - ]; - - // if they arent constants, we can test a normal add - if !matches!(consts, (true, true)) { - candidates.push(lhs_max.range_add(&rhs_max)); - candidates.push(lhs_min.range_add(&rhs_min)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value + the largest value - lhs_max - .range_add(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_add(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Sub(unchecked) => { - // quick check if rhs is const and zero, if so return min or max - if unchecked { - let mut candidates = vec![]; - // check if rhs contains zero, if so add lhs_min and max as candidates - - let one = Elem::from(Concrete::from(U256::from(1))); - let zero = Elem::from(Concrete::from(U256::from(0))); - let rhs_min_contains_zero = matches!( - rhs_min.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let rhs_max_contains_zero = matches!( - rhs_max.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if rhs_min_contains_zero && rhs_max_contains_zero { - candidates.push(Some(lhs_min.clone())); - candidates.push(Some(lhs_max.clone())); - } - - // If we have the below case, where the lhs - // contains the rhs, we can add zero. Futher more, if - // the lhs contains rhs - 1, we can add max as it - // would overflow to uint256.max - // zero min max uint256.max - // lhs: | - - |----------------------------| - - | - // rhs: | - - |--| - - - - - - - - - - - - - - - | - match lhs_max.range_ord(&rhs_min, analyzer) { - Some(std::cmp::Ordering::Less) => { - // We are going to overflow, zero not possible - } - Some(std::cmp::Ordering::Equal) => { - // We are going to at least be zero, - // we may overflow. check if rhs is const, otherwise - // add uint256.max as a candidate - candidates.push(Some(zero.clone())); - if !consts.1 { - candidates.push(zero.range_wrapping_sub(&one)); - } - } - Some(std::cmp::Ordering::Greater) => { - // No guarantees on overflow, check lhs_min - match lhs_min.range_ord(&rhs_min, analyzer) { - Some(std::cmp::Ordering::Less) => { - // fully contained, add zero and max - candidates.push(Some(zero.clone())); - candidates.push(zero.range_wrapping_sub(&one)); - } - Some(std::cmp::Ordering::Equal) => { - // We are going to at least be zero, - // we may overflow. check if rhs is const, otherwise - // add uint256.max as a candidate - candidates.push(Some(zero.clone())); - if !consts.1 { - candidates.push(zero.range_wrapping_sub(&one)); - } - } - Some(std::cmp::Ordering::Greater) => { - // current info: - // zero min max uint256.max - // lhs: | - - |----------------------------| - - | - // rhs: | - |----? - - - - - - - - - - - - - - - | - // figure out where rhs max is - match lhs_min.range_ord(&rhs_max, analyzer) { - Some(std::cmp::Ordering::Less) => { - // zero min - // lhs: | - - |---? - // rhs: | - |----| - // min max - // Add both - candidates.push(Some(zero.clone())); - candidates.push(zero.range_wrapping_sub(&one)); - } - Some(std::cmp::Ordering::Equal) => { - // zero min - // lhs: | - - |---? - // rhs: | |---| - // min max - // Add zero - candidates.push(Some(zero.clone())); - } - Some(std::cmp::Ordering::Greater) => { - // zero min - // lhs: | - - |---? - // rhs: |-----| - // min max - // Add nothing - } - _ => {} - } - } - _ => {} - } - } - _ => {} - } - - candidates.extend(vec![ - lhs_min.range_wrapping_sub(&rhs_min), - lhs_min.range_wrapping_sub(&rhs_max), - lhs_max.range_wrapping_sub(&rhs_min), - lhs_max.range_wrapping_sub(&rhs_max), - ]); - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, the largest value will always just be the the largest value - the smallest value - lhs_max - .range_sub(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - // if we are minimizing, the smallest value will always be smallest value - largest value - lhs_min - .range_sub(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Mul(unchecked) => { - if unchecked { - let mut candidates: Vec>> = vec![]; - let zero = Elem::from(Concrete::from(U256::from(0))); - let one = Elem::from(Concrete::from(U256::from(1))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - // check if rhs contains 1 - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - rhs_min.range_ord(&one, analyzer), - rhs_max.range_ord(&one, analyzer), - ) { - candidates.push(Some(lhs_max.clone())); - candidates.push(Some(lhs_min.clone())); - } - - // check if lhs contains 1 - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - lhs_min.range_ord(&one, analyzer), - lhs_max.range_ord(&one, analyzer), - ) { - candidates.push(Some(rhs_max.clone())); - candidates.push(Some(rhs_min.clone())); - } - - // check if rhs contains -1 - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - rhs_min.range_ord(&negative_one, analyzer), - rhs_max.range_ord(&negative_one, analyzer), - ) { - candidates.push(lhs_max.range_mul(&negative_one)); - candidates.push(lhs_min.range_mul(&negative_one)); - } - - // check if lhs contains -1 - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - lhs_min.range_ord(&negative_one, analyzer), - lhs_max.range_ord(&negative_one, analyzer), - ) { - candidates.push(rhs_max.range_mul(&negative_one)); - candidates.push(rhs_min.range_mul(&negative_one)); - } - - // check if rhs contains zero - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - rhs_min.range_ord(&zero, analyzer), - rhs_max.range_ord(&zero, analyzer), - ) { - candidates.push(Some(zero.clone())); - } - // check if lhs contains zero - if let ( - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal), - ) = ( - lhs_min.range_ord(&zero, analyzer), - lhs_max.range_ord(&zero, analyzer), - ) { - candidates.push(Some(zero.clone())); - } - candidates.extend(vec![ - lhs_min.range_wrapping_mul(&rhs_min), - lhs_min.range_wrapping_mul(&rhs_max), - lhs_max.range_wrapping_mul(&rhs_min), - lhs_max.range_wrapping_mul(&rhs_max), - ]); - let mut candidates = candidates.into_iter().flatten().collect::>(); - - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } else if maximize { - // if we are maximizing, and both mins are negative and both maxes are positive, - // we dont know which will be larger of the two (i.e. -1*2**255 * -1*2**255 > 100*100) - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (true, true, true, true) => { - // all negative, will be min * min because those are furthest from 0 resulting in the - // largest positive value - lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is larger or lhs_min * rhs_max is smaller - match (lhs_min.range_mul(&rhs_min), lhs_max.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr, analyzer) { - Some(std::cmp::Ordering::Less) => max_expr, - Some(std::cmp::Ordering::Greater) => min_expr, - _ => max_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => fallback(self, lhs_min, rhs_min, consts), - } - } - (_, false, _, false) => { - // rhs_max is positive, lhs_max is positive, guaranteed to be largest max value - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (false, false, true, true) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_min - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, true, false, false) => { - // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - lhs_max - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, _, true, _) => lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), - (false, true, _, _) | (_, _, false, true) => { - fallback(self, lhs_min, rhs_min, consts) - } - } - } else { - match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - (false, false, false, false) => { - // rhs_min is positive, lhs_min is positive, guaranteed to be smallest max value - lhs_min - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, true, true, true) => { - // all negative, will be max * max because those are closest to 0 resulting in the - // smallest positive value - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (true, false, true, false) => { - // we dont know if lhs_max * rhs_min is smaller or lhs_min * rhs_max is smaller - match (lhs_max.range_mul(&rhs_min), lhs_min.range_mul(&rhs_max)) { - (Some(min_expr), Some(max_expr)) => { - match min_expr.range_ord(&max_expr, analyzer) { - Some(std::cmp::Ordering::Less) => min_expr, - Some(std::cmp::Ordering::Greater) => max_expr, - _ => min_expr, - } - } - (None, Some(max_expr)) => max_expr, - (Some(min_expr), None) => min_expr, - (None, None) => fallback(self, lhs_min, rhs_min, consts), - } - } - (true, _, _, false) => { - // rhs_max is positive, lhs_min is negative, guaranteed to be largest min value - lhs_min - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (_, false, _, true) => { - // just lhs has a positive value, most negative will be lhs_max, rhs_max - lhs_max - .range_mul(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - (false, false, true, false) => lhs_max - .range_mul(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)), - (false, true, _, _) | (_, _, false, true) => { - fallback(self, lhs_min, rhs_min, consts) - } - } - } - } - RangeOp::Div(_unchecked) => { - let mut candidates = vec![ - lhs_min.range_div(&rhs_min), - lhs_min.range_div(&rhs_max), - lhs_max.range_div(&rhs_min), - lhs_max.range_div(&rhs_max), - ]; - - let one = Elem::from(Concrete::from(U256::from(1))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&one, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&one, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&one)); - candidates.push(lhs_max.range_div(&one)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_div(&negative_one)); - candidates.push(lhs_max.range_div(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_min is larger or lhs_max / rhs_max is larger - // match (lhs_min.range_div(&rhs_min), lhs_max.range_div(&rhs_max)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // max_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // min_expr - // } - // _ => { - // max_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (false, false, true, true) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, false, false) => { - // // since we are forced to go negative here, values closest to 0 will ensure we get the maximum - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, false, _) => { - // // lhs is positive, rhs min is positive, guaranteed to give largest - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, false) => { - // // lhs_max is positive and rhs_max is positive, guaranteed to be lhs_max and rhs_max - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, true, _) => { - // // at this point, its either all trues, or a single false - // // given that, to maximize, the only way to get a positive value is to use the most negative values - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (false, false, false, false) => { - // // smallest number will be lhs_min / rhs_min since both are positive - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, true) => { - // // smallest number will be lhs_max / rhs_min since both are negative - // lhs_max.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, true, false) => { - // // The way to maintain most negative value is lhs_min / rhs_max, all others would go - // // positive or guaranteed to be closer to 0 - // lhs_min.range_div(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, false, true, false) => { - // // we dont know if lhs_min / rhs_max is larger or lhs_max / rhs_min is larger - // match (lhs_min.range_div(&rhs_max), lhs_max.range_div(&rhs_min)) { - // (Some(min_expr), Some(max_expr)) => { - // match min_expr.range_ord(&max_expr) { - // Some(std::cmp::Ordering::Less) => { - // min_expr - // } - // Some(std::cmp::Ordering::Greater) => { - // max_expr - // } - // _ => { - // min_expr - // } - // } - // } - // (None, Some(max_expr)) => { - // max_expr - // } - // (Some(min_expr), None) => { - // min_expr - // } - // (None, None) => Elem::Expr(self.clone()) - // } - // } - // (_, false, true, _) => { - // // We are going negative here, so it will be most positive / least negative - // lhs_max.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, _) => { - // // We are going negative here, so it will be most negative / least positive - // lhs_min.range_div(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - // RangeOp::Mod => { - // lhs.range_mod(&rhs).unwrap_or(Elem::Expr(self.clone())) - // } - RangeOp::Min => { - let candidates = vec![ - lhs_min.range_min(&rhs_min), - lhs_min.range_min(&rhs_max), - lhs_max.range_min(&rhs_min), - lhs_max.range_min(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // // counter-intuitively, we want the maximum value from a call to minimum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the minimum values but getting the larger of the minimum - // lhs_min.range_max(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // lhs_min //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // rhs_min //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Max => { - let candidates = vec![ - lhs_min.range_max(&rhs_min), - lhs_min.range_max(&rhs_max), - lhs_max.range_max(&rhs_min), - lhs_max.range_max(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - // if maximize { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (true, _, true, _) | (false, _, false, _) => { - // lhs_max.range_max(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, _, false, false) => { - // rhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, false, true, _) => { - // lhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } else { - // match (lhs_min_neg, lhs_max_neg, rhs_min_neg, rhs_max_neg) { - // (_, true, _, true) | (_, false, _, false) => { - // // counter-intuitively, we want the minimum value from a call to maximum - // // this is due to the symbolic nature of the evaluation. We are still - // // using the maximum values but getting the smaller of the maximum - // lhs_max.range_min(&rhs_max).unwrap_or(Elem::Expr(self.clone())) - // } - // (_, false, true, true) => { - // lhs_max //.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (true, true, _, false) => { - // rhs_max //lhs_min.range_min(&rhs_min).unwrap_or(Elem::Expr(self.clone())) - // } - // (false, true, _, _) | (_, _, false, true)=> { - // panic!("unsatisfiable range") - // } - // } - // } - } - RangeOp::Gt => { - if maximize { - lhs_max - .range_gt(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_gt(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Lt => { - if maximize { - lhs_min - .range_lt(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_max - .range_lt(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Gte => { - if maximize { - lhs_max - .range_gte(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_min - .range_gte(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Lte => { - if maximize { - lhs_min - .range_lte(&rhs_max) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } else { - lhs_max - .range_lte(&rhs_min) - .unwrap_or_else(|| fallback(self, lhs_min, rhs_min, consts)) - } - } - RangeOp::Eq => { - // prevent trying to eval when we have dependents - if !lhs_min.dependent_on(analyzer).is_empty() - || !lhs_max.dependent_on(analyzer).is_empty() - || !rhs_min.dependent_on(analyzer).is_empty() - || !rhs_max.dependent_on(analyzer).is_empty() - { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - - if maximize { - // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min, analyzer); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max, analyzer); - - // if lhs max is less than the rhs min, it has to be false - if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // if lhs min is greater than the rhs max, it has to be false - if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - - // lhs_max >= rhs_min - // lhs_min <= rhs_max - // therefore its possible to set some value to true here - if lhs_max_rhs_min_ord.is_some() && lhs_min_rhs_max_ord.is_some() { - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }) - } else { - fallback(self, lhs_min, rhs_min, consts) - } - } else { - // check if either lhs element is *not* contained by rhs - match ( - // check if lhs is constant - lhs_min.range_ord(&lhs_max, analyzer), - // check if rhs is constant - rhs_min.range_ord(&rhs_max, analyzer), - // check if lhs is equal to rhs - lhs_min.range_ord(&rhs_min, analyzer), - ) { - ( - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - Some(std::cmp::Ordering::Equal), - ) => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }), - // if any of those are not equal, we can construct - // an element that is true - _ => Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }), - } - } - } - RangeOp::Neq => { - // prevent trying to eval when we have dependents - if !lhs_min.dependent_on(analyzer).is_empty() - || !lhs_max.dependent_on(analyzer).is_empty() - || !rhs_min.dependent_on(analyzer).is_empty() - || !rhs_max.dependent_on(analyzer).is_empty() - { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - let loc = if let Some(c) = lhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = lhs_max.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_min.maybe_concrete() { - c.loc - } else if let Some(c) = rhs_max.maybe_concrete() { - c.loc - } else { - Loc::Implicit - }; - - if maximize { - // the only case here in which we can't assert that - // true is the maximum is when they are both consts and equal - if matches!(consts, (true, true)) { - // both are consts, check if they are equal - if matches!( - lhs_min.range_ord(&rhs_min, analyzer), - Some(std::cmp::Ordering::Equal) - ) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - })); - } - } - - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - }) - } else { - // we *want* to produce false - if matches!(consts, (true, true)) { - // both are consts, check if we are forced to return true - if matches!( - lhs_min.range_ord(&rhs_min, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Less) - ) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - } - - // check for any overlap - let lhs_max_rhs_min_ord = lhs_max.range_ord(&rhs_min, analyzer); - let lhs_min_rhs_max_ord = lhs_min.range_ord(&rhs_max, analyzer); - - // if lhs max is less than the rhs min, it has to be != (true) - if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - - // if lhs min is greater than the rhs max, it has to be != (true) - if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { - return Ok(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc, - })); - } - - // we can force an equal value if needed - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc, - }) - // fallback(self, lhs_min, rhs_min, consts) - } - } - RangeOp::Shl => { - let candidates = vec![ - lhs_min.range_shl(&rhs_min), - lhs_min.range_shl(&rhs_max), - lhs_max.range_shl(&rhs_min), - lhs_max.range_shl(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Shr => { - let candidates = vec![ - lhs_min.range_shr(&rhs_min), - lhs_min.range_shr(&rhs_max), - lhs_max.range_shr(&rhs_min), - lhs_max.range_shr(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::And => { - let candidates = vec![ - lhs_min.range_and(&rhs_min), - lhs_min.range_and(&rhs_max), - lhs_max.range_and(&rhs_min), - lhs_max.range_and(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Or => { - let candidates = vec![ - lhs_min.range_or(&rhs_min), - lhs_min.range_or(&rhs_max), - lhs_max.range_or(&rhs_min), - lhs_max.range_or(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Not => { - assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); - let candidates = vec![lhs_min.range_not(), lhs_min.range_not()]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Cast => { - // the weird thing about cast is that we really dont know until after the cast due to sizing things - // so we should just try them all then compare - let candidates = vec![ - lhs_min.range_cast(&rhs_min), - lhs_min.range_cast(&rhs_max), - lhs_max.range_cast(&rhs_min), - lhs_max.range_cast(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Exp => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_exp(&rhs_min), - lhs_min.range_exp(&rhs_max), - lhs_max.range_exp(&rhs_min), - lhs_max.range_exp(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitAnd => { - let mut candidates = vec![ - lhs_min.range_bit_and(&rhs_min), - lhs_min.range_bit_and(&rhs_max), - lhs_max.range_bit_and(&rhs_min), - lhs_max.range_bit_and(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&zero)); - candidates.push(lhs_max.range_bit_and(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_and(&negative_one)); - candidates.push(lhs_max.range_bit_and(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitOr => { - let mut candidates = vec![ - lhs_min.range_bit_or(&rhs_min), - lhs_min.range_bit_or(&rhs_max), - lhs_max.range_bit_or(&rhs_min), - lhs_max.range_bit_or(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&zero)); - candidates.push(lhs_max.range_bit_or(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_or(&negative_one)); - candidates.push(lhs_max.range_bit_or(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitXor => { - let mut candidates = vec![ - lhs_min.range_bit_xor(&rhs_min), - lhs_min.range_bit_xor(&rhs_max), - lhs_max.range_bit_xor(&rhs_min), - lhs_max.range_bit_xor(&rhs_max), - ]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); - - let min_contains = matches!( - rhs_min.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - // if the rhs contains zero, in xor, thats just itself - candidates.push(lhs_max.range_bit_xor(&zero)); - } - - let min_contains = matches!( - rhs_min.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - rhs_max.range_ord(&negative_one, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - candidates.push(lhs_min.range_bit_xor(&negative_one)); - candidates.push(lhs_max.range_bit_xor(&negative_one)); - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::BitNot => { - let mut candidates = vec![lhs_min.range_bit_not(), lhs_max.range_bit_not()]; - - let zero = Elem::from(Concrete::from(U256::from(0))); - - let min_contains = matches!( - lhs_min.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) - ); - - let max_contains = matches!( - lhs_max.range_ord(&zero, analyzer), - Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) - ); - - if min_contains && max_contains { - match lhs_min { - Elem::Concrete( - ref r @ RangeConcrete { - val: Concrete::Uint(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::max(&r.val).unwrap()))), - Elem::Concrete( - ref r @ RangeConcrete { - val: Concrete::Int(..), - .. - }, - ) => candidates.push(Some(Elem::from(Concrete::min(&r.val).unwrap()))), - _ => {} - } - } - - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - RangeOp::Concat => { - // TODO: improve with smarter stuff - let candidates = vec![ - lhs_min.range_concat(&rhs_min), - lhs_min.range_concat(&rhs_max), - lhs_max.range_concat(&rhs_min), - lhs_max.range_concat(&rhs_max), - ]; - let mut candidates = candidates.into_iter().flatten().collect::>(); - candidates.sort_by(|a, b| match a.range_ord(b, analyzer) { - Some(r) => r, - _ => std::cmp::Ordering::Less, - }); - - if candidates.is_empty() { - return Ok(fallback(self, lhs_min, rhs_min, consts)); - } - - if maximize { - candidates[candidates.len() - 1].clone() - } else { - candidates[0].clone() - } - } - _ => fallback(self, lhs_min, rhs_min, consts), - }; + .unwrap_or_else(|| Elem::Expr(self.clone())); + tracing::trace!("result: {res}"); Ok(res) } } diff --git a/crates/graph/src/range/exec/exp.rs b/crates/graph/src/range/exec/exp.rs deleted file mode 100644 index 97462da5..00000000 --- a/crates/graph/src/range/exec/exp.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; -use ethers_core::types::U256; - -impl RangeExp for RangeConcrete { - fn range_exp(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - if let Some(num) = lhs_val.checked_pow(rhs_val) { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(num.min(max.into_u256().unwrap())), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(max.into_u256().unwrap()), - loc: self.loc, - })) - } - } - _ => match (&self.val, &other.val) { - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let pow2 = val % U256::from(2) == 0.into(); - if val > &U256::from(u32::MAX) { - if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::max(&self.val).unwrap(), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::min(&self.val).unwrap(), - loc: self.loc, - })) - } - } else { - let min = Concrete::min(&self.val).unwrap().int_val().unwrap(); - let max = Concrete::max(&self.val).unwrap().int_val().unwrap(); - - if let Some(num) = neg_v.checked_pow(val.as_u32()) { - if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, num.min(max)), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, num.max(min)), - loc: self.loc, - })) - } - } else if pow2 { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::max(&self.val).unwrap(), - loc: self.loc, - })) - } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::min(&self.val).unwrap(), - loc: self.loc, - })) - } - } - } - _ => None, - }, - } - } -} - -impl RangeExp for Elem { - fn range_exp(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_exp(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => { - Some(Elem::from(Concrete::from(U256::from(1)))) - } - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/logical.rs b/crates/graph/src/range/exec/logical.rs deleted file mode 100644 index 5d3c6129..00000000 --- a/crates/graph/src/range/exec/logical.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -impl RangeUnary for RangeConcrete { - fn range_not(&self) -> Option> { - match self.val { - Concrete::Bool(b) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(!b), - loc: self.loc, - })), - _ => None, - } - } - - fn range_and(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(*a && *b), - loc: self.loc, - })), - _ => None, - } - } - - fn range_or(&self, other: &Self) -> Option> { - match (&self.val, &other.val) { - (Concrete::Bool(a), Concrete::Bool(b)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(*a || *b), - loc: self.loc, - })), - _ => None, - } - } -} - -impl RangeUnary for Elem { - fn range_not(&self) -> Option> { - match self { - Elem::Concrete(a) => a.range_not(), - _ => None, - } - } - fn range_and(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_and(b), - _ => None, - } - } - fn range_or(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_or(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/math_ops/add.rs b/crates/graph/src/range/exec/math_ops/add.rs new file mode 100644 index 00000000..980ead1f --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/add.rs @@ -0,0 +1,569 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{I256, U256}; +use solang_parser::pt::Loc; + +impl RangeAdd for RangeConcrete { + fn range_add(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + // `max_of_type` cannot fail on uint + let max_uint = Concrete::max_of_type(&self.val) + .unwrap() + .into_u256() + .unwrap(); + // min { a + b, max } to cap at maximum of lhs sizing + let op_res = lhs_val.saturating_add(rhs_val).min(max_uint); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => { + match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + // neg_v guaranteed to be negative here + let abs = neg_v.unsigned_abs(); + if abs > *val { + // |b| - a + let op_res = + I256::from_raw(abs.saturating_sub(*val)) * I256::from(-1i32); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + // a - |b| + let op_res = val.saturating_sub(abs); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + // `min_of_type` cannot fail on int + let min = Concrete::min_of_type(&self.val).unwrap().int_val().unwrap(); + // lhs + rhs when both are negative is effectively lhs - rhs which means + // we saturate at the minimum value of the left hand side. + // therefore, max{ l + r, min } is the result + let op_res = l.saturating_add(*r).max(min); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + } + } + } + } + + fn range_wrapping_add(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let op_res = lhs_val.overflowing_add(rhs_val).0; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(..), Concrete::Int(..)) + | (Concrete::Int(..), Concrete::Uint(..)) => { + // just fall back to normal implementation because + // a positive and negative cannot overflow in addition + self.range_add(other) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let op_res = l.overflowing_add(*r).0; + let val = Concrete::Int(*lhs_size, op_res).size_wrap(); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } +} + +impl RangeAdd for Elem { + fn range_add(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), _) if a.val.is_zero() => Some(other.clone()), + (_, Elem::Concrete(b)) if b.val.is_zero() => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_add(b), + _ => None, + } + } + fn range_wrapping_add(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), _) if a.val.is_zero() => Some(other.clone()), + (_, Elem::Concrete(b)) if b.val.is_zero() => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_add(b), + _ => None, + } + } +} + +/// Executes an addition given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound of the operation. +/// +/// ### Explanation +/// A fact about addition is that the smallest value possible (in unbounded integer space), is between two _minimum_ values and the largest +/// is between two _maximum_ values. This fact is used in normal "unbounded" (really, saturating) addition calculations as well as wrapping addition as basis for another fact: +/// +/// In wrapping addition, if the bounds allow for optionally wrapping (e.g.: minimum + minimum does not wrap, but maximum + maximum does wrap), we can +/// by extension include *both* the type's maximum and minimum. +/// +/// For example, assume: +///uint256 x: [100, 2256-1] +///uint256 y: [100, 2256-1] +///unchecked { x + y } +/// +/// +/// In this addition of `x+y`, `100+100` does not wrap, but 2256-1 + 2256-1 does. We can construct a value of x and y such that +/// the result of `x+y` is equal to 2256-1 (100 + 2256-101) or `0` (100 + 2256-99). Therefore, the new bounds +/// on `unchecked { x + y }` is [0, 2256-1]. +/// +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked add` operation: +/// +///| Add | Uint | Int | BytesX | Address | Bytes | String | +///|-----------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|--------|---------|-------|--------| +///| **Uint** | min: lhsmin + rhsmin
max: lhsmax + rhsmax | min: lhsmin + rhsmin
max: lhsmax + rhsmax | N/A | N/A | N/A | N/A | +///| **Int** | min: lhsmin + rhsmin
max: lhsmax + rhsmax | min: lhsmin + rhsmin
max: lhsmax + rhsmax | N/A | N/A | N/A | N/A | +///| **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **String** | N/A | N/A | N/A | N/A | N/A | N/A | +/// +/// Truth table for `wrapping add` operation: +/// +///| Wrapping Add | Uint | Int | BytesX | Address | Bytes | String | +///|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------|---------|-------|--------| +///| **Uint** | min: {0, lhsmin + rhsmin}
max: {2size - 1, lhsmax + rhsmax} | min: {0, lhsmin + rhsmin}
max: {2size - 1, lhsmax + rhsmax} | N/A | N/A | N/A | N/A | +///| **Int** | min: {-2size-1, lhsmin + rhsmin}
max: {2size - 1, lhsmax + rhsmax} | min: {0, lhsmin + rhsmin}
max: {2size - 1, lhsmax + rhsmax} | N/A | N/A | N/A | N/A | +///| **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **String** | N/A | N/A | N/A | N/A | N/A | N/A | +pub fn exec_add( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + wrapping: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + tracing::trace!("exec add: unchecked - {wrapping}; maximize - {maximize};"); + if wrapping { + let mut candidates = vec![]; + let mut all_overflowed = true; + let mut one_overflowed = false; + + let zero = Elem::Concrete(RangeConcrete::new( + Concrete::from(U256::zero()), + Loc::Implicit, + )); + let add_candidate = |lhs: &Elem, + rhs: &Elem, + candidates: &mut Vec>, + all_overflowed: &mut bool, + one_overflowed: &mut bool, + arena: &mut RangeArena>| { + if let Some(c) = lhs.range_wrapping_add(rhs) { + let lhs_neg = matches!(lhs.range_ord(&zero, arena), Some(std::cmp::Ordering::Less)); + let rhs_neg = matches!(rhs.range_ord(&zero, arena), Some(std::cmp::Ordering::Less)); + let signed = lhs_neg || rhs_neg; + + let overflowed = if signed { + // signed safemath: (rhs >= 0 && c >= lhs) || (rhs < 0 && c < lhs) ==> no overflowed --invert-> overflowed + (rhs_neg + || matches!(c.range_ord(lhs, arena), Some(std::cmp::Ordering::Greater))) + && (!rhs_neg + || matches!( + c.range_ord(lhs, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + )) + } else { + // unsigned safemath: c < a ==> overflowed + matches!(c.range_ord(lhs, arena), Some(std::cmp::Ordering::Less)) + }; + + if *all_overflowed && !overflowed { + *all_overflowed = false; + } + + if !*one_overflowed && overflowed { + *one_overflowed = true; + } + + candidates.push(c); + } + }; + + add_candidate( + lhs_min, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_min, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + + // We need to check if there is a value in [lhs_min, lhs_max] that when added to a value in [rhs_min, rhs_max] + // will not overflow + // + // If that is the case we can additionally compare saturating addition cases to the candidates + if !all_overflowed { + // We didnt overflow in some case, add saturating addition candidates + let saturating_add = + |lhs: &Elem<_>, rhs: &Elem<_>, candidates: &mut Vec>| -> bool { + if let Some(c) = lhs.range_add(rhs) { + candidates.push(c); + true + } else { + false + } + }; + // if max + max returned a result, that saturating addition will be largest possible candidate + if !saturating_add(lhs_max, rhs_max, &mut candidates) { + saturating_add(lhs_min, rhs_min, &mut candidates); + saturating_add(lhs_min, rhs_max, &mut candidates); + saturating_add(lhs_max, rhs_min, &mut candidates); + } + } + + // We need to check if there is a value in [lhs_min, lhs_max] that when added to a value in [rhs_min, rhs_max] + // will overflow and can result in the minimum value of the type + // + // We can do this by checking if we can conditionally overflow. + let conditional_overflow = !all_overflowed && one_overflowed; + if conditional_overflow { + let add_min = |elem: &Elem, candidates: &mut Vec>| { + if let Some(c) = elem.maybe_concrete() { + if let Some(min) = Concrete::min_of_type(&c.val) { + candidates.push(RangeConcrete::new(min, c.loc).into()); + } + + if let Some(max) = Concrete::max_of_type(&c.val) { + candidates.push(RangeConcrete::new(max, c.loc).into()); + } + } + }; + // We are able to conditionally overflow, so add min + add_min(lhs_min, &mut candidates); + add_min(lhs_max, &mut candidates); + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value + the largest value + lhs_max.range_add(rhs_max) + } else { + // if we are minimizing, the smallest value will always just be the the smallest value + the smallest value + lhs_min.range_add(rhs_min) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use ethers_core::types::U256; + use solang_parser::pt::Loc; + + #[test] + fn uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(20))); + } + + #[test] + fn saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::MAX)); + } + + #[test] + fn sized_saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(8, U256::from(254)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(254)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(255))); + } + + #[test] + fn int_big_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(14))); + } + + #[test] + fn big_int_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(1)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-14i32))); + } + + #[test] + fn int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-30i32))); + } + + #[test] + fn min_int_min_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MIN)); + } + + #[test] + fn saturating_int_int() { + let x = RangeConcrete::new( + Concrete::Int(256, I256::MIN + I256::from(1i32)), + Loc::Implicit, + ); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-2i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MIN)); + } + + #[test] + fn sized_saturating_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(-2i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn wrapping_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(2)), Loc::Implicit); + let result = x + .range_wrapping_add(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(1))); + } + + #[test] + fn sized_wrapping_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(8, U256::from(255)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(2)), Loc::Implicit); + let result = x + .range_wrapping_add(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(1))); + } + + #[test] + fn wrapping_big_int_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(1)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-14i32))); + } + + #[test] + fn wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x + .range_wrapping_add(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MAX)); + } + + #[test] + fn sized_wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-128i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(-1i32)), Loc::Implicit); + let result = x + .range_wrapping_add(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(127i32))); + } + + #[test] + fn exec_wrapping_min_int_min_int() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let min = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit).into(); + let max = RangeConcrete::new(Concrete::Int(256, I256::MAX), Loc::Implicit).into(); + let max_result = exec_add(&min, &min, &min, &max, true, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(256, I256::MAX)); + let min_result = exec_add(&min, &min, &min, &max, false, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(256, I256::MIN)); + } + + #[test] + fn exec_sized_uint_uint_saturating() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(105).into(); + let lhs_max = rc_uint_sized(150).into(); + let rhs_min = rc_uint_sized(10).into(); + let rhs_max = rc_uint_sized(200).into(); + + let max_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(115))); + } + + #[test] + fn exec_sized_wrapping_uint_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(105).into(); + let lhs_max = rc_uint_sized(150).into(); + let rhs_min = rc_uint_sized(10).into(); + let rhs_max = rc_uint_sized(200).into(); + + let max_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_int_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(127).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_wrapping_int_int_max() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(-100).into(); + let rhs_min = rc_int_sized(-5).into(); + let rhs_max = rc_int_sized(5).into(); + + let max_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_add( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } +} diff --git a/crates/graph/src/range/exec/math_ops/div.rs b/crates/graph/src/range/exec/math_ops/div.rs new file mode 100644 index 00000000..00ed109d --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/div.rs @@ -0,0 +1,494 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{I256, U256}; +use solang_parser::pt::Loc; + +impl RangeDiv for RangeConcrete { + fn range_div(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val == 0.into() { + None + } else { + let op_res = lhs_val / rhs_val; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + // Divisor cannot be zero because it would have been converted + // to a uint + let abs = neg_v.into_sign_and_abs().1; + let op_res = I256::from_raw(val / abs).saturating_div(I256::from(-1i32)); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + if val == &U256::from(0) { + None + } else { + let abs = neg_v.into_sign_and_abs().1; + let op_res = I256::from_raw(abs / *val).saturating_div(I256::from(-1i32)); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + if r == &I256::from(0) { + None + } else { + let (op_res, overflow) = l.overflowing_div(*r); + if overflow { + let max = Concrete::max_of_type(&self.val).unwrap().int_val().unwrap(); + let val = Concrete::Int(*lhs_size, max); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + } + _ => None, + }, + } + } + + fn range_wrapping_div(&self, other: &Self) -> Option> { + // Only negative Int / negative Int needs overflowing_div + match (&self.val, &other.val) { + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) + if *l < I256::from(0i32) && *r < I256::from(0i32) => + { + let op_res = l.overflowing_div(*r).0; + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => self.range_div(other), + } + } +} + +impl RangeDiv for Elem { + fn range_div(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), + _ => None, + } + } + + fn range_wrapping_div(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_div(b), + _ => None, + } + } +} + +/// Executes an division given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked div` operation: +/// +/// `todo!()` +/// +/// Truth table for `wrapping div` operation: +/// +/// `todo!()` +/// +pub fn exec_div( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + wrapping: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let mut candidates = vec![]; + let saturating_div = |lhs: &Elem<_>, rhs: &Elem<_>, candidates: &mut Vec>| { + if let Some(c) = lhs.range_div(rhs) { + candidates.push(c); + } + }; + + let one = Elem::from(Concrete::from(U256::from(1))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + + let min_contains = matches!( + rhs_min.range_ord(&one, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains = matches!( + rhs_max.range_ord(&one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + // for division, if 1 is contained by the denominator, we can just add the left hand side as candidates + if min_contains && max_contains { + candidates.push(lhs_min.clone()); + candidates.push(lhs_max.clone()); + } + + let min_contains_neg_one = matches!( + rhs_min.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + ); + + let max_contains_neg_one = matches!( + rhs_max.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + if min_contains_neg_one && max_contains_neg_one { + // if the divisor contains -1, we can just saturating multiply by -1 + if matches!( + lhs_min.range_ord(&negative_one, arena), + Some(std::cmp::Ordering::Less) + ) { + // lhs can be negative, check if it contains int_min + let type_min = Concrete::min_of_type(&lhs_min.maybe_concrete().unwrap().val).unwrap(); + let int_val = type_min.int_val().unwrap(); + let min = Elem::from(type_min); + let min_plus_one = Elem::Concrete(rc_i256_sized(int_val + I256::from(1i32))); + + let lhs_contains_int_min = matches!( + lhs_min.range_ord(&min, arena), + Some(std::cmp::Ordering::Equal) + ); + + let max_contains_int_min_plus_one = matches!( + rhs_max.range_ord(&min_plus_one, arena), + Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) + ); + + // add int max to candidates + if lhs_contains_int_min && max_contains_int_min_plus_one { + if let Some(c) = min_plus_one.range_mul(&negative_one) { + candidates.push(c); + } + } else if let Some(c) = lhs_min.range_mul(&negative_one) { + // add min * -1 + candidates.push(c); + } + } else if let Some(c) = lhs_min.range_mul(&negative_one) { + // add min * -1 + candidates.push(c); + } + + if let Some(c) = lhs_max.range_mul(&negative_one) { + candidates.push(c); + } + } + + if wrapping { + let mut all_overflowed = true; + let mut one_overflowed = false; + let add_candidate = |lhs: &Elem, + rhs: &Elem, + candidates: &mut Vec>, + all_overflowed: &mut bool, + one_overflowed: &mut bool, + arena: &mut RangeArena>| { + if let Some(c) = lhs.range_wrapping_div(rhs) { + let mut overflowed = false; + let neg_one = + RangeConcrete::new(Concrete::Int(8, I256::from(-1i32)), Loc::Implicit).into(); + if matches!( + lhs.range_ord(&neg_one, arena), + Some(std::cmp::Ordering::Less) + ) { + // rhs == -1 + let div_neg_one = matches!( + rhs.range_ord(&neg_one, arena), + Some(std::cmp::Ordering::Equal) + ); + + let type_min = + Concrete::min_of_type(&lhs.maybe_concrete().unwrap().val).unwrap(); + let min = RangeConcrete::new(type_min, Loc::Implicit).into(); + + // lhs == INT_MIN + let num_int_min = + matches!(lhs.range_ord(&min, arena), Some(std::cmp::Ordering::Equal)); + if div_neg_one && num_int_min { + overflowed = true; + } + } + + if *all_overflowed && !overflowed { + *all_overflowed = false; + } + + if !*one_overflowed && overflowed { + *one_overflowed = true; + } + + candidates.push(c); + } + }; + + add_candidate( + lhs_min, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_min, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + + if one_overflowed { + let add_min = |elem: &Elem, candidates: &mut Vec>| { + if let Some(c) = elem.maybe_concrete() { + if let Some(min) = Concrete::min_of_type(&c.val) { + candidates.push(RangeConcrete::new(min, c.loc).into()); + } + } + }; + add_min(lhs_min, &mut candidates); + add_min(lhs_max, &mut candidates); + } + } else { + // without inspecting types of lhs and rhs, its easiest just to run them all and + // sort + saturating_div(lhs_min, rhs_min, &mut candidates); + saturating_div(lhs_min, rhs_max, &mut candidates); + saturating_div(lhs_max, rhs_min, &mut candidates); + saturating_div(lhs_max, rhs_max, &mut candidates); + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use solang_parser::pt::Loc; + + #[test] + fn uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(3))); + } + + #[test] + fn uint_int() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(5i32)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(3))); + } + + #[test] + fn uint_neg_int() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-3i32))); + } + + #[test] + fn neg_int_uint() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-3i32))); + } + + #[test] + fn neg_int_neg_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(3i32))); + } + + #[test] + fn uint_zero() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(0)), Loc::Implicit); + assert!(x.range_div(&y).is_none()); + } + + #[test] + fn int_zero() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(0)), Loc::Implicit); + assert!(x.range_div(&y).is_none()); + } + + #[test] + fn wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x.range_wrapping_div(&y).unwrap(); + let expected = x.clone(); + assert_eq!(result, expected.into()); + } + + #[test] + fn nonwrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x.range_div(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MAX)); + } + + #[test] + fn exec_sized_uint_uint_saturating() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(5).into(); + let lhs_max = rc_uint_sized(15).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(20).into(); + + let max_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(15))); + let min_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_uint_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(5).into(); + let lhs_max = rc_uint_sized(15).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(16).into(); + + let max_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(15))); + let min_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_int_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(127).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_wrapping_int_int_max() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(-100).into(); + let rhs_min = rc_int_sized(-5).into(); + let rhs_max = rc_int_sized(5).into(); + + let max_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_div( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } +} diff --git a/crates/graph/src/range/exec/math_ops/exp.rs b/crates/graph/src/range/exec/math_ops/exp.rs new file mode 100644 index 00000000..aad9faeb --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/exp.rs @@ -0,0 +1,201 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::U256; + +impl RangeExp for RangeConcrete { + fn range_exp(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let max = Concrete::max_of_type(&self.val).unwrap(); + + let op_res = lhs_val.checked_pow(rhs_val); + let op_res = if let Some(num) = op_res { + num.min(max.into_u256().unwrap()) + } else { + max.into_u256().unwrap() + }; + + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val.into_u256()) { + // exponent must be positive otherwise return None. + (Concrete::Int(lhs_size, neg_v), Some(val)) => { + let pow2 = val % U256::from(2) == 0.into(); + let val = if val > &U256::from(u32::MAX) { + if pow2 { + Concrete::max_of_type(&self.val).unwrap() + } else { + Concrete::min_of_type(&self.val).unwrap() + } + } else { + let min = Concrete::min_of_type(&self.val).unwrap().int_val().unwrap(); + let max = Concrete::max_of_type(&self.val).unwrap().int_val().unwrap(); + + let op_res = neg_v.checked_pow(val.as_u32()); + if let Some(num) = op_res { + if pow2 { + Concrete::Int(*lhs_size, num.min(max)) + } else { + Concrete::Int(*lhs_size, num.max(min)) + } + } else if pow2 { + Concrete::max_of_type(&self.val).unwrap() + } else { + Concrete::min_of_type(&self.val).unwrap() + } + }; + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } +} + +impl RangeExp for Elem { + fn range_exp(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_exp(b), + (Elem::Concrete(a), _) if a.val.is_zero() => Some(Concrete::from(U256::from(1)).into()), + (_, Elem::Concrete(b)) if b.val.is_zero() => Some(other.clone()), + _ => None, + } + } +} + +/// Executes the `exponentiation` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// TODO: Add wrapping/unchecked version +pub fn exec_exp( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // TODO: Improve this + let candidates = vec![ + lhs_min.range_exp(rhs_min), + lhs_min.range_exp(rhs_max), + lhs_max.range_exp(rhs_min), + lhs_max.range_exp(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use ethers_core::types::{I256, U256}; + use solang_parser::pt::Loc; + + #[test] + fn uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(759375))); + } + + #[test] + fn saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::MAX)); + } + + #[test] + fn sized_saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(8, U256::from(254)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(254)), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(255))); + } + + #[test] + fn int_uint() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-1i32))); + } + + #[test] + fn int_uint_2() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(15i32)), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!( + result.val, + Concrete::Int(256, I256::from(-437893890380859375i128)) + ); + } + + #[test] + fn saturating_int_int() { + let x = RangeConcrete::new( + Concrete::Int(256, I256::MIN + I256::from(1i32)), + Loc::Implicit, + ); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(2i32)), Loc::Implicit); + let result = x.range_exp(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MAX)); + } + + #[test] + fn sized_saturating_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(-2i32)), Loc::Implicit); + let result = x.range_add(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_uint_uint_saturating() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(2).into(); + let lhs_max = rc_uint_sized(150).into(); + let rhs_min = rc_uint_sized(3).into(); + let rhs_max = rc_uint_sized(200).into(); + + let max_result = exec_exp(&lhs_min, &lhs_max, &rhs_min, &rhs_max, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_exp( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(8))); + } +} diff --git a/crates/graph/src/range/exec/math_ops/mod.rs b/crates/graph/src/range/exec/math_ops/mod.rs new file mode 100644 index 00000000..fe4a92c5 --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/mod.rs @@ -0,0 +1,12 @@ +mod add; +mod div; +mod exp; +mod modulo; +mod mul; +mod sub; +pub use add::exec_add; +pub use div::exec_div; +pub use exp::exec_exp; +pub use modulo::exec_mod; +pub use mul::exec_mul; +pub use sub::exec_sub; diff --git a/crates/graph/src/range/exec/math_ops/modulo.rs b/crates/graph/src/range/exec/math_ops/modulo.rs new file mode 100644 index 00000000..54e653eb --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/modulo.rs @@ -0,0 +1,329 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{I256, U256}; + +impl RangeMod for RangeConcrete { + fn range_mod(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if rhs_val == 0.into() { + return None; + } + let op_res = lhs_val % rhs_val; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + let op_res = I256::from_raw(*val) % *neg_v; + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) if *val != 0.into() => { + let op_res = *neg_v % I256::from_raw(*val); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + // the wrapping never actually occurs mathematically. See ethers-rs docs for more info + let op_res = l.wrapping_rem(*r); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } +} + +impl RangeMod for Elem { + fn range_mod(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mod(b), + _ => None, + } + } +} + +/// Executes an modulus given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked mod` operation: +/// +/// `todo!()` +pub fn exec_mod( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let is_const = |l: &Elem<_>, r: &Elem<_>, arena: &mut RangeArena>| -> bool { + matches!(l.range_ord(r, arena), Some(std::cmp::Ordering::Equal)) + }; + + if is_const(lhs_min, lhs_max, arena) && is_const(rhs_min, rhs_max, arena) { + return lhs_min.range_mod(rhs_min); + } + + let zero = Elem::from(Concrete::from(U256::zero())); + + let lhs_min_is_pos = matches!( + lhs_min.range_ord(&zero, arena), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ); + + let lhs_max_is_pos = matches!( + lhs_max.range_ord(&zero, arena), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ); + let mod_min_is_pos = matches!( + rhs_min.range_ord(&zero, arena), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ); + + let mod_max_is_pos = matches!( + rhs_max.range_ord(&zero, arena), + Some(std::cmp::Ordering::Equal) | Some(std::cmp::Ordering::Greater) + ); + + // check if all lhs values are less than rhs values + if maximize + && lhs_max_is_pos + && mod_max_is_pos + && matches!( + lhs_max.range_ord(rhs_max, arena), + Some(std::cmp::Ordering::Less) + ) + { + // the lhs is entirely smaller than the modulo, so its effectively a noop, just return + // the min or max + return Some(lhs_max.clone()); + } + + let mut candidates = vec![]; + let one = Elem::from(Concrete::from(U256::from(1))); + let negative_one = Elem::from(Concrete::from(I256::from(-1i32))); + if !mod_min_is_pos { + if let Some(r) = rhs_min.range_add(&one) { + candidates.push(r); + } + } else if let Some(r) = rhs_min.range_sub(&one) { + candidates.push(r); + } + + if !mod_max_is_pos { + if let Some(r) = rhs_max.range_add(&one) { + candidates.push(r); + } + } else if let Some(r) = rhs_max.range_sub(&one) { + candidates.push(r); + } + + if !lhs_min_is_pos { + if let Some(neg_max) = rhs_max.range_mul(&negative_one) { + match neg_max.range_ord(lhs_min, arena) { + None => {} + Some(std::cmp::Ordering::Less) => candidates.push(lhs_min.clone()), + Some(std::cmp::Ordering::Greater) => { + candidates.push(neg_max.range_add(&one).unwrap()) + } + _ => candidates.push(lhs_min.clone()), + } + } + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use solang_parser::pt::Loc; + + #[test] + fn uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(17)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(2))); + } + + #[test] + fn uint_int() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(17)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(5i32)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(2))); + } + + #[test] + fn uint_neg_int() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(17)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(2))); + } + + #[test] + fn neg_int_uint() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-17i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-2i32))); + } + + #[test] + fn neg_int_neg_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-17i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-5i32)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-2i32))); + } + + #[test] + fn uint_zero() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(17)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(0)), Loc::Implicit); + assert!(x.range_mod(&y).is_none()); + } + + #[test] + fn int_zero() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-17i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(0)), Loc::Implicit); + assert!(x.range_mod(&y).is_none()); + } + + #[test] + fn int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x.range_mod(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(0i32))); + } + + #[test] + fn exec_sized_uint_uint_1() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(5).into(); + let lhs_max = rc_uint_sized(15).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(20).into(); + + let max_result = exec_mod(&lhs_min, &lhs_max, &rhs_min, &rhs_max, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(15))); + let min_result = exec_mod( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_uint_uint_2() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(16).into(); + let lhs_max = rc_uint_sized(160).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(16).into(); + + let max_result = exec_mod(&lhs_min, &lhs_max, &rhs_min, &rhs_max, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(15))); + let min_result = exec_mod( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_int_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(127).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_mod(&lhs_min, &lhs_max, &rhs_min, &rhs_max, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_mod( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_int_int_max() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(-100).into(); + let rhs_min = rc_int_sized(-5).into(); + let rhs_max = rc_int_sized(5).into(); + + let max_result = exec_mod(&lhs_min, &lhs_max, &rhs_min, &rhs_max, true, &g, &mut arena) + .unwrap() + .maybe_concrete() + .unwrap(); + // TODO: improve mod calc to consider lhs being entirely negative + // assert_eq!(max_result.val, Concrete::Int(8, I256::from(0i32))); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(4i32))); + let min_result = exec_mod( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-4i32))); + } +} diff --git a/crates/graph/src/range/exec/math_ops/mul.rs b/crates/graph/src/range/exec/math_ops/mul.rs new file mode 100644 index 00000000..a1cb33a0 --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/mul.rs @@ -0,0 +1,507 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{I256, U256}; + +impl RangeMul for RangeConcrete { + fn range_mul(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let max = Concrete::max_of_type(&self.val) + .unwrap() + .into_u256() + .unwrap(); + let mut op_res = lhs_val.saturating_mul(rhs_val).min(max); + if let Some(min) = Concrete::min_of_type(&self.val).unwrap().into_u256() { + op_res = op_res.max(min); + } + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); + let max = Concrete::max_of_type(&tmp).unwrap().int_val().unwrap(); + + let op_res = neg_v.saturating_mul(I256::from_raw(*val)).max(min).min(max); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); + let max = Concrete::max_of_type(&tmp).unwrap().int_val().unwrap(); + + let op_res = l.saturating_mul(*r).min(max).max(min); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } + + fn range_wrapping_mul(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let op_res = lhs_val.overflowing_mul(rhs_val).0; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let op_res = neg_v.overflowing_mul(I256::from_raw(*val)).0; + let val = Concrete::Int(*lhs_size, op_res).size_wrap(); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let op_res = l.overflowing_mul(*r).0; + let val = Concrete::Int(*lhs_size, op_res).size_wrap(); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } +} + +impl RangeMul for Elem { + fn range_mul(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mul(b), + (Elem::Concrete(a), _) if a.val.is_zero() => Some(self.clone()), + (_, Elem::Concrete(b)) if b.val.is_zero() => Some(other.clone()), + (Elem::Concrete(a), b) if a.val.is_one() => Some(b.clone()), + (a, Elem::Concrete(b)) if b.val.is_one() => Some(a.clone()), + _ => None, + } + } + + fn range_wrapping_mul(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_mul(b), + (Elem::Concrete(a), _) if a.val.is_zero() => Some(self.clone()), + (_, Elem::Concrete(b)) if b.val.is_zero() => Some(other.clone()), + (Elem::Concrete(a), b) if a.val.is_one() => Some(b.clone()), + (a, Elem::Concrete(b)) if b.val.is_one() => Some(a.clone()), + _ => None, + } + } +} + +/// Executes an multiplication given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +/// +/// ### Explanation +/// A fact about multiplication is that the smallest value possible (in unbounded unsigned integer space), is between two _minimum_ +/// values and the largest is between two _maximum_ values. In the unbounded signed integer space, the smallest value will be +/// the product of the most negative value and most positive value. +/// +/// Pyrometer _overestimates_ products of multiplication in both the saturating and wrapping cases. This is due to +/// to the fact that the multiplicants may not contain factors of the maximum/minimum. That is to say, +/// the factors of, for example, 2size-1 may not exactly be in the left hand side +/// and right hand side. By default, we allow this overestimation. The only case we cover is when both elements' minimums +/// product always overflows. +/// +/// +/// For example, assume: +///uint256 x: [2240, 2256-1] +///uint256 y: [216, 2256-1] +///unchecked { x * y } +/// +/// +/// In this multiplication of `x*y`, it will always overflow so the minimum is still `x.min * y.min`, and the maximum is still `x.max * y.max`. However, +/// had `x.min * y.min` _not_ overflowed, the maximum would have been `type(uint256).max` (despite not knowing if the factors of `type(uint256).max` are contained +/// in x & y) and the minimum would be `type(uint256).min` (despite not knowing if `unchecked { type(uint256).max + 1 }`'s factors are contained in x & y). Therefore, +/// we have potentially underestimated the minimum and overestimated the maximum of the product. Factorization of large integers is untenable from a performance standpoint +/// so this concession on precision is accepted (and remains sound but can result in false positive analyses if depended on). +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked mul` operation: +/// +///| Mul | Uint | Int | BytesX | Address | Bytes | String | +///|-----------------|------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------|--------|---------|-------|--------| +///| **Uint** | min: lhsmin * rhsmin
max: lhsmax * rhsmax | min: lhsmin * rhsmin
max: lhsmax * rhsmax | N/A | N/A | N/A | N/A | +///| **Int** | min: lhsmin * rhsmin
max: lhsmax * rhsmax | min: lhsmin * rhsmin
max: lhsmax * rhsmax | N/A | N/A | N/A | N/A | +///| **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **String** | N/A | N/A | N/A | N/A | N/A | N/A | +/// +/// Truth table for `wrapping mul` operation: +/// +/// `todo!()` +/// +// | Wrapping Mul | Uint | Int | BytesX | Address | Bytes | String | +// |---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|--------|---------|-------|--------| +// | **Uint** | min: {0, lhsmin * rhsmin}
max: {2size - 1, lhsmax * rhsmax} | min: {0, lhsmin + rhsmin}
max: {2size - 1, lhsmax + rhsmax} | N/A | N/A | N/A | N/A | +// | **Int** | min: {
   -2size-1,
   lhsmin * rhsmin,
   lhsmin * rhsmax,
   lhsmax * rhsmin
}
max: {
   2size - 1,
   lhsmax * rhsmax
} | min: {0, lhsmin * rhsmin}
max: {2size - 1, lhsmax + rhsmax} | N/A | N/A | N/A | N/A | +// | **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +// | **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +// | **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +// | **String** | N/A | N/A | N/A | N/A | N/A | N/A | +pub fn exec_mul( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + wrapping: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let mut candidates = vec![]; + let saturating_mul = |lhs: &Elem<_>, rhs: &Elem<_>, candidates: &mut Vec>| { + if let Some(c) = lhs.range_mul(rhs) { + candidates.push(c); + } + }; + + if wrapping { + let zero = Elem::from(Concrete::from(U256::zero())); + let mut all_overflowed = true; + let mut one_overflowed = false; + let add_candidate = |lhs: &Elem, + rhs: &Elem, + candidates: &mut Vec>, + all_overflowed: &mut bool, + one_overflowed: &mut bool, + arena: &mut RangeArena<_>| { + if let Some(c) = lhs.range_wrapping_mul(rhs) { + if !matches!(lhs.range_ord(&zero, arena), Some(std::cmp::Ordering::Equal)) { + let reverse = c.range_div(lhs).unwrap(); + let overflowed = !matches!( + reverse.range_ord(rhs, arena).unwrap(), + std::cmp::Ordering::Equal + ); + if *all_overflowed && !overflowed { + *all_overflowed = false; + } + + if !*one_overflowed && overflowed { + *one_overflowed = true; + } + } + + candidates.push(c); + } + }; + + add_candidate( + lhs_min, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_min, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + + if all_overflowed || one_overflowed { + // We overflowed in every case, or had a conditional overflow. + // In this case we just under/overestimate + saturating_mul(lhs_max, rhs_max, &mut candidates); + saturating_mul(lhs_min, rhs_min, &mut candidates); + saturating_mul(lhs_min, rhs_max, &mut candidates); + saturating_mul(lhs_max, rhs_min, &mut candidates); + + let add_min = |elem: &Elem, candidates: &mut Vec>| { + if let Some(c) = elem.maybe_concrete() { + if let Some(min) = Concrete::min_of_type(&c.val) { + candidates.push(RangeConcrete::new(min, c.loc).into()); + } + } + }; + // We are able to conditionally overflow, so add min of both types + add_min(lhs_min, &mut candidates); + add_min(lhs_max, &mut candidates); + add_min(rhs_min, &mut candidates); + add_min(rhs_max, &mut candidates); + } + } else { + // without inspecting types of lhs and rhs, its easiest just to run them all and + // sort + saturating_mul(lhs_min, rhs_min, &mut candidates); + saturating_mul(lhs_min, rhs_max, &mut candidates); + saturating_mul(lhs_max, rhs_min, &mut candidates); + saturating_mul(lhs_max, rhs_max, &mut candidates); + } + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use ethers_core::types::U256; + use solang_parser::pt::Loc; + + #[test] + fn sized_uint_uint() { + let x = rc_uint_sized(255); + let y = rc_uint_sized(255); + let result = x.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(255))); + } + + #[test] + fn sized_wrapping_uint_uint() { + let x = rc_uint_sized(255); + let y = rc_uint_sized(255); + let result = x + .range_wrapping_mul(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(1))); + } + + #[test] + fn sized_int_int() { + let x = rc_int_sized(-127); + let y = rc_int_sized(-127); + let result = x.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(127i32))); + } + + #[test] + fn sized_int_int_one() { + let x = rc_int_sized(-1); + let y = rc_int_sized(-128); + let result = x.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(127i32))); + } + + #[test] + fn sized_int_uint() { + let x = rc_int_sized(-127); + let y = rc_int_sized(127); + let y2 = rc_uint_sized(127); + let result = x.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + let result2 = x.range_mul(&y2).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result, result2); + assert_eq!(result.val, Concrete::Int(8, I256::from(-128i32))); + } + #[test] + fn sized_uint_int() { + let x = rc_int_sized(127); + let x2 = rc_uint_sized(127); + let y = rc_int_sized(-127); + let result = x.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + let result2 = x2.range_mul(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result, result2); + assert_eq!(result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn sized_wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let result = x + .range_wrapping_mul(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(1i32))); + } + + #[test] + fn sized_wrapping_int_uint() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(127i32)), Loc::Implicit); + let result = x + .range_wrapping_mul(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + let y2 = RangeConcrete::new(Concrete::Uint(8, U256::from(127i32)), Loc::Implicit); + let result2 = x + .range_wrapping_mul(&y2) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result, result2); + assert_eq!(result.val, Concrete::Int(8, I256::from(-1i32))); + } + + #[test] + fn exec_sized_uint_uint_saturating() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(5).into(); + let lhs_max = rc_uint_sized(15).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(20).into(); + + let max_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(5))); + } + + #[test] + fn exec_sized_wrapping_uint_uint_no_overflow() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(5).into(); + let lhs_max = rc_uint_sized(15).into(); + let rhs_min = rc_uint_sized(1).into(); + let rhs_max = rc_uint_sized(16).into(); + + let max_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(240))); + let min_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(5))); + } + + #[test] + fn exec_sized_wrapping_uint_uint_full_overflow() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(126).into(); + let lhs_max = rc_uint_sized(127).into(); + let rhs_min = rc_uint_sized(252).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + // we just have to overestimate + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + // we just have to underestimate + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_int_uint_cond_overflow() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(127).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_wrapping_int_uint_no_overflow() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-5).into(); + let lhs_max = rc_int_sized(5).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(3).into(); + + let max_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(15i32))); + let min_result = exec_mul( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-15i32))); + } +} diff --git a/crates/graph/src/range/exec/math_ops/sub.rs b/crates/graph/src/range/exec/math_ops/sub.rs new file mode 100644 index 00000000..acc5e1d1 --- /dev/null +++ b/crates/graph/src/range/exec/math_ops/sub.rs @@ -0,0 +1,567 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use ethers_core::types::{I256, U256}; +use solang_parser::pt::Loc; + +impl RangeSub for RangeConcrete { + fn range_sub(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if lhs_val > rhs_val { + let op_res = lhs_val.saturating_sub(rhs_val); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + match self.val { + Concrete::Int(size, val) => { + let min_int = + Concrete::min_of_type(&self.val).unwrap().int_val().unwrap(); + let op_res = val.saturating_sub(I256::from_raw(rhs_val)).max(min_int); + let val = Concrete::Int(size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => { + // TODO: this should cause a revert + let op_res = lhs_val.saturating_sub(rhs_val); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { + let tmp = Concrete::Uint(*lhs_size, U256::zero()); + let max = Concrete::max_of_type(&tmp).unwrap().uint_val().unwrap(); + let abs = neg_v.unsigned_abs(); + let op_res = val.saturating_add(abs).min(max); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); + + let op_res = neg_v.saturating_sub(I256::from_raw(*val).max(min)); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); + let max = Concrete::max_of_type(&tmp).unwrap().int_val().unwrap(); + + let op_res = l.saturating_sub(*r).max(min).min(max); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => None, + }, + } + } + + fn range_wrapping_sub(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + if lhs_val > rhs_val { + let op_res = lhs_val.overflowing_sub(rhs_val).0; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } else { + match self.val { + Concrete::Int(size, val) => { + let op_res = val.overflowing_sub(I256::from_raw(rhs_val)).0; + let val = Concrete::Int(size, op_res).size_wrap(); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + _ => { + let op_res = lhs_val.overflowing_sub(rhs_val).0; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + } + } + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, val), Concrete::Int(_, neg_v)) => { + let op_res = val.overflowing_add(neg_v.into_raw()).0; + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { + let op_res = I256::from_raw(neg_v.into_raw().overflowing_sub(*val).0); + let val = Concrete::Int(*lhs_size, op_res).size_wrap(); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } + (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(Elem::Concrete(RangeConcrete::new( + Concrete::Int(*lhs_size, l.overflowing_sub(*r).0).size_wrap(), + self.loc, + ))) + } + _ => None, + }, + } + } +} + +impl RangeSub for Elem { + fn range_sub(&self, other: &Self) -> Option> { + match (self, other) { + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), + _ => None, + } + } + + fn range_wrapping_sub(&self, other: &Self) -> Option> { + match (self, other) { + (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), + _ => None, + } + } +} + +/// Executes an subtraction given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound of the operation. +/// +/// ### Explanation +/// A fact about subtraction is that the largest value possible (in unbounded integer space), is between the left hand side _maximum_ and right hand side _minimum_ and the smallest +/// is between the left hand side _minimum_ and right hand side _maximum_ values. This fact is used in normal "unbounded" (really, saturating) subtraction calculations as well as wrapping subtraction as basis for another fact: +/// +/// In wrapping subtraction, if the bounds allow for optionally wrapping (e.g.: maximum - minimum does not wrap, but minimum - maximum does wrap), we can +/// by extension include *both* the type's maximum and minimum. +/// +/// For example, assume: +///uint256 x: [101, 2256-1] +///uint256 y: [100, 2256-1] +///unchecked { x - y } +/// +/// +/// In this subtraction of `x - y`, `101 - 100` does not wrap, but `101 - 102` does (unsigned integer). We can construct a value of x and y such that +/// the result of `x - y` is equal to 2256-1 (`101 - 102`) or `0` (`101 - 101`). Therefore, the new bounds +/// on `unchecked { x - y }` is [0, 2256-1]. +/// +/// ### Note +/// Signed integers use 2's complement representation so the maximum is 2size - 1 - 1, while unsigned integers are 2size - 1 +/// +/// +/// ### Truth Tables +/// Truth table for `checked sub` operation: +/// +///| Sub | Uint | Int | BytesX | Address | Bytes | String | +///|-----------------|----------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|--------|---------|-------|--------| +///| **Uint** | _min_: lhsmin - rhsmax
_max_: lhsmax - rhsmin | _min_: lhsmin - rhsmax
_max_: lhsmax - rhsmin | N/A | N/A | N/A | N/A | +///| **Int** | _min_: lhsmin - rhsmax
_max_: lhsmax - rhsmin | _min_: lhsmin - rhsmax
_max_: lhsmax - rhsmin | N/A | N/A | N/A | N/A | +///| **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **String** | N/A | N/A | N/A | N/A | N/A | N/A | +/// +/// Truth table for `wrapping sub` operation: +/// +///| Wrapping Sub | Uint | Int | BytesX | Address | Bytes | String | +///|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|--------|---------|-------|--------| +///| **Uint** | _min_: {0, lhsmin - rhsmax}
_max_: {2size - 1, lhsmax - rhsmin} | _min_: {0, lhsmin - rhsmax}
_max_: {2size - 1, lhsmax - rhsmin} | N/A | N/A | N/A | N/A | +///| **Int** | _min_: {-2size-1, lhsmin - rhsmax}
_max_: {2size-1 - 1, lhsmax - rhsmin} | _min_: {-2size-1, lhsmin - rhsmax}
_max_: {2size-1 - 1, lhsmax - rhsmin} | N/A | N/A | N/A | N/A | +///| **BytesX** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Address** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **Bytes** | N/A | N/A | N/A | N/A | N/A | N/A | +///| **String** | N/A | N/A | N/A | N/A | N/A | N/A | +pub fn exec_sub( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + wrapping: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // quick check if rhs is const and zero, if so return min or max + if wrapping { + let mut candidates = vec![]; + let mut all_overflowed = true; + let mut one_overflowed = false; + let zero = Elem::Concrete(RangeConcrete::new( + Concrete::from(U256::zero()), + Loc::Implicit, + )); + let add_candidate = |lhs: &Elem, + rhs: &Elem, + candidates: &mut Vec>, + all_overflowed: &mut bool, + one_overflowed: &mut bool, + arena: &mut RangeArena>| { + if let Some(c) = lhs.range_wrapping_sub(rhs) { + let lhs_neg = matches!(lhs.range_ord(&zero, arena), Some(std::cmp::Ordering::Less)); + let rhs_neg = matches!(rhs.range_ord(&zero, arena), Some(std::cmp::Ordering::Less)); + let signed = lhs_neg || rhs_neg; + + let overflowed = if signed { + // signed safemath: (rhs >= 0 && c <= lhs) || (rhs < 0 && c > lhs) ==> no overflowed --invert-> overflowed + // ( rhs < 0 ∣∣ c > lhs) && ( rhs ≥ 0 ∣∣ c ≤ lhs) + + (rhs_neg + || matches!(c.range_ord(lhs, arena), Some(std::cmp::Ordering::Greater))) + && (!rhs_neg + || matches!( + c.range_ord(lhs, arena), + Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) + )) + } else { + // unsigned safemath: c < a ==> overflowed + matches!(c.range_ord(lhs, arena), Some(std::cmp::Ordering::Greater)) + }; + + if *all_overflowed && !overflowed { + *all_overflowed = false; + } + + if !*one_overflowed && overflowed { + *one_overflowed = true; + } + + candidates.push(c); + } + }; + + add_candidate( + lhs_min, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_min, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_min, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + add_candidate( + lhs_max, + rhs_max, + &mut candidates, + &mut all_overflowed, + &mut one_overflowed, + arena, + ); + + // If we have a conditional overflow, add the min and max of the type of lhs to the candidates + if !all_overflowed && one_overflowed { + let add_extremes = |elem: &Elem, candidates: &mut Vec>| { + if let Some(c) = elem.maybe_concrete() { + if let Some(max) = Concrete::max_of_type(&c.val) { + candidates.push(RangeConcrete::new(max, c.loc).into()); + } + + if let Some(min) = Concrete::min_of_type(&c.val) { + candidates.push(RangeConcrete::new(min, c.loc).into()); + } + } + }; + + add_extremes(lhs_min, &mut candidates); + add_extremes(lhs_max, &mut candidates); + } + + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } + } else if maximize { + // if we are maximizing, the largest value will always just be the the largest value - the smallest value + lhs_max.range_sub(rhs_min) + } else { + // if we are minimizing, the smallest value will always be smallest value - largest value + lhs_min.range_sub(rhs_max) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use ethers_core::types::U256; + use solang_parser::pt::Loc; + + #[test] + fn uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(5)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(10))); + } + + #[test] + fn saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(1)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::MAX), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::zero())); + } + + #[test] + fn sized_saturating_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(8, U256::from(254)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(255)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::zero())); + } + + #[test] + fn int_big_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(15)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-1i32)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(16))); + } + + #[test] + fn big_int_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::from(1)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(16))); + } + + #[test] + fn int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(-15i32)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(0i32))); + } + + #[test] + fn max_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MAX), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MAX)); + } + + #[test] + fn int_max_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::MAX), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MIN)); + } + + #[test] + fn saturating_int_int() { + let x = RangeConcrete::new( + Concrete::Int(256, I256::MIN + I256::from(1i32)), + Loc::Implicit, + ); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(2i32)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MIN)); + } + + #[test] + fn sized_saturating_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-127i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(2i32)), Loc::Implicit); + let result = x.range_sub(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn wrapping_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(256, U256::zero()), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(256, U256::from(1)), Loc::Implicit); + let result = x + .range_wrapping_sub(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::MAX)); + } + + #[test] + fn sized_wrapping_uint_uint() { + let x = RangeConcrete::new(Concrete::Uint(8, U256::zero()), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Uint(8, U256::from(1)), Loc::Implicit); + let result = x + .range_wrapping_sub(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(8, U256::from(255))); + } + + #[test] + fn wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(256, I256::from(-1)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(15i32)), Loc::Implicit); + let result = x + .range_wrapping_sub(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::from(-16i32))); + } + + #[test] + fn wrapping_int_int_2() { + let x = RangeConcrete::new(Concrete::Int(256, I256::MIN), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(256, I256::from(1i32)), Loc::Implicit); + let result = x + .range_wrapping_sub(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(256, I256::MAX)); + } + + #[test] + fn sized_wrapping_int_int() { + let x = RangeConcrete::new(Concrete::Int(8, I256::from(-128i32)), Loc::Implicit); + let y = RangeConcrete::new(Concrete::Int(8, I256::from(1i32)), Loc::Implicit); + let result = x + .range_wrapping_sub(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Int(8, I256::from(127i32))); + } + + #[test] + fn exec_sized_uint_uint_saturating() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(105).into(); + let lhs_max = rc_uint_sized(150).into(); + let rhs_min = rc_uint_sized(10).into(); + let rhs_max = rc_uint_sized(200).into(); + + let max_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(140))); + let min_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, false, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_uint_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_uint_sized(105).into(); + let lhs_max = rc_uint_sized(150).into(); + let rhs_min = rc_uint_sized(10).into(); + let rhs_max = rc_uint_sized(200).into(); + + let max_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Uint(8, U256::from(255))); + let min_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Uint(8, U256::from(0))); + } + + #[test] + fn exec_sized_wrapping_int_uint() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(127).into(); + let rhs_min = rc_uint_sized(0).into(); + let rhs_max = rc_uint_sized(255).into(); + + let max_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } + + #[test] + fn exec_sized_wrapping_int_int_max() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let lhs_min = rc_int_sized(-128).into(); + let lhs_max = rc_int_sized(-100).into(); + let rhs_min = rc_int_sized(-5).into(); + let rhs_max = rc_int_sized(5).into(); + + let max_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, true, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(max_result.val, Concrete::Int(8, I256::from(127i32))); + let min_result = exec_sub( + &lhs_min, &lhs_max, &rhs_min, &rhs_max, false, true, &g, &mut arena, + ) + .unwrap() + .maybe_concrete() + .unwrap(); + assert_eq!(min_result.val, Concrete::Int(8, I256::from(-128i32))); + } +} diff --git a/crates/graph/src/range/exec/max.rs b/crates/graph/src/range/exec/max.rs index 74f1d62c..b2b32de6 100644 --- a/crates/graph/src/range/exec/max.rs +++ b/crates/graph/src/range/exec/max.rs @@ -1,31 +1,29 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; impl RangeMax for RangeConcrete { fn range_max(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val.max(rhs_val)), - loc: self.loc, - })), + (Some(lhs_val), Some(rhs_val)) => { + let op_res = lhs_val.max(rhs_val); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*lhs_size, *val), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, _), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*lhs_size, *val), - loc: self.loc, - })) + (Concrete::Uint(lhs_size, val), Concrete::Int(_, _)) + | (Concrete::Int(lhs_size, _), Concrete::Uint(_, val)) => { + let val = Concrete::Uint(*lhs_size, *val); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l.max(r)), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, *l.max(r)); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } _ => None, }, @@ -37,18 +35,48 @@ impl RangeMax for Elem { fn range_max(&self, other: &Self) -> Option> { match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_max(b), - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { - if a.op_num > b.op_num { - Some(self.clone()) - } else if a.op_num < b.op_num { - Some(other.clone()) - } else { - None - } - } + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => match a.op_num.cmp(&b.op_num) { + std::cmp::Ordering::Greater => Some(self.clone()), + std::cmp::Ordering::Less => Some(other.clone()), + _ => None, + }, (_, Elem::Null) => Some(self.clone()), (Elem::Null, _) => Some(other.clone()), _ => None, } } } + +/// Executes the maximum given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_max( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_max(rhs_min), + lhs_min.range_max(rhs_max), + lhs_max.range_max(rhs_min), + lhs_max.range_max(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} diff --git a/crates/graph/src/range/exec/mem_ops/concat.rs b/crates/graph/src/range/exec/mem_ops/concat.rs index e28dd4f3..3abf3bef 100644 --- a/crates/graph/src/range/exec/mem_ops/concat.rs +++ b/crates/graph/src/range/exec/mem_ops/concat.rs @@ -1,35 +1,26 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; use ethers_core::types::{H256, U256}; use std::collections::BTreeMap; impl RangeConcat for RangeConcrete { fn range_concat(&self, other: &Self) -> Option> { - Some(Elem::Concrete(RangeConcrete { - val: self.val.clone().concat(&other.val)?, - loc: self.loc, - })) + Some(Elem::Concrete(RangeConcrete::new( + self.val.clone().concat(&other.val)?, + self.loc, + ))) } } impl RangeConcat> for RangeDyn { fn range_concat(&self, other: &RangeConcrete) -> Option> { - match (other.val.clone(), self.val.iter().take(1).next()) { - ( - Concrete::DynBytes(val), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) - | (Concrete::DynBytes(val), None) => { + let inner = self.val.values().take(1).next().map(|(a, _)| a); + match (other.val.clone(), inner) { + (Concrete::DynBytes(val), inner) if inner.is_none() || inner.unwrap().is_bytes() => { let last = self.len.clone(); let mut existing = self.val.clone(); let new = val @@ -41,30 +32,19 @@ impl RangeConcat> for RangeDyn { let mut bytes = [0x00; 32]; bytes[0] = *v; let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, (v, self.op_num + i)) + (idx, (v, self.op_num + i + 1)) }) .collect::>(); existing.extend(new); Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( - Elem::from(Concrete::from(U256::from(val.len()))), + (*self.len).clone() + Elem::from(Concrete::from(U256::from(val.len()))), existing, other.loc, ))) } - ( - Concrete::String(val), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::String(..), - .. - }), - _, - ), - )), - ) - | (Concrete::String(val), None) => { + (Concrete::String(val), inner) + if inner.is_none() || inner.unwrap().is_string() || inner.unwrap().is_bytes() => + { let last = self.len.clone(); let mut existing = self.val.clone(); let new = val @@ -76,48 +56,30 @@ impl RangeConcat> for RangeDyn { let mut bytes = [0x00; 32]; v.encode_utf8(&mut bytes[..]); let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); - (idx, (v, self.op_num + i)) + (idx, (v, self.op_num + i + 1)) }) .collect::>(); existing.extend(new); Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( - Elem::from(Concrete::from(U256::from(val.len()))), + (*self.len).clone() + Elem::from(Concrete::from(U256::from(val.len()))), existing, other.loc, ))) } - _e => None, + e => { + debug_assert!(false, "was not concattable type: {e:#?}"); + None + } } } } impl RangeConcat> for RangeDyn { fn range_concat(&self, other: &Self) -> Option> { - let val: Option<(_, &(Elem, _))> = self.val.iter().take(1).next(); - let o_val: Option<(_, &(Elem, _))> = other.val.iter().take(1).next(); + let val = self.val.values().take(1).next().map(|(a, _)| a); + let o_val = other.val.values().take(1).next().map(|(a, _)| a); match (val, o_val) { - ( - Some(( - _, - &( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - Some(( - _, - &( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) => { + (Some(v), Some(o)) if v.is_bytes() && o.is_bytes() => { let last = self.len.clone(); let mut existing = self.val.clone(); let other_vals = other @@ -125,23 +87,19 @@ impl RangeConcat> for RangeDyn { .clone() .into_iter() .enumerate() - .map(|(i, (key, (v, _op)))| (key + *last.clone(), (v, self.op_num + i))) + .map(|(i, (key, (v, _op)))| (key + *last.clone(), (v, self.op_num + i + 1))) .collect::>(); existing.extend(other_vals); Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( - *self.len.clone() - + *other - .len - .clone() - .max(Box::new(Elem::from(Concrete::from(U256::from(1))))), + *self.len.clone() + *other.len.clone(), existing, other.loc, ))) } - (Some((_, (l @ Elem::Reference(_), _))), None) => Some(l.clone()), - (None, Some((_, (r @ Elem::Reference(_), _)))) => Some(r.clone()), + (Some(l @ Elem::Reference(_)), None) => Some(l.clone()), + (None, Some(r @ Elem::Reference(_))) => Some(r.clone()), (None, None) => Some(Elem::ConcreteDyn(self.clone())), _e => None, } @@ -159,3 +117,202 @@ impl RangeConcat for Elem { } } } + +/// Executes a concatenation of bytes. +pub fn exec_concat( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // TODO: improve with smarter stuff + let candidates = vec![ + lhs_min.range_concat(rhs_min), + lhs_min.range_concat(rhs_max), + lhs_max.range_concat(rhs_min), + lhs_max.range_concat(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use pretty_assertions::assert_eq; + use solang_parser::pt::Loc; + + #[test] + fn concrete_concrete_bytes() { + let x = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let y = RangeConcrete::new( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd']), + Loc::Implicit, + ); + let expected = Concrete::from(vec![ + b'h', b'e', b'l', b'l', b'o', b'w', b'o', b'r', b'l', b'd', + ]); + let result = x.range_concat(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, expected); + } + + #[test] + fn concrete_concrete_bytes_str_fail() { + let x = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let y = RangeConcrete::new(Concrete::from("world"), Loc::Implicit); + assert!(x.range_concat(&y).is_none()); + } + + #[test] + fn concrete_concrete_bytes_none() { + let x = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let y = RangeConcrete::new(Concrete::DynBytes(vec![]), Loc::Implicit); + let result = x.range_concat(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, x.val); + } + + #[test] + fn concrete_concrete_str() { + let x = RangeConcrete::new(Concrete::from("hello"), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from("world"), Loc::Implicit); + let expected = Concrete::from("helloworld"); + let result = x.range_concat(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, expected); + } + + #[test] + fn concrete_concrete_str_bytes_fail() { + let x = RangeConcrete::new(Concrete::from("world"), Loc::Implicit); + let y = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + assert!(x.range_concat(&y).is_none()); + } + + #[test] + fn concrete_concrete_str_none() { + let x = RangeConcrete::new(Concrete::from("hello"), Loc::Implicit); + let y = RangeConcrete::new(Concrete::from(""), Loc::Implicit); + let result = x.range_concat(&y).unwrap().maybe_concrete_value().unwrap(); + assert_eq!(result.val, x.val); + } + + #[test] + fn dyn_concrete_bytes() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let y = RangeConcrete::new( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd']), + Loc::Implicit, + ); + let expected: Elem<_> = Elem::ConcreteDyn( + RangeDyn::from_concrete( + Concrete::from(vec![ + b'h', b'e', b'l', b'l', b'o', b'w', b'o', b'r', b'l', b'd', + ]), + Loc::Implicit, + ) + .unwrap(), + ); + let result = x + .range_concat(&y) + .unwrap() + .maximize(&g, &mut arena) + .unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn dyn_dyn_bytes() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let y = RangeDyn::from_concrete( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd']), + Loc::Implicit, + ) + .unwrap(); + let expected: Elem<_> = Elem::ConcreteDyn( + RangeDyn::from_concrete( + Concrete::from(vec![ + b'h', b'e', b'l', b'l', b'o', b'w', b'o', b'r', b'l', b'd', + ]), + Loc::Implicit, + ) + .unwrap(), + ); + let result = x + .range_concat(&y) + .unwrap() + .maximize(&g, &mut arena) + .unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn dyn_concrete_str() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x = RangeDyn::from_concrete(Concrete::from("hello"), Loc::Implicit).unwrap(); + let y = RangeConcrete::new(Concrete::from("world"), Loc::Implicit); + let expected: Elem<_> = Elem::ConcreteDyn( + RangeDyn::from_concrete(Concrete::from("helloworld"), Loc::Implicit).unwrap(), + ); + let result = x.range_concat(&y).unwrap(); + let result = result.maximize(&g, &mut arena).unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn dyn_dyn_str() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x = RangeDyn::from_concrete(Concrete::from("hello"), Loc::Implicit).unwrap(); + let y = RangeDyn::from_concrete(Concrete::from("world"), Loc::Implicit).unwrap(); + let expected: Elem<_> = Elem::ConcreteDyn( + RangeDyn::from_concrete(Concrete::from("helloworld"), Loc::Implicit).unwrap(), + ); + let result = x + .range_concat(&y) + .unwrap() + .maximize(&g, &mut arena) + .unwrap(); + assert_eq!(result, expected); + } +} diff --git a/crates/graph/src/range/exec/mem_ops/mem_get.rs b/crates/graph/src/range/exec/mem_ops/mem_get.rs new file mode 100644 index 00000000..62d3c99e --- /dev/null +++ b/crates/graph/src/range/exec/mem_ops/mem_get.rs @@ -0,0 +1,409 @@ +use crate::GraphBackend; +use crate::{ + nodes::Concrete, + range::{elem::*, exec_traits::*}, +}; + +use shared::RangeArena; + +use ethers_core::types::U256; +use solang_parser::pt::Loc; + +impl RangeMemLen for RangeDyn { + fn range_get_length(&self) -> Option> { + Some(*self.len.clone()) + } +} + +impl> + Clone> RangeMemGet for RangeDyn { + fn range_get_index(&self, index: &Rhs) -> Option> { + self.val + .get(&(index.clone().into())) + .map(|(v, _)| v.clone()) + } +} + +impl RangeMemGet for RangeConcrete { + fn range_get_index(&self, index: &RangeConcrete) -> Option> { + self.val.get_index(&index.val).map(Elem::from) + } +} + +impl RangeMemLen for RangeConcrete { + fn range_get_length(&self) -> Option> { + Some(RangeConcrete::new(Concrete::from(self.val.maybe_array_size()?), self.loc).into()) + } +} + +impl RangeMemLen for Elem { + fn range_get_length(&self) -> Option> { + match self { + Elem::Concrete(a) => a.range_get_length(), + Elem::ConcreteDyn(a) => Some(*a.len.clone()), + _e => None, + } + } +} + +impl RangeMemGet> for Elem { + fn range_get_index(&self, index: &Elem) -> Option> { + match (self, index) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_get_index(b), + (Elem::ConcreteDyn(a), idx @ Elem::Concrete(_)) => { + if let Some((val, _)) = a.val.get(idx).cloned() { + Some(val) + } else { + None + } + } + (Elem::ConcreteDyn(a), idx @ Elem::Reference(_)) => { + if let Some((val, _)) = a.val.get(idx).cloned() { + Some(val) + } else { + None + } + } + _e => None, + } + } +} + +/// Executes the `get_length` operation given the minimum and maximum of an element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_get_length( + lhs_min: &Elem, + lhs_max: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + if maximize { + let new = lhs_max.clone(); + let new_max = new.simplify_maximize(analyzer, arena).ok()?; + + new_max.range_get_length() + } else { + let new_min = lhs_min.simplify_minimize(analyzer, arena).ok()?; + + new_min.range_get_length() + } +} + +/// Executes the `range_get_index` operation given the minimum and maximum of an element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_get_index( + lhs: &Elem, + rhs: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // for each key in LHS, check if it overlaps the RHS index range + // e.g.: + // lhs: { + // [12, 100]: val, + // [220, 1000]: val, + // } + // + // if: + // rhs: [0, 2**224] + // all values would be added to candidates + // + // if: + // rhs: [0, 2] + // No values would be added to candidates + // + // if: + // rhs: [50, 50] + // the first value would be added to candidates + + let mut candidates = vec![]; + fn match_lhs( + lhs: &Elem, + rhs: &Elem, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + candidates: &mut Vec>, + ) { + match lhs { + Elem::Arena(_) => { + let (d, idx) = lhs.dearenaize(arena); + match_lhs(&d, rhs, analyzer, arena, candidates); + lhs.rearenaize(d, idx, arena); + } + Elem::Reference(_) => { + if let Ok(min) = lhs.minimize(analyzer, arena) { + match_lhs(&min, rhs, analyzer, arena, candidates); + } + + if let Ok(max) = lhs.maximize(analyzer, arena) { + match_lhs(&max, rhs, analyzer, arena, candidates); + } + } + Elem::ConcreteDyn(d) => { + d.val.iter().for_each(|(k, (v, _op))| { + if let Ok(Some(true)) = k.overlaps(rhs, true, analyzer, arena) { + candidates.push(v.clone()) + } + }); + } + Elem::Concrete(c) => { + if let Some(size) = c.val.maybe_array_size() { + let min = U256::zero(); + // Iterates through concrete indices to check if RHS contains the index + let mut curr = min; + while curr < size { + let as_rc = RangeConcrete::new(Concrete::from(curr), Loc::Implicit); + let as_elem = Elem::from(as_rc.clone()); + if let Ok(Some(true)) = as_elem.overlaps(rhs, true, analyzer, arena) { + if let Some(val) = c.range_get_index(&as_rc) { + candidates.push(val) + } + } + curr += U256::from(1); + } + } + } + _ => {} + }; + } + + match_lhs(lhs, rhs, analyzer, arena, &mut candidates); + + candidates = candidates + .into_iter() + .filter_map(|val| { + if maximize { + val.maximize(analyzer, arena).ok() + } else { + val.minimize(analyzer, arena).ok() + } + }) + .collect(); + + // Sort the candidates + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return Some(Elem::Null); + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::DummyGraph; + use ethers_core::types::U256; + use pretty_assertions::assert_eq; + use solang_parser::pt::Loc; + + #[test] + fn concrete_len() { + let x: RangeConcrete = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let expected = rc_uint256(5); + let result = Elem::from(x) + .range_get_length() + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, expected.val); + } + + #[test] + fn dyn_len() { + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let expected = rc_uint256(5); + let result = x + .range_get_length() + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, expected.val); + } + + #[test] + fn concrete_concrete_index() { + let x = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let idx = rc_uint256(2); + let result = x + .range_get_index(&idx) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::from(b'l')); + } + + #[test] + fn dyn_concrete_index() { + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let idx = rc_uint256(2); + let result = x + .range_get_index(&idx) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::from(b'l')); + } + + #[test] + fn dyn_ref_index() { + let idx = Elem::Reference(Reference::new(1.into())); + let rand: Elem<_> = rc_uint256(0).into(); + let val = rc_uint256(200).into(); + let x = RangeDyn::new_for_indices( + vec![(rand.clone(), rand), (idx.clone(), val)], + Loc::Implicit, + ); + + let result = x + .range_get_index(&idx) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(200))); + } + + #[test] + fn exec_dyn_get_ref_idx_low() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let idx0 = test_reference(1, 12.into(), 100.into()); + let idx1 = test_reference(2, 220.into(), 1000.into()); + let val0 = rc_uint256(200).into(); + let val1 = rc_uint256(201).into(); + let x = RangeDyn::new_for_indices(vec![(idx0, val0), (idx1, val1)], Loc::Implicit); + + let get_idx = test_reference(3, 0.into(), 12.into()); + + let result = exec_get_index(&Elem::ConcreteDyn(x), &get_idx, true, &g, &mut arena) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(200))); + } + + #[test] + fn exec_dyn_get_ref_idx_high() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let idx0 = test_reference(1, 12.into(), 100.into()); + let idx1 = test_reference(2, 220.into(), 1000.into()); + let val0 = rc_uint256(200).into(); + let val1 = rc_uint256(201).into(); + let x = RangeDyn::new_for_indices(vec![(idx0, val0), (idx1, val1)], Loc::Implicit); + + let get_idx = test_reference(3, 400.into(), 400.into()); + + let result = exec_get_index(&Elem::ConcreteDyn(x), &get_idx, true, &g, &mut arena) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(201))); + } + + #[test] + fn exec_dyn_get_ref_idx_all() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let idx0 = test_reference(1, 12.into(), 100.into()); + let idx1 = test_reference(2, 220.into(), 1000.into()); + let val0 = rc_uint256(200).into(); + let val1 = rc_uint256(201).into(); + let x = RangeDyn::new_for_indices(vec![(idx0, val0), (idx1, val1)], Loc::Implicit); + + let get_idx = test_reference(3, 0.into(), U256::MAX); + + let result = exec_get_index(&Elem::ConcreteDyn(x), &get_idx, true, &g, &mut arena) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::Uint(256, U256::from(201))); + } + + #[test] + fn exec_dyn_get_ref_idx_null() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let idx0 = test_reference(1, 12.into(), 100.into()); + let idx1 = test_reference(2, 220.into(), 1000.into()); + let val0 = rc_uint256(200).into(); + let val1 = rc_uint256(201).into(); + let x = RangeDyn::new_for_indices(vec![(idx0, val0), (idx1, val1)], Loc::Implicit); + + let get_idx = test_reference(3, 0.into(), 2.into()); + + let result = exec_get_index(&Elem::ConcreteDyn(x), &get_idx, true, &g, &mut arena); + assert_eq!(result.unwrap(), Elem::Null); + } + + #[test] + fn exec_concrete_get_ref_idx_low() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x: RangeConcrete = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let get_idx = test_reference(1, 0.into(), 2.into()); + + let result = exec_get_index(&Elem::Concrete(x), &get_idx, true, &g, &mut arena) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, Concrete::from(b'l')); + } + + #[test] + fn exec_concrete_get_ref_idx_null() { + let g = DummyGraph::default(); + let mut arena = Default::default(); + let x: RangeConcrete = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let get_idx = test_reference(1, 6.into(), 8.into()); + + let result = exec_get_index(&Elem::Concrete(x), &get_idx, true, &g, &mut arena); + assert_eq!(result.unwrap(), Elem::Null); + } + + fn test_reference(id: usize, min: U256, max: U256) -> Elem { + let mut re = Reference::new(id.into()); + let mi = Box::new(Elem::Concrete(RangeConcrete::new( + Concrete::from(min), + Loc::Implicit, + ))); + let ma = Box::new(Elem::Concrete(RangeConcrete::new( + Concrete::from(max), + Loc::Implicit, + ))); + re.minimized = Some(MinMaxed::Minimized(mi.clone())); + re.maximized = Some(MinMaxed::Maximized(ma.clone())); + re.flattened_min = Some(mi); + re.flattened_max = Some(ma); + Elem::Reference(re) + } +} diff --git a/crates/graph/src/range/exec/mem_ops/mem_set.rs b/crates/graph/src/range/exec/mem_ops/mem_set.rs index 6fb7028f..acc6ab72 100644 --- a/crates/graph/src/range/exec/mem_ops/mem_set.rs +++ b/crates/graph/src/range/exec/mem_ops/mem_set.rs @@ -1,8 +1,11 @@ +use crate::GraphBackend; use crate::{ nodes::Concrete, range::{elem::*, exec_traits::*}, }; +use shared::RangeArena; + use ethers_core::types::{H256, U256}; use std::collections::BTreeMap; @@ -23,36 +26,20 @@ impl RangeMemSet for RangeDyn { ))) } - fn range_get_index(&self, _index: &Self) -> Option> { - unreachable!() - } - - fn range_set_length(&self, _other: &Self) -> Option> { - unreachable!() - } - - fn range_get_length(&self) -> Option> { - unreachable!() + fn range_set_length(&self, other: &Self) -> Option> { + let mut a = self.clone(); + a.len.clone_from(&other.len); + Some(Elem::ConcreteDyn(a)) } } impl RangeMemSet> for RangeDyn { fn range_set_indices(&self, range: &RangeConcrete) -> Option> { - match (range.val.clone(), self.val.iter().take(1).next()) { - ( - Concrete::DynBytes(val), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(..), - .. - }), - _, - ), - )), - ) - | (Concrete::DynBytes(val), None) => { + match ( + range.val.clone(), + self.val.values().take(1).next().map(|(a, _)| a), + ) { + (Concrete::DynBytes(val), s) if s.is_none() || s.unwrap().is_bytes() => { let mut existing = self.val.clone(); let new = val .iter() @@ -74,20 +61,7 @@ impl RangeMemSet> for RangeDyn { range.loc, ))) } - ( - Concrete::String(val), - Some(( - _, - ( - Elem::Concrete(RangeConcrete { - val: Concrete::String(..), - .. - }), - _, - ), - )), - ) - | (Concrete::String(val), None) => { + (Concrete::String(val), s) if s.is_none() || s.unwrap().is_string() => { let mut existing = self.val.clone(); let new = val .chars() @@ -113,16 +87,10 @@ impl RangeMemSet> for RangeDyn { } } - fn range_get_index(&self, _index: &RangeConcrete) -> Option> { - unreachable!() - } - - fn range_set_length(&self, _other: &RangeConcrete) -> Option> { - unreachable!() - } - - fn range_get_length(&self) -> Option> { - unreachable!() + fn range_set_length(&self, other: &RangeConcrete) -> Option> { + let mut a = self.clone(); + a.len = Box::new(Elem::Concrete(other.clone())); + Some(Elem::ConcreteDyn(a)) } } @@ -130,22 +98,89 @@ impl RangeMemSet for RangeConcrete { fn range_set_indices(&self, range: &Self) -> Option> { let mut new_val = self.val.clone(); new_val.set_indices(&range.val); - Some(Elem::Concrete(RangeConcrete { - val: new_val, - loc: range.loc, - })) - } - - fn range_get_index(&self, index: &Self) -> Option> { - self.val.get_index(&index.val).map(Elem::from) - } - - fn range_set_length(&self, _other: &Self) -> Option> { - unreachable!() + Some(Elem::Concrete(RangeConcrete::new(new_val, range.loc))) } - fn range_get_length(&self) -> Option> { - unreachable!() + fn range_set_length(&self, other: &Self) -> Option> { + match other.val.into_u256() { + Some(len) if len <= U256::from(32) => match self.val { + Concrete::DynBytes(ref val) => Some(Elem::Concrete(RangeConcrete::new( + Concrete::DynBytes({ + let mut v = val.clone(); + v.resize(len.as_usize(), 0); + v + }), + self.loc, + ))), + Concrete::String(ref val) => Some(Elem::Concrete(RangeConcrete::new( + Concrete::String({ + let mut v = val.clone(); + v.push_str(&" ".repeat(len.as_usize() - v.chars().count())); + v + }), + self.loc, + ))), + Concrete::Bytes(_, val) => Some(Elem::Concrete(RangeConcrete::new( + Concrete::Bytes(len.as_u32() as u8, val), + self.loc, + ))), + _ => None, + }, + _ => { + let new = match self.val { + Concrete::DynBytes(ref val) => Some( + val.iter() + .enumerate() + .map(|(i, v)| { + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (Elem::from(Concrete::from(U256::from(i))), (v, i)) + }) + .collect::>(), + ), + Concrete::String(ref val) => Some( + val.chars() + .enumerate() + .map(|(i, v)| { + let mut bytes = [0x00; 32]; + v.encode_utf8(&mut bytes[..]); + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (Elem::from(Concrete::from(U256::from(i))), (v, i)) + }) + .collect::>(), + ), + Concrete::Array(ref val) => Some( + val.iter() + .enumerate() + .map(|(i, v)| { + let t = Elem::Concrete(RangeConcrete::new(v.clone(), self.loc)); + (Elem::from(Concrete::from(U256::from(i))), (t, i)) + }) + .collect::>(), + ), + Concrete::Bytes(size, val) => Some( + val.0 + .iter() + .take(size as usize) + .enumerate() + .map(|(i, v)| { + let mut bytes = [0x00; 32]; + bytes[0] = *v; + let v = Elem::from(Concrete::Bytes(1, H256::from(bytes))); + (Elem::from(Concrete::from(U256::from(i))), (v, i)) + }) + .collect::>(), + ), + _ => None, + }; + Some(Elem::ConcreteDyn(RangeDyn::new_w_op_nums( + Elem::Concrete(other.clone()), + new?, + self.loc, + ))) + } + } } } @@ -154,17 +189,9 @@ impl RangeMemSet> for RangeConcrete { todo!() } - fn range_get_index(&self, _range: &RangeDyn) -> Option> { - unreachable!() - } - fn range_set_length(&self, _other: &RangeDyn) -> Option> { unreachable!() } - - fn range_get_length(&self) -> Option> { - unreachable!() - } } impl RangeMemSet for Elem { @@ -180,47 +207,221 @@ impl RangeMemSet for Elem { fn range_set_length(&self, other: &Self) -> Option> { match (self, other) { - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { - let mut a = a.clone(); - a.len.clone_from(&b.len); - Some(Elem::ConcreteDyn(a.clone())) - } - (a @ Elem::Concrete(_), _b @ Elem::Concrete(_)) => Some(a.clone()), + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => a.range_set_length(b), + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_set_length(b), (Elem::ConcreteDyn(a), _) => { let mut a = a.clone(); a.len = Box::new(other.clone()); - Some(Elem::ConcreteDyn(a.clone())) + Some(Elem::ConcreteDyn(a)) } _e => None, } } +} - fn range_get_length(&self) -> Option> { - match self { - Elem::Concrete(a) => Some(Elem::from(Concrete::from(a.val.maybe_array_size()?))), - Elem::ConcreteDyn(a) => Some(*a.len.clone()), - _e => None, - } +pub fn exec_set_length( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + lhs_max.range_set_length(rhs_max) + } else { + lhs_min.range_set_length(rhs_min) } +} - fn range_get_index(&self, index: &Elem) -> Option> { - match (self, index) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_get_index(b), - (Elem::ConcreteDyn(a), idx @ Elem::Concrete(_)) => { - if let Some((val, _)) = a.val.get(idx).cloned() { - Some(val) - } else { - None - } - } - (Elem::ConcreteDyn(a), idx @ Elem::Reference(_)) => { - if let Some((val, _)) = a.val.get(idx).cloned() { - Some(val) - } else { - None - } - } - _e => None, +pub fn exec_set_indices( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + rhs: &Elem, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + if maximize { + if let Some(t) = lhs_max.range_set_indices(rhs_max) { + Some(t) + } else { + let max = rhs.simplify_maximize(analyzer, arena).ok()?; + lhs_max.range_set_indices(&max) } + } else if let Some(t) = lhs_min.range_set_indices(rhs_min) { + Some(t) + } else { + let min = rhs.simplify_minimize(analyzer, arena).ok()?; + lhs_min.range_set_indices(&min) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use ethers_core::types::U256; + use pretty_assertions::assert_eq; + use solang_parser::pt::Loc; + + #[test] + fn concrete_set_len() { + let x: RangeConcrete = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ); + let new_len = rc_uint256(10); + let result = x.range_set_length(&new_len).unwrap(); + assert_eq!(result.range_get_length().unwrap(), Elem::Concrete(new_len)); + } + + #[test] + fn dyn_set_len() { + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let new_len = rc_uint256(10); + let result = x.range_set_length(&new_len).unwrap(); + assert_eq!(result.range_get_length().unwrap(), Elem::Concrete(new_len)); + } + + #[test] + fn dyn_set_ref_len() { + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o']), + Loc::Implicit, + ) + .unwrap(); + let new_len = test_reference(0, 6.into(), 10.into()); + let result = Elem::ConcreteDyn(x).range_set_length(&new_len).unwrap(); + assert_eq!(result.range_get_length().unwrap(), new_len); + } + + #[test] + fn concrete_concrete_set_indices() { + let x = RangeConcrete::new( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o', b's']), + Loc::Implicit, + ); + let y = RangeConcrete::new( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd']), + Loc::Implicit, + ); + + let expected = RangeConcrete::new( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd', b's']), + Loc::Implicit, + ); + let result = x + .range_set_indices(&y) + .unwrap() + .maybe_concrete_value() + .unwrap(); + assert_eq!(result.val, expected.val); + } + + #[test] + fn dyn_concrete_index() { + let x = RangeDyn::from_concrete( + Concrete::from(vec![b'h', b'e', b'l', b'l', b'o', b's']), + Loc::Implicit, + ) + .unwrap(); + let y = RangeConcrete::new( + Concrete::from(vec![b'w', b'o', b'r', b'l', b'd']), + Loc::Implicit, + ); + + let expected = RangeDyn::new_w_op_nums( + rc_uint256(6).into(), + vec![ + ( + Elem::from(rc_uint256(0)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b'w'), Loc::Implicit)), + 5usize, + ), + ), + ( + Elem::from(rc_uint256(1)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b'o'), Loc::Implicit)), + 6usize, + ), + ), + ( + Elem::from(rc_uint256(2)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b'r'), Loc::Implicit)), + 7usize, + ), + ), + ( + Elem::from(rc_uint256(3)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b'l'), Loc::Implicit)), + 8usize, + ), + ), + ( + Elem::from(rc_uint256(4)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b'd'), Loc::Implicit)), + 9usize, + ), + ), + ( + Elem::from(rc_uint256(5)), + ( + Elem::Concrete(RangeConcrete::new(Concrete::from(b's'), Loc::Implicit)), + 5usize, + ), + ), + ] + .into_iter() + .collect::, (Elem<_>, usize)>>(), + Loc::Implicit, + ); + + let result = x.range_set_indices(&y).unwrap(); + assert_eq!(result.dyn_map().unwrap(), &expected.val); + } + + #[test] + fn dyn_ref_set_indices() { + let idx = test_reference(0, 0.into(), 2000.into()); + let rand: Elem<_> = rc_uint256(1337).into(); + let val: Elem<_> = rc_uint256(200).into(); + let x = RangeDyn::new_for_indices(vec![(rand.clone(), rand.clone())], Loc::Implicit); + + let y = RangeDyn::new_for_indices(vec![(idx.clone(), val.clone())], Loc::Implicit); + + let expected = Elem::ConcreteDyn(RangeDyn::new_for_indices( + vec![(rand.clone(), rand), (idx.clone(), val)], + Loc::Implicit, + )); + let result = x.range_set_indices(&y).unwrap(); + assert_eq!(result, expected); + } + + fn test_reference(id: usize, min: U256, max: U256) -> Elem { + let mut re = Reference::new(id.into()); + let mi = Box::new(Elem::Concrete(RangeConcrete::new( + Concrete::from(min), + Loc::Implicit, + ))); + let ma = Box::new(Elem::Concrete(RangeConcrete::new( + Concrete::from(max), + Loc::Implicit, + ))); + re.minimized = Some(MinMaxed::Minimized(mi.clone())); + re.maximized = Some(MinMaxed::Maximized(ma.clone())); + re.flattened_min = Some(mi); + re.flattened_max = Some(ma); + Elem::Reference(re) } } diff --git a/crates/graph/src/range/exec/mem_ops/memcopy.rs b/crates/graph/src/range/exec/mem_ops/memcopy.rs new file mode 100644 index 00000000..1df79ff9 --- /dev/null +++ b/crates/graph/src/range/exec/mem_ops/memcopy.rs @@ -0,0 +1,25 @@ +use crate::elem::Elem; +use crate::exec_traits::RangeMemOps; +use crate::nodes::Concrete; + +impl RangeMemOps for Elem { + fn range_memcopy(&self) -> Option> { + match self { + Elem::Concrete(_a) => Some(self.clone()), + Elem::ConcreteDyn(_a) => Some(self.clone()), + _e => None, + } + } +} + +pub fn exec_memcopy( + lhs_min: &Elem, + lhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + Some(lhs_max.clone()) + } else { + Some(lhs_min.clone()) + } +} diff --git a/crates/graph/src/range/exec/mem_ops/mod.rs b/crates/graph/src/range/exec/mem_ops/mod.rs index 4bbd3e2c..2b8c69f7 100644 --- a/crates/graph/src/range/exec/mem_ops/mod.rs +++ b/crates/graph/src/range/exec/mem_ops/mod.rs @@ -1,16 +1,9 @@ mod concat; +mod mem_get; mod mem_set; +mod memcopy; -use crate::elem::Elem; -use crate::exec_traits::RangeMemOps; -use crate::nodes::Concrete; - -impl RangeMemOps for Elem { - fn range_memcopy(&self) -> Option> { - match self { - Elem::Concrete(_a) => Some(self.clone()), - Elem::ConcreteDyn(_a) => Some(self.clone()), - _e => None, - } - } -} +pub use concat::exec_concat; +pub use mem_get::{exec_get_index, exec_get_length}; +pub use mem_set::{exec_set_indices, exec_set_length}; +pub use memcopy::exec_memcopy; diff --git a/crates/graph/src/range/exec/min.rs b/crates/graph/src/range/exec/min.rs index 823d8a26..adb818ad 100644 --- a/crates/graph/src/range/exec/min.rs +++ b/crates/graph/src/range/exec/min.rs @@ -1,31 +1,29 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; impl RangeMin for RangeConcrete { fn range_min(&self, other: &Self) -> Option> { match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val.min(rhs_val)), - loc: self.loc, - })), + (Some(lhs_val), Some(rhs_val)) => { + let op_res = lhs_val.min(rhs_val); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) + } _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, _), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v), - loc: self.loc, - })) + (Concrete::Uint(lhs_size, _), Concrete::Int(_, neg_v)) + | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, _)) => { + let val = Concrete::Int(*lhs_size, *neg_v); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l.min(r)), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, *l.min(r)); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } _ => None, }, @@ -37,15 +35,11 @@ impl RangeMin for Elem { fn range_min(&self, other: &Self) -> Option> { match (self, other) { (Elem::Concrete(a), Elem::Concrete(b)) => a.range_min(b), - (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => { - if a.op_num > b.op_num { - Some(self.clone()) - } else if a.op_num < b.op_num { - Some(other.clone()) - } else { - None - } - } + (Elem::ConcreteDyn(a), Elem::ConcreteDyn(b)) => match a.op_num.cmp(&b.op_num) { + std::cmp::Ordering::Greater => Some(self.clone()), + std::cmp::Ordering::Less => Some(other.clone()), + _ => None, + }, (c @ Elem::Concrete(_), Elem::ConcreteDyn(b)) | (Elem::ConcreteDyn(b), c @ Elem::Concrete(_)) => { if b.op_num == 0 { @@ -60,3 +54,37 @@ impl RangeMin for Elem { } } } + +/// Executes the minimum given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_min( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_min(rhs_min), + lhs_min.range_min(rhs_max), + lhs_max.range_min(rhs_min), + lhs_max.range_min(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} diff --git a/crates/graph/src/range/exec/mod.rs b/crates/graph/src/range/exec/mod.rs index f7aed5af..a12a21e8 100644 --- a/crates/graph/src/range/exec/mod.rs +++ b/crates/graph/src/range/exec/mod.rs @@ -1,15 +1,29 @@ -mod add; +pub mod exec_op; + mod bitwise; +pub use bitwise::{exec_bit_and, exec_bit_not, exec_bit_or, exec_bit_xor}; + mod cast; -mod div; -mod exec_op; -mod exp; -mod logical; +pub use cast::exec_cast; + mod max; -mod mem_ops; +pub use max::exec_max; + mod min; -mod modulo; -mod mul; -mod ord; +pub use min::exec_min; + mod shift; -mod sub; +pub use shift::{exec_shl, exec_shr}; + +mod math_ops; +pub use math_ops::{exec_add, exec_div, exec_exp, exec_mod, exec_mul, exec_sub}; + +mod truthy_ops; +pub use truthy_ops::{ + exec_and, exec_eq_neq, exec_gt, exec_gte, exec_lt, exec_lte, exec_not, exec_or, +}; + +mod mem_ops; +pub use mem_ops::{ + exec_concat, exec_get_index, exec_get_length, exec_memcopy, exec_set_indices, exec_set_length, +}; diff --git a/crates/graph/src/range/exec/modulo.rs b/crates/graph/src/range/exec/modulo.rs deleted file mode 100644 index 7e8a8eea..00000000 --- a/crates/graph/src/range/exec/modulo.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -use ethers_core::types::I256; - -impl RangeMod for RangeConcrete { - fn range_mod(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) if rhs_val != 0.into() => { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val % rhs_val), - loc: self.loc, - })) - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from_raw(*val) % *neg_v), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) if *val != 0.into() => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *neg_v % I256::from_raw(*val)), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, *l % *r), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMod for Elem { - fn range_mod(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mod(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/mul.rs b/crates/graph/src/range/exec/mul.rs deleted file mode 100644 index 63940124..00000000 --- a/crates/graph/src/range/exec/mul.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -use ethers_core::types::{I256, U256}; - -impl RangeMul for RangeConcrete { - fn range_mul(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let max = Concrete::max(&self.val).unwrap(); - let res = lhs_val - .saturating_mul(rhs_val) - .min(max.into_u256().unwrap()); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(res), - loc: self.loc, - })) - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_mul(I256::from_raw(*val)).max(min), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_mul(*r).min(max)), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_wrapping_mul(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - let _max = Concrete::max(&self.val).unwrap(); - let res = lhs_val.overflowing_mul(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(res), - loc: self.loc, - })) - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) - | (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.overflowing_mul(I256::from_raw(*val)).0, - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_mul(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeMul for Elem { - fn range_mul(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_mul(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (Elem::Concrete(a), b) if a.val.into_u256() == Some(U256::from(1)) => Some(b.clone()), - (a, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::from(1)) => Some(a.clone()), - _ => None, - } - } - - fn range_wrapping_mul(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_mul(b), - (Elem::Concrete(a), _) if a.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => { - Some(other.clone()) - } - (Elem::Concrete(a), b) if a.val.into_u256() == Some(U256::from(1)) => Some(b.clone()), - (a, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::from(1)) => Some(a.clone()), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/ord.rs b/crates/graph/src/range/exec/ord.rs deleted file mode 100644 index 4e867e25..00000000 --- a/crates/graph/src/range/exec/ord.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -impl RangeOrd for RangeConcrete { - fn range_ord_eq(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val == rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_, _), Concrete::Int(_, _)) - | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l == r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_neq(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val != rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_, _), Concrete::Int(_, _)) - | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l != r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_gt(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val > rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l > r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_lt(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val < rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l < r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_gte(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val >= rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l >= r), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_lte(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(lhs_val <= rhs_val), - loc: self.loc, - })), - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: self.loc, - })) - } - (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Bool(l <= r), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeOrd for Elem { - fn range_ord_eq(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_ord_eq(b), - _ => None, - } - } - fn range_neq(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_neq(b), - _ => None, - } - } - fn range_gt(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gt(b), - _ => None, - } - } - - fn range_lt(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lt(b), - _ => None, - } - } - - fn range_gte(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gte(b), - _ => None, - } - } - - fn range_lte(&self, other: &Self) -> Option> { - match (self, other) { - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lte(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/shift.rs b/crates/graph/src/range/exec/shift.rs index cf68f6fc..13436542 100644 --- a/crates/graph/src/range/exec/shift.rs +++ b/crates/graph/src/range/exec/shift.rs @@ -1,5 +1,8 @@ use crate::nodes::Concrete; use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; use ethers_core::types::{I256, U256}; @@ -8,31 +11,28 @@ impl RangeShift for RangeConcrete { match (self.val.into_u256(), other.val.into_u256()) { (Some(lhs_val), Some(rhs_val)) => { if rhs_val > 256.into() { - return Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })); + let val = self.val.u256_as_original(U256::zero()); + let rc = RangeConcrete::new(val, self.loc); + return Some(rc.into()); } - let max = Concrete::max(&self.val).unwrap().into_u256().unwrap(); + + let max = Concrete::max_of_type(&self.val) + .unwrap() + .into_u256() + .unwrap(); if self.val.int_val().is_some() { // ints get weird treatment because they can push into the negatives - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - self.val.int_size().unwrap(), - I256::from_raw(lhs_val << rhs_val), - ), - loc: self.loc, - })) + let size = self.val.int_size().unwrap(); + let op_res = I256::from_raw(lhs_val << rhs_val); + let val = Concrete::Int(size, op_res); + Some(RangeConcrete::new(val, self.loc).into()) } else if rhs_val > lhs_val.leading_zeros().into() { - Some(Elem::Concrete(RangeConcrete { - val: max.into(), - loc: self.loc, - })) + Some(RangeConcrete::new(max.into(), self.loc).into()) } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original((lhs_val << rhs_val).min(max)), - loc: self.loc, - })) + let op_res = (lhs_val << rhs_val).min(max); + let val = self.val.u256_as_original(op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } } _ => match (&self.val, &other.val) { @@ -41,28 +41,22 @@ impl RangeShift for RangeConcrete { return Some(Elem::Concrete(self.clone())); } - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); - let min = max * I256::from(-1i32) - I256::from(1i32); let (abs, is_min) = neg_v.overflowing_abs(); if is_min { if val > &U256::zero() { - Some(Elem::from(self.clone())) + Some(self.clone().into()) } else { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::zero()), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, I256::zero()); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } } else if val > &U256::from(abs.leading_zeros()) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::zero()), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, I256::zero()); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } else { let raw = I256::from_raw(abs.into_raw() << val); let as_int = if raw == I256::MIN { @@ -70,10 +64,11 @@ impl RangeShift for RangeConcrete { } else { I256::from(-1i32) * raw }; - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, as_int.max(min)), - loc: self.loc, - })) + + let op_res = as_int.max(min); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } } _ => None, @@ -87,15 +82,13 @@ impl RangeShift for RangeConcrete { if rhs_val == U256::zero() { Some(Elem::Concrete(self.clone())) } else if rhs_val > U256::from(256) { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(U256::zero()), - loc: self.loc, - })) + let op_res = self.val.u256_as_original(U256::zero()); + let rc = RangeConcrete::new(op_res, self.loc); + Some(rc.into()) } else { - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(lhs_val >> rhs_val), - loc: self.loc, - })) + let op_res = self.val.u256_as_original(lhs_val >> rhs_val); + let rc = RangeConcrete::new(op_res, self.loc); + Some(rc.into()) } } _ => match (&self.val, &other.val) { @@ -103,19 +96,12 @@ impl RangeShift for RangeConcrete { if val == &U256::zero() { Some(Elem::Concrete(self.clone())) } else if val > &U256::from(*lhs_size) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(-1i32)), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, I256::from(-1i32)); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } else { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - - I256::from(1) - }; - let min = max * I256::from(-1i32) - I256::from(1i32); - + let tmp = Concrete::Int(*lhs_size, I256::from(0i32)); + let min = Concrete::min_of_type(&tmp).unwrap().int_val().unwrap(); let (abs, is_min) = neg_v.overflowing_abs(); let bits = if is_min { 255 @@ -124,20 +110,16 @@ impl RangeShift for RangeConcrete { }; if val >= &U256::from(bits) { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, I256::from(-1i32)), - loc: self.loc, - })) + let val = Concrete::Int(*lhs_size, I256::from(-1i32)); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } else { let shr_val = abs.into_raw() >> val; let as_int = I256::from_raw(shr_val); - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - (I256::from(-1i32) * as_int).max(min), - ), - loc: self.loc, - })) + let op_res = (I256::from(-1i32) * as_int).max(min); + let val = Concrete::Int(*lhs_size, op_res); + let rc = RangeConcrete::new(val, self.loc); + Some(rc.into()) } } } @@ -161,3 +143,71 @@ impl RangeShift for Elem { } } } + +/// Executes the `shift left` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_shl( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_shl(rhs_min), + lhs_min.range_shl(rhs_max), + lhs_max.range_shl(rhs_min), + lhs_max.range_shl(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +/// Executes the `shift right` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_shr( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_shr(rhs_min), + lhs_min.range_shr(rhs_max), + lhs_max.range_shr(rhs_min), + lhs_max.range_shr(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} diff --git a/crates/graph/src/range/exec/sub.rs b/crates/graph/src/range/exec/sub.rs deleted file mode 100644 index dfe80219..00000000 --- a/crates/graph/src/range/exec/sub.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::nodes::Concrete; -use crate::range::{elem::*, exec_traits::*}; - -use ethers_core::types::{I256, U256}; - -impl RangeSub for RangeConcrete { - fn range_sub(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if lhs_val > rhs_val { - let val = lhs_val.saturating_sub(rhs_val); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } else { - match self.val { - Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(size, val.saturating_sub(I256::from_raw(rhs_val))), - loc: self.loc, - })), - _ => { - // TODO: this should cause a revert - let val = lhs_val.saturating_sub(rhs_val); - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } - } - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(lhs_size, val), Concrete::Int(_, neg_v)) => { - let max = if *lhs_size == 256 { - U256::MAX - } else { - U256::from(2).pow(U256::from(*lhs_size)) - 1 - }; - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.saturating_add(neg_v.into_raw()).min(max)), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - let max = if *lhs_size == 256 { - I256::MAX - } else { - I256::from_raw(U256::from(1u8) << U256::from(*lhs_size - 1)) - I256::from(1) - }; - - let min = max * I256::from(-1i32) - I256::from(1i32); - - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - neg_v.saturating_sub(I256::from_raw(*val).max(min)), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.saturating_sub(*r)), - loc: self.loc, - })) - } - _ => None, - }, - } - } - - fn range_wrapping_sub(&self, other: &Self) -> Option> { - match (self.val.into_u256(), other.val.into_u256()) { - (Some(lhs_val), Some(rhs_val)) => { - if lhs_val > rhs_val { - let val = lhs_val.overflowing_sub(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } else { - match self.val { - Concrete::Int(size, val) => Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - size, - val.overflowing_sub(I256::from_raw(rhs_val)).0, - ), - loc: self.loc, - })), - _ => { - let val = lhs_val.overflowing_sub(rhs_val).0; - Some(Elem::Concrete(RangeConcrete { - val: self.val.u256_as_original(val), - loc: self.loc, - })) - } - } - } - } - _ => match (&self.val, &other.val) { - (Concrete::Uint(_lhs_size, val), Concrete::Int(_, neg_v)) => { - Some(Elem::Concrete(RangeConcrete { - val: self - .val - .u256_as_original(val.overflowing_add(neg_v.into_raw()).0), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, neg_v), Concrete::Uint(_, val)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int( - *lhs_size, - I256::from_raw(neg_v.into_raw().overflowing_sub(*val).0), - ), - loc: self.loc, - })) - } - (Concrete::Int(lhs_size, l), Concrete::Int(_rhs_size, r)) => { - Some(Elem::Concrete(RangeConcrete { - val: Concrete::Int(*lhs_size, l.overflowing_sub(*r).0), - loc: self.loc, - })) - } - _ => None, - }, - } - } -} - -impl RangeSub for Elem { - fn range_sub(&self, other: &Self) -> Option> { - match (self, other) { - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_sub(b), - _ => None, - } - } - - fn range_wrapping_sub(&self, other: &Self) -> Option> { - match (self, other) { - (_, Elem::Concrete(b)) if b.val.into_u256() == Some(U256::zero()) => Some(self.clone()), - (Elem::Concrete(a), Elem::Concrete(b)) => a.range_wrapping_sub(b), - _ => None, - } - } -} diff --git a/crates/graph/src/range/exec/truthy_ops/logical.rs b/crates/graph/src/range/exec/truthy_ops/logical.rs new file mode 100644 index 00000000..aa4796b7 --- /dev/null +++ b/crates/graph/src/range/exec/truthy_ops/logical.rs @@ -0,0 +1,145 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +impl RangeUnary for RangeConcrete { + fn range_not(&self) -> Option> { + match self.val { + Concrete::Bool(b) => Some(RangeConcrete::new(Concrete::Bool(!b), self.loc).into()), + _ => None, + } + } + + fn range_and(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Bool(a), Concrete::Bool(b)) => { + Some(RangeConcrete::new(Concrete::Bool(*a && *b), self.loc).into()) + } + _ => None, + } + } + + fn range_or(&self, other: &Self) -> Option> { + match (&self.val, &other.val) { + (Concrete::Bool(a), Concrete::Bool(b)) => { + Some(RangeConcrete::new(Concrete::Bool(*a || *b), self.loc).into()) + } + _ => None, + } + } +} + +impl RangeUnary for Elem { + fn range_not(&self) -> Option> { + match self { + Elem::Concrete(a) => a.range_not(), + _ => None, + } + } + fn range_and(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_and(b), + _ => None, + } + } + fn range_or(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_or(b), + _ => None, + } + } +} + +pub fn exec_and( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_and(rhs_min), + lhs_min.range_and(rhs_max), + lhs_max.range_and(rhs_min), + lhs_max.range_and(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +pub fn exec_or( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + let candidates = vec![ + lhs_min.range_or(rhs_min), + lhs_min.range_or(rhs_max), + lhs_max.range_or(rhs_min), + lhs_max.range_or(rhs_max), + ]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} + +pub fn exec_not( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + _analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + assert!(matches!(rhs_min, Elem::Null) && matches!(rhs_max, Elem::Null)); + let candidates = vec![lhs_min.range_not(), lhs_max.range_not()]; + let mut candidates = candidates.into_iter().flatten().collect::>(); + candidates.sort_by(|a, b| match a.range_ord(b, arena) { + Some(r) => r, + _ => std::cmp::Ordering::Less, + }); + + if candidates.is_empty() { + return None; + } + + if maximize { + Some(candidates.remove(candidates.len() - 1)) + } else { + Some(candidates.remove(0)) + } +} diff --git a/crates/graph/src/range/exec/truthy_ops/mod.rs b/crates/graph/src/range/exec/truthy_ops/mod.rs new file mode 100644 index 00000000..4a100732 --- /dev/null +++ b/crates/graph/src/range/exec/truthy_ops/mod.rs @@ -0,0 +1,5 @@ +mod logical; +mod ord; + +pub use logical::{exec_and, exec_not, exec_or}; +pub use ord::{exec_eq_neq, exec_gt, exec_gte, exec_lt, exec_lte}; diff --git a/crates/graph/src/range/exec/truthy_ops/ord.rs b/crates/graph/src/range/exec/truthy_ops/ord.rs new file mode 100644 index 00000000..b5bc1046 --- /dev/null +++ b/crates/graph/src/range/exec/truthy_ops/ord.rs @@ -0,0 +1,333 @@ +use crate::nodes::Concrete; +use crate::range::{elem::*, exec_traits::*}; +use crate::GraphBackend; + +use shared::RangeArena; + +use solang_parser::pt::Loc; + +impl RangeOrd for RangeConcrete { + fn range_ord_eq(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + let rc = RangeConcrete::new(Concrete::Bool(lhs_val == rhs_val), self.loc); + Some(rc.into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_, _), Concrete::Int(_, _)) + | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(false), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l == r), self.loc).into()) + } + _ => None, + }, + } + } + + fn range_neq(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + Some(RangeConcrete::new(Concrete::Bool(lhs_val != rhs_val), self.loc).into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_, _), Concrete::Int(_, _)) + | (Concrete::Int(_, _), Concrete::Uint(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(true), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l != r), self.loc).into()) + } + _ => None, + }, + } + } + + fn range_gt(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + Some(RangeConcrete::new(Concrete::Bool(lhs_val > rhs_val), self.loc).into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(true), self.loc).into()) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(RangeConcrete::new(Concrete::Bool(false), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l > r), self.loc).into()) + } + _ => None, + }, + } + } + + fn range_lt(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + Some(RangeConcrete::new(Concrete::Bool(lhs_val < rhs_val), self.loc).into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(false), self.loc).into()) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(RangeConcrete::new(Concrete::Bool(true), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l < r), self.loc).into()) + } + _ => None, + }, + } + } + + fn range_gte(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + Some(RangeConcrete::new(Concrete::Bool(lhs_val >= rhs_val), self.loc).into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(true), self.loc).into()) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(RangeConcrete::new(Concrete::Bool(false), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l >= r), self.loc).into()) + } + _ => None, + }, + } + } + + fn range_lte(&self, other: &Self) -> Option> { + match (self.val.into_u256(), other.val.into_u256()) { + (Some(lhs_val), Some(rhs_val)) => { + Some(RangeConcrete::new(Concrete::Bool(lhs_val <= rhs_val), self.loc).into()) + } + _ => match (&self.val, &other.val) { + (Concrete::Uint(_lhs_size, _val), Concrete::Int(_, _)) => { + Some(RangeConcrete::new(Concrete::Bool(false), self.loc).into()) + } + (Concrete::Int(_lhs_size, _), Concrete::Uint(_, _val)) => { + Some(RangeConcrete::new(Concrete::Bool(true), self.loc).into()) + } + (Concrete::Int(_lhs_size, l), Concrete::Int(_rhs_size, r)) => { + Some(RangeConcrete::new(Concrete::Bool(l <= r), self.loc).into()) + } + _ => None, + }, + } + } +} + +impl RangeOrd for Elem { + fn range_ord_eq(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_ord_eq(b), + _ => None, + } + } + fn range_neq(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_neq(b), + _ => None, + } + } + fn range_gt(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gt(b), + _ => None, + } + } + + fn range_lt(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lt(b), + _ => None, + } + } + + fn range_gte(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_gte(b), + _ => None, + } + } + + fn range_lte(&self, other: &Self) -> Option> { + match (self, other) { + (Elem::Concrete(a), Elem::Concrete(b)) => a.range_lte(b), + _ => None, + } + } +} + +/// Executes the `greater than` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_gt( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + lhs_max.range_gt(rhs_min) + } else { + lhs_min.range_gt(rhs_max) + } +} + +/// Executes the `less than` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_lt( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + lhs_min.range_lt(rhs_max) + } else { + lhs_max.range_lt(rhs_min) + } +} + +/// Executes the `greater than or equal` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_gte( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + lhs_max.range_gte(rhs_min) + } else { + lhs_min.range_gte(rhs_max) + } +} + +/// Executes the `less than or equal` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_lte( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, +) -> Option> { + if maximize { + lhs_min.range_lte(rhs_max) + } else { + lhs_max.range_lte(rhs_min) + } +} + +/// Executes the `equal` operation or `not equal` operation given the minimum and maximum of each element. It returns either the _minimum_ bound or _maximum_ bound +/// of the operation. +pub fn exec_eq_neq( + lhs_min: &Elem, + lhs_max: &Elem, + rhs_min: &Elem, + rhs_max: &Elem, + maximize: bool, + eq: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, +) -> Option> { + // prevent trying to eval when we have dependents + if !lhs_min.dependent_on(analyzer, arena).is_empty() + || !lhs_max.dependent_on(analyzer, arena).is_empty() + || !rhs_min.dependent_on(analyzer, arena).is_empty() + || !rhs_max.dependent_on(analyzer, arena).is_empty() + { + return None; + } + + let loc = if let Some(c) = lhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = lhs_max.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_min.maybe_concrete() { + c.loc + } else if let Some(c) = rhs_max.maybe_concrete() { + c.loc + } else { + Loc::Implicit + }; + + // We want to prove that there exists some values for LHS and RHS that are equal + // We do this for equality maximization and inequality minimization + let overlap_test = eq && maximize || !eq && !maximize; + + if overlap_test { + // check for any overlap + // + // Check if lhs max > rhs min + // LHS: <--?---| max + // RHS: min |----?----> + let lhs_max_rhs_min_ord = lhs_max.range_ord(rhs_min, arena); + + // Check if lhs min < rhs max + // LHS: min |----?----> + // RHS: <--?---| max + let lhs_min_rhs_max_ord = lhs_min.range_ord(rhs_max, arena); + + // if lhs max is less than the rhs min, it has to be false + if matches!(lhs_max_rhs_min_ord, Some(std::cmp::Ordering::Less)) { + return Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(!eq), + loc, + })); + } + + // if lhs min is greater than the rhs max, it has to be false + if matches!(lhs_min_rhs_max_ord, Some(std::cmp::Ordering::Greater)) { + return Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(!eq), + loc, + })); + } + + // lhs_max >= rhs_min + // lhs_min <= rhs_max + Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(eq), + loc, + })) + } else { + // We want to check that there is *some* case in which they can be *not* equal. + // This only occurs when both sides are constant and equal + match ( + // check if lhs is constant + lhs_min.range_ord(lhs_max, arena), + // check if rhs is constant + rhs_min.range_ord(rhs_max, arena), + // check if lhs is equal to rhs + lhs_min.range_ord(rhs_min, arena), + ) { + // LHS & RHS are constant and equal + ( + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + Some(std::cmp::Ordering::Equal), + ) => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(eq), + loc, + })), + // LHS or RHS is not constant or they are constant and unequal + _ => Some(Elem::Concrete(RangeConcrete { + val: Concrete::Bool(!eq), + loc, + })), + } + } +} diff --git a/crates/graph/src/range/exec_traits.rs b/crates/graph/src/range/exec_traits.rs index 6fb33895..061b466d 100644 --- a/crates/graph/src/range/exec_traits.rs +++ b/crates/graph/src/range/exec_traits.rs @@ -1,7 +1,10 @@ use crate::{range::elem::Elem, GraphBackend}; +use shared::RangeArena; + +use std::hash::Hash; /// For execution of operations to be performed on range expressions -pub trait ExecOp { +pub trait ExecOp { type GraphError; /// Attempts to execute ops by evaluating expressions and applying the op for the left-hand-side /// and right-hand-side @@ -9,6 +12,7 @@ pub trait ExecOp { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError>; fn exec( @@ -16,22 +20,26 @@ pub trait ExecOp { parts: (Elem, Elem, Elem, Elem), maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError>; /// Cache execution fn cache_exec_op( &mut self, maximize: bool, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(), Self::GraphError>; fn spread( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; fn simplify_spread( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(Elem, Elem, Elem, Elem), Self::GraphError>; fn uncache_exec(&mut self); @@ -40,6 +48,7 @@ pub trait ExecOp { &self, maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError>; /// Attempts to simplify an expression (i.e. just apply constant folding) @@ -48,8 +57,9 @@ pub trait ExecOp { parts: (Elem, Elem, Elem, Elem), maximize: bool, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError> { - self.exec(parts, maximize, analyzer) + self.exec(parts, maximize, analyzer, arena) } } @@ -158,9 +168,16 @@ pub trait RangeConcat { pub trait RangeMemSet { /// Applies a transformation of indices fn range_set_indices(&self, other: &Rhs) -> Option>; - /// Gets an index - fn range_get_index(&self, other: &Rhs) -> Option>; /// Applies a transformation of length fn range_set_length(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMemGet: RangeMemLen { + /// Gets an index + fn range_get_index(&self, other: &Rhs) -> Option>; +} + +pub trait RangeMemLen { + /// Gets the length fn range_get_length(&self) -> Option>; } diff --git a/crates/graph/src/range/mod.rs b/crates/graph/src/range/mod.rs index f61240b9..119e48ac 100644 --- a/crates/graph/src/range/mod.rs +++ b/crates/graph/src/range/mod.rs @@ -1,3 +1,14 @@ +//! Ranges consist of a minimum range element and a maximum range element. +//! +//! +//! +//! We define an algebra of types. This means we can perform calculations between two range elements. +//! +//! +//! +//! +//! + pub mod elem; pub mod exec; pub mod exec_traits; diff --git a/crates/graph/src/range/range_string.rs b/crates/graph/src/range/range_string.rs index 6a56660d..d845012f 100644 --- a/crates/graph/src/range/range_string.rs +++ b/crates/graph/src/range/range_string.rs @@ -3,6 +3,8 @@ use crate::{ range::elem::*, GraphBackend, }; +use shared::RangeArena; + use solang_parser::pt::Loc; use std::collections::BTreeMap; @@ -37,13 +39,26 @@ impl RangeString { /// String related functions for ranges pub trait ToRangeString { /// Gets the definition string of the range element - fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString; + fn def_string( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString; /// Converts a range to a human string - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString; + fn to_range_string( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString; } impl ToRangeString for Elem { - fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { + fn def_string( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), Elem::Reference(Reference { idx, .. }) => { @@ -53,34 +68,42 @@ impl ToRangeString for Elem { .unwrap(); RangeElemString::new(cvar.display_name.clone(), cvar.loc.unwrap_or(Loc::Implicit)) } - Elem::ConcreteDyn(rd) => rd.def_string(analyzer), - Elem::Expr(expr) => expr.def_string(analyzer), + Elem::ConcreteDyn(rd) => rd.def_string(analyzer, arena), + Elem::Expr(expr) => expr.def_string(analyzer, arena), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), - Elem::Arena(_) => self.dearenaize(analyzer).borrow().def_string(analyzer), + Elem::Arena(_) => self.dearenaize_clone(arena).def_string(analyzer, arena), } } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { + fn to_range_string( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { match self { Elem::Concrete(c) => RangeElemString::new(c.val.as_human_string(), c.loc), Elem::Reference(Reference { idx, .. }) => { let as_var = ContextVarNode::from(*idx); - let name = as_var.as_controllable_name(analyzer).unwrap(); + let name = as_var.as_controllable_name(analyzer, arena).unwrap(); RangeElemString::new(name, as_var.loc(analyzer).unwrap()) } - Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer), - Elem::Expr(expr) => expr.to_range_string(maximize, analyzer), + Elem::ConcreteDyn(rd) => rd.to_range_string(maximize, analyzer, arena), + Elem::Expr(expr) => expr.to_range_string(maximize, analyzer, arena), Elem::Null => RangeElemString::new("null".to_string(), Loc::Implicit), Elem::Arena(_) => self - .dearenaize(analyzer) - .borrow() - .to_range_string(maximize, analyzer), + .dearenaize_clone(arena) + .to_range_string(maximize, analyzer, arena), } } } impl ToRangeString for RangeDyn { - fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { + fn def_string( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { let displayed_vals = self.val.iter().take(20).collect::>(); let val_str = displayed_vals @@ -88,8 +111,8 @@ impl ToRangeString for RangeDyn { .map(|(key, (val, _))| { format!( "{}: {}", - key.def_string(analyzer).s, - val.def_string(analyzer).s + key.def_string(analyzer, arena).s, + val.def_string(analyzer, arena).s ) }) .collect::>() @@ -98,14 +121,19 @@ impl ToRangeString for RangeDyn { RangeElemString::new( format!( "{{len: {}, indices: [{}]}}", - self.len.to_range_string(false, analyzer).s, + self.len.to_range_string(false, analyzer, arena).s, val_str ), self.loc, ) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { + fn to_range_string( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { let val_str = if self.val.len() > 10 { let displayed_vals = self .val @@ -114,8 +142,8 @@ impl ToRangeString for RangeDyn { .filter(|(_key, (val, _op))| *val != Elem::Null) .map(|(key, (val, _op))| { ( - key.to_range_string(maximize, analyzer).s, - val.to_range_string(maximize, analyzer).s, + key.to_range_string(maximize, analyzer, arena).s, + val.to_range_string(maximize, analyzer, arena).s, ) }) .collect::>(); @@ -135,8 +163,8 @@ impl ToRangeString for RangeDyn { .map(|(key, (val, _op))| { // (key.to_range_string(maximize, analyzer).s, val.to_range_string(maximize, analyzer).s) ( - key.to_range_string(maximize, analyzer).s, - val.to_range_string(maximize, analyzer).s, + key.to_range_string(maximize, analyzer, arena).s, + val.to_range_string(maximize, analyzer, arena).s, ) }) .collect::>(); @@ -155,8 +183,8 @@ impl ToRangeString for RangeDyn { .filter(|(_key, (val, _op))| *val != Elem::Null) .map(|(key, (val, _op))| { ( - key.to_range_string(maximize, analyzer).s, - val.to_range_string(maximize, analyzer).s, + key.to_range_string(maximize, analyzer, arena).s, + val.to_range_string(maximize, analyzer, arena).s, ) }) .collect::>(); @@ -171,7 +199,7 @@ impl ToRangeString for RangeDyn { RangeElemString::new( format!( "{{len: {}, indices: {{{}}}}}", - self.len.to_range_string(maximize, analyzer).s, + self.len.to_range_string(maximize, analyzer, arena).s, val_str ), self.loc, @@ -180,17 +208,26 @@ impl ToRangeString for RangeDyn { } impl ToRangeString for RangeExpr { - fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { - self.lhs.def_string(analyzer) + fn def_string( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { + self.lhs.def_string(analyzer, arena) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { + fn to_range_string( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { if let MaybeCollapsed::Collapsed(collapsed) = - collapse(&self.lhs, self.op, &self.rhs, analyzer) + collapse(*self.lhs.clone(), self.op, *self.rhs.clone(), arena) { - return collapsed.to_range_string(maximize, analyzer); + return collapsed.to_range_string(maximize, analyzer, arena); } - let lhs_r_str = self.lhs.to_range_string(maximize, analyzer); + let lhs_r_str = self.lhs.to_range_string(maximize, analyzer, arena); let lhs_str = match *self.lhs { Elem::Expr(_) => { let new_str = format!("({})", lhs_r_str.s); @@ -199,7 +236,7 @@ impl ToRangeString for RangeExpr { _ => lhs_r_str, }; - let rhs_r_str = self.rhs.to_range_string(maximize, analyzer); + let rhs_r_str = self.rhs.to_range_string(maximize, analyzer, arena); let rhs_str = match *self.rhs { Elem::Expr(_) => { @@ -216,9 +253,9 @@ impl ToRangeString for RangeExpr { ) } else if matches!(self.op, RangeOp::Cast) { let rhs = if maximize { - self.rhs.maximize(analyzer).unwrap() + self.rhs.maximize(analyzer, arena).unwrap() } else { - self.rhs.minimize(analyzer).unwrap() + self.rhs.minimize(analyzer, arena).unwrap() }; match rhs { @@ -237,9 +274,9 @@ impl ToRangeString for RangeExpr { } } else if matches!(self.op, RangeOp::BitNot) { let lhs = if maximize { - self.lhs.maximize(analyzer).unwrap() + self.lhs.maximize(analyzer, arena).unwrap() } else { - self.lhs.minimize(analyzer).unwrap() + self.lhs.minimize(analyzer, arena).unwrap() }; match lhs { diff --git a/crates/graph/src/range/range_trait.rs b/crates/graph/src/range/range_trait.rs index 4a5f0853..e5b1bd75 100644 --- a/crates/graph/src/range/range_trait.rs +++ b/crates/graph/src/range/range_trait.rs @@ -1,32 +1,40 @@ use crate::FlattenedRange; use crate::{range::elem::RangeElem, GraphBackend}; -use shared::NodeIdx; -use std::borrow::Cow; +use shared::{NodeIdx, RangeArena}; +use std::{borrow::Cow, hash::Hash}; -pub trait Range { +pub trait Range { type GraphError; - type ElemTy: RangeElem + Clone; + type ElemTy: RangeElem + Clone + Hash; /// Evaluate both the minimum and the maximum - cache along the way - fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_eval( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, + ) -> Result<(), Self::GraphError>; /// Evaluate the range minimum fn evaled_range_min( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena, ) -> Result; /// Evaluate the range maximum fn evaled_range_max( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena, ) -> Result; /// Simplify the minimum, leaving references in place fn simplified_range_min( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena, ) -> Result; /// Simplify the maximum, leaving references in place fn simplified_range_max( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena, ) -> Result; /// Return the range minimum fn range_min(&self) -> std::borrow::Cow<'_, Self::ElemTy>; @@ -66,6 +74,7 @@ pub trait Range { self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, ); /// Replace a potential recursion causing node index with a new index fn filter_max_recursion( @@ -73,13 +82,19 @@ pub trait Range { self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, ); /// Cache the flattened range - fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError>; + fn cache_flatten( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, + ) -> Result<(), Self::GraphError>; /// Produce a flattened range or use the cached flattened range fn flattened_range<'a>( &'a mut self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, ) -> Result, Self::GraphError> where Self: Sized + Clone; @@ -87,17 +102,33 @@ pub trait Range { fn take_flattened_range( &mut self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena, ) -> Result where Self: Sized; } -pub trait RangeEval> { - fn sat(&self, analyzer: &impl GraphBackend) -> bool; - fn unsat(&self, analyzer: &impl GraphBackend) -> bool { - !self.sat(analyzer) +pub trait RangeEval + Hash> { + fn sat(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena) -> bool; + fn unsat(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena) -> bool { + !self.sat(analyzer, arena) } - fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; - fn contains_elem(&self, other: &T, analyzer: &impl GraphBackend) -> bool; - fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool; + fn contains( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena, + ) -> bool; + fn contains_elem( + &self, + other: &T, + analyzer: &impl GraphBackend, + arena: &mut RangeArena, + ) -> bool; + fn overlaps( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena, + ) -> bool; } diff --git a/crates/graph/src/range/solc_range.rs b/crates/graph/src/range/solc_range.rs index cb6bd8a8..eddff194 100644 --- a/crates/graph/src/range/solc_range.rs +++ b/crates/graph/src/range/solc_range.rs @@ -4,7 +4,7 @@ use crate::{ AsDotStr, GraphBackend, GraphError, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::Loc; @@ -39,20 +39,24 @@ pub struct SolcRange { } impl AsDotStr for SolcRange { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> String { format!( "[{}, {}] excluding: [{}]", - self.evaled_range_min(analyzer) + self.evaled_range_min(analyzer, arena) .unwrap() - .to_range_string(false, analyzer) + .to_range_string(false, analyzer, arena) .s, - self.evaled_range_max(analyzer) + self.evaled_range_max(analyzer, arena) .unwrap() - .to_range_string(true, analyzer) + .to_range_string(true, analyzer, arena) .s, self.exclusions .iter() - .map(|excl| Elem::Arena(*excl).to_range_string(false, analyzer).s) + .map(|excl| Elem::Arena(*excl).to_range_string(false, analyzer, arena).s) .collect::>() .join(", ") ) @@ -61,10 +65,7 @@ impl AsDotStr for SolcRange { impl From for SolcRange { fn from(b: bool) -> Self { - let val = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(b), - loc: Loc::Implicit, - }); + let val = Elem::Concrete(RangeConcrete::new(Concrete::Bool(b), Loc::Implicit)); Self::new(val.clone(), val, vec![]) } } @@ -77,9 +78,13 @@ impl From> for SolcRange { impl SolcRange { /// Get all ContextVarNodes that this range references - pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { - let mut deps = self.range_min().dependent_on(analyzer); - deps.extend(self.range_max().dependent_on(analyzer)); + pub fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { + let mut deps = self.range_min().dependent_on(analyzer, arena); + deps.extend(self.range_max().dependent_on(analyzer, arena)); deps.dedup(); deps.into_iter().map(ContextVarNode::from).collect() @@ -88,9 +93,10 @@ impl SolcRange { pub fn recursive_dependent_on( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { - let mut deps = self.range_min().recursive_dependent_on(analyzer)?; - deps.extend(self.range_max().recursive_dependent_on(analyzer)?); + let mut deps = self.range_min().recursive_dependent_on(analyzer, arena)?; + deps.extend(self.range_max().recursive_dependent_on(analyzer, arena)?); deps.dedup(); Ok(deps) @@ -112,37 +118,51 @@ impl SolcRange { to_replace: NodeIdx, replacement: Elem, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) { if let Some(ref mut flattened) = &mut self.flattened { - Elem::Arena(flattened.min).replace_dep(to_replace, replacement.clone(), analyzer); - Elem::Arena(flattened.max).replace_dep(to_replace, replacement.clone(), analyzer); + Elem::Arena(flattened.min).replace_dep( + to_replace, + replacement.clone(), + analyzer, + arena, + ); + Elem::Arena(flattened.max).replace_dep( + to_replace, + replacement.clone(), + analyzer, + arena, + ); } self.min - .replace_dep(to_replace, replacement.clone(), analyzer); - self.max.replace_dep(to_replace, replacement, analyzer); + .replace_dep(to_replace, replacement.clone(), analyzer, arena); + self.max + .replace_dep(to_replace, replacement, analyzer, arena); self.min_cached = None; self.max_cached = None; } - pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { - let min = self.evaled_range_min(analyzer)?; - let max = self.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max, analyzer)) + pub fn is_const( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + let min = self.evaled_range_min(analyzer, arena)?; + let max = self.evaled_range_max(analyzer, arena)?; + Ok(min.range_eq(&max, arena)) } - pub fn min_is_negative(&self, analyzer: &impl GraphBackend) -> Result { - self.min.is_negative(false, analyzer) + pub fn min_is_negative( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { + self.min.is_negative(false, analyzer, arena) } pub fn default_bool() -> Self { - let min = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: Loc::Implicit, - }); - let max = Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: Loc::Implicit, - }); + let min = Elem::Concrete(RangeConcrete::new(Concrete::Bool(false), Loc::Implicit)); + let max = Elem::Concrete(RangeConcrete::new(Concrete::Bool(true), Loc::Implicit)); Self::new(min, max, vec![]) } pub fn from(c: Concrete) -> Option { @@ -152,14 +172,8 @@ impl SolcRange { | c @ Concrete::Bool(_) | c @ Concrete::Address(_) | c @ Concrete::Bytes(_, _) => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: c.clone(), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: c, - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new(c.clone(), Loc::Implicit)), + Elem::Concrete(RangeConcrete::new(c, Loc::Implicit)), vec![], )), Concrete::String(s) => { @@ -209,26 +223,26 @@ impl SolcRange { Builtin::Uint(size) => { if *size == 256 { Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, 0.into()), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, U256::MAX), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Uint(*size, 0.into()), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Uint(*size, U256::MAX), + Loc::Implicit, + )), vec![], )) } else { Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, 0.into()), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Uint(*size, U256::from(2).pow(U256::from(*size)) - 1), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Uint(*size, 0.into()), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Uint(*size, U256::from(2).pow(U256::from(*size)) - 1), + Loc::Implicit, + )), vec![], )) } @@ -236,14 +250,14 @@ impl SolcRange { Builtin::Int(size) => { if *size == 256 { Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, I256::MIN), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, I256::MAX), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Int(*size, I256::MIN), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Int(*size, I256::MAX), + Loc::Implicit, + )), vec![], )) } else { @@ -251,38 +265,32 @@ impl SolcRange { I256::from_raw(U256::from(1u8) << U256::from(size - 1)) - I256::from(1); let min = max * I256::from(-1i32) - I256::from(1i32); Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, min), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Int(*size, max), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Int(*size, min), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Int(*size, max), + Loc::Implicit, + )), vec![], )) } } Builtin::Bool => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(false), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Bool(true), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new(Concrete::Bool(false), Loc::Implicit)), + Elem::Concrete(RangeConcrete::new(Concrete::Bool(true), Loc::Implicit)), vec![], )), Builtin::Address | Builtin::Payable | Builtin::AddressPayable => Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Address(Address::from_slice(&[0x00; 20])), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Address(Address::from_slice(&[0xff; 20])), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Address(Address::from_slice(&[0x00; 20])), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Address(Address::from_slice(&[0xff; 20])), + Loc::Implicit, + )), vec![], )), Builtin::Bytes(size) => { @@ -290,14 +298,14 @@ impl SolcRange { .map(|i| if i < *size { 0xff } else { 0x00 }) .collect(); Some(SolcRange::new( - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, H256::from_slice(&[0x00; 32])), - loc: Loc::Implicit, - }), - Elem::Concrete(RangeConcrete { - val: Concrete::Bytes(*size, H256::from_slice(&v[..])), - loc: Loc::Implicit, - }), + Elem::Concrete(RangeConcrete::new( + Concrete::Bytes(*size, H256::from_slice(&[0x00; 32])), + Loc::Implicit, + )), + Elem::Concrete(RangeConcrete::new( + Concrete::Bytes(*size, H256::from_slice(&v[..])), + Loc::Implicit, + )), vec![], )) } @@ -347,10 +355,7 @@ impl SolcRange { self.min, self.max.min( Elem::from(other) - - Elem::Concrete(RangeConcrete { - val: U256::from(1).into(), - loc: Loc::Implicit, - }), + - Elem::Concrete(RangeConcrete::new(U256::from(1).into(), Loc::Implicit)), ), self.exclusions, ) @@ -360,10 +365,7 @@ impl SolcRange { Self::new( self.min.max( Elem::from(other) - + Elem::Concrete(RangeConcrete { - val: U256::from(1).into(), - loc: Loc::Implicit, - }), + + Elem::Concrete(RangeConcrete::new(U256::from(1).into(), Loc::Implicit)), ), self.max, self.exclusions, @@ -395,14 +397,6 @@ impl SolcRange { RangeOp::BitAnd => &Self::bit_and_dyn, RangeOp::BitOr => &Self::bit_or_dyn, RangeOp::BitXor => &Self::bit_xor_dyn, - // RangeOp::And => ( - // &Self::and_dyn, - // (DynSide::Min, DynSide::Max), - // ), - // RangeOp::Or => ( - // &Self::or_dyn, - // (DynSide::Min, DynSide::Max), - // ), e => unreachable!("Comparator operations shouldn't exist in a range: {:?}", e), } } @@ -556,23 +550,24 @@ impl SolcRange { pub fn into_flattened_range( &mut self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { if let Some(cached) = &self.flattened { return Ok(cached.clone()); } - let mut min = Elem::Arena(analyzer.range_arena_idx_or_upsert(self.min.clone())); - let mut max = Elem::Arena(analyzer.range_arena_idx_or_upsert(self.max.clone())); - min.cache_flatten(analyzer)?; - max.cache_flatten(analyzer)?; + let mut min = Elem::Arena(arena.idx_or_upsert(self.min.clone(), analyzer)); + let mut max = Elem::Arena(arena.idx_or_upsert(self.max.clone(), analyzer)); + min.cache_flatten(analyzer, arena)?; + max.cache_flatten(analyzer, arena)?; self.min = min.clone(); self.max = max.clone(); - let simp_min = min.simplify_minimize(analyzer)?; - let simp_max = max.simplify_maximize(analyzer)?; - let min = analyzer.range_arena_idx_or_upsert(simp_min); - let max = analyzer.range_arena_idx_or_upsert(simp_max); + let simp_min = min.simplify_minimize(analyzer, arena)?; + let simp_max = max.simplify_maximize(analyzer, arena)?; + let min = arena.idx_or_upsert(simp_min, analyzer); + let max = arena.idx_or_upsert(simp_max, analyzer); let flat_range = FlattenedRange { min, @@ -601,57 +596,71 @@ impl Range for SolcRange { &mut self.max } - fn cache_eval(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), GraphError> { + fn cache_eval( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), GraphError> { let min = std::mem::take(&mut self.min); let max = std::mem::take(&mut self.max); - self.min = Elem::Arena(analyzer.range_arena_idx_or_upsert(min)); - self.max = Elem::Arena(analyzer.range_arena_idx_or_upsert(max)); + self.min = Elem::Arena(arena.idx_or_upsert(min, analyzer)); + self.max = Elem::Arena(arena.idx_or_upsert(max, analyzer)); if self.max_cached.is_none() { let max = self.range_max_mut(); - max.cache_maximize(analyzer)?; - self.max_cached = - Some(analyzer.range_arena_idx_or_upsert(self.range_max().maximize(analyzer)?)); + max.cache_maximize(analyzer, arena)?; + let res = self.range_max().maximize(analyzer, arena)?; + self.max_cached = Some(arena.idx_or_upsert(res, analyzer)); } if self.min_cached.is_none() { let min = self.range_min_mut(); - min.cache_minimize(analyzer)?; - self.min_cached = - Some(analyzer.range_arena_idx_or_upsert(self.range_min().minimize(analyzer)?)); + min.cache_minimize(analyzer, arena)?; + let res = self.range_min().minimize(analyzer, arena)?; + self.min_cached = Some(arena.idx_or_upsert(res, analyzer)); } Ok(()) } - fn evaled_range_min(&self, analyzer: &impl GraphBackend) -> Result { + fn evaled_range_min( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { if let Some(cached) = &self.min_cached { - Ok(Elem::Arena(*cached).dearenaize(analyzer).borrow().clone()) + Ok(Elem::Arena(*cached).dearenaize_clone(arena)) } else { - self.range_min().minimize(analyzer) + self.range_min().minimize(analyzer, arena) } } - fn evaled_range_max(&self, analyzer: &impl GraphBackend) -> Result { + fn evaled_range_max( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { if let Some(cached) = &self.max_cached { - Ok(Elem::Arena(*cached).dearenaize(analyzer).borrow().clone()) + Ok(Elem::Arena(*cached).dearenaize_clone(arena)) } else { - self.range_max().maximize(analyzer) + self.range_max().maximize(analyzer, arena) } } fn simplified_range_min( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { self.range_min() - .flatten(false, analyzer)? - .simplify_minimize(analyzer) + .flatten(false, analyzer, arena)? + .simplify_minimize(analyzer, arena) } fn simplified_range_max( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { self.range_max() - .flatten(true, analyzer)? - .simplify_maximize(analyzer) + .flatten(true, analyzer, arena)? + .simplify_maximize(analyzer, arena) } fn range_exclusions(&self) -> Vec { @@ -685,21 +694,29 @@ impl Range for SolcRange { self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) { - self.min.filter_recursion(self_idx, new_idx, analyzer); + self.min + .filter_recursion(self_idx, new_idx, analyzer, arena); } fn filter_max_recursion( &mut self, self_idx: NodeIdx, new_idx: NodeIdx, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) { - self.max.filter_recursion(self_idx, new_idx, analyzer); + self.max + .filter_recursion(self_idx, new_idx, analyzer, arena); } - fn cache_flatten(&mut self, analyzer: &mut impl GraphBackend) -> Result<(), Self::GraphError> { + fn cache_flatten( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result<(), Self::GraphError> { if self.flattened.is_none() { - self.into_flattened_range(analyzer)?; + self.into_flattened_range(analyzer, arena)?; } Ok(()) } @@ -707,12 +724,13 @@ impl Range for SolcRange { fn flattened_range<'a>( &'a mut self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Self::GraphError> where Self: Sized + Clone, { if self.flattened.is_none() { - self.cache_flatten(analyzer)?; + self.cache_flatten(analyzer, arena)?; let Some(flat) = &self.flattened else { unreachable!(); }; @@ -728,6 +746,7 @@ impl Range for SolcRange { fn take_flattened_range( &mut self, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result where Self: Sized, @@ -736,46 +755,56 @@ impl Range for SolcRange { if let Some(flat) = taken { Ok(flat) } else { - self.cache_flatten(analyzer)?; - self.take_flattened_range(analyzer) + self.cache_flatten(analyzer, arena)?; + self.take_flattened_range(analyzer, arena) } } } impl RangeEval> for SolcRange { #[tracing::instrument(level = "trace", skip_all)] - fn sat(&self, analyzer: &impl GraphBackend) -> bool { + fn sat(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena>) -> bool { matches!( - self.evaled_range_min(analyzer) + self.evaled_range_min(analyzer, arena) .unwrap() - .range_ord(&self.evaled_range_max(analyzer).unwrap(), analyzer), + .range_ord(&self.evaled_range_max(analyzer, arena).unwrap(), arena), None | Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ) } - fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + fn contains( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { let min_contains = matches!( - self.evaled_range_min(analyzer) + self.evaled_range_min(analyzer, arena) .unwrap() - .range_ord(&other.evaled_range_min(analyzer).unwrap(), analyzer), + .range_ord(&other.evaled_range_min(analyzer, arena).unwrap(), arena), Some(std::cmp::Ordering::Less) | Some(std::cmp::Ordering::Equal) ); let max_contains = matches!( - self.evaled_range_max(analyzer) + self.evaled_range_max(analyzer, arena) .unwrap() - .range_ord(&other.evaled_range_max(analyzer).unwrap(), analyzer), + .range_ord(&other.evaled_range_max(analyzer, arena).unwrap(), arena), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ); min_contains && max_contains } - fn contains_elem(&self, other: &Elem, analyzer: &impl GraphBackend) -> bool { + fn contains_elem( + &self, + other: &Elem, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { let min_contains = match self - .evaled_range_min(analyzer) + .evaled_range_min(analyzer, arena) .unwrap() - .range_ord(&other.minimize(analyzer).unwrap(), analyzer) + .range_ord(&other.minimize(analyzer, arena).unwrap(), arena) { Some(std::cmp::Ordering::Less) => true, Some(std::cmp::Ordering::Equal) => return true, @@ -783,9 +812,9 @@ impl RangeEval> for SolcRange { }; let max_contains = match self - .evaled_range_max(analyzer) + .evaled_range_max(analyzer, arena) .unwrap() - .range_ord(&other.maximize(analyzer).unwrap(), analyzer) + .range_ord(&other.maximize(analyzer, arena).unwrap(), arena) { Some(std::cmp::Ordering::Greater) => true, Some(std::cmp::Ordering::Equal) => return true, @@ -795,18 +824,23 @@ impl RangeEval> for SolcRange { min_contains && max_contains } - fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { - let lhs_min = self.evaled_range_min(analyzer).unwrap(); - let rhs_max = other.evaled_range_max(analyzer).unwrap(); + fn overlaps( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { + let lhs_min = self.evaled_range_min(analyzer, arena).unwrap(); + let rhs_max = other.evaled_range_max(analyzer, arena).unwrap(); - match lhs_min.range_ord(&rhs_max, analyzer) { + match lhs_min.range_ord(&rhs_max, arena) { Some(std::cmp::Ordering::Less) => { // we know our min is less than the other max // check that the max is greater than or eq their min - let lhs_max = self.evaled_range_max(analyzer).unwrap(); - let rhs_min = other.evaled_range_min(analyzer).unwrap(); + let lhs_max = self.evaled_range_max(analyzer, arena).unwrap(); + let rhs_min = other.evaled_range_min(analyzer, arena).unwrap(); matches!( - lhs_max.range_ord(&rhs_min, analyzer), + lhs_max.range_ord(&rhs_min, arena), Some(std::cmp::Ordering::Greater) | Some(std::cmp::Ordering::Equal) ) } @@ -817,21 +851,37 @@ impl RangeEval> for SolcRange { } impl RangeEval> for FlattenedRange { - fn sat(&self, analyzer: &impl GraphBackend) -> bool { - >::into(self.clone()).sat(analyzer) + fn sat(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena>) -> bool { + >::into(self.clone()).sat(analyzer, arena) } - fn unsat(&self, analyzer: &impl GraphBackend) -> bool { - !self.sat(analyzer) + fn unsat(&self, analyzer: &impl GraphBackend, arena: &mut RangeArena>) -> bool { + !self.sat(analyzer, arena) } - fn contains(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + fn contains( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { let other = >::into(other.clone()); - >::into(self.clone()).contains(&other, analyzer) + >::into(self.clone()).contains(&other, analyzer, arena) } - fn contains_elem(&self, other: &Elem, analyzer: &impl GraphBackend) -> bool { - >::into(self.clone()).contains_elem(other, analyzer) + fn contains_elem( + &self, + other: &Elem, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { + >::into(self.clone()) + .contains_elem(other, analyzer, arena) } - fn overlaps(&self, other: &Self, analyzer: &impl GraphBackend) -> bool { + fn overlaps( + &self, + other: &Self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { let other = >::into(other.clone()); - >::into(self.clone()).overlaps(&other, analyzer) + >::into(self.clone()).overlaps(&other, analyzer, arena) } } diff --git a/crates/graph/src/solvers/atoms.rs b/crates/graph/src/solvers/atoms.rs index bdb1351f..27f0d3c3 100644 --- a/crates/graph/src/solvers/atoms.rs +++ b/crates/graph/src/solvers/atoms.rs @@ -8,6 +8,7 @@ use crate::{ }, GraphBackend, }; +use shared::RangeArena; use ethers_core::types::U256; use std::{collections::BTreeMap, rc::Rc}; @@ -42,16 +43,17 @@ impl AtomOrPart { &self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Self { match self { AtomOrPart::Part(part) => { let mut new_part = part.clone(); solves.iter().for_each(|(dep, replacement)| { - new_part.replace_dep(dep.0.into(), replacement.clone(), analyzer) + new_part.replace_dep(dep.0.into(), replacement.clone(), analyzer, arena) }); AtomOrPart::Part(new_part) } - AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves, analyzer)), + AtomOrPart::Atom(atom) => AtomOrPart::Atom(atom.replace_deps(solves, analyzer, arena)), } } @@ -86,10 +88,14 @@ impl AtomOrPart { } } - pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { + pub fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { match self { - AtomOrPart::Part(e) => e.dependent_on(analyzer), - AtomOrPart::Atom(a) => a.dependent_on(analyzer), + AtomOrPart::Part(e) => e.dependent_on(analyzer, arena), + AtomOrPart::Atom(a) => a.dependent_on(analyzer, arena), } } } @@ -126,25 +132,41 @@ pub struct SolverAtom { } impl ToRangeString for SolverAtom { - fn def_string(&self, analyzer: &impl GraphBackend) -> RangeElemString { - self.into_expr_elem().def_string(analyzer) + fn def_string( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { + self.into_expr_elem().def_string(analyzer, arena) } - fn to_range_string(&self, maximize: bool, analyzer: &impl GraphBackend) -> RangeElemString { - self.into_expr_elem().to_range_string(maximize, analyzer) + fn to_range_string( + &self, + maximize: bool, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> RangeElemString { + self.into_expr_elem() + .to_range_string(maximize, analyzer, arena) } } impl SolverAtom { + pub fn assert_nonnull(&self) { + self.lhs.into_elem().assert_nonnull(); + self.rhs.into_elem().assert_nonnull(); + } + pub fn replace_deps( &self, solves: &BTreeMap>, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Self { SolverAtom { ty: self.ty, - lhs: Rc::new(self.lhs.clone().replace_deps(solves, analyzer)), + lhs: Rc::new(self.lhs.clone().replace_deps(solves, analyzer, arena)), op: self.op, - rhs: Rc::new(self.rhs.clone().replace_deps(solves, analyzer)), + rhs: Rc::new(self.rhs.clone().replace_deps(solves, analyzer, arena)), } } @@ -167,9 +189,13 @@ impl SolverAtom { self.ty = self.max_ty(); } - pub fn dependent_on(&self, analyzer: &impl GraphBackend) -> Vec { - let mut deps = self.lhs.dependent_on(analyzer); - deps.extend(self.rhs.dependent_on(analyzer)); + pub fn dependent_on( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Vec { + let mut deps = self.lhs.dependent_on(analyzer, arena); + deps.extend(self.rhs.dependent_on(analyzer, arena)); deps } @@ -247,32 +273,45 @@ pub static LIA_OPS: &[RangeOp] = &[ ]; pub trait Atomize { - fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart; - fn atomize(&self, analyzer: &mut impl GraphBackend) -> Option; + fn atoms_or_part( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> AtomOrPart; + fn atomize( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option; } impl Atomize for Elem { #[tracing::instrument(level = "trace", skip_all)] - fn atoms_or_part(&self, analyzer: &mut impl GraphBackend) -> AtomOrPart { + fn atoms_or_part( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> AtomOrPart { match self { - Elem::Arena(_) => self.dearenaize(analyzer).borrow().atoms_or_part(analyzer), + Elem::Arena(_) => self.dearenaize_clone(arena).atoms_or_part(analyzer, arena), Elem::Concrete(_) | Elem::Reference(_) => AtomOrPart::Part(self.clone()), Elem::ConcreteDyn(_) => AtomOrPart::Part(self.clone()), - Elem::Expr(expr) => { - match collapse(&expr.lhs, expr.op, &expr.rhs, analyzer) { + _e @ Elem::Expr(expr) => { + // println!("collapsing: {e}"); + match collapse(*expr.lhs.clone(), expr.op, *expr.rhs.clone(), arena) { MaybeCollapsed::Concretes(_l, _r) => { - let exec_res = expr.exec_op(true, analyzer).unwrap(); - return exec_res.atoms_or_part(analyzer); + let exec_res = expr.exec_op(true, analyzer, arena).unwrap(); + return exec_res.atoms_or_part(analyzer, arena); } MaybeCollapsed::Collapsed(elem) => { - return elem.atoms_or_part(analyzer); + return elem.atoms_or_part(analyzer, arena); } MaybeCollapsed::Not(..) => {} } match ( - expr.lhs.atoms_or_part(analyzer), - expr.rhs.atoms_or_part(analyzer), + expr.lhs.atoms_or_part(analyzer, arena), + expr.rhs.atoms_or_part(analyzer, arena), ) { (ref lp @ AtomOrPart::Part(ref l), ref rp @ AtomOrPart::Part(ref r)) => { // println!("part part"); @@ -325,12 +364,12 @@ impl Atomize for Elem { todo!("here4"); } (Elem::Concrete(_), Elem::Concrete(_)) => { - let _ = expr.clone().arenaize(analyzer); - let res = expr.exec_op(true, analyzer).unwrap(); + let _ = expr.clone().arenaize(analyzer, arena); + let res = expr.exec_op(true, analyzer, arena).unwrap(); if res == Elem::Expr(expr.clone()) { AtomOrPart::Part(res) } else { - res.atoms_or_part(analyzer) + res.atoms_or_part(analyzer, arena) } } (Elem::ConcreteDyn(_), _) => AtomOrPart::Part(Elem::Null), @@ -359,9 +398,13 @@ impl Atomize for Elem { } #[tracing::instrument(level = "trace", skip_all)] - fn atomize(&self, analyzer: &mut impl GraphBackend) -> Option { + fn atomize( + &self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Option { use Elem::*; - + tracing::trace!("atomize: {}", self); match self { Reference(_) => None, //{ println!("was dyn"); None}, Null => None, //{ println!("was null"); None}, @@ -369,24 +412,19 @@ impl Atomize for Elem { ConcreteDyn(_) => None, //{ println!("was concDyn"); None}, Expr(_) => { // println!("atomized: was expr"); - let AtomOrPart::Atom(mut a) = self.atoms_or_part(analyzer) else { + let AtomOrPart::Atom(mut a) = self.atoms_or_part(analyzer, arena) else { // println!("returning none"); return None; }; a.update_max_ty(); Some(a) } - Arena(_) => match &*self.dearenaize(analyzer).borrow() { - e @ Expr(_) => { - let AtomOrPart::Atom(mut a) = e.atoms_or_part(analyzer) else { - // println!("returning none arena"); - return None; - }; - a.update_max_ty(); - Some(a) - } - _ => None, - }, + Arena(_) => { + let (dearenized, idx) = self.dearenaize(arena); + let res = dearenized.atomize(analyzer, arena); + self.rearenaize(dearenized, idx, arena); + res + } } } } diff --git a/crates/graph/src/solvers/brute.rs b/crates/graph/src/solvers/brute.rs index 55c00381..a810c170 100644 --- a/crates/graph/src/solvers/brute.rs +++ b/crates/graph/src/solvers/brute.rs @@ -8,20 +8,24 @@ use crate::{ AnalyzerBackend, GraphBackend, GraphError, Range, RangeEval, SolcRange, }; +use shared::RangeArena; + use ethers_core::types::U256; use std::collections::BTreeMap; pub trait SolcSolver { - fn simplify(&mut self, analyzer: &impl AnalyzerBackend); + fn simplify(&mut self, analyzer: &impl AnalyzerBackend, arena: &mut RangeArena>); fn solve( &mut self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result; fn recurse_check( &mut self, idx: usize, solved_atomics: &mut Vec, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result; fn check( &mut self, @@ -29,6 +33,7 @@ pub trait SolcSolver { lmr: (Elem, Elem, Elem), solved_atomics: &mut Vec, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(bool, Option), GraphError>; } @@ -84,6 +89,7 @@ impl BruteBinSearchSolver { pub fn maybe_new( deps: Vec, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, GraphError> { let mut atomic_idxs = vec![]; @@ -91,14 +97,14 @@ impl BruteBinSearchSolver { let mut atomic_ranges = BTreeMap::default(); deps.iter().try_for_each(|dep| { let mut range = dep.range(analyzer)?.unwrap(); - if range.unsat(analyzer) { + if range.unsat(analyzer, arena) { panic!( "initial range for {} not sat", dep.display_name(analyzer).unwrap() ); } - let r: SolcRange = range.flattened_range(analyzer)?.into_owned().into(); - atomic_idxs.extend(r.dependent_on(analyzer)); + let r: SolcRange = range.flattened_range(analyzer, arena)?.into_owned().into(); + atomic_idxs.extend(r.dependent_on(analyzer, arena)); ranges.insert(*dep, r); Ok(()) })?; @@ -150,7 +156,10 @@ impl BruteBinSearchSolver { atomic_ranges.insert(atomic.clone(), range); Ok(()) })?; - if let Some((dep, unsat_range)) = ranges.iter().find(|(_, range)| range.unsat(analyzer)) { + if let Some((dep, unsat_range)) = ranges + .iter() + .find(|(_, range)| range.unsat(analyzer, arena)) + { panic!( "Initial ranges not sat for dep {}: {} {}", dep.display_name(analyzer).unwrap(), @@ -177,7 +186,7 @@ impl BruteBinSearchSolver { successful_passes: 0, }; - s.reset_lmrs(analyzer); + s.reset_lmrs(analyzer, arena); Ok(Some(s)) } @@ -185,47 +194,63 @@ impl BruteBinSearchSolver { &self, atomic: &Atomic, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> (Elem, Elem, Elem) { let range = &self.atomic_ranges[atomic]; - let mut min = range.evaled_range_min(analyzer).unwrap(); - min.cache_minimize(analyzer).unwrap(); - // println!("min: {}", min.minimize(analyzer).unwrap().to_range_string(false, analyzer).s); - let mut max = range.evaled_range_max(analyzer).unwrap(); - max.cache_maximize(analyzer).unwrap(); + let mut min = range.evaled_range_min(analyzer, arena).unwrap(); + min.cache_minimize(analyzer, arena).unwrap(); + // println!("min: {}", min.minimize(analyzer).unwrap().to_range_string(false, analyzer, arena).s); + let mut max = range.evaled_range_max(analyzer, arena).unwrap(); + max.cache_maximize(analyzer, arena).unwrap(); let mut mid = (min.clone() + max.clone()) / Elem::from(Concrete::from(U256::from(2))); - mid.cache_maximize(analyzer).unwrap(); + mid.cache_maximize(analyzer, arena).unwrap(); (min, mid, max) } - pub fn reset_lmrs(&mut self, analyzer: &mut impl GraphBackend) { + pub fn reset_lmrs( + &mut self, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) { self.lmrs = vec![]; (0..self.atomic_ranges.len()).for_each(|i| { - self.lmrs.push(self.lmr(&self.atomics[i], analyzer).into()); + self.lmrs + .push(self.lmr(&self.atomics[i], analyzer, arena).into()); }); } - pub fn reset_lmr(&mut self, i: usize, analyzer: &mut impl GraphBackend) { - self.lmrs[i] = self.lmr(&self.atomics[i], analyzer).into(); + pub fn reset_lmr( + &mut self, + i: usize, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) { + self.lmrs[i] = self.lmr(&self.atomics[i], analyzer, arena).into(); } - pub fn raise_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) -> bool { + pub fn raise_lmr( + &mut self, + i: usize, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { // move the low to low + mid / 2 // reset the mid let mut curr_lmr = self.lmrs[i].clone(); curr_lmr.low = (curr_lmr.low + curr_lmr.mid) / Elem::from(Concrete::from(U256::from(2))) - .minimize(analyzer) + .minimize(analyzer, arena) .unwrap(); curr_lmr.mid = (curr_lmr.low.clone() + curr_lmr.high.clone()) / Elem::from(Concrete::from(U256::from(2))) - .minimize(analyzer) + .minimize(analyzer, arena) .unwrap(); - let new_mid_conc = curr_lmr.mid.maximize(analyzer).unwrap(); - let old_mid_conc = self.lmrs[i].mid.maximize(analyzer).unwrap(); + let new_mid_conc = curr_lmr.mid.maximize(analyzer, arena).unwrap(); + let old_mid_conc = self.lmrs[i].mid.maximize(analyzer, arena).unwrap(); if matches!( - new_mid_conc.range_ord(&old_mid_conc, analyzer), + new_mid_conc.range_ord(&old_mid_conc, arena), Some(std::cmp::Ordering::Equal) ) { return false; @@ -234,27 +259,32 @@ impl BruteBinSearchSolver { true } - pub fn lower_lmr(&mut self, i: usize, analyzer: &impl GraphBackend) -> bool { + pub fn lower_lmr( + &mut self, + i: usize, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> bool { // println!("lowering mid"); // move the high to high + mid / 2 // reset the mid let mut curr_lmr = self.lmrs[i].clone(); - curr_lmr.high = (curr_lmr.mid.minimize(analyzer).unwrap() - + curr_lmr.high.minimize(analyzer).unwrap()) + curr_lmr.high = (curr_lmr.mid.minimize(analyzer, arena).unwrap() + + curr_lmr.high.minimize(analyzer, arena).unwrap()) / Elem::from(Concrete::from(U256::from(2))) - .minimize(analyzer) + .minimize(analyzer, arena) .unwrap(); - curr_lmr.mid = (curr_lmr.low.minimize(analyzer).unwrap() - + curr_lmr.high.minimize(analyzer).unwrap()) + curr_lmr.mid = (curr_lmr.low.minimize(analyzer, arena).unwrap() + + curr_lmr.high.minimize(analyzer, arena).unwrap()) / Elem::from(Concrete::from(U256::from(2))) - .minimize(analyzer) + .minimize(analyzer, arena) .unwrap(); - let new_high_conc = curr_lmr.high.minimize(analyzer).unwrap(); - let old_high_conc = self.lmrs[i].high.minimize(analyzer).unwrap(); + let new_high_conc = curr_lmr.high.minimize(analyzer, arena).unwrap(); + let old_high_conc = self.lmrs[i].high.minimize(analyzer, arena).unwrap(); if matches!( - new_high_conc.range_ord(&old_high_conc, analyzer), + new_high_conc.range_ord(&old_high_conc, arena), Some(std::cmp::Ordering::Equal) ) { return false; @@ -270,19 +300,23 @@ impl BruteBinSearchSolver { } impl SolcSolver for BruteBinSearchSolver { - fn simplify(&mut self, _analyzer: &impl AnalyzerBackend) {} + fn simplify( + &mut self, + _analyzer: &impl AnalyzerBackend, + _arena: &mut RangeArena>, + ) { + } fn solve( &mut self, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result { // pick a value for a variable. check if it satisfies all dependendies // if is sat, try to reduce using bin search? Not sure how that will // affect other dependencies If it doesnt, // raise or lower - println!("-------------------------"); - println!("DL SOLVER CHECK"); let atoms = self .ranges .iter() @@ -290,20 +324,19 @@ impl SolcSolver for BruteBinSearchSolver { // println!("dep: {}", dep.display_name(analyzer).unwrap()); // println!("atom: {atom:#?}"); - if let Some(atom) = range.min.atomize(analyzer) { + if let Some(atom) = range.min.atomize(analyzer, arena) { Some(atom) } else { - range.max.atomize(analyzer) + range.max.atomize(analyzer, arena) } }) .collect::>(); - let mut dl_solver = DLSolver::new(atoms, analyzer); + let mut dl_solver = DLSolver::new(atoms, analyzer, arena); let mut atomic_solves: BTreeMap<_, _>; - match dl_solver.solve_partial(analyzer)? { + match dl_solver.solve_partial(analyzer, arena)? { SolveStatus::Unsat => { - println!("TRUE UNSAT"); return Ok(AtomicSolveStatus::Unsat); } SolveStatus::Sat { @@ -318,7 +351,11 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect(); @@ -331,7 +368,11 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect::>(), @@ -346,24 +387,25 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect() } } // println!("solved for: {:#?}", atomic_solves); - println!("-------------------------"); if atomic_solves.len() == self.atomics.len() { - println!("DONE HERE"); - return Ok(AtomicSolveStatus::Sat(atomic_solves)); } else { atomic_solves.iter().for_each(|(atomic, val)| { self.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { atomic.idxs.iter().for_each(|idx| { - r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer) + r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer, arena) }); }); }); @@ -380,22 +422,25 @@ impl SolcSolver for BruteBinSearchSolver { .keys() .filter_map(|k| self.atomics.iter().position(|r| r == k)) .collect(); - while self.recurse_check(self.start_idx, &mut solved_for, analyzer)? {} + while self.recurse_check(self.start_idx, &mut solved_for, analyzer, arena)? {} if self.successful_passes == self.atomics.len() { let mapping = self .intermediate_atomic_ranges .iter() - .filter(|(_, range)| range.is_const(analyzer).unwrap()) - .map(|(name, range)| { - ( - name.clone(), - range - .evaled_range_min(analyzer) - .unwrap() - .maybe_concrete() - .unwrap() - .val, - ) + .filter_map(|(name, range)| { + if !range.is_const(analyzer, arena).ok()? { + None + } else { + Some(( + name.clone(), + range + .evaled_range_min(analyzer, arena) + .unwrap() + .maybe_concrete() + .unwrap() + .val, + )) + } }) .collect::>(); if mapping.len() == self.intermediate_atomic_ranges.len() { @@ -405,12 +450,17 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .for_each(|(atomic, range)| { atomic.idxs.iter().for_each(|idx| { - new_range.replace_dep(idx.0.into(), range.min.clone(), analyzer); + new_range.replace_dep( + idx.0.into(), + range.min.clone(), + analyzer, + arena, + ); }); }); - new_range.cache_eval(analyzer).unwrap(); + new_range.cache_eval(analyzer, arena).unwrap(); // println!("{}, original range: [{}, {}], new range: [{}, {}]", dep.display_name(analyzer).unwrap(), range.min, range.max, new_range.min_cached.clone().unwrap(), new_range.max_cached.clone().unwrap()); - new_range.sat(analyzer) + new_range.sat(analyzer, arena) }); if all_good { Ok(AtomicSolveStatus::Sat(mapping)) @@ -431,6 +481,7 @@ impl SolcSolver for BruteBinSearchSolver { i: usize, solved_atomics: &mut Vec, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result { // println!("recurse check for: {}", self.atomics[i].idxs[0].display_name(analyzer).unwrap()); if i >= self.lmrs.len() { @@ -448,7 +499,13 @@ impl SolcSolver for BruteBinSearchSolver { let lmr = self.lmrs[i].clone(); // println!("solving: {i}, {}, successful passes: {}", atomic.idxs[0].display_name(analyzer).unwrap(), self.successful_passes); // println!("initial range: [{min_s},{max_s}], is_const: {}", atomic.idxs[0].is_const(analyzer)?); - match self.check(i, (lmr.low, lmr.mid, lmr.high), solved_atomics, analyzer)? { + match self.check( + i, + (lmr.low, lmr.mid, lmr.high), + solved_atomics, + analyzer, + arena, + )? { (true, Some(HintOrRanges::Ranges(new_ranges))) => { // sat, try solving next var with new intermediate ranges solved_atomics.push(i); @@ -461,13 +518,13 @@ impl SolcSolver for BruteBinSearchSolver { self.successful_passes = 0; *solved_atomics = vec![]; // unsat, try raising - if self.raise_lmr(i, analyzer) { - self.recurse_check(i, solved_atomics, analyzer) + if self.raise_lmr(i, analyzer, arena) { + self.recurse_check(i, solved_atomics, analyzer, arena) } else { // we couldn't solve, try increasing global start if self.increase_start() { self.intermediate_ranges = self.ranges.clone(); - self.recurse_check(self.start_idx, solved_atomics, analyzer) + self.recurse_check(self.start_idx, solved_atomics, analyzer, arena) } else { Ok(false) } @@ -477,13 +534,13 @@ impl SolcSolver for BruteBinSearchSolver { // unsat, try lowering self.successful_passes = 0; *solved_atomics = vec![]; - if self.lower_lmr(i, analyzer) { - self.recurse_check(i, solved_atomics, analyzer) + if self.lower_lmr(i, analyzer, arena) { + self.recurse_check(i, solved_atomics, analyzer, arena) } else { // we couldn't solve, try increasing global start if self.increase_start() { self.intermediate_ranges = self.ranges.clone(); - self.recurse_check(self.start_idx, solved_atomics, analyzer) + self.recurse_check(self.start_idx, solved_atomics, analyzer, arena) } else { Ok(false) } @@ -493,13 +550,13 @@ impl SolcSolver for BruteBinSearchSolver { // unsat, try lowering self.successful_passes = 0; *solved_atomics = vec![]; - if self.lower_lmr(i, analyzer) { - self.recurse_check(i, solved_atomics, analyzer) + if self.lower_lmr(i, analyzer, arena) { + self.recurse_check(i, solved_atomics, analyzer, arena) } else { // we couldn't solve, try increasing global start if self.increase_start() { self.intermediate_ranges = self.ranges.clone(); - self.recurse_check(self.start_idx, solved_atomics, analyzer) + self.recurse_check(self.start_idx, solved_atomics, analyzer, arena) } else { Ok(false) } @@ -515,6 +572,7 @@ impl SolcSolver for BruteBinSearchSolver { (low, mid, high): (Elem, Elem, Elem), solved_atomics: &mut Vec, analyzer: &mut impl AnalyzerBackend, + arena: &mut RangeArena>, ) -> Result<(bool, Option), GraphError> { let solved_dep = &self.atomics[solved_for_idx].clone(); @@ -528,6 +586,7 @@ impl SolcSolver for BruteBinSearchSolver { mut high_done: bool, solved_atomics: &mut Vec, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(bool, Option), GraphError> { let res = if !low_done { check_for_lmr( @@ -537,6 +596,7 @@ impl SolcSolver for BruteBinSearchSolver { low.clone(), solved_atomics, analyzer, + arena, ) } else if !mid_done { check_for_lmr( @@ -546,6 +606,7 @@ impl SolcSolver for BruteBinSearchSolver { mid.clone(), solved_atomics, analyzer, + arena, ) } else { check_for_lmr( @@ -555,6 +616,7 @@ impl SolcSolver for BruteBinSearchSolver { high.clone(), solved_atomics, analyzer, + arena, ) }; @@ -576,6 +638,7 @@ impl SolcSolver for BruteBinSearchSolver { high_done, solved_atomics, analyzer, + arena, ) } } @@ -590,8 +653,9 @@ impl SolcSolver for BruteBinSearchSolver { conc: Elem, solved_atomics: &mut Vec, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result<(bool, Option), GraphError> { - // println!("checking: {}, conc: {}, {}", this.atomics[solved_for_idx].idxs[0].display_name(analyzer).unwrap(), conc.maximize(analyzer)?.to_range_string(true, analyzer).s, conc.minimize(analyzer)?.to_range_string(false, analyzer).s); + // println!("checking: {}, conc: {}, {}", this.atomics[solved_for_idx].idxs[0].display_name(analyzer).unwrap(), conc.maximize(analyzer, arena)?.to_range_string(true, analyzer, arena).s, conc.minimize(analyzer)?.to_range_string(false, analyzer, arena).s); solved_atomics.push(solved_for_idx); let mut new_ranges = BTreeMap::default(); this.intermediate_atomic_ranges.insert( @@ -604,25 +668,25 @@ impl SolcSolver for BruteBinSearchSolver { .filter_map(|(_, range)| { if let Some(atom) = range .min - .simplify_minimize(analyzer) + .simplify_minimize(analyzer, arena) .unwrap() - .atomize(analyzer) + .atomize(analyzer, arena) { Some(atom) } else { range .max - .simplify_maximize(analyzer) + .simplify_maximize(analyzer, arena) .unwrap() - .atomize(analyzer) + .atomize(analyzer, arena) } }) .collect::>(); - let mut dl_solver = DLSolver::new(atoms, analyzer); + let mut dl_solver = DLSolver::new(atoms, analyzer, arena); let mut atomic_solves: BTreeMap<_, _>; - match dl_solver.solve_partial(analyzer)? { + match dl_solver.solve_partial(analyzer, arena)? { SolveStatus::Unsat => { println!("TRUE UNSAT"); return Ok((false, None)); @@ -639,7 +703,11 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect(); @@ -652,7 +720,11 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect::>(), @@ -667,7 +739,11 @@ impl SolcSolver for BruteBinSearchSolver { .iter() .find(|atomic| atomic.idxs.contains(&dep))? .clone(), - solve.maximize(analyzer).unwrap().maybe_concrete()?.val, + solve + .maximize(analyzer, arena) + .unwrap() + .maybe_concrete()? + .val, )) }) .collect() @@ -677,7 +753,7 @@ impl SolcSolver for BruteBinSearchSolver { atomic_solves.iter().for_each(|(atomic, val)| { this.intermediate_ranges.iter_mut().for_each(|(_dep, r)| { atomic.idxs.iter().for_each(|idx| { - r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer) + r.replace_dep(idx.0.into(), Elem::from(val.clone()), analyzer, arena) }); }); }); @@ -734,7 +810,7 @@ impl SolcSolver for BruteBinSearchSolver { // check if the new range is dependent on the solved variable let is_dependent_on_solved = new_range - .dependent_on(analyzer) + .dependent_on(analyzer, arena) .iter() .any(|dep| solved_dep.idxs.contains(dep)); @@ -747,15 +823,15 @@ impl SolcSolver for BruteBinSearchSolver { // println!("new range for {} dependent_on: {:?}, replacing {:?}, is dependent on solved: {is_dependent_on_solved}", dep.display_name(analyzer).unwrap(), new_range.dependent_on(), solved_dep.idxs); // println!("dep {}:\n\tinitial range: [{}, {}],\n\tcurr range: [{}, {}]", // dep.display_name(analyzer).unwrap(), - // dep.evaled_range_min(analyzer)?.unwrap().to_range_string(false, analyzer).s, - // dep.evaled_range_max(analyzer)?.unwrap().to_range_string(true, analyzer).s, - // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, - // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, + // dep.evaled_range_min(analyzer, arena)?.unwrap().to_range_string(false, analyzer, arena).s, + // dep.evaled_range_max(analyzer, arena)?.unwrap().to_range_string(true, analyzer, arena).s, + // new_range.evaled_range_min(analyzer, arena)?.to_range_string(false, analyzer, arena).s, + // new_range.evaled_range_max(analyzer, arena)?.to_range_string(true, analyzer, arena).s, // // new_range.range_min() // ); // println!("dep {} range: {:#?} {:#?}", dep.display_name(analyzer).unwrap(), new_range.min, new_range.max); - if new_range.unsat(analyzer) { + if new_range.unsat(analyzer, arena) { return Ok((false, None)); // panic!("initial range unsat???") } @@ -764,21 +840,21 @@ impl SolcSolver for BruteBinSearchSolver { .idxs .iter() .for_each(|atomic_alias| { - new_range.replace_dep(atomic_alias.0.into(), conc.clone(), analyzer); + new_range.replace_dep(atomic_alias.0.into(), conc.clone(), analyzer, arena); }); - new_range.cache_eval(analyzer)?; + new_range.cache_eval(analyzer, arena)?; // println!("new range: [{}, {}], [{}, {}]", - // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, - // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, - // new_range.min.to_range_string(false, analyzer).s, - // new_range.max.to_range_string(true, analyzer).s, + // new_range.evaled_range_min(analyzer, arena)?.to_range_string(false, analyzer, arena).s, + // new_range.evaled_range_max(analyzer, arena)?.to_range_string(true, analyzer, arena).s, + // new_range.min.to_range_string(false, analyzer, arena).s, + // new_range.max.to_range_string(true, analyzer, arena).s, // ); - if new_range.unsat(analyzer) { + if new_range.unsat(analyzer, arena) { // figure out *where* we need to increase or decrease // work on the unreplace range for now - let min_is_dependent = !range.min.dependent_on(analyzer).is_empty(); - let max_is_dependent = !range.max.dependent_on(analyzer).is_empty(); + let min_is_dependent = !range.min.dependent_on(analyzer, arena).is_empty(); + let max_is_dependent = !range.max.dependent_on(analyzer, arena).is_empty(); match (min_is_dependent, max_is_dependent) { (true, true) => { @@ -799,18 +875,18 @@ impl SolcSolver for BruteBinSearchSolver { } // println!("new unsat range: [{}, {}]", - // new_range.evaled_range_min(analyzer)?.to_range_string(false, analyzer).s, - // new_range.evaled_range_max(analyzer)?.to_range_string(true, analyzer).s, + // new_range.evaled_range_min(analyzer, arena)?.to_range_string(false, analyzer, arena).s, + // new_range.evaled_range_max(analyzer, arena)?.to_range_string(true, analyzer, arena).s, // ); // compare new range to prev range to see if they moved down or up // panic!("here"); let min_change = new_range - .evaled_range_min(analyzer)? - .range_ord(&range.evaled_range_min(analyzer)?, analyzer); + .evaled_range_min(analyzer, arena)? + .range_ord(&range.evaled_range_min(analyzer, arena)?, arena); let max_change = new_range - .evaled_range_max(analyzer)? - .range_ord(&range.evaled_range_max(analyzer)?, analyzer); + .evaled_range_max(analyzer, arena)? + .range_ord(&range.evaled_range_max(analyzer, arena)?, arena); match (min_change, max_change) { (Some(std::cmp::Ordering::Less), Some(std::cmp::Ordering::Greater)) => { // panic!("initial range must have been unsat to start"); @@ -859,6 +935,7 @@ impl SolcSolver for BruteBinSearchSolver { false, solved_atomics, analyzer, + arena, ) } } diff --git a/crates/graph/src/solvers/dl.rs b/crates/graph/src/solvers/dl.rs index 56783a0e..68782961 100644 --- a/crates/graph/src/solvers/dl.rs +++ b/crates/graph/src/solvers/dl.rs @@ -1,10 +1,13 @@ use crate::{ nodes::{Concrete, ContextVarNode}, range::elem::*, + range::range_string::ToRangeString, solvers::{AtomOrPart, Atomize, OpType, SolverAtom}, GraphBackend, GraphError, }; +use shared::RangeArena; + use ethers_core::types::{I256, U256}; use itertools::Itertools; use petgraph::{ @@ -62,7 +65,11 @@ pub struct DLSolveResult { } impl DLSolver { - pub fn new(mut constraints: Vec, analyzer: &mut impl GraphBackend) -> Self { + pub fn new( + mut constraints: Vec, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, + ) -> Self { constraints.iter_mut().for_each(|c| { c.update_max_ty(); }); @@ -74,7 +81,7 @@ impl DLSolver { root_node, ..Default::default() }; - s.add_constraints(vec![], analyzer); + s.add_constraints(vec![], analyzer, arena); s } @@ -102,11 +109,49 @@ impl DLSolver { &mut self, constraints: Vec, analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> BTreeMap>> { // println!("adding constriants: {constraints:#?}"); + let constraints: Vec<_> = constraints + .into_iter() + .flat_map(|mut constraint| { + if let AtomOrPart::Part(c) = &*constraint.lhs { + if let Some(mut c) = c.maybe_concrete() { + c.val = c.val.max_size(); + constraint.lhs = AtomOrPart::Part(Elem::Concrete(c)).into() + } + } + + if let AtomOrPart::Part(c) = &*constraint.rhs { + if let Some(mut c) = c.maybe_concrete() { + c.val = c.val.max_size(); + constraint.rhs = AtomOrPart::Part(Elem::Concrete(c)).into() + } + } + + if constraint.op == RangeOp::And { + vec![ + SolverAtom { + ty: OpType::Const, + lhs: constraint.lhs, + op: RangeOp::Eq, + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from(true)))), + }, + SolverAtom { + ty: OpType::Const, + lhs: constraint.rhs, + op: RangeOp::Eq, + rhs: Rc::new(AtomOrPart::Part(Elem::from(Concrete::from(true)))), + }, + ] + } else { + vec![constraint] + } + }) + .collect(); let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -129,9 +174,8 @@ impl DLSolver { .collect(); // println!("unique constraints: {constraints:#?}"); - constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -181,7 +225,7 @@ impl DLSolver { let still_unknown_constraints: Vec<_> = constraints .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); !deps.iter().all(|dep| const_solves.contains_key(dep)) }) .cloned() @@ -196,7 +240,7 @@ impl DLSolver { let res = still_unknown_constraints .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); deps.iter().all(|dep| { dep_to_solve_ty .get(dep) @@ -208,14 +252,15 @@ impl DLSolver { .collect::>() .iter() .map(|constraint| { - ( - constraint.clone(), - Self::dl_atom_normalize(constraint.clone().clone(), analyzer), - ) + let t = Self::dl_atom_normalize(constraint.clone().clone(), analyzer, arena); + t.map(|t| (constraint.clone(), t)) }) - .collect::>>>(); + .collect::>>>>(); // println!("normalized map: {res:#?}"); - res + match res { + Some(t) => t, + None => Default::default(), + } } pub fn dl_solvable_constraints(&self) -> Vec>> { @@ -224,12 +269,13 @@ impl DLSolver { pub fn solve_partial( &mut self, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { // println!("constraints {:#?}", self.constraints); let mut dep_to_solve_ty: BTreeMap> = BTreeMap::default(); self.constraints.iter().for_each(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); deps.into_iter().for_each(|dep| { if let Some(entry) = dep_to_solve_ty.get_mut(&dep) { if constraint.ty == OpType::Const { @@ -250,7 +296,7 @@ impl DLSolver { atoms.iter().any(|atom| { atom.op == RangeOp::Neq && atom.lhs == atom.rhs - && !atom.lhs.dependent_on(analyzer).is_empty() + && !atom.lhs.dependent_on(analyzer, arena).is_empty() }) }) { return Ok(SolveStatus::Unsat); @@ -291,7 +337,7 @@ impl DLSolver { .clone() .into_iter() .filter(|constraint| { - let deps = constraint.dependent_on(analyzer); + let deps = constraint.dependent_on(analyzer, arena); !deps.iter().all(|dep| const_solves.contains_key(dep)) }) .collect(); @@ -342,10 +388,10 @@ impl DLSolver { // check if basics are unsat, if so the extra constraints wont help that // so its truly unsat // println!("basic: {basic:#?}"); - let basic_solve = self.dl_solve(basic.clone(), analyzer)?; - // if matches!(basic_solve.status, SolveStatus::Unsat) { - // return Ok(SolveStatus::Unsat); - // } + let basic_solve = self.dl_solve(basic.clone(), analyzer, arena)?; + if matches!(basic_solve.status, SolveStatus::Unsat) { + return Ok(SolveStatus::Unsat); + } // println!("basic solve: {basic_solve:?}"); @@ -397,7 +443,7 @@ impl DLSolver { .collect(); // add the constant paths flattened.extend(basic.clone()); - let solve = self.dl_solve(flattened, analyzer)?; + let solve = self.dl_solve(flattened, analyzer, arena)?; // remove the added constraints, keeping the basic graph in tact self.remove_added(&solve); // now that we checked that @@ -434,11 +480,22 @@ impl DLSolver { }); } + #[tracing::instrument(level = "trace", skip_all)] pub fn dl_solve( &mut self, normalized_constraints: Vec, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Result { + if self.graph.node_count() == 0 { + let root_node = self.graph.add_node(AtomOrPart::Part(Elem::Null)); + self.root_node = root_node; + } + + // println!("constraints:"); + // normalized_constraints.iter().for_each(|c| { + // println!("{}", c.into_expr_elem()); + // }); let mut added_atoms = vec![]; let mut added_deps = vec![]; if normalized_constraints.is_empty() { @@ -463,8 +520,8 @@ impl DLSolver { }; let rhs_atom = constraint.rhs.expect_atom(); - let rhs_lhs_deps = rhs_atom.lhs.dependent_on(analyzer); - let rhs_rhs_deps = rhs_atom.rhs.dependent_on(analyzer); + let rhs_lhs_deps = rhs_atom.lhs.dependent_on(analyzer, arena); + let rhs_rhs_deps = rhs_atom.rhs.dependent_on(analyzer, arena); let ((dyn_elem, dep), const_elem) = match (!rhs_lhs_deps.is_empty(), !rhs_rhs_deps.is_empty()) { (true, true) => { @@ -476,7 +533,7 @@ impl DLSolver { if matches!(rhs_atom.op, RangeOp::Sub(_)) { let const_elem = (rhs_atom.rhs.into_elem() * Elem::from(Concrete::from(I256::from(-1)))) - .maximize(analyzer) + .maximize(analyzer, arena) .unwrap(); ( (rhs_atom.lhs, Some(rhs_lhs_deps[0])), @@ -490,7 +547,7 @@ impl DLSolver { if matches!(rhs_atom.op, RangeOp::Sub(_)) { let const_elem = (rhs_atom.lhs.into_elem() * Elem::from(Concrete::from(I256::from(-1)))) - .maximize(analyzer) + .maximize(analyzer, arena) .unwrap(); ( (rhs_atom.rhs, Some(rhs_rhs_deps[0])), @@ -537,7 +594,7 @@ impl DLSolver { ); }); - if find_negative_cycle(&self.graph, root_node, analyzer).is_some() { + if find_negative_cycle(&self.graph, root_node, analyzer, arena).is_some() { return Ok(DLSolveResult { status: SolveStatus::Unsat, added_atoms, @@ -545,13 +602,13 @@ impl DLSolver { }); } - let (mut dists, _) = bellman_ford_initialize_relax(&self.graph, root_node, analyzer); + let (mut dists, _) = bellman_ford_initialize_relax(&self.graph, root_node, analyzer, arena); dists = dists .into_iter() .map(|dist| { (dist * Elem::from(Concrete::from(I256::from(-1)))) - .maximize(analyzer) + .maximize(analyzer, arena) .unwrap() }) .collect(); @@ -584,10 +641,17 @@ impl DLSolver { /// Normalizes a DL atom into x <= y - k, where x and y are variables and k is a constant. /// Needed for running negative cycle check. Additionally, if we have an `OR`, we + #[tracing::instrument(level = "trace", skip_all)] pub fn dl_atom_normalize( constraint: SolverAtom, analyzer: &mut impl GraphBackend, - ) -> Vec> { + arena: &mut RangeArena>, + ) -> Option>> { + constraint.assert_nonnull(); + tracing::trace!( + "constraint: {}, {constraint:#?}", + constraint.to_range_string(false, analyzer, arena).s + ); let zero_part = AtomOrPart::Part(Elem::from(Concrete::from(U256::zero()))); let false_part = AtomOrPart::Part(Elem::from(Concrete::from(false))); let true_part = AtomOrPart::Part(Elem::from(Concrete::from(true))); @@ -599,26 +663,26 @@ impl DLSolver { (true, true) => { if constraint.lhs == constraint.rhs { // true == true || false == false, just disregard this atom - return vec![vec![]]; + return Some(vec![vec![]]); } else { panic!("During normalization of a DL atom, got true == false"); } } (true, false) => { // lhs is just a boolean, drop it - return Self::dl_atom_normalize(constraint.rhs.as_solver_atom(), analyzer); + return Self::dl_atom_normalize(constraint.rhs.as_solver_atom(), analyzer, arena); } (false, true) => { // rhs is just a boolean, drop it - return Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); + return Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer, arena); } _ => {} } // x <==> y // x + x + y => AtomOrPart::Atom(Atom { lhs x, op: +, rhs: AtomOrPart::Atom(Atom { lhs: x, op: +, rhs: y})}) - let lhs_symbs = constraint.lhs.dependent_on(analyzer); - let rhs_symbs = constraint.rhs.dependent_on(analyzer); + let lhs_symbs = constraint.lhs.dependent_on(analyzer, arena); + let rhs_symbs = constraint.rhs.dependent_on(analyzer, arena); let constraint = match (!lhs_symbs.is_empty(), !rhs_symbs.is_empty()) { (true, true) => { // TODO: in theory could have x x + y @@ -711,7 +775,7 @@ impl DLSolver { }; // println!("normalizing: {}", constraint.into_expr_elem()); - match constraint.op { + let res = match constraint.op { RangeOp::Eq => { // convert `x == y` into `x <= y - 0 || y <= x - 0` let mut res = Self::dl_atom_normalize( @@ -727,7 +791,8 @@ impl DLSolver { })), }, analyzer, - ); + arena, + )?; assert!(res.len() == 1); res[0].extend( @@ -744,10 +809,11 @@ impl DLSolver { })), }, analyzer, - ) + arena, + )? .remove(0), ); - res + Some(res) } RangeOp::Neq => { // convert `x != y` into `x <= y - 1 || y <= x - 1` @@ -766,7 +832,8 @@ impl DLSolver { })), }, analyzer, - ); + arena, + )?; assert!(res.len() == 1); @@ -786,10 +853,11 @@ impl DLSolver { })), }, analyzer, - ) + arena, + )? .remove(0), ); - res + Some(res) } RangeOp::Lt => { // x < y @@ -798,7 +866,7 @@ impl DLSolver { .rhs .into_elem() .wrapping_sub(Elem::from(Concrete::from(U256::one()))) - .atoms_or_part(analyzer); + .atoms_or_part(analyzer, arena); Self::dl_atom_normalize( SolverAtom { ty: OpType::DL, @@ -807,6 +875,7 @@ impl DLSolver { rhs: Rc::new(new_rhs), }, analyzer, + arena, ) } RangeOp::Gte => Self::dl_atom_normalize( @@ -817,6 +886,7 @@ impl DLSolver { rhs: constraint.lhs, }, analyzer, + arena, ), RangeOp::Gt => Self::dl_atom_normalize( SolverAtom { @@ -826,21 +896,24 @@ impl DLSolver { rhs: constraint.lhs, }, analyzer, + arena, ), RangeOp::Or => { - let mut res = Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer); + let mut res = + Self::dl_atom_normalize(constraint.lhs.as_solver_atom(), analyzer, arena)?; res.extend(Self::dl_atom_normalize( constraint.rhs.as_solver_atom(), analyzer, - )); - res + arena, + )?); + Some(res) } RangeOp::Lte => { if constraint.lhs.is_atom() { // some form of (x + k <= y) let lhs_atom = constraint.lhs.expect_atom(); - let atom_lhs_is_symb = !lhs_atom.lhs.dependent_on(analyzer).is_empty(); - let atom_rhs_is_symb = !lhs_atom.rhs.dependent_on(analyzer).is_empty(); + let atom_lhs_is_symb = !lhs_atom.lhs.dependent_on(analyzer, arena).is_empty(); + let atom_rhs_is_symb = !lhs_atom.rhs.dependent_on(analyzer, arena).is_empty(); match lhs_atom.op { RangeOp::Sub(_) => { @@ -862,6 +935,7 @@ impl DLSolver { })), }, analyzer, + arena, ) } _ => { @@ -880,6 +954,7 @@ impl DLSolver { })), }, analyzer, + arena, ) } } @@ -894,6 +969,7 @@ impl DLSolver { rhs: constraint.rhs, }, analyzer, + arena, ) } else if lhs_atom.rhs == zero_part.into() { Self::dl_atom_normalize( @@ -904,9 +980,28 @@ impl DLSolver { rhs: constraint.rhs, }, analyzer, + arena, + ) + } else if lhs_atom.lhs.dependent_on(analyzer, arena).is_empty() { + // (k + x <= y) + // ==> (x <= y - k) + Self::dl_atom_normalize( + SolverAtom { + ty: constraint.ty, + lhs: lhs_atom.rhs, + op: constraint.op, + rhs: Rc::new(AtomOrPart::Atom(SolverAtom { + ty: constraint.ty, + lhs: constraint.rhs, + op: RangeOp::Sub(true), + rhs: lhs_atom.lhs, + })), + }, + analyzer, + arena, ) } else { - // (k + x <= y) || (x + k <= y) + // (x + k <= y) // ==> (x <= y - k) Self::dl_atom_normalize( SolverAtom { @@ -921,6 +1016,7 @@ impl DLSolver { })), }, analyzer, + arena, ) } } @@ -933,7 +1029,8 @@ impl DLSolver { rhs: constraint.rhs.clone(), }, analyzer, - ); + arena, + )?; let mut rhs = Self::dl_atom_normalize( SolverAtom { @@ -943,8 +1040,9 @@ impl DLSolver { rhs: constraint.rhs.clone(), }, analyzer, - ); - match (res.len() > 1, rhs.len() > 1) { + arena, + )?; + let res = match (res.len() > 1, rhs.len() > 1) { (true, true) => { res.extend(rhs); res @@ -961,41 +1059,9 @@ impl DLSolver { res[0].extend(rhs.remove(0)); res } - } + }; + Some(res) } - // RangeOp::Eq => { - // // (atom.lhs == atom.rhs) <= rhs - // // try just swapping - // // rhs >= - // let new_lhs_atom = SolverAtom { - // ty: constraint.ty, - // lhs: lhs_atom.lhs, - // op: RangeOp::Sub(true), - // rhs: lhs_atom.rhs - // }; - // Self::dl_atom_normalize(SolverAtom { - // ty: constraint.ty, - // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), - // op: constraint.op, - // rhs: constraint.rhs.clone(), - // }) - // } - // RangeOp::Neq => { - // // (atom.lhs != atom.rhs) <= rhs - // // (atom.lhs - atom.rhs) <= rhs - // let new_lhs_atom = SolverAtom { - // ty: constraint.ty, - // lhs: lhs_atom.lhs, - // op: RangeOp::Sub(true), - // rhs: lhs_atom.rhs - // }; - // Self::dl_atom_normalize(SolverAtom { - // ty: constraint.ty, - // lhs: Box::new(AtomOrPart::Atom(new_lhs_atom)), - // op: constraint.op, - // rhs: constraint.rhs.clone(), - // }) - // } other => panic!("other op: {}, {constraint:#?}", other.to_string()), } } else if constraint.rhs.is_part() { @@ -1014,29 +1080,36 @@ impl DLSolver { rhs: Rc::new(new_rhs), }, analyzer, + arena, ) } else { - vec![vec![constraint]] + Some(vec![vec![constraint]]) } } - _other => { - // println!("other: {}, {}", other.to_string(), constraint.into_expr_elem()); - Self::dl_atom_normalize(constraint, analyzer) + other => { + tracing::trace!( + "unable to dl normalize -- other: {}, {}", + other.to_string(), + constraint.into_expr_elem() + ); + None } - } + }; + res } } pub fn find_negative_cycle( g: &DLGraph, source: NodeIndex, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> Option>> { let ix = |i| g.to_index(i); let mut path = Vec::>::new(); // Step 1: initialize and relax - let (distance, predecessor) = bellman_ford_initialize_relax(g, source, analyzer); + let (distance, predecessor) = bellman_ford_initialize_relax(g, source, analyzer, arena); // Step 2: Check for negative weight cycle 'outer: for i in g.node_identifiers() { @@ -1044,10 +1117,10 @@ pub fn find_negative_cycle( let j = edge.target(); let w = edge.weight(); let dist = (distance[ix(i)].clone() + w.into_elem()) - .maximize(analyzer) + .maximize(analyzer, arena) .unwrap(); let lt = matches!( - dist.range_ord(&distance[ix(j)], analyzer), + dist.range_ord(&distance[ix(j)], arena), Some(std::cmp::Ordering::Less) ); if lt { @@ -1104,7 +1177,8 @@ pub fn find_negative_cycle( fn bellman_ford_initialize_relax( g: &DLGraph, source: NodeIndex, - analyzer: &impl GraphBackend, + analyzer: &mut impl GraphBackend, + arena: &mut RangeArena>, ) -> (Vec>, Vec>>) { // Step 1: initialize graph let mut predecessor = vec![None; g.node_bound()]; @@ -1120,10 +1194,10 @@ fn bellman_ford_initialize_relax( let j = edge.target(); let w = edge.weight(); let dist = (distance[ix(i)].clone() + w.into_elem()) - .maximize(analyzer) + .maximize(analyzer, arena) .unwrap(); let lt = matches!( - dist.range_ord(&distance[ix(j)], analyzer), + dist.range_ord(&distance[ix(j)], arena), Some(std::cmp::Ordering::Less) ); if lt { diff --git a/crates/graph/src/var_type.rs b/crates/graph/src/var_type.rs index b56d1df0..23112944 100644 --- a/crates/graph/src/var_type.rs +++ b/crates/graph/src/var_type.rs @@ -9,6 +9,7 @@ use crate::{ }, AnalyzerBackend, AsDotStr, GraphBackend, GraphError, Node, }; +use shared::RangeArena; use shared::NodeIdx; @@ -22,7 +23,11 @@ pub enum VarType { } impl AsDotStr for VarType { - fn as_dot_str(&self, analyzer: &impl GraphBackend) -> String { + fn as_dot_str( + &self, + analyzer: &impl GraphBackend, + _arena: &mut RangeArena>, + ) -> String { self.as_string(analyzer).unwrap() } } @@ -488,15 +493,19 @@ impl VarType { } } - pub fn is_const(&self, analyzer: &impl GraphBackend) -> Result { + pub fn is_const( + &self, + analyzer: &impl GraphBackend, + arena: &mut RangeArena>, + ) -> Result { match self { Self::Concrete(_) => Ok(true), Self::User(TypeNode::Func(_), _) => Ok(false), _ => { if let Some(range) = self.ref_range(analyzer)? { - let min = range.evaled_range_min(analyzer)?; - let max = range.evaled_range_max(analyzer)?; - Ok(min.range_eq(&max, analyzer)) + let min = range.evaled_range_min(analyzer, arena)?; + let max = range.evaled_range_max(analyzer, arena)?; + Ok(min.range_eq(&max, arena)) } else { Ok(false) } @@ -514,11 +523,12 @@ impl VarType { pub fn evaled_range( &self, analyzer: &impl GraphBackend, + arena: &mut RangeArena>, ) -> Result, Elem)>, GraphError> { Ok(self.ref_range(analyzer)?.map(|range| { ( - range.evaled_range_min(analyzer).unwrap(), - range.evaled_range_max(analyzer).unwrap(), + range.evaled_range_min(analyzer, arena).unwrap(), + range.evaled_range_max(analyzer, arena).unwrap(), ) })) } @@ -533,13 +543,13 @@ impl VarType { // Self::BuiltIn(node, Some(r)) => { // if let Builtin::Bytes(size) = node.underlying(analyzer)? { // if r.is_const(analyzer)? && index.is_const(analyzer)? { - // let Some(min) = r.evaled_range_min(analyzer)?.maybe_concrete() else { + // let Some(min) = r.evaled_range_min(analyzer, arena)?.maybe_concrete() else { // return Ok(None); // }; // let Concrete::Bytes(_, val) = min.val else { // return Ok(None); // }; - // let Some(idx) = index.evaled_range_min(analyzer)?.unwrap().maybe_concrete() + // let Some(idx) = index.evaled_range_min(analyzer, arena)?.unwrap().maybe_concrete() // else { // return Ok(None); // }; @@ -570,7 +580,7 @@ impl VarType { // _ => false, // }, // c @ Elem::Concrete(..) if is_const => { - // let index_val = index.evaled_range_min(analyzer).unwrap().unwrap(); + // let index_val = index.evaled_range_min(analyzer, arena).unwrap().unwrap(); // index_val.range_eq(c) // } // _ => false, @@ -589,7 +599,7 @@ impl VarType { // Self::Concrete(node) => { // if index.is_const(analyzer)? { // let idx = index - // .evaled_range_min(analyzer) + // .evaled_range_min(analyzer, arena) // .unwrap() // .unwrap() // .concrete() diff --git a/crates/pyrometer/benches/parse.rs b/crates/pyrometer/benches/parse.rs index 1f2f0e58..d4e5a37f 100644 --- a/crates/pyrometer/benches/parse.rs +++ b/crates/pyrometer/benches/parse.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use pyrometer::{Analyzer, SourcePath}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::env::{self}; use std::fs; @@ -23,17 +23,18 @@ criterion_main!(benches); /// /// A vector of tuples representing the targets. fn get_targets(bench_contracts_root: PathBuf) -> Vec<(String, PathBuf, usize)> { - let mut targets = vec![]; - targets.push(( - "ctoken".to_string(), - bench_contracts_root.join("flat_ctoken.sol"), - 50, // range of tens ms - )); - targets.push(( - "comptroller".to_string(), - bench_contracts_root.join("flat_comptroller.sol"), - 10, // range of singles seconds. 10 samples is lowest - )); + let targets = vec![ + ( + "ctoken".to_string(), + bench_contracts_root.join("flat_ctoken.sol"), + 50, // range of tens ms + ), + ( + "comptroller".to_string(), + bench_contracts_root.join("flat_comptroller.sol"), + 10, // range of singles seconds. 10 samples is lowest + ), + ]; targets } @@ -59,8 +60,8 @@ fn bench(c: &mut Criterion) { parsing_group.sample_size(sample_size); let sol = fs::read_to_string(path.clone()).expect("Could not find file"); let bench_id = BenchmarkId::new("parse", sample_size); - parsing_group.bench_with_input(bench_id, &(path, &sol), |b, (path, &ref sol)| { - b.iter(|| parse(path, sol.clone())); + parsing_group.bench_with_input(bench_id, &(path, &sol), |b, (path, sol)| { + b.iter(|| parse(path, sol.to_string())); }); parsing_group.finish(); } @@ -72,8 +73,10 @@ fn bench(c: &mut Criterion) { /// /// * `path` - A `PathBuf` representing the path to the source code file. /// * `sol` - A string containing the Solidity source code. -fn parse(path: &PathBuf, sol: String) { +fn parse(path: &Path, sol: String) { let mut analyzer = Analyzer::default(); - let current_path = SourcePath::SolidityFile(path.clone()); - let _maybe_entry = analyzer.parse(&sol, ¤t_path, true); + let mut arena_base = Default::default(); + let arena = &mut arena_base; + let current_path = SourcePath::SolidityFile(path.to_path_buf()); + let _maybe_entry = analyzer.parse(arena, &sol, ¤t_path, true); } diff --git a/crates/pyrometer/src/analyzer.rs b/crates/pyrometer/src/analyzer.rs index 0bae6119..8dee588d 100644 --- a/crates/pyrometer/src/analyzer.rs +++ b/crates/pyrometer/src/analyzer.rs @@ -22,11 +22,9 @@ use solang_parser::{ }; use std::{ - cell::RefCell, collections::BTreeMap, fs, path::{Path, PathBuf}, - rc::Rc, }; /// A path to either a single solidity file or a Solc Standard JSON file @@ -138,6 +136,8 @@ pub struct Analyzer { pub join_stats: JoinStats, /// An arena of ranges pub range_arena: RangeArena>, + /// Parsed functions + pub handled_funcs: Vec, } impl Default for Analyzer { @@ -166,13 +166,14 @@ impl Default for Analyzer { fn_calls_fns: Default::default(), join_stats: JoinStats::default(), range_arena: RangeArena { - ranges: vec![Rc::new(RefCell::new(Elem::Null))], + ranges: vec![Elem::Null], map: { let mut map: AHashMap, usize> = Default::default(); map.insert(Elem::Null, 0); map }, }, + handled_funcs: Vec::default(), }; a.builtin_fn_inputs = builtin_fns::builtin_fns_inputs(&mut a); @@ -198,7 +199,11 @@ impl Default for Analyzer { } impl Analyzer { - pub fn stats(&self, duration: std::time::Duration) -> String { + pub fn stats( + &self, + duration: std::time::Duration, + arena: &RangeArena>, + ) -> String { let num_nodes = self.graph.node_count(); let num_contracts = self.number_of_contracts(); let num_funcs = self.number_of_functions(); @@ -233,7 +238,7 @@ impl Analyzer { format!(""), format!( " Unique Range Elements: {}", - self.range_arena.ranges.len() + arena.ranges.len() ), format!(""), format!( @@ -340,6 +345,7 @@ impl Analyzer { pub fn complicated_parse( &mut self, + arena: &mut RangeArena>, expr: &Expression, parent: Option, ) -> Option { @@ -368,7 +374,7 @@ impl Analyzer { }; let full_stmt = solang_parser::pt::Statement::Return(expr.loc(), Some(expr.clone())); - self.parse_ctx_statement(&full_stmt, false, Some(ctx)); + self.parse_ctx_statement(arena, &full_stmt, false, Some(ctx)); let edges = self.add_if_err(ctx.successful_edges(self).into_expr_err(expr.loc()))?; if edges.len() == 1 { let res = edges[0].return_nodes(self).into_expr_err(expr.loc()); @@ -481,8 +487,13 @@ impl Analyzer { } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse(&mut self, src: &str, current_path: &SourcePath, entry: bool) -> Option { - // tracing::trace!("parsing: {:?}", current_path); + pub fn parse( + &mut self, + arena: &mut RangeArena>, + src: &str, + current_path: &SourcePath, + entry: bool, + ) -> Option { let file_no = self.file_no; self.sources .push((current_path.clone(), src.to_string(), Some(file_no), None)); @@ -491,11 +502,16 @@ impl Analyzer { let parent = self.add_node(Node::SourceUnit(graph::nodes::SourceUnit::new(file_no))); self.add_edge(parent, self.entry, Edge::Source); - let final_pass_part = - self.parse_source_unit(source_unit, file_no, parent.into(), current_path); + let final_pass_part = self.parse_source_unit( + arena, + source_unit, + file_no, + parent.into(), + current_path, + ); self.final_pass_items.push(final_pass_part); if entry { - self.final_pass(); + self.final_pass(arena); } Some(parent) @@ -508,8 +524,13 @@ impl Analyzer { } } - pub fn final_pass(&mut self) { + pub fn final_pass(&mut self, arena: &mut RangeArena>) { let elems = self.final_pass_items.clone(); + elems.iter().for_each(|final_pass_item| { + final_pass_item.funcs.iter().for_each(|func| { + func.set_params_and_ret(self, arena).unwrap(); + }); + }); elems.iter().for_each(|final_pass_item| { final_pass_item .inherits @@ -517,20 +538,22 @@ impl Analyzer { .for_each(|(contract, inherits)| { contract.inherit(inherits.to_vec(), self); }); - final_pass_item.funcs.iter().for_each(|func| { - // add params now that parsing is done - func.set_params_and_ret(self).unwrap(); - }); + // final_pass_item.funcs.iter().for_each(|func| { + // // add params now that parsing is done + // func.set_params_and_ret(self, arena).unwrap(); + // }); final_pass_item .usings .iter() .for_each(|(using, scope_node)| { - self.parse_using(using, *scope_node); + self.parse_using(arena, using, *scope_node); }); final_pass_item.vars.iter().for_each(|(var, parent)| { let loc = var.underlying(self).unwrap().loc; - let res = var.parse_initializer(self, *parent).into_expr_err(loc); + let res = var + .parse_initializer(self, arena, *parent) + .into_expr_err(loc); let _ = self.add_if_err(res); }); }); @@ -540,7 +563,6 @@ impl Analyzer { .funcs .iter() .for_each(|func| self.analyze_fn_calls(*func)); - let mut handled_funcs = vec![]; let mut func_mapping = BTreeMap::default(); let mut call_dep_graph: StableGraph = StableGraph::default(); let fn_calls_fns = std::mem::take(&mut self.fn_calls_fns); @@ -566,9 +588,9 @@ impl Analyzer { call_dep_graph.add_edge(func_idx, call_idx, 0); }); } else { - handled_funcs.push(func); + self.handled_funcs.push(*func); if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(*func)); + self.parse_ctx_statement(arena, body, false, Some(*func)); } } }); @@ -583,18 +605,18 @@ impl Analyzer { indices.iter().for_each(|idx| { let func = call_dep_graph.node_weight(*idx).unwrap(); - if !handled_funcs.contains(&func) { - handled_funcs.push(func); + if !self.handled_funcs.contains(func) { + self.handled_funcs.push(*func); if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(*func)); + self.parse_ctx_statement(arena, body, false, Some(*func)); } } }); final_pass_item.funcs.into_iter().for_each(|func| { - if !handled_funcs.contains(&&func) { + if !self.handled_funcs.contains(&func) { if let Some(body) = &func.underlying(self).unwrap().body.clone() { - self.parse_ctx_statement(body, false, Some(func)); + self.parse_ctx_statement(arena, body, false, Some(func)); } } }); @@ -606,6 +628,7 @@ impl Analyzer { #[tracing::instrument(level = "trace", skip_all)] pub fn parse_source_unit( &mut self, + arena: &mut RangeArena>, source_unit: SourceUnit, file_no: usize, parent: SourceUnitNode, @@ -621,6 +644,7 @@ impl Analyzer { .enumerate() .for_each(|(unit_part, source_unit_part)| { let (sup, funcs, usings, inherits, vars) = self.parse_source_unit_part( + arena, source_unit_part, file_no, unit_part, @@ -639,6 +663,7 @@ impl Analyzer { #[tracing::instrument(level = "trace", skip_all)] pub fn parse_source_unit_part( &mut self, + arena: &mut RangeArena>, sup: &SourceUnitPart, file_no: usize, unit_part: usize, @@ -668,7 +693,7 @@ impl Analyzer { match sup { ContractDefinition(def) => { let (node, funcs, con_usings, unhandled_inherits, unhandled_vars) = - self.parse_contract_def(def, parent); + self.parse_contract_def(arena, def, parent); s_node.add_contract(node, self).unwrap(); self.add_edge(node, sup_node, Edge::Contract); func_nodes.extend(funcs); @@ -677,7 +702,7 @@ impl Analyzer { vars.extend(unhandled_vars); } StructDefinition(def) => { - let node = self.parse_struct_def(def); + let node = self.parse_struct_def(arena, def); s_node.add_struct(node, self).unwrap(); self.add_edge(node, sup_node, Edge::Struct); } @@ -686,11 +711,11 @@ impl Analyzer { self.add_edge(node, sup_node, Edge::Enum); } ErrorDefinition(def) => { - let node = self.parse_err_def(def); + let node = self.parse_err_def(arena, def); self.add_edge(node, sup_node, Edge::Error); } VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, false); + let (node, maybe_func, needs_final_pass) = self.parse_var_def(arena, def, false); s_node.add_constant(node, self).unwrap(); if let Some(func) = maybe_func { let func = self.handle_func(func, None); @@ -712,7 +737,7 @@ impl Analyzer { self.add_edge(node, sup_node, Edge::Func); } TypeDefinition(def) => { - let node = self.parse_ty_def(def); + let node = self.parse_ty_def(arena, def); self.add_edge(node, sup_node, Edge::Ty); } EventDefinition(_def) => todo!(), @@ -721,7 +746,7 @@ impl Analyzer { StraySemicolon(_loc) => todo!(), PragmaDirective(_, _, _) => {} ImportDirective(import) => { - self.parse_import(import, current_path, parent); + self.parse_import(arena, import, current_path, parent); } } @@ -731,6 +756,7 @@ impl Analyzer { #[tracing::instrument(level = "trace", skip_all)] pub fn parse_import( &mut self, + arena: &mut RangeArena>, import: &Import, current_path: &SourcePath, parent: SourceUnitNode, @@ -959,7 +985,7 @@ impl Analyzer { *optional_file_no = Some(file_no); } - let maybe_entry = self.parse(&sol, &remapped, false); + let maybe_entry = self.parse(arena, &sol, &remapped, false); // take self.sources entry with the same path as remapped and update the entry node if let Some((_, _, _, optional_entry)) = self.sources.iter_mut().find(|(path, _, _, _)| { @@ -977,6 +1003,7 @@ impl Analyzer { #[tracing::instrument(level = "trace", skip_all)] pub fn parse_contract_def( &mut self, + arena: &mut RangeArena>, contract_def: &ContractDefinition, source: SourceUnitNode, ) -> ( @@ -1028,7 +1055,7 @@ impl Analyzer { let mut vars = vec![]; contract_def.parts.iter().for_each(|cpart| match cpart { StructDefinition(def) => { - let node = self.parse_struct_def(def); + let node = self.parse_struct_def(arena, def); self.add_edge(node, con_node, Edge::Struct); } EnumDefinition(def) => { @@ -1036,11 +1063,11 @@ impl Analyzer { self.add_edge(node, con_node, Edge::Enum); } ErrorDefinition(def) => { - let node = self.parse_err_def(def); + let node = self.parse_err_def(arena, def); self.add_edge(node, con_node, Edge::Error); } VariableDefinition(def) => { - let (node, maybe_func, needs_final_pass) = self.parse_var_def(def, true); + let (node, maybe_func, needs_final_pass) = self.parse_var_def(arena, def, true); if let Some(func) = maybe_func { func_nodes.push(self.handle_func(func, Some(con_node))); } @@ -1056,7 +1083,7 @@ impl Analyzer { func_nodes.push(node); } TypeDefinition(def) => { - let node = self.parse_ty_def(def); + let node = self.parse_ty_def(arena, def); self.add_edge(node, con_node, Edge::Ty); } EventDefinition(_def) => {} @@ -1068,7 +1095,12 @@ impl Analyzer { } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_using(&mut self, using_def: &Using, scope_node: NodeIdx) { + pub fn parse_using( + &mut self, + arena: &mut RangeArena>, + using_def: &Using, + scope_node: NodeIdx, + ) { tracing::trace!("Parsing \"using\" {:?}", using_def); let Some(ref using_def_ty) = using_def.ty else { self.add_expr_err(ExprErr::Todo( @@ -1077,7 +1109,7 @@ impl Analyzer { )); return; }; - let maybe_cvar_idx = self.parse_expr(using_def_ty, None); + let maybe_cvar_idx = self.parse_expr(arena, using_def_ty, None); let ty_idx = match VarType::try_from_idx(self, maybe_cvar_idx) { Some(v_ty) => v_ty.ty_idx(), None => { @@ -1208,7 +1240,11 @@ impl Analyzer { } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_struct_def(&mut self, struct_def: &StructDefinition) -> StructNode { + pub fn parse_struct_def( + &mut self, + arena: &mut RangeArena>, + struct_def: &StructDefinition, + ) -> StructNode { tracing::trace!("Parsing struct {:?}", struct_def.name); let strukt = Struct::from(struct_def.clone()); @@ -1227,7 +1263,7 @@ impl Analyzer { }; struct_def.fields.iter().for_each(|field| { - let f = Field::new(self, field.clone()); + let f = Field::new(self, arena, field.clone()); let field_node = self.add_node(f); self.add_edge(field_node, strukt_node, Edge::Field); }); @@ -1235,11 +1271,15 @@ impl Analyzer { } #[tracing::instrument(level = "trace", skip_all)] - pub fn parse_err_def(&mut self, err_def: &ErrorDefinition) -> ErrorNode { + pub fn parse_err_def( + &mut self, + arena: &mut RangeArena>, + err_def: &ErrorDefinition, + ) -> ErrorNode { tracing::trace!("Parsing error {:?}", err_def); let err_node = ErrorNode(self.add_node(Error::from(err_def.clone())).index()); err_def.fields.iter().for_each(|field| { - let param = ErrorParam::new(self, field.clone()); + let param = ErrorParam::new(self, arena, field.clone()); let field_node = self.add_node(param); self.add_edge(field_node, err_node, Edge::ErrorParam); }); @@ -1314,11 +1354,12 @@ impl Analyzer { pub fn parse_var_def( &mut self, + arena: &mut RangeArena>, var_def: &VariableDefinition, in_contract: bool, ) -> (VarNode, Option, bool) { tracing::trace!("Parsing variable definition: {:?}", var_def.name); - let var = Var::new(self, var_def.clone(), in_contract); + let var = Var::new(self, arena, var_def.clone(), in_contract); let mut func = None; if var.is_public() { func = Some(Function::from(var_def.clone())); @@ -1330,9 +1371,13 @@ impl Analyzer { (var_node, func, needs_final_pass) } - pub fn parse_ty_def(&mut self, ty_def: &TypeDefinition) -> TyNode { + pub fn parse_ty_def( + &mut self, + arena: &mut RangeArena>, + ty_def: &TypeDefinition, + ) -> TyNode { tracing::trace!("Parsing type definition"); - let ty = Ty::new(self, ty_def.clone()); + let ty = Ty::new(self, arena, ty_def.clone()); let name = ty.name.name.clone(); let ty_node: TyNode = if let Some(user_ty_node) = self.user_types.get(&name).cloned() { let unresolved = self.node_mut(user_ty_node); diff --git a/crates/pyrometer/src/analyzer_backend.rs b/crates/pyrometer/src/analyzer_backend.rs index 97de48d9..b4834d50 100644 --- a/crates/pyrometer/src/analyzer_backend.rs +++ b/crates/pyrometer/src/analyzer_backend.rs @@ -1,22 +1,38 @@ use crate::Analyzer; use graph::{ + elem::Elem, nodes::{ - BlockNode, Builtin, Concrete, ConcreteNode, Function, FunctionNode, FunctionParam, - FunctionParamNode, FunctionReturn, MsgNode, + BlockNode, Builtin, Concrete, ConcreteNode, ContextVar, Function, FunctionNode, + FunctionParam, FunctionParamNode, FunctionReturn, MsgNode, }, AnalyzerBackend, Edge, Node, VarType, }; -use shared::{AnalyzerLike, GraphLike, JoinStats, NodeIdx}; +use shared::{AnalyzerLike, GraphLike, JoinStats, NodeIdx, RangeArena}; use solc_expressions::{ExprErr, IntoExprErr}; use ahash::AHashMap; use ethers_core::types::U256; -use solang_parser::{helpers::CodeLocation, pt::Expression}; +use solang_parser::{ + helpers::CodeLocation, + pt::{Expression, Loc}, +}; use std::collections::BTreeMap; -impl AnalyzerBackend for Analyzer {} +impl AnalyzerBackend for Analyzer { + fn add_concrete_var( + &mut self, + ctx: graph::nodes::ContextNode, + concrete: Concrete, + loc: Loc, + ) -> Result { + let cnode = self.add_node(Node::Concrete(concrete)); + let var = ContextVar::new_from_concrete(loc, ctx, cnode.into(), self); + let cnode = self.add_node(Node::ContextVar(var.into_expr_err(loc)?)); + Ok(cnode.into()) + } +} impl AnalyzerLike for Analyzer { type Expr = Expression; @@ -96,11 +112,16 @@ impl AnalyzerLike for Analyzer { &mut self.user_types } - fn parse_expr(&mut self, expr: &Expression, parent: Option) -> NodeIdx { + fn parse_expr( + &mut self, + arena: &mut RangeArena>, + expr: &Expression, + parent: Option, + ) -> NodeIdx { use Expression::*; match expr { Type(_loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self, arena) { if let Some(idx) = self.builtins.get(&builtin) { *idx } else { @@ -108,7 +129,7 @@ impl AnalyzerLike for Analyzer { self.builtins.insert(builtin, idx); idx } - } else if let Some(idx) = self.complicated_parse(expr, parent) { + } else if let Some(idx) = self.complicated_parse(arena, expr, parent) { self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) .unwrap_or(0.into()) } else { @@ -125,7 +146,7 @@ impl AnalyzerLike for Analyzer { } } ArraySubscript(_loc, ty_expr, None) => { - let inner_ty = self.parse_expr(ty_expr, parent); + let inner_ty = self.parse_expr(arena, ty_expr, parent); if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { let dyn_b = Builtin::Array(var_type); if let Some(idx) = self.builtins.get(&dyn_b) { @@ -140,8 +161,8 @@ impl AnalyzerLike for Analyzer { } } ArraySubscript(loc, ty_expr, Some(idx_expr)) => { - let inner_ty = self.parse_expr(ty_expr, parent); - let idx = self.parse_expr(idx_expr, parent); + let inner_ty = self.parse_expr(arena, ty_expr, parent); + let idx = self.parse_expr(arena, idx_expr, parent); if let Some(var_type) = VarType::try_from_idx(self, inner_ty) { let res = ConcreteNode::from(idx) .underlying(self) @@ -179,7 +200,7 @@ impl AnalyzerLike for Analyzer { self.add_node(Node::Concrete(Concrete::Uint(256, val))) } _ => { - if let Some(idx) = self.complicated_parse(expr, parent) { + if let Some(idx) = self.complicated_parse(arena, expr, parent) { self.add_if_err(idx.expect_single().into_expr_err(expr.loc())) .unwrap_or(0.into()) } else { @@ -247,4 +268,12 @@ impl AnalyzerLike for Analyzer { fn join_stats_mut(&mut self) -> &mut JoinStats { &mut self.join_stats } + + fn handled_funcs(&self) -> &[FunctionNode] { + &self.handled_funcs + } + + fn handled_funcs_mut(&mut self) -> &mut Vec { + &mut self.handled_funcs + } } diff --git a/crates/pyrometer/src/graph_backend.rs b/crates/pyrometer/src/graph_backend.rs index bb859a23..3512cbdd 100644 --- a/crates/pyrometer/src/graph_backend.rs +++ b/crates/pyrometer/src/graph_backend.rs @@ -1,13 +1,10 @@ use crate::Analyzer; use graph::elem::Elem; -use graph::elem::RangeElem; use graph::nodes::Concrete; use shared::RangeArena; -use std::cell::RefCell; -use std::collections::hash_map::DefaultHasher; -use std::hash::Hash; -use std::hash::Hasher; -use std::rc::Rc; +// use std::collections::hash_map::DefaultHasher; +// use std::hash::Hash; +// use std::hash::Hasher; use graph::{ as_dot_str, nodes::ContextNode, AnalyzerBackend, AsDotStr, ContextEdge, Edge, GraphBackend, @@ -42,78 +39,28 @@ impl GraphLike for Analyzer { &mut self.range_arena } - fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { - if let Elem::Arena(idx) = elem { - Some(*idx) - } else { - self.range_arena().map.get(elem).copied() - } - } - - fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize { - // tracing::trace!("arenaizing: {}", elem); - if let Elem::Arena(idx) = elem { - return idx; - } - - if let Some(idx) = self.range_arena_idx(&elem) { - let existing = &self.range_arena().ranges[idx]; - let Ok(existing) = existing.try_borrow_mut() else { - return idx; - }; - let (min_cached, max_cached) = existing.is_min_max_cached(self); - let mut existing_count = 0; - if min_cached { - existing_count += 1; - } - if max_cached { - existing_count += 1; - } - if existing.is_flatten_cached(self) { - existing_count += 1; - } - - let (min_cached, max_cached) = elem.is_min_max_cached(self); - let mut new_count = 0; - if min_cached { - new_count += 1; - } - if max_cached { - new_count += 1; - } - if elem.is_flatten_cached(self) { - new_count += 1; - } - - drop(existing); - - if new_count >= existing_count { - self.range_arena_mut().ranges[idx] = Rc::new(RefCell::new(elem)); - } - - idx - } else { - let idx = self.range_arena().ranges.len(); - self.range_arena_mut() - .ranges - .push(Rc::new(RefCell::new(elem.clone()))); - self.range_arena_mut().map.insert(elem, idx); - idx - } - } + // fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { + // if let Elem::Arena(idx) = elem { + // Some(*idx) + // } else { + // self.range_arena().map.get(elem).copied() + // } + // } } -fn calculate_hash(t: &T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() -} +// fn calculate_hash(t: &T) -> u64 { +// let mut s = DefaultHasher::new(); +// t.hash(&mut s); +// s.finish() +// } impl GraphBackend for Analyzer {} impl GraphDot for Analyzer { + type T = Elem; fn cluster_str( &self, + arena: &mut RangeArena>, node: NodeIdx, cluster_num: &mut usize, is_killed: bool, @@ -177,10 +124,15 @@ impl GraphDot for Analyzer { let child_node_str = children .iter() .filter_map(|child| { + if handled_nodes.lock().unwrap().contains(child) { + return None; + } + let post_str = match self.node(*child) { Node::Context(c) => { *cluster_num += 2; if let Some(inner) = self.cluster_str( + arena, *child, cluster_num, c.killed.is_some(), @@ -203,6 +155,7 @@ impl GraphDot for Analyzer { let r_ctx = ContextNode::from(*r_fork); *cluster_num += 1; let l_fork = if let Some(inner) = self.cluster_str( + arena, *l_fork, cluster_num, l_ctx.is_killed(self).ok()?, @@ -218,6 +171,7 @@ impl GraphDot for Analyzer { *cluster_num += 2; let r_fork = if let Some(inner) = self.cluster_str( + arena, *r_fork, cluster_num, r_ctx.is_killed(self).ok()?, @@ -239,6 +193,7 @@ impl GraphDot for Analyzer { let func = child_iter.next()?; let func_ctx = ContextNode::from(*func); if let Some(inner) = self.cluster_str( + arena, *func, cluster_num, func_ctx.is_killed(self).ok()?, @@ -262,12 +217,18 @@ impl GraphDot for Analyzer { children .iter() .map(|child| { - // if !handled_nodes.lock().unwrap().contains(child) { - // return None - // } else { - // handled_nodes.lock().unwrap().insert(*child); - // } - mermaid_node(self, &indent, *child, true, Some(&curr_cluster_name)) + if !handled_nodes.lock().unwrap().contains(child) { + handled_nodes.lock().unwrap().insert(*child); + } + mermaid_node( + self, + arena, + &indent, + *child, + true, + true, + Some(&curr_cluster_name), + ) }) .collect::>() .join("\n") @@ -276,25 +237,30 @@ impl GraphDot for Analyzer { }; if as_mermaid { - if !post_str.is_empty() { - Some(post_str) - } else { - if !handled_nodes.lock().unwrap().contains(child) { - return None; + if handled_nodes.lock().unwrap().contains(child) { + return if !post_str.is_empty() { + Some(post_str) } else { - handled_nodes.lock().unwrap().insert(*child); - } - Some(mermaid_node( + None + }; + } else { + handled_nodes.lock().unwrap().insert(*child); + } + Some(format!( + "{}\n{indent}{post_str}", + mermaid_node( self, + arena, &indent, *child, true, + true, Some(&curr_cluster_name), - )) - } + ) + )) } else { { - if !handled_nodes.lock().unwrap().contains(child) { + if handled_nodes.lock().unwrap().contains(child) { return None; } else { handled_nodes.lock().unwrap().insert(*child); @@ -303,7 +269,7 @@ impl GraphDot for Analyzer { Some(format!( "{indent}{} [label = \"{}\", color = \"{}\"]\n{}", petgraph::graph::GraphIndex::index(child), - as_dot_str(*child, g).replace('\"', "\'"), + as_dot_str(*child, g, arena).replace('\"', "\'"), self.node(*child).dot_str_color(), post_str )) @@ -324,7 +290,7 @@ impl GraphDot for Analyzer { if as_mermaid { format!("{indent}{from:} -->|\"{edge_str}\"| {to:}\n{indent}class {to} linkSource{edge_idx}\n{indent}class {from} linkTarget{edge_idx}") } else { - format!("{indent}{from:} -> {to:} [label = \"{edge_str}\"]",) + format!("{indent}{from:} -> {to:} [label = \"{edge_str}\"]",) } }) .collect::>() @@ -338,7 +304,15 @@ impl GraphDot for Analyzer { { handled_nodes.lock().unwrap().insert(node); } - mermaid_node(self, &indent, node, true, Some(&curr_cluster_name)) + mermaid_node( + self, + arena, + &indent, + node, + true, + true, + Some(&curr_cluster_name), + ) } }; @@ -360,30 +334,27 @@ impl GraphDot for Analyzer { )) } else { Some(format!( - "{preindent}subgraph cluster_{} {{\n{}\n{}\n{}\n{}\n}}", + "{preindent}subgraph cluster_{} {{\n{indent}{}\n{indent}{} [label = \"{}\", color = \"{}\"]\n{}\n{}\n}}", cluster_num, if is_killed && curr_cluster % 2 == 0 { - format!("{indent}bgcolor=\"#7a0b0b\"") + "bgcolor=\"#7a0b0b\"" } else if is_killed { - format!("{indent}bgcolor=\"#e04646\"") + "bgcolor=\"#e04646\"" } else if curr_cluster % 2 == 0 { - format!("{indent}bgcolor=\"#545e87\"") + "bgcolor=\"#545e87\"" } else { - format!("{indent}bgcolor=\"#1a1b26\"") + "bgcolor=\"#1a1b26\"" }, - format!( - "{indent}{} [label = \"{}\", color = \"{}\"]", - node.index(), - as_dot_str(node, g).replace('\"', "\'"), - self.node(node).dot_str_color() - ), + node.index(), + as_dot_str(node, g, arena).replace('\"', "\'"), + self.node(node).dot_str_color(), child_node_str, edge_str, )) } } - fn dot_str(&self) -> String + fn dot_str(&self, arena: &mut RangeArena>) -> String where Self: std::marker::Sized, Self: AnalyzerBackend, @@ -420,6 +391,7 @@ impl GraphDot for Analyzer { Node::Function(_) => { cluster_num += 2; Some(self.cluster_str( + arena, *node, &mut cluster_num, false, @@ -432,7 +404,7 @@ impl GraphDot for Analyzer { n => Some(format!( " {} [label = \"{}\", color = \"{}\"]", petgraph::graph::GraphIndex::index(node), - as_dot_str(*node, self).replace('\"', "\'"), + as_dot_str(*node, self, arena).replace('\"', "\'"), n.dot_str_color() )), } @@ -469,7 +441,7 @@ impl GraphDot for Analyzer { dot_str.join("\n") } - fn dot_str_no_tmps(&self) -> String + fn dot_str_no_tmps(&self, arena: &mut RangeArena>) -> String where Self: std::marker::Sized, Self: GraphLike + AnalyzerBackend, @@ -514,7 +486,7 @@ impl GraphDot for Analyzer { let inner = match node_ref { Node::ContextVar(cvar) => { let range_str = if let Some(r) = cvar.ty.ref_range(self).unwrap() { - r.as_dot_str(self) + r.as_dot_str(self, &mut arena.clone()) // format!("[{}, {}]", r.min.eval(self).to_range_string(self).s, r.max.eval(self).to_range_string(self).s) } else { "".to_string() @@ -527,7 +499,7 @@ impl GraphDot for Analyzer { range_str ) } - _ => as_dot_str(idx, &G { graph: &new_graph }), + _ => as_dot_str(idx, &G { graph: &new_graph }, &mut arena.clone()), }; format!( "label = \"{}\", color = \"{}\"", @@ -543,7 +515,7 @@ impl GraphDot for Analyzer { dot_str.join("\n") } - fn mermaid_str(&self) -> String + fn mermaid_str(&self, arena: &mut RangeArena>) -> String where Self: std::marker::Sized, Self: AnalyzerBackend, @@ -596,6 +568,7 @@ flowchart BT Node::Function(_) => { cluster_num += 2; Some(self.cluster_str( + arena, *node, &mut cluster_num, false, @@ -611,7 +584,7 @@ flowchart BT Some(format!( " {}(\"{}\")\n style {} stroke:{}", petgraph::graph::GraphIndex::index(node), - as_dot_str(*node, self).replace('\"', "\'"), + as_dot_str(*node, self, arena).replace('\"', "\'"), petgraph::graph::GraphIndex::index(node), n.dot_str_color() )) @@ -671,29 +644,23 @@ impl GraphLike for G<'_> { fn range_arena_mut(&mut self) -> &mut RangeArena> { panic!("Should not call this") } - - fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option { - panic!("Should not call this") - } - - fn range_arena_idx_or_upsert(&mut self, _elem: Self::RangeElem) -> usize { - panic!("Should not call this") - } } impl GraphBackend for G<'_> {} pub fn mermaid_node( g: &impl GraphBackend, + arena: &mut RangeArena>, indent: &str, node: NodeIdx, style: bool, + loc: bool, class: Option<&str>, ) -> String { let mut node_str = format!( "{indent}{}(\"{}\")", petgraph::graph::GraphIndex::index(&node), - as_dot_str(node, g).replace('\"', "\'"), + as_dot_str(node, g, arena).replace('\"', "\'"), ); if style { @@ -704,6 +671,22 @@ pub fn mermaid_node( )); } + if loc { + match g.node(node) { + Node::ContextVar(..) => { + if let solang_parser::pt::Loc::File(f, s, e) = + graph::nodes::ContextVarNode::from(node).loc(g).unwrap() + { + node_str.push_str(&format!( + "\n{indent}class {} loc_{f}_{s}_{e}", + petgraph::graph::GraphIndex::index(&node) + )); + } + } + _ => {} + } + } + if let Some(class) = class { node_str.push_str(&format!( "\n{indent}class {} {class}", diff --git a/crates/pyrometer/tests/helpers.rs b/crates/pyrometer/tests/helpers.rs index 3a14b641..02f28c97 100644 --- a/crates/pyrometer/tests/helpers.rs +++ b/crates/pyrometer/tests/helpers.rs @@ -2,9 +2,14 @@ use analyzers::FunctionVarsBoundAnalyzer; use analyzers::ReportConfig; use analyzers::ReportDisplay; use ariadne::sources; -use graph::{nodes::FunctionNode, Edge}; +use graph::{ + elem::Elem, + nodes::{Concrete, FunctionNode}, + Edge, +}; use pyrometer::{Analyzer, SourcePath}; use shared::NodeIdx; +use shared::RangeArena; use shared::Search; use std::collections::BTreeMap; use std::collections::HashMap; @@ -13,8 +18,10 @@ use std::path::PathBuf; pub fn assert_no_parse_errors(path_str: String) { let sol = std::fs::read_to_string(path_str.clone()).unwrap(); let mut analyzer = Analyzer::default(); + let mut arena_base = Default::default(); + let arena = &mut arena_base; let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); - let _ = analyzer.parse(&sol, ¤t_path, true); + let _ = analyzer.parse(arena, &sol, ¤t_path, true); assert!( analyzer.expr_errs.is_empty(), "Analyzer encountered parse errors in {}", @@ -24,22 +31,30 @@ pub fn assert_no_parse_errors(path_str: String) { pub fn assert_no_ctx_killed(path_str: String, sol: &str) { let mut analyzer = Analyzer::default(); + let mut arena_base = Default::default(); + let arena = &mut arena_base; let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); - let maybe_entry = analyzer.parse(sol, ¤t_path, true); + let maybe_entry = analyzer.parse(arena, sol, ¤t_path, true); let entry = maybe_entry.unwrap(); - no_ctx_killed(analyzer, entry); + no_ctx_killed(analyzer, arena, entry); } pub fn remapping_assert_no_ctx_killed(path_str: String, remapping_file: String, sol: &str) { let mut analyzer = Analyzer::default(); analyzer.set_remappings_and_root(remapping_file); let current_path = SourcePath::SolidityFile(PathBuf::from(path_str.clone())); - let maybe_entry = analyzer.parse(sol, ¤t_path, true); + let mut arena_base = Default::default(); + let arena = &mut arena_base; + let maybe_entry = analyzer.parse(arena, sol, ¤t_path, true); let entry = maybe_entry.unwrap(); - no_ctx_killed(analyzer, entry); + no_ctx_killed(analyzer, arena, entry); } -pub fn no_ctx_killed(mut analyzer: Analyzer, entry: NodeIdx) { +pub fn no_ctx_killed( + mut analyzer: Analyzer, + arena: &mut RangeArena>, + entry: NodeIdx, +) { assert!( analyzer.expr_errs.is_empty(), "Analyzer encountered parse errors" @@ -78,17 +93,17 @@ pub fn no_ctx_killed(mut analyzer: Analyzer, entry: NodeIdx) { if let Some(ctx) = FunctionNode::from(func).maybe_body_ctx(&mut analyzer) { if ctx.killed_loc(&analyzer).unwrap().is_some() { analyzer - .bounds_for_all(&file_mapping, ctx, config) + .bounds_for_all(arena, &file_mapping, ctx, config) .as_cli_compat(&file_mapping) - .print_reports(&mut source_map, &analyzer); + .print_reports(&mut source_map, &analyzer, arena); panic!("Killed context in test"); } ctx.all_edges(&analyzer).unwrap().iter().for_each(|subctx| { if subctx.killed_loc(&analyzer).unwrap().is_some() { analyzer - .bounds_for_all(&file_mapping, *subctx, config) + .bounds_for_all(arena, &file_mapping, *subctx, config) .as_cli_compat(&file_mapping) - .print_reports(&mut source_map, &analyzer); + .print_reports(&mut source_map, &analyzer, arena); panic!("Killed context in test"); } }); diff --git a/crates/pyrometer/tests/no_killed_ctxs.rs b/crates/pyrometer/tests/no_killed_ctxs.rs index afd170a7..b56de34f 100644 --- a/crates/pyrometer/tests/no_killed_ctxs.rs +++ b/crates/pyrometer/tests/no_killed_ctxs.rs @@ -150,8 +150,7 @@ fn test_interface() { fn test_const_var() { let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let path_str = format!("{manifest_dir}/tests/test_data/const_var.sol"); - let sol = include_str!("./test_data/const_var.sol"); - assert_no_ctx_killed(path_str, sol); + assert_no_parse_errors(path_str); } #[test] diff --git a/crates/pyrometer/tests/test_data/bitwise.sol b/crates/pyrometer/tests/test_data/bitwise.sol index 8c34d50d..2d198c18 100644 --- a/crates/pyrometer/tests/test_data/bitwise.sol +++ b/crates/pyrometer/tests/test_data/bitwise.sol @@ -137,7 +137,7 @@ contract BitNot { require(~type(uint24).max == 0); require(bit_not(50) == 115792089237316195423570985008687907853269984665640564039457584007913129639885); } - + function int_bit_not(int256 x) public returns (int256) { return ~x; } diff --git a/crates/pyrometer/tests/test_data/cast.sol b/crates/pyrometer/tests/test_data/cast.sol index d2cd7041..b31a7228 100644 --- a/crates/pyrometer/tests/test_data/cast.sol +++ b/crates/pyrometer/tests/test_data/cast.sol @@ -291,4 +291,4 @@ contract FuncCast { bytes memory data = hex"01234567"; } -} \ No newline at end of file +} diff --git a/crates/pyrometer/tests/test_data/const_var.sol b/crates/pyrometer/tests/test_data/const_var.sol index eb5c9da9..a30ec42a 100644 --- a/crates/pyrometer/tests/test_data/const_var.sol +++ b/crates/pyrometer/tests/test_data/const_var.sol @@ -32,4 +32,4 @@ contract ConstVar { bytes16 _bytesString = "0123456789abcdef"; require(bytesString == _bytesString); } -} \ No newline at end of file +} diff --git a/crates/pyrometer/tests/test_data/intrinsics.sol b/crates/pyrometer/tests/test_data/intrinsics.sol index 3f984539..f9754dc9 100644 --- a/crates/pyrometer/tests/test_data/intrinsics.sol +++ b/crates/pyrometer/tests/test_data/intrinsics.sol @@ -253,4 +253,4 @@ contract Other { interface IOther { function dummyFunc() external returns (uint256); -} \ No newline at end of file +} diff --git a/crates/pyrometer/tests/test_data/math.sol b/crates/pyrometer/tests/test_data/math.sol index 963f87c6..014a72d4 100644 --- a/crates/pyrometer/tests/test_data/math.sol +++ b/crates/pyrometer/tests/test_data/math.sol @@ -236,6 +236,44 @@ contract Mul { } } +contract Exp { + function exp(uint256 x, uint256 y) public pure returns (uint256) { + return x ** y; + } + + function int_exp(int256 x, uint256 y) public pure returns (int256) { + return x ** y; + } + + function exp_conc() public pure returns (uint256) { + uint256 a1 = exp(0, 0); + require(a1 == 1); + uint256 a2 = exp(0, 1); + require(a2 == 0); + uint256 a3 = exp(100, 4); + require(a3 == 100000000); + uint256 a4 = exp(100, 8); + require(a4 == 10000000000000000); + uint256 a5 = exp(1000000000, 8); + require(a5 == 1000000000000000000000000000000000000000000000000000000000000000000000000); + uint256 a6 = exp(2, 24); + require(a6 == 16777216); + } + + function int_exp_conc() public pure { + int256 a1 = int_exp(-100, 0); + require(a1 == 1); + int256 a2 = int_exp(-100, 2); + require(a2 == 10000); + int256 a3 = int_exp(-100, 3); + require(a3 == -1000000); + int256 a4 = int_exp(-100, 8); + require(a4 == 10000000000000000); + int256 a5 = int_exp(-2, 23); + require(a5 == -8388608); + } +} + contract Add { function add(uint256 x, uint256 y) public pure returns (uint256) { return x + y; @@ -641,4 +679,4 @@ contract Unchecked { a := mul(a, b) } } -} \ No newline at end of file +} diff --git a/crates/pyrometer/tests/test_data/storage.sol b/crates/pyrometer/tests/test_data/storage.sol index 135f3dad..25749895 100644 --- a/crates/pyrometer/tests/test_data/storage.sol +++ b/crates/pyrometer/tests/test_data/storage.sol @@ -40,4 +40,4 @@ contract Storage { nestedArr[idx][idx2] = 1000; require(nestedArr[idx][idx2] == 1000); } -} \ No newline at end of file +} diff --git a/crates/shared/src/analyzer_like.rs b/crates/shared/src/analyzer_like.rs index 7c901612..e4cd7b25 100644 --- a/crates/shared/src/analyzer_like.rs +++ b/crates/shared/src/analyzer_like.rs @@ -1,4 +1,4 @@ -use crate::{GraphLike, NodeIdx}; +use crate::{GraphLike, NodeIdx, RangeArena}; use ahash::AHashMap; @@ -129,7 +129,12 @@ pub trait AnalyzerLike: GraphLike { fn max_width(&self) -> usize; fn user_types(&self) -> &AHashMap; fn user_types_mut(&mut self) -> &mut AHashMap; - fn parse_expr(&mut self, expr: &Self::Expr, parent: Option) -> NodeIdx; + fn parse_expr( + &mut self, + arena: &mut RangeArena, + expr: &Self::Expr, + parent: Option, + ) -> NodeIdx; fn msg(&mut self) -> Self::MsgNode; fn block(&mut self) -> Self::BlockNode; fn entry(&self) -> NodeIdx; @@ -176,4 +181,6 @@ pub trait AnalyzerLike: GraphLike { } fn join_stats_mut(&mut self) -> &mut JoinStats; + fn handled_funcs(&self) -> &[Self::FunctionNode]; + fn handled_funcs_mut(&mut self) -> &mut Vec; } diff --git a/crates/shared/src/graph_like.rs b/crates/shared/src/graph_like.rs index e1c7ba6c..041f99aa 100644 --- a/crates/shared/src/graph_like.rs +++ b/crates/shared/src/graph_like.rs @@ -7,10 +7,8 @@ use petgraph::{ }; use std::{ - cell::RefCell, collections::BTreeSet, hash::Hash, - rc::Rc, sync::{Arc, Mutex}, }; @@ -20,7 +18,7 @@ pub type RangeArenaIdx = usize; #[derive(Default, Clone, Debug)] pub struct RangeArena { - pub ranges: Vec>>, + pub ranges: Vec, pub map: AHashMap, } @@ -28,7 +26,7 @@ pub struct RangeArena { pub trait GraphLike { type Node; type Edge: Ord + PartialEq + Heirarchical + Copy; - type RangeElem: Hash + PartialEq + Eq + PartialOrd + Clone + std::fmt::Display; + type RangeElem: Hash + PartialEq + Eq + PartialOrd + Clone + std::fmt::Display + Default; /// Get a mutable reference to the graph fn graph_mut(&mut self) -> &mut Graph; /// Get a reference to the graph @@ -63,16 +61,26 @@ pub trait GraphLike { fn range_arena(&self) -> &RangeArena; fn range_arena_mut(&mut self) -> &mut RangeArena; + fn try_take_range_arena(&mut self) -> Option> { + let arena = self.range_arena_mut(); + if !arena.ranges.is_empty() { + Some(std::mem::take(arena)) + } else { + None + } + } - fn range_arena_idx(&self, elem: &Self::RangeElem) -> Option; - - fn range_arena_idx_or_upsert(&mut self, elem: Self::RangeElem) -> usize; + fn take_range_arena(&mut self) -> RangeArena { + let arena = self.range_arena_mut(); + std::mem::take(arena) + } } /// A trait that constructs dot-like visualization strings (either mermaid or graphviz) pub trait GraphDot: GraphLike { + type T: Hash; /// Open a dot using graphviz - fn open_dot(&self) + fn open_dot(&self, arena: &mut RangeArena) where Self: std::marker::Sized, Self: AnalyzerLike, @@ -88,7 +96,7 @@ pub trait GraphDot: GraphLike { let temp_svg_filename: String = format!("{}/dot.svg", &temp_dir.to_string_lossy()); let mut file = fs::File::create(temp_path.clone()).unwrap(); - file.write_all(self.dot_str().as_bytes()).unwrap(); + file.write_all(self.dot_str(arena).as_bytes()).unwrap(); Command::new("dot") .arg("-Tsvg") .arg(temp_path) @@ -102,7 +110,7 @@ pub trait GraphDot: GraphLike { .expect("failed to execute process"); } - fn open_mermaid(&self) + fn open_mermaid(&self, arena: &mut RangeArena) where Self: std::marker::Sized, Self: AnalyzerLike, @@ -127,7 +135,7 @@ pub trait GraphDot: GraphLike { let temp_svg_filename: String = format!("{}/mermaid.svg", &temp_dir.to_string_lossy()); let mut file = fs::File::create(temp_path.clone()).unwrap(); - file.write_all(self.mermaid_str().as_bytes()).unwrap(); + file.write_all(self.mermaid_str(arena).as_bytes()).unwrap(); Command::new("mmdc") .arg("-i") .arg(temp_path) @@ -149,6 +157,7 @@ pub trait GraphDot: GraphLike { /// Creates a subgraph for visually identifying contexts and subcontexts fn cluster_str( &self, + arena: &mut RangeArena, node: NodeIdx, cluster_num: &mut usize, is_killed: bool, @@ -161,18 +170,18 @@ pub trait GraphDot: GraphLike { Self: std::marker::Sized; /// Constructs a dot string - fn dot_str(&self) -> String + fn dot_str(&self, arena: &mut RangeArena) -> String where Self: std::marker::Sized, Self: AnalyzerLike; /// Construct a dot string while filtering temporary variables - fn dot_str_no_tmps(&self) -> String + fn dot_str_no_tmps(&self, arena: &mut RangeArena) -> String where Self: std::marker::Sized, Self: GraphLike + AnalyzerLike; - fn mermaid_str(&self) -> String + fn mermaid_str(&self, arena: &mut RangeArena) -> String where Self: std::marker::Sized, Self: AnalyzerLike; diff --git a/crates/solc-expressions/src/array.rs b/crates/solc-expressions/src/array.rs index f0412805..a1d61761 100644 --- a/crates/solc-expressions/src/array.rs +++ b/crates/solc-expressions/src/array.rs @@ -2,13 +2,13 @@ use crate::{ require::Require, variable::Variable, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, ListAccess, }; -use graph::elem::RangeElem; use graph::{ elem::{Elem, RangeDyn, RangeOp}, - nodes::{Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TmpConstruction}, - AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, + nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, TmpConstruction}, + AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; +use shared::RangeArena; use solang_parser::{ helpers::CodeLocation, @@ -20,9 +20,14 @@ impl Array for T where T: AnalyzerBackend + Sized { /// Gets the array type #[tracing::instrument(level = "trace", skip_all)] - fn array_ty(&mut self, ty_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - self.parse_ctx_expr(ty_expr, ctx)?; - self.apply_to_edges(ctx, ty_expr.loc(), &|analyzer, ctx, loc| { + fn array_ty( + &mut self, + arena: &mut RangeArena>, + ty_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(arena, ty_expr, ctx)?; + self.apply_to_edges(ctx, ty_expr.loc(), arena, &|analyzer, arena, ctx, loc| { if let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { if matches!(ret, ExprRet::CtxKilled(_)) { ctx.push_expr(ret, analyzer).into_expr_err(loc)?; @@ -82,14 +87,15 @@ pub trait Array: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn index_into_array( &mut self, + arena: &mut RangeArena>, loc: Loc, ty_expr: &Expression, index_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { tracing::trace!("Indexing into array"); - self.parse_ctx_expr(index_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, index_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(index_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -100,8 +106,8 @@ pub trait Array: AnalyzerBackend + Sized { ctx.push_expr(index_tys, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_expr(ty_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, ty_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(inner_tys) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs(loc, "Could not find the array".to_string())); }; @@ -110,6 +116,7 @@ pub trait Array: AnalyzerBackend + Sized { return Ok(()); } analyzer.index_into_array_inner( + arena, ctx, loc, inner_tys.flatten(), @@ -122,6 +129,7 @@ pub trait Array: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn index_into_array_inner( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, inner_paths: ExprRet, @@ -138,7 +146,7 @@ pub trait Array: AnalyzerBackend + Sized { (ExprRet::Single(parent), ExprRet::Single(index)) | (ExprRet::Single(parent), ExprRet::SingleLiteral(index)) => { let index = ContextVarNode::from(index).latest_version(self); let parent = ContextVarNode::from(parent).latest_version(self); - let _ = self.index_into_array_raw(ctx, loc, index, parent, true, false)?; + let _ = self.index_into_array_raw(arena, ctx, loc, index, parent, true, false)?; Ok(()) } e => Err(ExprErr::ArrayIndex(loc, format!("Expected single expr evaluation of index expression, but was: {e:?}. This is a bug. Please report it at github.com/nascentxyz/pyrometer."))), @@ -147,6 +155,7 @@ pub trait Array: AnalyzerBackend + Sized { fn index_into_array_raw( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, index: ContextVarNode, @@ -160,10 +169,11 @@ pub trait Array: AnalyzerBackend + Sized { && parent.is_indexable(self).into_expr_err(loc)? { let len_var = self - .get_length(ctx, loc, parent, true)? + .get_length(arena, ctx, loc, parent, true)? .unwrap() .latest_version(self); self.require( + arena, len_var.latest_version(self), idx.latest_version(self), ctx, @@ -240,11 +250,12 @@ pub trait Array: AnalyzerBackend + Sized { let idx_access_cvar = self.advance_var_in_ctx(ContextVarNode::from(idx_access_node), loc, ctx)?; + idx_access_cvar - .set_range_min(self, min) + .set_range_min(self, arena, min) .into_expr_err(loc)?; idx_access_cvar - .set_range_max(self, max) + .set_range_max(self, arena, max) .into_expr_err(loc)?; if idx_access_cvar @@ -256,7 +267,7 @@ pub trait Array: AnalyzerBackend + Sized { { // if the index access is also an array, produce a length variable // we specify to return the variable because we dont want it on the stack - let _ = self.get_length(ctx, loc, idx_access_node.into(), true)?; + let _ = self.get_length(arena, ctx, loc, idx_access_node.into(), true)?; } idx_access_cvar } else { @@ -278,6 +289,7 @@ pub trait Array: AnalyzerBackend + Sized { fn update_array_if_index_access( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, maybe_index_access: ContextVarNode, @@ -304,8 +316,13 @@ pub trait Array: AnalyzerBackend + Sized { vec![(index.into(), new_value.into())], loc, )); - next_arr.set_range_min(self, min).into_expr_err(loc)?; - next_arr.set_range_max(self, max).into_expr_err(loc)?; + + next_arr + .set_range_min(self, arena, min) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, arena, max) + .into_expr_err(loc)?; } // handle nested arrays, i.e. if: @@ -313,6 +330,7 @@ pub trait Array: AnalyzerBackend + Sized { // z[x][y] = 5; // first pass sets z[x][y] = 5, second pass needs to set z[x] = x self.update_array_if_index_access( + arena, ctx, loc, next_arr.latest_version(self), @@ -325,6 +343,7 @@ pub trait Array: AnalyzerBackend + Sized { fn update_array_if_length_var( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, maybe_length: ContextVarNode, @@ -333,15 +352,18 @@ pub trait Array: AnalyzerBackend + Sized { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; let new_len = Elem::from(backing_arr).set_length(maybe_length.into()); next_arr - .set_range_min(self, new_len.clone()) + .set_range_min(self, arena, new_len.clone()) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, arena, new_len) .into_expr_err(loc)?; - next_arr.set_range_max(self, new_len).into_expr_err(loc)?; } Ok(()) } fn set_var_as_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, new_length: ContextVarNode, @@ -350,10 +372,17 @@ pub trait Array: AnalyzerBackend + Sized { let next_arr = self.advance_var_in_ctx(backing_arr.latest_version(self), loc, ctx)?; let new_len = Elem::from(backing_arr).get_length().max(new_length.into()); let min = Elem::from(backing_arr).set_length(new_len); - next_arr.set_range_min(self, min).into_expr_err(loc)?; + let new_len = Elem::from(backing_arr).get_length().min(new_length.into()); let max = Elem::from(backing_arr).set_length(new_len); - next_arr.set_range_max(self, max).into_expr_err(loc)?; + + next_arr + .set_range_min(self, arena, min) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, arena, max) + .into_expr_err(loc)?; + self.add_edge( new_length, next_arr, @@ -364,6 +393,7 @@ pub trait Array: AnalyzerBackend + Sized { fn update_array_from_index_access( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, index: ContextVarNode, @@ -387,8 +417,12 @@ pub trait Array: AnalyzerBackend + Sized { vec![(index.into(), access.into())], loc, )); - next_arr.set_range_min(self, min).into_expr_err(loc)?; - next_arr.set_range_max(self, max).into_expr_err(loc)?; + next_arr + .set_range_min(self, arena, min) + .into_expr_err(loc)?; + next_arr + .set_range_max(self, arena, max) + .into_expr_err(loc)?; } // handle nested arrays @@ -397,6 +431,7 @@ pub trait Array: AnalyzerBackend + Sized { next_arr.index_access_to_index(self), ) { self.update_array_from_index_access( + arena, ctx, loc, parent_nested_index, @@ -410,6 +445,7 @@ pub trait Array: AnalyzerBackend + Sized { fn update_array_min_if_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, maybe_length: ContextVarNode, @@ -420,13 +456,16 @@ pub trait Array: AnalyzerBackend + Sized { .get_length() .max(maybe_length.into()); let min = Elem::from(backing_arr).set_length(new_len); - next_arr.set_range_min(self, min).into_expr_err(loc)?; + next_arr + .set_range_min(self, arena, min) + .into_expr_err(loc)?; } Ok(()) } fn update_array_max_if_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, maybe_length: ContextVarNode, @@ -437,7 +476,9 @@ pub trait Array: AnalyzerBackend + Sized { .get_length() .min(maybe_length.into()); let max = Elem::from(backing_arr).set_length(new_len); - next_arr.set_range_max(self, max).into_expr_err(loc)?; + next_arr + .set_range_max(self, arena, max) + .into_expr_err(loc)?; } Ok(()) } diff --git a/crates/solc-expressions/src/assign.rs b/crates/solc-expressions/src/assign.rs index c3759746..38c89a6e 100644 --- a/crates/solc-expressions/src/assign.rs +++ b/crates/solc-expressions/src/assign.rs @@ -5,10 +5,11 @@ use crate::{ use graph::{ elem::{Elem, RangeElem}, - nodes::{ContextNode, ContextVarNode, ExprRet}, + nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, GraphError, Node, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; impl Assign for T where T: AnalyzerBackend + Sized {} @@ -18,13 +19,14 @@ pub trait Assign: AnalyzerBackend + Sized /// Parse an assignment expression fn assign_exprs( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_expr: &Expression, rhs_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(rhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -36,8 +38,8 @@ pub trait Assign: AnalyzerBackend + Sized ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -48,7 +50,7 @@ pub trait Assign: AnalyzerBackend + Sized ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_assign_sides(ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; + analyzer.match_assign_sides(arena, ctx, loc, &lhs_paths.flatten(), &rhs_paths)?; Ok(()) }) }) @@ -57,6 +59,7 @@ pub trait Assign: AnalyzerBackend + Sized /// Match on the [`ExprRet`]s of an assignment expression fn match_assign_sides( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, lhs_paths: &ExprRet, @@ -71,40 +74,40 @@ pub trait Assign: AnalyzerBackend + Sized (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - let res = rhs_cvar - .literal_cast_from(&lhs_cvar, self) - .into_expr_err(loc); - let _ = self.add_if_err(res); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + // let res = rhs_cvar + // .literal_cast_from(&lhs_cvar, self) + // .into_expr_err(loc); + // let _ = self.add_if_err(res); + ctx.push_expr(self.assign(arena, loc, lhs_cvar, rhs_cvar, ctx)?, self) .into_expr_err(loc)?; Ok(()) } (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.assign(loc, lhs_cvar, rhs_cvar, ctx)?, self) + ctx.push_expr(self.assign(arena, loc, lhs_cvar, rhs_cvar, ctx)?, self) .into_expr_err(loc)?; Ok(()) } (l @ ExprRet::Single(_), ExprRet::Multi(rhs_sides)) => rhs_sides .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, l, expr_ret)), + .try_for_each(|expr_ret| self.match_assign_sides(arena, ctx, loc, l, expr_ret)), (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { lhs_sides .iter() - .try_for_each(|expr_ret| self.match_assign_sides(ctx, loc, expr_ret, r)) + .try_for_each(|expr_ret| self.match_assign_sides(arena, ctx, loc, expr_ret, r)) } (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { // try to zip sides if they are the same length if lhs_sides.len() == rhs_sides.len() { lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( |(lhs_expr_ret, rhs_expr_ret)| { - self.match_assign_sides(ctx, loc, lhs_expr_ret, rhs_expr_ret) + self.match_assign_sides(arena, ctx, loc, lhs_expr_ret, rhs_expr_ret) }, ) } else { rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.match_assign_sides(ctx, loc, lhs_paths, rhs_expr_ret) + self.match_assign_sides(arena, ctx, loc, lhs_paths, rhs_expr_ret) }) } } @@ -115,6 +118,7 @@ pub trait Assign: AnalyzerBackend + Sized /// Perform an assignment fn assign( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_cvar: ContextVarNode, rhs_cvar: ContextVarNode, @@ -126,16 +130,20 @@ pub trait Assign: AnalyzerBackend + Sized lhs_cvar.display_name(self).unwrap(), ); + rhs_cvar + .cast_from(&lhs_cvar, self, arena) + .into_expr_err(loc)?; + let (new_lower_bound, new_upper_bound) = ( Elem::from(rhs_cvar.latest_version(self)), Elem::from(rhs_cvar.latest_version(self)), ); let needs_forcible = new_lower_bound - .depends_on(lhs_cvar, &mut vec![], self) + .depends_on(lhs_cvar, &mut vec![], self, arena) .into_expr_err(loc)? || new_upper_bound - .depends_on(lhs_cvar, &mut vec![], self) + .depends_on(lhs_cvar, &mut vec![], self, arena) .into_expr_err(loc)?; let new_lhs = if needs_forcible { @@ -209,11 +217,11 @@ pub trait Assign: AnalyzerBackend + Sized } }; - let _ = new_lhs.try_set_range_min(self, new_lower_bound.cast(cast_to_min)); - let _ = new_lhs.try_set_range_max(self, new_upper_bound.cast(cast_to_max)); + let _ = new_lhs.try_set_range_min(self, arena, new_lower_bound.cast(cast_to_min)); + let _ = new_lhs.try_set_range_max(self, arena, new_upper_bound.cast(cast_to_max)); } else { - let _ = new_lhs.try_set_range_min(self, new_lower_bound); - let _ = new_lhs.try_set_range_max(self, new_upper_bound); + let _ = new_lhs.try_set_range_min(self, arena, new_lower_bound); + let _ = new_lhs.try_set_range_max(self, arena, new_upper_bound); } if let Some(rhs_range) = rhs_cvar.ref_range(self).into_expr_err(loc)? { let res = new_lhs @@ -225,14 +233,14 @@ pub trait Assign: AnalyzerBackend + Sized if rhs_cvar.is_indexable(self).into_expr_err(loc)? { // rhs is indexable. get the length attribute, create a new length for the lhs, // and perform assign - let rhs_len_cvar = self.get_length(ctx, loc, rhs_cvar, true)?.unwrap(); - let lhs_len_cvar = self.get_length(ctx, loc, lhs_cvar, true)?.unwrap(); - self.assign(loc, lhs_len_cvar, rhs_len_cvar, ctx)?; + let rhs_len_cvar = self.get_length(arena, ctx, loc, rhs_cvar, true)?.unwrap(); + let lhs_len_cvar = self.get_length(arena, ctx, loc, lhs_cvar, true)?.unwrap(); + self.assign(arena, loc, lhs_len_cvar, rhs_len_cvar, ctx)?; // update the range - self.update_array_if_length_var(ctx, loc, lhs_len_cvar.latest_version(self))?; + self.update_array_if_length_var(arena, ctx, loc, lhs_len_cvar.latest_version(self))?; } - self.update_array_if_index_access(ctx, loc, lhs_cvar, rhs_cvar)?; + self.update_array_if_index_access(arena, ctx, loc, lhs_cvar, rhs_cvar)?; // handle struct assignment if let Ok(fields) = rhs_cvar.struct_to_fields(self) { diff --git a/crates/solc-expressions/src/bin_op.rs b/crates/solc-expressions/src/bin_op.rs index a9c45591..57aad7ff 100644 --- a/crates/solc-expressions/src/bin_op.rs +++ b/crates/solc-expressions/src/bin_op.rs @@ -5,11 +5,11 @@ use crate::{ use graph::{ elem::*, nodes::{ - BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, - KilledKind, TmpConstruction, + Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, KilledKind, TmpConstruction, }, - AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, + AnalyzerBackend, ContextEdge, Edge, Node, }; +use shared::RangeArena; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; @@ -21,6 +21,7 @@ pub trait BinOp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn op_expr( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_expr: &Expression, rhs_expr: &Expression, @@ -30,8 +31,8 @@ pub trait BinOp: AnalyzerBackend + Sized { ) -> Result<(), ExprErr> { ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) .into_expr_err(loc)?; - self.parse_ctx_expr(rhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Binary operation had no right hand side".to_string())) }; @@ -41,8 +42,8 @@ pub trait BinOp: AnalyzerBackend + Sized { } let rhs_paths = rhs_paths.flatten(); let rhs_ctx = ctx; - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs(loc, format!("Binary operation had no left hand side, Expr: {lhs_expr:#?}, rhs ctx: {}, curr ctx: {}", rhs_ctx.path(analyzer), ctx.path(analyzer)))) }; @@ -51,13 +52,14 @@ pub trait BinOp: AnalyzerBackend + Sized { return Ok(()); } let lhs_paths = lhs_paths.flatten(); - analyzer.op_match(ctx, loc, &lhs_paths, &rhs_paths, op, assign) + analyzer.op_match(arena, ctx, loc, &lhs_paths, &rhs_paths, op, assign) }) }) } fn op_match( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, lhs_paths: &ExprRet, @@ -77,50 +79,62 @@ pub trait BinOp: AnalyzerBackend + Sized { (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - lhs_cvar.try_increase_size(self).into_expr_err(loc)?; - rhs_cvar.try_increase_size(self).into_expr_err(loc)?; - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; + lhs_cvar.try_increase_size(self, arena).into_expr_err(loc)?; + rhs_cvar.try_increase_size(self, arena).into_expr_err(loc)?; + ctx.push_expr( + self.op(arena, loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, + self, + ) + .into_expr_err(loc)?; Ok(()) } (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { ContextVarNode::from(*lhs) - .cast_from(&ContextVarNode::from(*rhs), self) + .cast_from(&ContextVarNode::from(*rhs), self, arena) .into_expr_err(loc)?; let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; + ctx.push_expr( + self.op(arena, loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, + self, + ) + .into_expr_err(loc)?; Ok(()) } (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { ContextVarNode::from(*rhs) - .cast_from(&ContextVarNode::from(*lhs), self) + .cast_from(&ContextVarNode::from(*lhs), self, arena) .into_expr_err(loc)?; let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; + ctx.push_expr( + self.op(arena, loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, + self, + ) + .into_expr_err(loc)?; Ok(()) } (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - ctx.push_expr(self.op(loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, self) - .into_expr_err(loc)?; + ctx.push_expr( + self.op(arena, loc, lhs_cvar, rhs_cvar, ctx, op, assign)?, + self, + ) + .into_expr_err(loc)?; Ok(()) } (lhs @ ExprRet::Single(..), ExprRet::Multi(rhs_sides)) => { rhs_sides .iter() - .map(|expr_ret| self.op_match(ctx, loc, lhs, expr_ret, op, assign)) + .map(|expr_ret| self.op_match(arena, ctx, loc, lhs, expr_ret, op, assign)) .collect::, ExprErr>>()?; Ok(()) } (ExprRet::Multi(lhs_sides), rhs @ ExprRet::Single(..)) => { lhs_sides .iter() - .map(|expr_ret| self.op_match(ctx, loc, expr_ret, rhs, op, assign)) + .map(|expr_ret| self.op_match(arena, ctx, loc, expr_ret, rhs, op, assign)) .collect::, ExprErr>>()?; Ok(()) } @@ -141,6 +155,7 @@ pub trait BinOp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn op( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_cvar: ContextVarNode, rhs_cvar: ContextVarNode, @@ -156,34 +171,6 @@ pub trait BinOp: AnalyzerBackend + Sized { assign ); - // if rhs_cvar.is_const(self).unwrap() { - // let int = rhs_cvar.evaled_range_max(self).unwrap().unwrap(); - // match collapse(&Elem::from(lhs_cvar), op, &int, self) { - // MaybeCollapsed::Collapsed(c) => { - // println!("collapsed: {c:?}"); - // } - // MaybeCollapsed::Concretes(_, _) => { - // println!("concretes"); - // } - // MaybeCollapsed::Not(..) => { - // println!("not collapsed"); - // } - // } - // } else if lhs_cvar.is_const(self).unwrap() { - // let int = lhs_cvar.evaled_range_max(self).unwrap().unwrap(); - // match collapse(&int, op, &Elem::from(rhs_cvar), self) { - // MaybeCollapsed::Collapsed(c) => { - // println!("collapsed: {c:?}"); - // } - // MaybeCollapsed::Concretes(_, _) => { - // println!("concretes"); - // } - // MaybeCollapsed::Not(..) => { - // println!("not collapsed"); - // } - // } - // } - let unchecked = match op { RangeOp::Add(u) | RangeOp::Sub(u) | RangeOp::Mul(u) | RangeOp::Div(u) => u, _ => false, @@ -207,7 +194,7 @@ pub trait BinOp: AnalyzerBackend + Sized { ContextVar::new_bin_op_tmp(lhs_cvar, op, rhs_cvar, ctx, loc, self) .into_expr_err(loc)?; if let Ok(Some(existing)) = - self.get_unchanged_tmp_variable(&new_lhs_underlying.display_name, ctx) + self.get_unchanged_tmp_variable(arena, &new_lhs_underlying.display_name, ctx) { self.advance_var_in_ctx_forcible(existing, loc, ctx, true)? } else { @@ -224,458 +211,78 @@ pub trait BinOp: AnalyzerBackend + Sized { } }; - let mut new_rhs = rhs_cvar.latest_version(self); + let new_rhs = rhs_cvar.latest_version(self); let expr = Elem::Expr(RangeExpr::::new( Elem::from(Reference::new(lhs_cvar.latest_version(self).into())), op, Elem::from(Reference::new(rhs_cvar.latest_version(self).into())), )); + let new_lhs = new_lhs.latest_version(self); + new_lhs + .set_range_min(self, arena, expr.clone()) + .into_expr_err(loc)?; + new_lhs + .set_range_max(self, arena, expr) + .into_expr_err(loc)?; // to prevent some recursive referencing, forcibly increase lhs_cvar self.advance_var_in_ctx_forcible(lhs_cvar.latest_version(self), loc, ctx, true)?; - // TODO: If one of lhs_cvar OR rhs_cvar are not symbolic, - // apply the requirement on the symbolic expression side instead of - // ignoring the case where - - // if lhs_cvar.is_symbolic(self) && new_rhs.is_symbolic(self) { if !unchecked { match op { RangeOp::Div(..) | RangeOp::Mod => { - // x / y - - if new_rhs.is_const(self).into_expr_err(loc)? { - // y is constant, do a check if it is 0 - if new_rhs - .evaled_range_min(self) - .into_expr_err(loc)? - .expect("No range?") - .range_eq(&Elem::from(Concrete::from(U256::zero())), self) - { - let res = ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc); - let _ = self.add_if_err(res); - - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { - // y is symbolic, add - let tmp_rhs = self.advance_var_in_ctx(new_rhs, loc, ctx)?; - let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); - let var = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero_node.into(), - self, - ); - let zero_node = self.add_node(Node::ContextVar(var.into_expr_err(loc)?)); - - if self - .require( - tmp_rhs, - zero_node.into(), - ctx, - loc, - RangeOp::Neq, - RangeOp::Neq, - (RangeOp::Eq, RangeOp::Neq), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } + if let Some(killed) = + self.checked_require_mod_div(arena, lhs_cvar, new_rhs, loc, ctx)? + { + return Ok(killed); } } RangeOp::Sub(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_const(self).into_expr_err(loc)? { - if !lhs_cvar.is_int(self).into_expr_err(loc)? { - if let (Some(lmax), Some(rmin)) = ( - lhs_cvar.evaled_range_max(self).into_expr_err(loc)?, - rhs_cvar.evaled_range_min(self).into_expr_err(loc)?, - ) { - if matches!( - lmax.range_ord(&rmin, self), - Some(std::cmp::Ordering::Less) - | Some(std::cmp::Ordering::Equal) - ) { - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } - } - } else if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; - // let tmp_rhs = self.advance_var_in_ctx_forcible(new_rhs, loc, ctx, true)?; - if self - .require( - tmp_lhs, - new_rhs, - ctx, - loc, - RangeOp::Gte, - RangeOp::Lte, - (RangeOp::Lte, RangeOp::Gte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - // the new min is max(lhs.min, rhs.min) - let min = Elem::max( - Elem::from(Reference::new(lhs_cvar.into())), - Elem::from(rhs_cvar), - ); - let tmp_lhs = tmp_lhs.latest_version(self); - tmp_lhs.set_range_min(self, min).into_expr_err(loc)?; - - // let tmp_var = ContextVar { - // loc: Some(loc), - // name: format!( - // "tmp{}({} >= {})", - // ctx.new_tmp(self).into_expr_err(loc)?, - // tmp_lhs.name(self).into_expr_err(loc)?, - // new_rhs.name(self).into_expr_err(loc)?, - // ), - // display_name: format!( - // "({} >= {})", - // tmp_lhs.display_name(self).unwrap(), - // new_rhs.display_name(self).unwrap(), - // ), - // storage: None, - // is_tmp: true, - // tmp_of: Some(TmpConstruction::new( - // tmp_lhs, - // RangeOp::Gte, - // Some(new_rhs), - // )), - // is_symbolic: true, - // is_return: false, - // ty: VarType::BuiltIn( - // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - // SolcRange::from(Concrete::Bool(true)), - // ), - // }; - - // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + if let Some(killed) = + self.checked_require_sub(arena, lhs_cvar, new_lhs, new_rhs, loc, ctx)? + { + return Ok(killed); } } RangeOp::Add(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - - // the new max is min(lhs.max, (2**256 - rhs.min)) - let max = Elem::min( - Elem::from(Reference::new(lhs_cvar.into())), - Elem::from(Concrete::from(U256::MAX)) - Elem::from(rhs_cvar), - ); - - tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; - - let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); - let tmp_max = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - max_node.into(), - self, - ); - let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); - - let tmp_rhs = self.op( - loc, - max_node.into(), - new_rhs, - ctx, - RangeOp::Sub(true), - false, - )?; - - if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { - return Ok(tmp_rhs); - } - - let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; - - let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { - self.advance_var_in_ctx_forcible( - tmp_lhs.latest_version(self), - loc, - ctx, - true, - )? - } else { - tmp_lhs - }; - - if self - .require( - tmp_lhs, - tmp_rhs.into(), - ctx, - loc, - RangeOp::Lte, - RangeOp::Gte, - (RangeOp::Gte, RangeOp::Lte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } + if let Some(killed) = + self.checked_require_add(arena, lhs_cvar, new_lhs, new_rhs, loc, ctx)? + { + return Ok(killed); } } RangeOp::Mul(..) => { - let lhs_cvar = lhs_cvar.latest_version(self); - if lhs_cvar.is_symbolic(self).into_expr_err(loc)? { - let tmp_lhs = self.advance_var_in_ctx(lhs_cvar, loc, ctx)?; - - // the new max is min(lhs.max, (2**256 / max(1, rhs.min))) - let max = Elem::min( - Elem::from(Reference::new(lhs_cvar.into())), - Elem::from(Concrete::from(U256::MAX)) - / Elem::max( - Elem::from(Concrete::from(U256::from(1))), - Elem::from(rhs_cvar), - ), - ); - - tmp_lhs.set_range_max(self, max).into_expr_err(loc)?; - - let max_node = self.add_node(Node::Concrete(Concrete::from(U256::MAX))); - let tmp_max = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - max_node.into(), - self, - ); - let max_node = self.add_node(Node::ContextVar(tmp_max.into_expr_err(loc)?)); - - let tmp_rhs = self.op( - loc, - max_node.into(), - new_rhs, - ctx, - RangeOp::Div(true), - false, - )?; - - if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { - return Ok(tmp_rhs); - } - - let tmp_rhs = tmp_rhs.expect_single().into_expr_err(loc)?; - - let tmp_lhs = if new_rhs.latest_version(self) == tmp_lhs { - self.advance_var_in_ctx_forcible( - tmp_lhs.latest_version(self), - loc, - ctx, - true, - )? - } else { - tmp_lhs - }; - - if self - .require( - tmp_lhs, - tmp_rhs.into(), - ctx, - loc, - RangeOp::Lte, - RangeOp::Gte, - (RangeOp::Gte, RangeOp::Lte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - // let tmp_rhs = ContextVarNode::from(tmp_rhs).latest_version(self); - - // let tmp_var = ContextVar { - // loc: Some(loc), - // name: format!( - // "tmp{}({} <= (2**256 - 1) / {})", - // ctx.new_tmp(self).into_expr_err(loc)?, - // tmp_lhs.name(self).into_expr_err(loc)?, - // new_rhs.name(self).into_expr_err(loc)?, - // ), - // display_name: format!( - // "({} <= (2**256 - 1) / {})", - // tmp_lhs.display_name(self).unwrap(), - // new_rhs.display_name(self).unwrap(), - // ), - // storage: None, - // is_tmp: true, - // tmp_of: Some(TmpConstruction::new( - // tmp_lhs, - // RangeOp::Lte, - // Some(tmp_rhs), - // )), - // is_symbolic: true, - // is_return: false, - // ty: VarType::BuiltIn( - // BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - // SolcRange::from(Concrete::Bool(true)), - // ), - // }; - - // let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - // ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; + if let Some(killed) = + self.checked_require_mul(arena, lhs_cvar, new_lhs, new_rhs, loc, ctx)? + { + return Ok(killed); } } RangeOp::Exp => { - if new_rhs.is_const(self).into_expr_err(loc)? { - if matches!( - new_rhs - .evaled_range_min(self) - .into_expr_err(loc)? - .expect("No range") - .range_ord(&Elem::from(Concrete::from(U256::zero())), self), - Some(std::cmp::Ordering::Less) - ) { - ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - } else if new_rhs.is_symbolic(self).into_expr_err(loc)? { - let tmp_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; - // the new min is max(lhs.min, rhs.min) - let min = Elem::max( - Elem::from(Reference::new(rhs_cvar.into())), - // .range_min(self) - // .into_expr_err(loc)? - // .expect("No range minimum?"), - Elem::from(Concrete::from(U256::zero())), - ); - - tmp_rhs.set_range_min(self, min).into_expr_err(loc)?; - - let zero_node = self.add_node(Node::Concrete(Concrete::from(U256::zero()))); - let tmp_zero = ContextVar::new_from_concrete( - Loc::Implicit, - ctx, - zero_node.into(), - self, - ); - let zero_node = - self.add_node(Node::ContextVar(tmp_zero.into_expr_err(loc)?)); - - if self - .require( - tmp_rhs, - zero_node.into(), - ctx, - loc, - RangeOp::Gte, - RangeOp::Lte, - (RangeOp::Lte, RangeOp::Gte), - )? - .is_none() - { - return Ok(ExprRet::CtxKilled(KilledKind::Revert)); - } - - let tmp_var = ContextVar { - loc: Some(loc), - name: format!( - "tmp{}({} >= 0)", - ctx.new_tmp(self).into_expr_err(loc)?, - tmp_rhs.name(self).into_expr_err(loc)?, - ), - display_name: format!( - "({} >= 0)", - tmp_rhs.display_name(self).into_expr_err(loc)?, - ), - storage: None, - is_tmp: true, - tmp_of: Some(TmpConstruction::new( - tmp_rhs, - RangeOp::Gte, - Some(zero_node.into()), - )), - dep_on: { - let mut deps = - tmp_rhs.dependent_on(self, true).into_expr_err(loc)?; - deps.push(zero_node.into()); - Some(deps) - }, - is_symbolic: true, - is_return: false, - ty: VarType::BuiltIn( - BuiltInNode::from(self.builtin_or_add(Builtin::Bool)), - SolcRange::from(Concrete::Bool(true)), - ), - }; - - let cvar = ContextVarNode::from(self.add_node(Node::ContextVar(tmp_var))); - ctx.add_ctx_dep(cvar, self).into_expr_err(loc)?; - new_rhs = tmp_rhs; + if let Some(killed) = + self.checked_require_exp(arena, lhs_cvar, new_lhs, new_rhs, loc, ctx)? + { + return Ok(killed); } } _ => {} } - } else { - - // self.advance_var_in_ctx_forcible(rhs_cvar.latest_version(self), loc, ctx, true)?; } - // let lhs_range = if let Some(lhs_range) = new_lhs.range(self).into_expr_err(loc)? { - // lhs_range - // } else { - // new_rhs - // .range(self) - // .into_expr_err(loc)? - // .expect("Neither lhs nor rhs had a usable range") - // }; - - // let func = SolcRange::dyn_fn_from_op(op); - // let new_range = func(lhs_range, new_rhs); - new_lhs - .latest_version(self) - .set_range_min(self, expr.clone()) - .into_expr_err(loc)?; - new_lhs - .latest_version(self) - .set_range_max(self, expr) - .into_expr_err(loc)?; - - // last ditch effort to prevent exponentiation from having a minimum of 1 instead of 0. - // if the lhs is 0 check if the rhs is also 0, otherwise set minimum to 0. - if matches!(op, RangeOp::Exp) { - if let (Some(old_lhs_range), Some(rhs_range)) = ( - lhs_cvar - .latest_version(self) - .ref_range(self) - .into_expr_err(loc)?, - new_rhs.ref_range(self).into_expr_err(loc)?, - ) { - let zero = Elem::from(Concrete::from(U256::zero())); - let zero_range = SolcRange::new(zero.clone(), zero.clone(), vec![]); - // We have to check if the the lhs and the right hand side contain the zero range. - // If they both do, we have to set the minimum to zero due to 0**0 = 1, but 0**x = 0. - // This is technically a slight widening of the interval and could be improved. - if old_lhs_range.contains(&zero_range, self) - && rhs_range.contains(&zero_range, self) - { - new_lhs.set_range_min(self, zero).into_expr_err(loc)?; - } - } - } Ok(ExprRet::Single(new_lhs.latest_version(self).into())) } #[tracing::instrument(level = "trace", skip_all)] fn bit_not( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(lhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, lhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -687,13 +294,14 @@ pub trait BinOp: AnalyzerBackend + Sized { ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.bit_not_inner(ctx, loc, lhs.flatten()) + analyzer.bit_not_inner(arena, ctx, loc, lhs.flatten()) }) } #[tracing::instrument(level = "trace", skip_all)] fn bit_not_inner( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, lhs_expr: ExprRet, @@ -708,9 +316,9 @@ pub trait BinOp: AnalyzerBackend + Sized { // TODO: try to pop from the stack and if there is a single element there // use it as a type hint, then place it back on the stack ContextVarNode::from(lhs) - .try_increase_size(self) + .try_increase_size(self, arena) .into_expr_err(loc)?; - self.bit_not_inner(ctx, loc, ExprRet::Single(lhs))?; + self.bit_not_inner(arena, ctx, loc, ExprRet::Single(lhs))?; Ok(()) } ExprRet::Single(lhs) => { @@ -745,9 +353,11 @@ pub trait BinOp: AnalyzerBackend + Sized { let out_var = ContextVarNode::from(self.add_node(Node::ContextVar(out_var))); out_var - .set_range_min(self, expr.clone()) + .set_range_min(self, arena, expr.clone()) + .into_expr_err(loc)?; + out_var + .set_range_max(self, arena, expr) .into_expr_err(loc)?; - out_var.set_range_max(self, expr).into_expr_err(loc)?; self.advance_var_in_ctx_forcible(lhs_cvar, loc, ctx, true)?; ctx.push_expr(ExprRet::Single(out_var.into()), self) @@ -764,4 +374,374 @@ pub trait BinOp: AnalyzerBackend + Sized { )), } } + + fn checked_require_mod_div( + &mut self, + arena: &mut RangeArena>, + lhs: ContextVarNode, + rhs: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result, ExprErr> { + // x / y || x % y + // revert if div or mod by 0 + if rhs.is_const(self, arena).into_expr_err(loc)? + && rhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .range_eq(&Elem::from(Concrete::from(U256::zero())), arena) + { + let res = ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc); + let _ = self.add_if_err(res); + + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // otherwise, require rhs != 0 + let tmp_rhs = self.advance_var_in_ctx(rhs, loc, ctx)?; + let zero_node = self.add_concrete_var(ctx, Concrete::from(U256::zero()), loc)?; + + if self + .require( + arena, + tmp_rhs, + zero_node, + ctx, + loc, + RangeOp::Neq, + RangeOp::Neq, + (RangeOp::Eq, RangeOp::Neq), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + Ok(None) + } + + fn checked_require_sub( + &mut self, + arena: &mut RangeArena>, + lhs: ContextVarNode, + new_lhs: ContextVarNode, + rhs: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result, ExprErr> { + // x - y >= type(x).min + let new_lhs = new_lhs.latest_version(self); + let tmp_lhs = self.advance_var_in_ctx_forcible(new_lhs, loc, ctx, true)?; + + // in checked subtraction, we have to make sure x - y >= type(x).min ==> x >= type(x).min + y + // get the lhs min + let min_conc = lhs.ty_min_concrete(self).into_expr_err(loc)?.unwrap(); + let min: ContextVarNode = self.add_concrete_var(ctx, min_conc, loc)?; + + // require lhs - rhs >= type(lhs).min + if self + .require( + arena, + tmp_lhs.latest_version(self), + min, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // If x and y are signed ints, we have to check that x - -y <= type(x).max + // because it could overflow in the positive direction + let lhs_is_int = lhs.is_int(self).into_expr_err(loc)?; + let rhs_is_int = rhs.is_int(self).into_expr_err(loc)?; + if lhs_is_int && rhs_is_int { + let rhs_min = rhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?"); + if rhs_min.is_negative(false, self, arena).into_expr_err(loc)? { + // rhs can be negative, require that lhs <= type(x).max + -rhs + // get the lhs max + let max_conc = lhs.ty_max_concrete(self).into_expr_err(loc)?.unwrap(); + let max: ContextVarNode = self.add_concrete_var(ctx, max_conc, loc)?; + + if self + .require( + arena, + tmp_lhs.latest_version(self), + max, + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + } + } + Ok(None) + } + + fn checked_require_add( + &mut self, + arena: &mut RangeArena>, + lhs: ContextVarNode, + new_lhs: ContextVarNode, + rhs: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result, ExprErr> { + // lhs + rhs <= type(lhs).max + let new_lhs = new_lhs.latest_version(self); + let tmp_lhs = self.advance_var_in_ctx_forcible(new_lhs, loc, ctx, true)?; + + // get type(lhs).max + let max_conc = lhs.ty_max_concrete(self).into_expr_err(loc)?.unwrap(); + let max = self.add_concrete_var(ctx, max_conc, loc)?; + + // require lhs + rhs <= type(lhs).max + if self + .require( + arena, + tmp_lhs.latest_version(self), + max, + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // If x and y are signed ints, we have to check that x + -y >= type(x).min + // because it could overflow in the negative direction + let lhs_is_int = lhs.is_int(self).into_expr_err(loc)?; + let rhs_is_int = rhs.is_int(self).into_expr_err(loc)?; + if lhs_is_int && rhs_is_int { + let rhs_min_is_negative = rhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(false, self, arena) + .into_expr_err(loc)?; + if rhs_min_is_negative { + // rhs can be negative, require that lhs + rhs >= type(x).min + // get the lhs min + let min_conc = lhs.ty_min_concrete(self).into_expr_err(loc)?.unwrap(); + let min = self.add_concrete_var(ctx, min_conc, loc)?; + + if self + .require( + arena, + new_lhs.latest_version(self), + min, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + } + } + + Ok(None) + } + + fn checked_require_mul( + &mut self, + arena: &mut RangeArena>, + lhs: ContextVarNode, + new_lhs: ContextVarNode, + rhs: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result, ExprErr> { + // lhs * rhs <= type(lhs).max + let new_lhs = new_lhs.latest_version(self); + let tmp_lhs = self.advance_var_in_ctx_forcible(new_lhs, loc, ctx, true)?; + + // get type(lhs).max + let max_conc = lhs.ty_max_concrete(self).into_expr_err(loc)?.unwrap(); + let max = self.add_concrete_var(ctx, max_conc, loc)?; + + // require lhs * rhs <= type(lhs).max + if self + .require( + arena, + tmp_lhs.latest_version(self), + max, + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // If x and y are signed ints, we have to check that x * -y >= type(x).min + // because it could overflow in the negative direction + let lhs_is_int = lhs.is_int(self).into_expr_err(loc)?; + let rhs_is_int = rhs.is_int(self).into_expr_err(loc)?; + if lhs_is_int || rhs_is_int { + let rhs_min_is_negative = rhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(false, self, arena) + .into_expr_err(loc)?; + let lhs_min_is_negative = lhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(false, self, arena) + .into_expr_err(loc)?; + let rhs_max_is_positive = !rhs + .evaled_range_max(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(true, self, arena) + .into_expr_err(loc)?; + let lhs_max_is_positive = !lhs + .evaled_range_max(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(true, self, arena) + .into_expr_err(loc)?; + + let can_go_very_negative = lhs_min_is_negative && rhs_max_is_positive + || rhs_min_is_negative && lhs_max_is_positive; + if can_go_very_negative { + // signs can be opposite so require that lhs * rhs >= type(x).min + // get the lhs min + let min_conc = lhs.ty_min_concrete(self).into_expr_err(loc)?.unwrap(); + let min = self.add_concrete_var(ctx, min_conc, loc)?; + + if self + .require( + arena, + new_lhs.latest_version(self), + min, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + } + } + + Ok(None) + } + + fn checked_require_exp( + &mut self, + arena: &mut RangeArena>, + lhs: ContextVarNode, + new_lhs: ContextVarNode, + rhs: ContextVarNode, + loc: Loc, + ctx: ContextNode, + ) -> Result, ExprErr> { + // exponent must be greater or equal to zero + let zero = rhs.ty_zero_concrete(self).into_expr_err(loc)?.unwrap(); + let zero = self.add_concrete_var(ctx, zero, loc)?; + if self + .require( + arena, + rhs, + zero, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // lhs ** rhs <= type(lhs).max + let new_lhs = new_lhs.latest_version(self); + let tmp_lhs = self.advance_var_in_ctx_forcible(new_lhs, loc, ctx, true)?; + + // get type(lhs).max + let max_conc = lhs.ty_max_concrete(self).into_expr_err(loc)?.unwrap(); + let max = self.add_concrete_var(ctx, max_conc, loc)?; + + // require lhs ** rhs <= type(lhs).max + if self + .require( + arena, + tmp_lhs.latest_version(self), + max, + ctx, + loc, + RangeOp::Lte, + RangeOp::Gte, + (RangeOp::Gte, RangeOp::Lte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + + // If x is signed int, we have to check that x ** y >= type(x).min + // because it could overflow in the negative direction + let lhs_is_int = lhs.is_int(self).into_expr_err(loc)?; + if lhs_is_int { + let lhs_min_is_negative = lhs + .evaled_range_min(self, arena) + .into_expr_err(loc)? + .expect("No range?") + .is_negative(false, self, arena) + .into_expr_err(loc)?; + if lhs_min_is_negative { + // rhs can be negative, require that lhs + rhs >= type(x).min + // get the lhs min + let min_conc = lhs.ty_min_concrete(self).into_expr_err(loc)?.unwrap(); + let min = self.add_concrete_var(ctx, min_conc, loc)?; + + if self + .require( + arena, + new_lhs.latest_version(self), + min, + ctx, + loc, + RangeOp::Gte, + RangeOp::Lte, + (RangeOp::Lte, RangeOp::Gte), + )? + .is_none() + { + return Ok(Some(ExprRet::CtxKilled(KilledKind::Revert))); + } + } + } + + Ok(None) + } } diff --git a/crates/solc-expressions/src/cmp.rs b/crates/solc-expressions/src/cmp.rs index fe29b227..e66b53f7 100644 --- a/crates/solc-expressions/src/cmp.rs +++ b/crates/solc-expressions/src/cmp.rs @@ -3,10 +3,12 @@ use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ elem::*, nodes::{ - BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TmpConstruction, + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, + TmpConstruction, }, AnalyzerBackend, GraphError, Node, Range, SolcRange, VarType, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; use std::cmp::Ordering; @@ -15,9 +17,15 @@ impl Cmp for T where T: AnalyzerBackend /// Handles comparator operations, i.e: `!` pub trait Cmp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] - fn not(&mut self, loc: Loc, lhs_expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { - self.parse_ctx_expr(lhs_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + fn not( + &mut self, + arena: &mut RangeArena>, + loc: Loc, + lhs_expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + self.parse_ctx_expr(arena, lhs_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -29,12 +37,18 @@ pub trait Cmp: AnalyzerBackend + Sized { ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.not_inner(ctx, loc, lhs.flatten()) + analyzer.not_inner(arena, ctx, loc, lhs.flatten()) }) } #[tracing::instrument(level = "trace", skip_all)] - fn not_inner(&mut self, ctx: ContextNode, loc: Loc, lhs_expr: ExprRet) -> Result<(), ExprErr> { + fn not_inner( + &mut self, + arena: &mut RangeArena>, + ctx: ContextNode, + loc: Loc, + lhs_expr: ExprRet, + ) -> Result<(), ExprErr> { match lhs_expr { ExprRet::CtxKilled(kind) => { ctx.kill(self, loc, kind).into_expr_err(loc)?; @@ -50,10 +64,10 @@ pub trait Cmp: AnalyzerBackend + Sized { RangeOp::Not, Elem::Null, )); - elem.arenaize(self); + elem.arenaize(self, arena); let mut range = SolcRange::new(elem.clone(), elem, vec![]); - range.cache_eval(self).into_expr_err(loc)?; + range.cache_eval(self, arena).into_expr_err(loc)?; let out_var = ContextVar { loc: Some(loc), name: format!( @@ -95,15 +109,16 @@ pub trait Cmp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn cmp( &mut self, + arena: &mut RangeArena>, loc: Loc, lhs_expr: &Expression, op: RangeOp, rhs_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.parse_ctx_expr(rhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { + analyzer.parse_ctx_expr(arena, rhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -117,8 +132,8 @@ pub trait Cmp: AnalyzerBackend + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs_expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -131,7 +146,7 @@ pub trait Cmp: AnalyzerBackend + Sized { ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.cmp_inner(ctx, loc, &lhs_paths.flatten(), op, &rhs_paths) + analyzer.cmp_inner(arena, ctx, loc, &lhs_paths.flatten(), op, &rhs_paths) }) }) }) @@ -140,6 +155,7 @@ pub trait Cmp: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] fn cmp_inner( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, lhs_paths: &ExprRet, @@ -152,14 +168,15 @@ pub trait Cmp: AnalyzerBackend + Sized { ContextVarNode::from(*lhs) .literal_cast_from(&ContextVarNode::from(*rhs), self) .into_expr_err(loc)?; - self.cmp_inner(ctx, loc, &ExprRet::Single(*rhs), op, rhs_paths) + self.cmp_inner(arena, ctx, loc, &ExprRet::Single(*rhs), op, rhs_paths) } (ExprRet::SingleLiteral(lhs), ExprRet::SingleLiteral(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs).latest_version(self); let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); - lhs_cvar.try_increase_size(self).into_expr_err(loc)?; - rhs_cvar.try_increase_size(self).into_expr_err(loc)?; + lhs_cvar.try_increase_size(self, arena).into_expr_err(loc)?; + rhs_cvar.try_increase_size(self, arena).into_expr_err(loc)?; self.cmp_inner( + arena, ctx, loc, &ExprRet::Single(lhs_cvar.into()), @@ -171,7 +188,7 @@ pub trait Cmp: AnalyzerBackend + Sized { ContextVarNode::from(*rhs) .literal_cast_from(&ContextVarNode::from(*lhs), self) .into_expr_err(loc)?; - self.cmp_inner(ctx, loc, lhs_paths, op, &ExprRet::Single(*rhs)) + self.cmp_inner(arena, ctx, loc, lhs_paths, op, &ExprRet::Single(*rhs)) } (ExprRet::Single(lhs), ExprRet::Single(rhs)) => { let lhs_cvar = ContextVarNode::from(*lhs); @@ -243,13 +260,13 @@ pub trait Cmp: AnalyzerBackend + Sized { (l @ ExprRet::Single(_lhs), ExprRet::Multi(rhs_sides)) => { rhs_sides .iter() - .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, l, op, expr_ret))?; + .try_for_each(|expr_ret| self.cmp_inner(arena, ctx, loc, l, op, expr_ret))?; Ok(()) } (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_)) => { lhs_sides .iter() - .try_for_each(|expr_ret| self.cmp_inner(ctx, loc, expr_ret, op, r))?; + .try_for_each(|expr_ret| self.cmp_inner(arena, ctx, loc, expr_ret, op, r))?; Ok(()) } (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { @@ -257,13 +274,13 @@ pub trait Cmp: AnalyzerBackend + Sized { if lhs_sides.len() == rhs_sides.len() { lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( |(lhs_expr_ret, rhs_expr_ret)| { - self.cmp_inner(ctx, loc, lhs_expr_ret, op, rhs_expr_ret) + self.cmp_inner(arena, ctx, loc, lhs_expr_ret, op, rhs_expr_ret) }, )?; Ok(()) } else { rhs_sides.iter().try_for_each(|rhs_expr_ret| { - self.cmp_inner(ctx, loc, lhs_paths, op, rhs_expr_ret) + self.cmp_inner(arena, ctx, loc, lhs_paths, op, rhs_expr_ret) })?; Ok(()) } @@ -282,10 +299,10 @@ pub trait Cmp: AnalyzerBackend + Sized { // lhs_cvar: ContextVarNode, // ) -> Result { // if let Some(lhs_range) = lhs_cvar.ref_range(self).into_expr_err(loc)? { - // let lhs_min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + // let lhs_min = lhs_range.evaled_range_min(self, arena).into_expr_err(loc)?; // // invert - // if lhs_min.range_eq(&lhs_range.evaled_range_max(self).into_expr_err(loc)?, self) { + // if lhs_min.range_eq(&lhs_range.minimize(self, arena).into_expr_err(loc)?, self) { // let val = Elem::Expr(RangeExpr::new( // lhs_range.range_min().into_owned(), // RangeOp::Not, @@ -314,6 +331,7 @@ pub trait Cmp: AnalyzerBackend + Sized { fn range_eval( &self, + arena: &mut RangeArena>, _ctx: ContextNode, lhs_cvar: ContextVarNode, rhs_cvar: ContextVarNode, @@ -326,17 +344,17 @@ pub trait Cmp: AnalyzerBackend + Sized { // if lhs_max < rhs_min, we know this cmp will evaluate to // true - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, self) { + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, arena) { return Ok(true.into()); } // Similarly if lhs_min >= rhs_max, we know this cmp will evaluate to // false - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max, self) { + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; + match lhs_min.range_ord(&rhs_max, arena) { Some(Ordering::Greater) => { return Ok(false.into()); } @@ -349,17 +367,17 @@ pub trait Cmp: AnalyzerBackend + Sized { RangeOp::Gt => { // if lhs_min > rhs_max, we know this cmp will evaluate to // true - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, self) { + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, arena) { return Ok(true.into()); } // if lhs_max <= rhs_min, we know this cmp will evaluate to // false - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min, self) { + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + match lhs_max.range_ord(&rhs_min, arena) { Some(Ordering::Less) => { return Ok(false.into()); } @@ -372,9 +390,9 @@ pub trait Cmp: AnalyzerBackend + Sized { RangeOp::Lte => { // if lhs_max <= rhs_min, we know this cmp will evaluate to // true - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - match lhs_max.range_ord(&rhs_min, self) { + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + match lhs_max.range_ord(&rhs_min, arena) { Some(Ordering::Less) => { return Ok(true.into()); } @@ -386,18 +404,18 @@ pub trait Cmp: AnalyzerBackend + Sized { // Similarly if lhs_min > rhs_max, we know this cmp will evaluate to // false - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, self) { + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; + if let Some(Ordering::Greater) = lhs_min.range_ord(&rhs_max, arena) { return Ok(false.into()); } } RangeOp::Gte => { // if lhs_min >= rhs_max, we know this cmp will evaluate to // true - let lhs_min = lhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; - match lhs_min.range_ord(&rhs_max, self) { + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; + match lhs_min.range_ord(&rhs_max, arena) { Some(Ordering::Greater) => { return Ok(true.into()); } @@ -409,30 +427,30 @@ pub trait Cmp: AnalyzerBackend + Sized { // if lhs_max < rhs_min, we know this cmp will evaluate to // false - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, self) { + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + if let Some(Ordering::Less) = lhs_max.range_ord(&rhs_min, arena) { return Ok(false.into()); } } RangeOp::Eq => { // if all elems are equal we know its true // we dont know anything else - let lhs_min = lhs_range.evaled_range_min(self)?; - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; if let ( Some(Ordering::Equal), Some(Ordering::Equal), Some(Ordering::Equal), ) = ( // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max, self), + lhs_min.range_ord(&lhs_max, arena), // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min, self), + lhs_min.range_ord(&rhs_min, arena), // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max, self), + rhs_min.range_ord(&rhs_max, arena), ) { return Ok(true.into()); } @@ -440,21 +458,21 @@ pub trait Cmp: AnalyzerBackend + Sized { RangeOp::Neq => { // if all elems are equal we know its true // we dont know anything else - let lhs_min = lhs_range.evaled_range_min(self)?; - let lhs_max = lhs_range.evaled_range_max(self)?; - let rhs_min = rhs_range.evaled_range_min(self)?; - let rhs_max = rhs_range.evaled_range_max(self)?; + let lhs_min = lhs_range.evaled_range_min(self, arena)?; + let lhs_max = lhs_range.evaled_range_max(self, arena)?; + let rhs_min = rhs_range.evaled_range_min(self, arena)?; + let rhs_max = rhs_range.evaled_range_max(self, arena)?; if let ( Some(Ordering::Equal), Some(Ordering::Equal), Some(Ordering::Equal), ) = ( // check lhs_min == lhs_max, ensures lhs is const - lhs_min.range_ord(&lhs_max, self), + lhs_min.range_ord(&lhs_max, arena), // check lhs_min == rhs_min, checks if lhs == rhs - lhs_min.range_ord(&rhs_min, self), + lhs_min.range_ord(&rhs_min, arena), // check rhs_min == rhs_max, ensures rhs is const - rhs_min.range_ord(&rhs_max, self), + rhs_min.range_ord(&rhs_max, arena), ) { return Ok(false.into()); } diff --git a/crates/solc-expressions/src/cond_op.rs b/crates/solc-expressions/src/cond_op.rs index 95b06017..c2d0f178 100644 --- a/crates/solc-expressions/src/cond_op.rs +++ b/crates/solc-expressions/src/cond_op.rs @@ -3,10 +3,11 @@ use crate::{ }; use graph::{ - nodes::{Context, ContextNode}, + elem::Elem, + nodes::{Concrete, Context, ContextNode}, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::CodeLocation; use solang_parser::pt::{Expression, Loc, Statement}; @@ -19,13 +20,14 @@ pub trait CondOp: AnalyzerBackend + Requir /// Handles a conditional operation like `if .. else ..` fn cond_op_stmt( &mut self, + arena: &mut RangeArena>, loc: Loc, if_expr: &Expression, true_stmt: &Statement, false_stmt: &Option>, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) .into_expr_err(loc)?; @@ -56,10 +58,12 @@ pub trait CondOp: AnalyzerBackend + Requir ); // we want to check if the true branch is possible to take - analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; + analyzer.true_fork_if_cvar(arena, if_expr.clone(), true_subctx)?; let mut true_killed = false; if true_subctx.is_killed(analyzer).into_expr_err(loc)? - || true_subctx.unreachable(analyzer).into_expr_err(loc)? + || true_subctx + .unreachable(analyzer, arena) + .into_expr_err(loc)? { // it was killed, therefore true branch is unreachable. // since it is unreachable, we want to not create @@ -68,10 +72,12 @@ pub trait CondOp: AnalyzerBackend + Requir } // we want to check if the false branch is possible to take - analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; + analyzer.false_fork_if_cvar(arena, if_expr.clone(), false_subctx)?; let mut false_killed = false; if false_subctx.is_killed(analyzer).into_expr_err(loc)? - || false_subctx.unreachable(analyzer).into_expr_err(loc)? + || false_subctx + .unreachable(analyzer, arena) + .into_expr_err(loc)? { // it was killed, therefore true branch is unreachable. // since it is unreachable, we want to not create @@ -90,12 +96,17 @@ pub trait CondOp: AnalyzerBackend + Requir // the true context has been killed, delete child, process the false fork expression // in the parent context and parse the false body ctx.delete_child(analyzer).into_expr_err(loc)?; - analyzer.false_fork_if_cvar(if_expr.clone(), ctx)?; + analyzer.false_fork_if_cvar(arena, if_expr.clone(), ctx)?; if let Some(false_stmt) = false_stmt { - return analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); - Ok(()) - }); + return analyzer.apply_to_edges( + ctx, + loc, + arena, + &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_statement(arena, false_stmt, false, Some(ctx)); + Ok(()) + }, + ); } } (false, true) => { @@ -103,9 +114,10 @@ pub trait CondOp: AnalyzerBackend + Requir // the false context has been killed, delete child, process the true fork expression // in the parent context and parse the true body ctx.delete_child(analyzer).into_expr_err(loc)?; - analyzer.true_fork_if_cvar(if_expr.clone(), ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.true_fork_if_cvar(arena, if_expr.clone(), ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { analyzer.parse_ctx_statement( + arena, true_stmt, ctx.unchecked(analyzer).into_expr_err(loc)?, Some(ctx), @@ -116,20 +128,27 @@ pub trait CondOp: AnalyzerBackend + Requir (false, false) => { // println!("NEITHER KILLED"); // both branches are reachable. process each body - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement( - true_stmt, - ctx.unchecked(analyzer).into_expr_err(loc)?, - Some(ctx), - ); - Ok(()) - })?; + analyzer.apply_to_edges( + true_subctx, + loc, + arena, + &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_statement( + arena, + true_stmt, + ctx.unchecked(analyzer).into_expr_err(loc)?, + Some(ctx), + ); + Ok(()) + }, + )?; if let Some(false_stmt) = false_stmt { return analyzer.apply_to_edges( false_subctx, loc, - &|analyzer, ctx, _loc| { - analyzer.parse_ctx_statement(false_stmt, false, Some(ctx)); + arena, + &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_statement(arena, false_stmt, false, Some(ctx)); Ok(()) }, ); @@ -146,6 +165,7 @@ pub trait CondOp: AnalyzerBackend + Requir #[tracing::instrument(level = "trace", skip_all)] fn cond_op_expr( &mut self, + arena: &mut RangeArena>, loc: Loc, if_expr: &Expression, true_expr: &Expression, @@ -153,7 +173,7 @@ pub trait CondOp: AnalyzerBackend + Requir ctx: ContextNode, ) -> Result<(), ExprErr> { tracing::trace!("conditional operator"); - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) .into_expr_err(loc)?; @@ -183,14 +203,14 @@ pub trait CondOp: AnalyzerBackend + Requir Edge::Context(ContextEdge::Subcontext), ); - analyzer.true_fork_if_cvar(if_expr.clone(), true_subctx)?; - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_expr(true_expr, ctx) + analyzer.true_fork_if_cvar(arena, if_expr.clone(), true_subctx)?; + analyzer.apply_to_edges(true_subctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_expr(arena, true_expr, ctx) })?; - analyzer.false_fork_if_cvar(if_expr.clone(), false_subctx)?; - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_expr(false_expr, ctx) + analyzer.false_fork_if_cvar(arena, if_expr.clone(), false_subctx)?; + analyzer.apply_to_edges(false_subctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_expr(arena, false_expr, ctx) }) }) } @@ -198,25 +218,32 @@ pub trait CondOp: AnalyzerBackend + Requir /// Creates the true_fork cvar (updates bounds assuming its true) fn true_fork_if_cvar( &mut self, + arena: &mut RangeArena>, if_expr: Expression, true_fork_ctx: ContextNode, ) -> Result<(), ExprErr> { - self.apply_to_edges(true_fork_ctx, if_expr.loc(), &|analyzer, ctx, _loc| { - analyzer.handle_require(&[if_expr.clone()], ctx)?; - Ok(()) - }) + self.apply_to_edges( + true_fork_ctx, + if_expr.loc(), + arena, + &|analyzer, arena, ctx, _loc| { + analyzer.handle_require(arena, &[if_expr.clone()], ctx)?; + Ok(()) + }, + ) } /// Creates the false_fork cvar (inverts the expression and sets the bounds assuming its false) fn false_fork_if_cvar( &mut self, + arena: &mut RangeArena>, if_expr: Expression, false_fork_ctx: ContextNode, ) -> Result<(), ExprErr> { let loc = if_expr.loc(); let inv_if_expr = self.inverse_expr(if_expr); - self.apply_to_edges(false_fork_ctx, loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(&[inv_if_expr.clone()], ctx)?; + self.apply_to_edges(false_fork_ctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.handle_require(arena, &[inv_if_expr.clone()], ctx)?; Ok(()) }) } diff --git a/crates/solc-expressions/src/context_builder/expr.rs b/crates/solc-expressions/src/context_builder/expr.rs index d5e03f0e..ded16451 100644 --- a/crates/solc-expressions/src/context_builder/expr.rs +++ b/crates/solc-expressions/src/context_builder/expr.rs @@ -9,6 +9,7 @@ use graph::{ nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; +use shared::RangeArena; use ethers_core::types::I256; use solang_parser::{ @@ -26,15 +27,20 @@ pub trait ExpressionParser: AnalyzerBackend + Sized + ExprTyParser { /// Perform setup for parsing an expression - fn parse_ctx_expr(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + fn parse_ctx_expr( + &mut self, + arena: &mut RangeArena>, + expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { if !ctx.killed_or_ret(self).unwrap() { let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; if edges.is_empty() { - self.parse_ctx_expr_inner(expr, ctx) + self.parse_ctx_expr_inner(arena, expr, ctx) } else { edges .iter() - .try_for_each(|fork_ctx| self.parse_ctx_expr(expr, *fork_ctx))?; + .try_for_each(|fork_ctx| self.parse_ctx_expr(arena, expr, *fork_ctx))?; Ok(()) } } else { @@ -44,7 +50,12 @@ pub trait ExpressionParser: #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self).replace('.', "\n\t.")))] /// Perform parsing of an expression - fn parse_ctx_expr_inner(&mut self, expr: &Expression, ctx: ContextNode) -> Result<(), ExprErr> { + fn parse_ctx_expr_inner( + &mut self, + arena: &mut RangeArena>, + expr: &Expression, + ctx: ContextNode, + ) -> Result<(), ExprErr> { use Expression::*; // tracing::trace!( // "ctx: {}, current stack: {:?}, \nexpr: {:?}\n", @@ -70,7 +81,7 @@ pub trait ExpressionParser: HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, false), HexLiteral(hexes) => self.hex_literals(ctx, hexes), RationalNumberLiteral(loc, integer, fraction, exp, unit) => { - self.rational_number_literal(ctx, *loc, integer, fraction, exp, unit) + self.rational_number_literal(arena, ctx, *loc, integer, fraction, exp, unit) } Negate(_loc, expr) => match &**expr { NumberLiteral(loc, int, exp, unit) => { @@ -78,8 +89,8 @@ pub trait ExpressionParser: } HexNumberLiteral(loc, b, _unit) => self.hex_num_literal(ctx, *loc, b, true), e => { - self.parse_ctx_expr(e, ctx)?; - self.apply_to_edges(ctx, e.loc(), &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, e, ctx)?; + self.apply_to_edges(ctx, e.loc(), arena, &|analyzer, arena, ctx, loc| { tracing::trace!("Negate variable pop"); let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? @@ -119,11 +130,12 @@ pub trait ExpressionParser: analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); ContextVarNode::from(node) - .cast_from(&ContextVarNode::from(zero), analyzer) + .cast_from(&ContextVarNode::from(zero), analyzer, arena) .into_expr_err(loc)?; let lhs_paths = ExprRet::Single(zero); analyzer.op_match( + arena, ctx, loc, &lhs_paths, @@ -140,9 +152,10 @@ pub trait ExpressionParser: // Binary ops Power(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Exp, false) } Add(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -151,6 +164,7 @@ pub trait ExpressionParser: false, ), AssignAdd(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -159,6 +173,7 @@ pub trait ExpressionParser: true, ), Subtract(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -167,6 +182,7 @@ pub trait ExpressionParser: false, ), AssignSubtract(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -175,6 +191,7 @@ pub trait ExpressionParser: true, ), Multiply(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -183,6 +200,7 @@ pub trait ExpressionParser: false, ), AssignMultiply(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, *loc, lhs_expr, rhs_expr, @@ -190,62 +208,76 @@ pub trait ExpressionParser: RangeOp::Mul(ctx.unchecked(self).into_expr_err(*loc)?), true, ), - Divide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), false) - } - AssignDivide(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Div(false), true) - } + Divide(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Div(false), + false, + ), + AssignDivide(loc, lhs_expr, rhs_expr) => self.op_expr( + arena, + *loc, + lhs_expr, + rhs_expr, + ctx, + RangeOp::Div(false), + true, + ), Modulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, false) } AssignModulo(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Mod, true) } ShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, false) } AssignShiftLeft(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Shl, true) } ShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, false) } AssignShiftRight(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::Shr, true) } ConditionalOperator(loc, if_expr, true_expr, false_expr) => { - self.cond_op_expr(*loc, if_expr, true_expr, false_expr, ctx) + self.cond_op_expr(arena, *loc, if_expr, true_expr, false_expr, ctx) } // Bitwise ops BitwiseAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, false) } AssignAnd(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitAnd, true) } BitwiseXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, false) } AssignXor(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitXor, true) } BitwiseOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, false) } AssignOr(loc, lhs_expr, rhs_expr) => { - self.op_expr(*loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) + self.op_expr(arena, *loc, lhs_expr, rhs_expr, ctx, RangeOp::BitOr, true) } - BitwiseNot(loc, lhs_expr) => self.bit_not(*loc, lhs_expr, ctx), + BitwiseNot(loc, lhs_expr) => self.bit_not(arena, *loc, lhs_expr, ctx), // assign - Assign(loc, lhs_expr, rhs_expr) => self.assign_exprs(*loc, lhs_expr, rhs_expr, ctx), - List(loc, params) => self.list(ctx, *loc, params), + Assign(loc, lhs_expr, rhs_expr) => { + self.assign_exprs(arena, *loc, lhs_expr, rhs_expr, ctx) + } + List(loc, params) => self.list(arena, ctx, *loc, params), // array - ArraySubscript(_loc, ty_expr, None) => self.array_ty(ty_expr, ctx), + ArraySubscript(_loc, ty_expr, None) => self.array_ty(arena, ty_expr, ctx), ArraySubscript(loc, ty_expr, Some(index_expr)) => { - self.index_into_array(*loc, ty_expr, index_expr, ctx) + self.index_into_array(arena, *loc, ty_expr, index_expr, ctx) } ArraySlice(loc, _lhs_expr, _maybe_middle_expr, _maybe_rhs) => Err(ExprErr::Todo( *loc, @@ -257,17 +289,17 @@ pub trait ExpressionParser: )), // Comparator - Equal(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Eq, rhs, ctx), - NotEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Neq, rhs, ctx), - Less(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lt, rhs, ctx), - More(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gt, rhs, ctx), - LessEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Lte, rhs, ctx), - MoreEqual(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Gte, rhs, ctx), + Equal(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Eq, rhs, ctx), + NotEqual(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Neq, rhs, ctx), + Less(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Lt, rhs, ctx), + More(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Gt, rhs, ctx), + LessEqual(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Lte, rhs, ctx), + MoreEqual(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Gte, rhs, ctx), // Logical - Not(loc, expr) => self.not(*loc, expr, ctx), - And(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::And, rhs, ctx), - Or(loc, lhs, rhs) => self.cmp(*loc, lhs, RangeOp::Or, rhs, ctx), + Not(loc, expr) => self.not(arena, *loc, expr, ctx), + And(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::And, rhs, ctx), + Or(loc, lhs, rhs) => self.cmp(arena, *loc, lhs, RangeOp::Or, rhs, ctx), // Function calls FunctionCallBlock(loc, _func_expr, _input_exprs) => { @@ -279,7 +311,7 @@ pub trait ExpressionParser: )) } NamedFunctionCall(loc, func_expr, input_args) => { - self.named_fn_call_expr(ctx, loc, func_expr, input_args) + self.named_fn_call_expr(arena, ctx, loc, func_expr, input_args) } FunctionCall(loc, func_expr, input_exprs) => { let updated_func_expr = match **func_expr { @@ -296,14 +328,14 @@ pub trait ExpressionParser: _ => func_expr.clone(), }; - self.fn_call_expr(ctx, loc, &updated_func_expr, input_exprs) + self.fn_call_expr(arena, ctx, loc, &updated_func_expr, input_exprs) } // member New(loc, expr) => { match &**expr { Expression::FunctionCall(_loc, func, inputs) => { // parse the type - self.new_call(loc, func, inputs, ctx) + self.new_call(arena, loc, func, inputs, ctx) } _ => panic!("Bad new call"), } @@ -323,7 +355,7 @@ pub trait ExpressionParser: Ok(()) } MemberAccess(loc, member_expr, ident) => { - self.member_access(*loc, member_expr, ident, ctx) + self.member_access(arena, *loc, member_expr, ident, ctx) } Delete(loc, expr) => { @@ -352,8 +384,8 @@ pub trait ExpressionParser: } } - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { tracing::trace!("Delete variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -373,15 +405,15 @@ pub trait ExpressionParser: } // de/increment stuff - PreIncrement(loc, expr) => self.pre_increment(expr, *loc, ctx), - PostIncrement(loc, expr) => self.post_increment(expr, *loc, ctx), - PreDecrement(loc, expr) => self.pre_decrement(expr, *loc, ctx), - PostDecrement(loc, expr) => self.post_decrement(expr, *loc, ctx), + PreIncrement(loc, expr) => self.pre_increment(arena, expr, *loc, ctx), + PostIncrement(loc, expr) => self.post_increment(arena, expr, *loc, ctx), + PreDecrement(loc, expr) => self.pre_decrement(arena, expr, *loc, ctx), + PostDecrement(loc, expr) => self.post_decrement(arena, expr, *loc, ctx), // Misc. - Variable(ident) => self.variable(ident, ctx, None), + Variable(ident) => self.variable(arena, ident, ctx, None), Type(loc, ty) => { - if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self) { + if let Some(builtin) = Builtin::try_from_ty(ty.clone(), self, arena) { if let Some(idx) = self.builtins().get(&builtin) { ctx.push_expr(ExprRet::Single(*idx), self) .into_expr_err(*loc)?; @@ -398,7 +430,7 @@ pub trait ExpressionParser: Ok(()) } } - Parenthesis(_loc, expr) => self.parse_ctx_expr(expr, ctx), + Parenthesis(_loc, expr) => self.parse_ctx_expr(arena, expr, ctx), } } } diff --git a/crates/solc-expressions/src/context_builder/fn_calls.rs b/crates/solc-expressions/src/context_builder/fn_calls.rs index 3be6c374..34dcc8e7 100644 --- a/crates/solc-expressions/src/context_builder/fn_calls.rs +++ b/crates/solc-expressions/src/context_builder/fn_calls.rs @@ -251,8 +251,8 @@ pub trait FnCallBuilder: _ => {} }, - FunctionCallBlock(_, func_expr, _input_exprs) => match *func_expr { - Variable(ref ident) => { + FunctionCallBlock(_, func_expr, _input_exprs) => { + if let Variable(ref ident) = *func_expr { let loc = func_expr.loc(); let ctx = Context::new( caller, @@ -270,10 +270,9 @@ pub trait FnCallBuilder: self.add_fn_call(caller, func); } } - _ => {} - }, - NamedFunctionCall(_, func_expr, _input_args) => match *func_expr { - Variable(ref ident) => { + } + NamedFunctionCall(_, func_expr, input_args) => { + if let Variable(ref ident) = *func_expr { let loc = func_expr.loc(); let ctx = Context::new( caller, @@ -282,38 +281,36 @@ pub trait FnCallBuilder: ); let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); let visible_funcs = ctx.visible_funcs(self).unwrap(); - let possible_funcs: Vec<_> = visible_funcs + let mut possible_funcs: Vec<_> = visible_funcs .into_iter() .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) .collect(); + possible_funcs.retain(|func| func.params(self).len() == input_args.len()); if possible_funcs.len() == 1 { let func = possible_funcs[0]; self.add_fn_call(caller, func); } } - _ => {} - }, + } FunctionCall(_, func_expr, input_exprs) => { - match *func_expr { - Variable(ref ident) => { - let loc = func_expr.loc(); - let ctx = Context::new( - caller, - format!("<{}_parser_fn>", caller.name(self).unwrap()), - loc, - ); - let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); - let visible_funcs = ctx.visible_funcs(self).unwrap(); - let possible_funcs: Vec<_> = visible_funcs - .into_iter() - .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) - .collect(); - if possible_funcs.len() == 1 { - let func = possible_funcs[0]; - self.add_fn_call(caller, func); - } + if let Variable(ref ident) = *func_expr { + let loc = func_expr.loc(); + let ctx = Context::new( + caller, + format!("<{}_parser_fn>", caller.name(self).unwrap()), + loc, + ); + let ctx = ContextNode::from(self.add_node(Node::Context(ctx))); + let visible_funcs = ctx.visible_funcs(self).unwrap(); + let mut possible_funcs: Vec<_> = visible_funcs + .into_iter() + .filter(|f| f.name(self).unwrap().starts_with(&ident.name)) + .collect(); + possible_funcs.retain(|func| func.params(self).len() == input_exprs.len()); + if possible_funcs.len() == 1 { + let func = possible_funcs[0]; + self.add_fn_call(caller, func); } - _ => {} } input_exprs.iter().for_each(|expr| { diff --git a/crates/solc-expressions/src/context_builder/mod.rs b/crates/solc-expressions/src/context_builder/mod.rs index a4249979..d79b71d2 100644 --- a/crates/solc-expressions/src/context_builder/mod.rs +++ b/crates/solc-expressions/src/context_builder/mod.rs @@ -2,9 +2,11 @@ use crate::{ExprErr, IntoExprErr}; use graph::{ - nodes::{ContextNode, ContextVarNode, ExprRet, KilledKind}, - AnalyzerBackend, ContextEdge, Edge, GraphError, + elem::Elem, + nodes::{Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, KilledKind}, + AnalyzerBackend, ContextEdge, Edge, GraphError, Node, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; @@ -51,13 +53,58 @@ pub trait ContextBuilder: } /// Match on the [`ExprRet`]s of a return statement and performs the return - fn return_match(&mut self, ctx: ContextNode, loc: &Loc, paths: &ExprRet) { + fn return_match( + &mut self, + arena: &mut RangeArena>, + ctx: ContextNode, + loc: &Loc, + paths: &ExprRet, + idx: usize, + ) { match paths { ExprRet::CtxKilled(kind) => { let _ = ctx.kill(self, *loc, *kind); } ExprRet::Single(expr) | ExprRet::SingleLiteral(expr) => { + // construct a variable from the return type + let target_var = ctx + .associated_fn(self) + .map(|func| { + let rets = func.returns(arena, self); + let Some(ret) = rets.get(idx) else { + return Ok(None) + }; + + ret.underlying(self) + .cloned() + .map(|underlying| { + ContextVar::new_from_func_ret(ctx, self, underlying).map(|var| { + var.map(|var| { + ContextVarNode::from(self.add_node(Node::ContextVar(var))) + }).ok_or(GraphError::NodeConfusion("Could not construct a context variable from function return".to_string())) + .map(Some) + }).and_then(|i| i) + }) + .and_then(|i| i) + }) + .and_then(|i| i) + .into_expr_err(*loc); + let latest = ContextVarNode::from(*expr).latest_version(self); + + match target_var { + Ok(Some(target_var)) => { + // perform a cast + let next = self + .advance_var_in_ctx_forcible(latest, *loc, ctx, true) + .unwrap(); + let res = next.cast_from(&target_var, self, arena).into_expr_err(*loc); + self.add_if_err(res); + } + Ok(None) => {} + Err(e) => self.add_expr_err(e), + } + // let ret = self.advance_var_in_ctx(latest, *loc, *ctx); let path = ctx.path(self); let res = latest.underlying_mut(self).into_expr_err(*loc); @@ -76,8 +123,8 @@ pub trait ContextBuilder: } } ExprRet::Multi(rets) => { - rets.iter().for_each(|expr_ret| { - self.return_match(ctx, loc, expr_ret); + rets.iter().enumerate().for_each(|(i, expr_ret)| { + self.return_match(arena, ctx, loc, expr_ret, i); }); } ExprRet::Null => {} @@ -91,7 +138,13 @@ pub trait ContextBuilder: &mut self, ctx: ContextNode, loc: Loc, - closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result<(), ExprErr>, + arena: &mut RangeArena>, + closure: &impl Fn( + &mut Self, + &mut RangeArena>, + ContextNode, + Loc, + ) -> Result<(), ExprErr>, ) -> Result<(), ExprErr> { let live_edges = ctx.live_edges(self).into_expr_err(loc)?; tracing::trace!( @@ -106,14 +159,14 @@ pub trait ContextBuilder: } else { live_edges .iter() - .try_for_each(|ctx| closure(self, *ctx, loc)) + .try_for_each(|ctx| closure(self, arena, *ctx, loc)) } } else if live_edges.is_empty() { - closure(self, ctx, loc) + closure(self, arena, ctx, loc) } else { live_edges .iter() - .try_for_each(|ctx| closure(self, *ctx, loc)) + .try_for_each(|ctx| closure(self, arena, *ctx, loc)) } } else { Ok(()) @@ -126,7 +179,13 @@ pub trait ContextBuilder: &mut self, ctx: ContextNode, loc: Loc, - closure: &impl Fn(&mut Self, ContextNode, Loc) -> Result, + arena: &mut RangeArena>, + closure: &impl Fn( + &mut Self, + &mut RangeArena>, + ContextNode, + Loc, + ) -> Result, ) -> Result, ExprErr> { let live_edges = ctx.live_edges(self).into_expr_err(loc)?; tracing::trace!( @@ -136,11 +195,11 @@ pub trait ContextBuilder: ); if live_edges.is_empty() { - Ok(vec![closure(self, ctx, loc)?]) + Ok(vec![closure(self, arena, ctx, loc)?]) } else { live_edges .iter() - .map(|ctx| closure(self, *ctx, loc)) + .map(|ctx| closure(self, arena, *ctx, loc)) .collect::, ExprErr>>() } } diff --git a/crates/solc-expressions/src/context_builder/stmt.rs b/crates/solc-expressions/src/context_builder/stmt.rs index 85a6b170..07137a0f 100644 --- a/crates/solc-expressions/src/context_builder/stmt.rs +++ b/crates/solc-expressions/src/context_builder/stmt.rs @@ -7,13 +7,14 @@ use crate::{ }; use graph::{ + elem::Elem, nodes::{ - Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, - FunctionReturnNode, KilledKind, + Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, FunctionReturnNode, KilledKind, }, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use petgraph::{visit::EdgeRef, Direction}; use solang_parser::{ @@ -33,6 +34,7 @@ pub trait StatementParser: /// Performs setup for parsing a solidity statement fn parse_ctx_statement( &mut self, + arena: &mut RangeArena>, stmt: &Statement, unchecked: bool, parent_ctx: Option + Copy>, @@ -48,19 +50,24 @@ pub trait StatementParser: self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { if live_edges.is_empty() { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + self.parse_ctx_stmt_inner(arena, stmt, unchecked, parent_ctx) } else { live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_stmt_inner(stmt, unchecked, Some(*fork_ctx)); + self.parse_ctx_stmt_inner( + arena, + stmt, + unchecked, + Some(*fork_ctx), + ); }); } } } } - _ => self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx), + _ => self.parse_ctx_stmt_inner(arena, stmt, unchecked, parent_ctx), } } else { - self.parse_ctx_stmt_inner(stmt, unchecked, parent_ctx) + self.parse_ctx_stmt_inner(arena, stmt, unchecked, parent_ctx) } } @@ -68,6 +75,7 @@ pub trait StatementParser: /// Performs parsing of a solidity statement fn parse_ctx_stmt_inner( &mut self, + arena: &mut RangeArena>, stmt: &Statement, unchecked: bool, parent_ctx: Option + Copy>, @@ -206,11 +214,12 @@ pub trait StatementParser: if !mods_set { let parent = FunctionNode::from(parent.into()); let _ = self - .set_modifiers(parent, ctx_node.into()) + .set_modifiers(arena, parent, ctx_node.into()) .map_err(|e| self.add_expr_err(e)); } let res = self.func_call_inner( + arena, true, ctx_node.into(), parent.into().into(), @@ -223,20 +232,25 @@ pub trait StatementParser: if self.widen_if_limit_hit(ctx_node.into(), res) { return; } - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad funciton call"); - let res = ContextNode::from(ctx_node) - .kill( - analyzer, - fn_loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(fn_loc); - let _ = analyzer.add_if_err(res); - } - Ok(()) - }); + let res = self.apply_to_edges( + ctx_node.into(), + *loc, + arena, + &|analyzer, arena, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad funciton call"); + let res = ContextNode::from(ctx_node) + .kill( + analyzer, + fn_loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(fn_loc); + let _ = analyzer.add_if_err(res); + } + Ok(()) + }, + ); if self.widen_if_limit_hit(ctx_node.into(), res) { return; @@ -245,12 +259,17 @@ pub trait StatementParser: return; } - let res = self.apply_to_edges(ctx_node.into(), *loc, &|analyzer, ctx, _loc| { - statements - .iter() - .for_each(|stmt| analyzer.parse_ctx_statement(stmt, *unchecked, Some(ctx))); - Ok(()) - }); + let res = self.apply_to_edges( + ctx_node.into(), + *loc, + arena, + &|analyzer, arena, ctx, _loc| { + statements.iter().for_each(|stmt| { + analyzer.parse_ctx_statement(arena, stmt, *unchecked, Some(ctx)) + }); + Ok(()) + }, + ); if self.widen_if_limit_hit(ctx_node.into(), res) {} } VariableDefinition(loc, var_decl, maybe_expr) => { @@ -265,58 +284,71 @@ pub trait StatementParser: ); if let Some(rhs) = maybe_expr { - match self.parse_ctx_expr(rhs, ctx) { + match self.parse_ctx_expr(arena, rhs, ctx) { Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - let Some(rhs_paths) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - format!( - "Variable definition had no right hand side, {}", - ctx.path(analyzer) - ), - )); - }; - - if matches!(rhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_expr(&var_decl.ty, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = ctx + let res = self.apply_to_edges( + ctx, + *loc, + arena, + &|analyzer, arena, ctx, loc| { + if !ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + let Some(rhs_paths) = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? else { - return Err(ExprErr::NoLhs( + return Err(ExprErr::NoRhs( loc, - "Variable definition had no left hand side" - .to_string(), + format!( + "Variable definition had no right hand side, {}", + ctx.path(analyzer) + ), )); }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer) + if matches!(rhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_paths, analyzer) .into_expr_err(loc)?; return Ok(()); } - analyzer.match_var_def( + + analyzer.parse_ctx_expr(arena, &var_decl.ty, ctx)?; + analyzer.apply_to_edges( ctx, - var_decl, loc, - &lhs_paths, - Some(&rhs_paths), - )?; + arena, + &|analyzer, arena, ctx, loc| { + let Some(lhs_paths) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side" + .to_string(), + )); + }; + + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer) + .into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def( + arena, + ctx, + var_decl, + loc, + &lhs_paths, + Some(&rhs_paths), + )?; + Ok(()) + }, + ) + } else { Ok(()) - }) - } else { - Ok(()) - } - }); + } + }, + ); let _ = self.widen_if_limit_hit(ctx, res); } ret => { @@ -324,26 +356,27 @@ pub trait StatementParser: } } } else { - let res = self.parse_ctx_expr(&var_decl.ty, ctx); + let res = self.parse_ctx_expr(arena, &var_decl.ty, ctx); if self.widen_if_limit_hit(ctx, res) { return; } - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_paths) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "Variable definition had no left hand side".to_string(), - )); - }; - if matches!(lhs_paths, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_var_def(ctx, var_decl, loc, &lhs_paths, None)?; - Ok(()) - }); + let res = + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { + let Some(lhs_paths) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoLhs( + loc, + "Variable definition had no left hand side".to_string(), + )); + }; + if matches!(lhs_paths, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_paths, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_var_def(arena, ctx, var_decl, loc, &lhs_paths, None)?; + Ok(()) + }); let _ = self.widen_if_limit_hit(ctx, res); } } @@ -353,8 +386,8 @@ pub trait StatementParser: If(loc, if_expr, true_expr, maybe_false_expr) => { tracing::trace!("parsing if, {if_expr:?}"); let ctx = ContextNode::from(parent_ctx.expect("Dangling if statement").into()); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - analyzer.cond_op_stmt(loc, if_expr, true_expr, maybe_false_expr, ctx) + let res = self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { + analyzer.cond_op_stmt(arena, loc, if_expr, true_expr, maybe_false_expr, ctx) }); let _ = self.widen_if_limit_hit(ctx, res); } @@ -364,7 +397,10 @@ pub trait StatementParser: let res = self.apply_to_edges( ContextNode::from(parent.into()), *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, cond, body), + arena, + &|analyzer, arena, ctx, loc| { + analyzer.while_loop(arena, loc, ctx, cond, body) + }, ); let _ = self.widen_if_limit_hit(parent.into().into(), res); } @@ -373,21 +409,26 @@ pub trait StatementParser: tracing::trace!("parsing expr, {expr:?}"); if let Some(parent) = parent_ctx { let ctx = parent.into().into(); - match self.parse_ctx_expr(expr, ctx) { + match self.parse_ctx_expr(arena, expr, ctx) { Ok(()) => { - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { - tracing::trace!("killing due to bad expr"); - ContextNode::from(parent.into()) - .kill( - analyzer, - loc, - ctx.underlying(analyzer).unwrap().killed.unwrap().1, - ) - .into_expr_err(loc)?; - } - Ok(()) - }); + let res = self.apply_to_edges( + ctx, + *loc, + arena, + &|analyzer, arena, ctx, loc| { + if ctx.killed_or_ret(analyzer).into_expr_err(loc)? { + tracing::trace!("killing due to bad expr"); + ContextNode::from(parent.into()) + .kill( + analyzer, + loc, + ctx.underlying(analyzer).unwrap().killed.unwrap().1, + ) + .into_expr_err(loc)?; + } + Ok(()) + }, + ); let _ = self.widen_if_limit_hit(ctx, res); } e => { @@ -399,9 +440,13 @@ pub trait StatementParser: For(loc, maybe_for_start, maybe_for_middle, maybe_for_end, maybe_for_body) => { tracing::trace!("parsing for loop"); if let Some(parent) = parent_ctx { - let res = - self.apply_to_edges(parent.into().into(), *loc, &|analyzer, ctx, loc| { + let res = self.apply_to_edges( + parent.into().into(), + *loc, + arena, + &|analyzer, arena, ctx, loc| { analyzer.for_loop( + arena, loc, ctx, maybe_for_start, @@ -409,7 +454,8 @@ pub trait StatementParser: maybe_for_end, maybe_for_body, ) - }); + }, + ); let _ = self.widen_if_limit_hit(parent.into().into(), res); } } @@ -419,7 +465,10 @@ pub trait StatementParser: let res = self.apply_to_edges( ContextNode::from(parent.into()), *loc, - &|analyzer, ctx, loc| analyzer.while_loop(loc, ctx, while_expr, while_stmt), + arena, + &|analyzer, arena, ctx, loc| { + analyzer.while_loop(arena, loc, ctx, while_expr, while_stmt) + }, ); let _ = self.widen_if_limit_hit(parent.into().into(), res); } @@ -444,8 +493,12 @@ pub trait StatementParser: .expect("No context for variable definition?") .into(), ); - let res = self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(&YulStatement::Block(yul_block.clone()), ctx); + let res = self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_yul_statement( + arena, + &YulStatement::Block(yul_block.clone()), + ctx, + ); Ok(()) }); let _ = self.widen_if_limit_hit(ctx, res); @@ -454,14 +507,15 @@ pub trait StatementParser: tracing::trace!("parsing return"); if let Some(ret_expr) = maybe_ret_expr { if let Some(parent) = parent_ctx { - let res = self.parse_ctx_expr(ret_expr, parent.into().into()); + let res = self.parse_ctx_expr(arena, ret_expr, parent.into().into()); if self.widen_if_limit_hit(parent.into().into(), res) { return; } let res = self.apply_to_edges( parent.into().into(), *loc, - &|analyzer, ctx, loc| { + arena, + &|analyzer, arena, ctx, loc| { let Ok(Some(ret)) = ctx.pop_expr_latest(loc, analyzer) else { return Err(ExprErr::NoLhs( loc, @@ -483,7 +537,7 @@ pub trait StatementParser: let _ = analyzer.add_if_err(res); return Ok(()); } - analyzer.return_match(ctx, &loc, &paths); + analyzer.return_match(arena, ctx, &loc, &paths, 0); Ok(()) }, ); @@ -495,13 +549,14 @@ pub trait StatementParser: tracing::trace!("parsing revert"); if let Some(parent) = parent_ctx { let parent = ContextNode::from(parent.into()); - let res = self.apply_to_edges(parent, *loc, &|analyzer, ctx, loc| { - let res = ctx - .kill(analyzer, loc, KilledKind::Revert) - .into_expr_err(loc); - let _ = analyzer.add_if_err(res); - Ok(()) - }); + let res = + self.apply_to_edges(parent, *loc, arena, &|analyzer, arena, ctx, loc| { + let res = ctx + .kill(analyzer, loc, KilledKind::Revert) + .into_expr_err(loc); + let _ = analyzer.add_if_err(res); + Ok(()) + }); let _ = self.add_if_err(res); } } diff --git a/crates/solc-expressions/src/env.rs b/crates/solc-expressions/src/env.rs index 5795e670..414e6f12 100644 --- a/crates/solc-expressions/src/env.rs +++ b/crates/solc-expressions/src/env.rs @@ -3,10 +3,11 @@ use crate::{ }; use graph::{ + elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::StorageLocation; +use shared::{RangeArena, StorageLocation}; use solang_parser::pt::{Expression, Identifier, Loc}; @@ -15,6 +16,7 @@ impl Env for T where T: AnalyzerBackend pub trait Env: AnalyzerBackend + Sized { fn env_variable( &mut self, + arena: &mut RangeArena>, ident: &Identifier, ctx: ContextNode, ) -> Result, ExprErr> { @@ -44,7 +46,7 @@ pub trait Env: AnalyzerBackend + Sized { { ctx.add_gas_cost(self, shared::gas::FUNC_CALL_GAS) .into_expr_err(ident.loc)?; - self.resume_from_modifier(ctx, mod_state.clone())?; + self.resume_from_modifier(arena, ctx, mod_state.clone())?; self.modifier_inherit_return(ctx, mod_state.parent_ctx); Ok(Some(())) } else { diff --git a/crates/solc-expressions/src/func_call/func_caller.rs b/crates/solc-expressions/src/func_call/func_caller.rs index 11090938..143b316b 100644 --- a/crates/solc-expressions/src/func_call/func_caller.rs +++ b/crates/solc-expressions/src/func_call/func_caller.rs @@ -10,13 +10,14 @@ use std::cell::RefCell; use std::rc::Rc; use graph::{ + elem::Elem, nodes::{ - Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode, - ModifierState, + Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, ModifierState, }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Loc, NamedArgument}; @@ -66,20 +67,21 @@ impl<'a> NamedOrUnnamedArgs<'a> { pub fn parse( &self, + arena: &mut RangeArena>, analyzer: &mut (impl AnalyzerBackend + Sized), ctx: ContextNode, loc: Loc, ) -> Result<(), ExprErr> { match self { - NamedOrUnnamedArgs::Unnamed(inner) => analyzer.parse_inputs(ctx, loc, inner), + NamedOrUnnamedArgs::Unnamed(inner) => analyzer.parse_inputs(arena, ctx, loc, inner), NamedOrUnnamedArgs::Named(inner) => { let append = Rc::new(RefCell::new(false)); inner.iter().try_for_each(|arg| { - analyzer.parse_input(ctx, loc, &arg.expr, &append)?; + analyzer.parse_input(arena, ctx, loc, &arg.expr, &append)?; Ok(()) })?; if !inner.is_empty() { - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -97,6 +99,7 @@ impl<'a> NamedOrUnnamedArgs<'a> { pub fn parse_n( &self, + arena: &mut RangeArena>, n: usize, analyzer: &mut (impl AnalyzerBackend + Sized), ctx: ContextNode, @@ -106,11 +109,11 @@ impl<'a> NamedOrUnnamedArgs<'a> { match self { NamedOrUnnamedArgs::Unnamed(inner) => { inner.iter().take(n).try_for_each(|arg| { - analyzer.parse_input(ctx, loc, arg, &append)?; + analyzer.parse_input(arena, ctx, loc, arg, &append)?; Ok(()) })?; if !inner.is_empty() { - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -125,11 +128,11 @@ impl<'a> NamedOrUnnamedArgs<'a> { } NamedOrUnnamedArgs::Named(inner) => { inner.iter().take(n).try_for_each(|arg| { - analyzer.parse_input(ctx, loc, &arg.expr, &append)?; + analyzer.parse_input(arena, ctx, loc, &arg.expr, &append)?; Ok(()) })?; if !inner.is_empty() { - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -185,6 +188,7 @@ pub trait FuncCaller: /// Perform a function call with named inputs fn named_fn_call_expr( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, func_expr: &Expression, @@ -193,13 +197,14 @@ pub trait FuncCaller: use solang_parser::pt::Expression::*; match func_expr { MemberAccess(loc, member_expr, ident) => self.call_name_spaced_func( + arena, ctx, loc, member_expr, ident, NamedOrUnnamedArgs::Named(input_exprs), ), - Variable(ident) => self.call_internal_named_func(ctx, loc, ident, input_exprs), + Variable(ident) => self.call_internal_named_func(arena, ctx, loc, ident, input_exprs), e => Err(ExprErr::IntrinsicNamedArgs( *loc, format!("Cannot call intrinsic functions with named arguments. Call: {e:?}"), @@ -210,6 +215,7 @@ pub trait FuncCaller: /// Perform a function call fn fn_call_expr( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, func_expr: &Expression, @@ -218,6 +224,7 @@ pub trait FuncCaller: use solang_parser::pt::Expression::*; match func_expr { MemberAccess(loc, member_expr, ident) => self.call_name_spaced_func( + arena, ctx, loc, member_expr, @@ -225,6 +232,7 @@ pub trait FuncCaller: NamedOrUnnamedArgs::Unnamed(input_exprs), ), Variable(ident) => self.call_internal_func( + arena, ctx, loc, ident, @@ -232,8 +240,8 @@ pub trait FuncCaller: NamedOrUnnamedArgs::Unnamed(input_exprs), ), _ => { - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -245,6 +253,7 @@ pub trait FuncCaller: return Ok(()); } analyzer.match_intrinsic_fallback( + arena, ctx, &loc, &NamedOrUnnamedArgs::Unnamed(input_exprs), @@ -258,6 +267,7 @@ pub trait FuncCaller: /// Perform an intrinsic function call fn match_intrinsic_fallback( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, input_exprs: &NamedOrUnnamedArgs, @@ -265,11 +275,11 @@ pub trait FuncCaller: ) -> Result<(), ExprErr> { match ret { ExprRet::Single(func_idx) | ExprRet::SingleLiteral(func_idx) => { - self.intrinsic_func_call(loc, input_exprs, func_idx, ctx) + self.intrinsic_func_call(arena, loc, input_exprs, func_idx, ctx) } - ExprRet::Multi(inner) => inner - .into_iter() - .try_for_each(|ret| self.match_intrinsic_fallback(ctx, loc, input_exprs, ret)), + ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { + self.match_intrinsic_fallback(arena, ctx, loc, input_exprs, ret) + }), ExprRet::CtxKilled(kind) => ctx.kill(self, *loc, kind).into_expr_err(*loc), ExprRet::Null => Ok(()), } @@ -278,6 +288,7 @@ pub trait FuncCaller: /// Setups up storage variables for a function call and calls it fn setup_fn_call( &mut self, + arena: &mut RangeArena>, loc: &Loc, inputs: &ExprRet, func_idx: NodeIdx, @@ -301,7 +312,7 @@ pub trait FuncCaller: .into_expr_err(*loc)? .func_node(self) { - self.func_call(ctx, *loc, inputs, func_node, func_call_str, None) + self.func_call(arena, ctx, *loc, inputs, func_node, func_call_str, None) } else { unreachable!() } @@ -310,6 +321,7 @@ pub trait FuncCaller: /// Matches the input kinds and performs the call fn func_call( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, input_paths: &ExprRet, @@ -329,8 +341,9 @@ pub trait FuncCaller: // if we get a single var, we expect the func to only take a single // variable let inputs = vec![ContextVarNode::from(input_var).latest_version(self)]; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { analyzer.func_call_inner( + arena, false, ctx, func, @@ -362,8 +375,9 @@ pub trait FuncCaller: Ok(ContextVarNode::from(var).latest_version(self)) }) .collect::, ExprErr>>()?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { analyzer.func_call_inner( + arena, false, ctx, func, @@ -393,6 +407,7 @@ pub trait FuncCaller: #[tracing::instrument(level = "trace", skip_all)] fn func_call_inner( &mut self, + arena: &mut RangeArena>, entry_call: bool, ctx: ContextNode, func_node: FunctionNode, @@ -403,7 +418,7 @@ pub trait FuncCaller: modifier_state: &Option, ) -> Result<(), ExprErr> { if !entry_call { - if let Ok(true) = self.join(ctx, loc, func_node, params, inputs) { + if let Ok(true) = self.join(arena, ctx, loc, func_node, params, inputs, &mut vec![]) { return Ok(()); } } @@ -422,26 +437,56 @@ pub trait FuncCaller: // handle remapping of variable names and bringing variables into the new context let renamed_inputs = - self.map_inputs_to_params(loc, entry_call, params, inputs, callee_ctx)?; + self.map_inputs_to_params(arena, loc, entry_call, params, inputs, callee_ctx)?; // begin modifier handling by making sure modifiers were set if !func_node.modifiers_set(self).into_expr_err(loc)? { - self.set_modifiers(func_node, ctx)?; + self.set_modifiers(arena, func_node, ctx)?; } // get modifiers let mods = func_node.modifiers(self); - self.apply_to_edges(callee_ctx, loc, &|analyzer, callee_ctx, loc| { - if let Some(mod_state) = &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state { - // we are iterating through modifiers - if mod_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = mod_state.clone(); - mstate.num += 1; - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, mstate) + self.apply_to_edges( + callee_ctx, + loc, + arena, + &|analyzer, arena, callee_ctx, loc| { + if let Some(mod_state) = + &ctx.underlying(analyzer).into_expr_err(loc)?.modifier_state + { + // we are iterating through modifiers + if mod_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = mod_state.clone(); + mstate.num += 1; + analyzer.call_modifier_for_fn(arena, loc, callee_ctx, func_node, mstate) + } else { + // out of modifiers, execute the actual function call + analyzer.execute_call_inner( + arena, + loc, + ctx, + callee_ctx, + func_node, + &renamed_inputs, + func_call_str, + ) + } + } else if !mods.is_empty() { + // we have modifiers and havent executed them, start the process of executing them + let state = ModifierState::new( + 0, + loc, + func_node, + callee_ctx, + ctx, + renamed_inputs.clone(), + ); + analyzer.call_modifier_for_fn(arena, loc, callee_ctx, func_node, state) } else { - // out of modifiers, execute the actual function call + // no modifiers, just execute the function analyzer.execute_call_inner( + arena, loc, ctx, callee_ctx, @@ -450,29 +495,15 @@ pub trait FuncCaller: func_call_str, ) } - } else if !mods.is_empty() { - // we have modifiers and havent executed them, start the process of executing them - let state = - ModifierState::new(0, loc, func_node, callee_ctx, ctx, renamed_inputs.clone()); - analyzer.call_modifier_for_fn(loc, callee_ctx, func_node, state) - } else { - // no modifiers, just execute the function - analyzer.execute_call_inner( - loc, - ctx, - callee_ctx, - func_node, - &renamed_inputs, - func_call_str, - ) - } - }) + }, + ) } /// Actually executes the function // #[tracing::instrument(level = "trace", skip_all)] fn execute_call_inner( &mut self, + arena: &mut RangeArena>, loc: Loc, caller_ctx: ContextNode, callee_ctx: ContextNode, @@ -483,23 +514,19 @@ pub trait FuncCaller: tracing::trace!("executing: {}", func_node.name(self).into_expr_err(loc)?); if let Some(body) = func_node.underlying(self).into_expr_err(loc)?.body.clone() { // add return nodes into the subctx - func_node - .returns(self) - .to_vec() - .into_iter() - .for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - callee_ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); - } - }); + #[allow(clippy::unnecessary_to_owned)] + func_node.returns(arena, self).into_iter().for_each(|ret| { + if let Some(var) = + ContextVar::maybe_new_from_func_ret(self, ret.underlying(self).unwrap().clone()) + { + let cvar = self.add_node(Node::ContextVar(var)); + callee_ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, callee_ctx, Edge::Context(ContextEdge::Variable)); + } + }); // parse the function body - self.parse_ctx_statement(&body, false, Some(callee_ctx)); + self.parse_ctx_statement(arena, &body, false, Some(callee_ctx)); if let Some(mod_state) = &callee_ctx .underlying(self) .into_expr_err(loc)? @@ -507,12 +534,12 @@ pub trait FuncCaller: .clone() { if mod_state.num == 0 { - return self.ctx_rets(loc, mod_state.parent_caller_ctx, callee_ctx); + return self.ctx_rets(arena, loc, mod_state.parent_caller_ctx, callee_ctx); } } if callee_ctx != caller_ctx { - self.ctx_rets(loc, caller_ctx, callee_ctx) + self.ctx_rets(arena, loc, caller_ctx, callee_ctx) } else { Ok(()) } @@ -541,10 +568,10 @@ pub trait FuncCaller: .set_child_call(ret_subctx, self) .into_expr_err(loc); let _ = self.add_if_err(res); - self.apply_to_edges(callee_ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(callee_ctx, loc, arena, &|analyzer, arena, ctx, loc| { + #[allow(clippy::unnecessary_to_owned)] func_node - .returns(analyzer) - .to_vec() + .returns(arena, analyzer) .into_iter() .try_for_each(|ret| { let underlying = ret.underlying(analyzer).unwrap(); diff --git a/crates/solc-expressions/src/func_call/helper.rs b/crates/solc-expressions/src/func_call/helper.rs index ffae7ce9..e5d87812 100644 --- a/crates/solc-expressions/src/func_call/helper.rs +++ b/crates/solc-expressions/src/func_call/helper.rs @@ -5,13 +5,14 @@ use crate::{ }; use graph::{ + elem::Elem, nodes::{ - CallFork, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, - FunctionParamNode, ModifierState, + CallFork, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, + FunctionNode, FunctionParamNode, ModifierState, }, AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, }; -use shared::{NodeIdx, StorageLocation}; +use shared::{NodeIdx, RangeArena, StorageLocation}; use solang_parser::pt::{CodeLocation, Expression, Loc}; @@ -24,6 +25,7 @@ pub trait CallerHelper: AnalyzerBackend + /// we map `y -> x` for future lookups fn map_inputs_to_params( &mut self, + arena: &mut RangeArena>, loc: Loc, entry_call: bool, params: &[FunctionParamNode], @@ -67,7 +69,7 @@ pub trait CallerHelper: AnalyzerBackend + if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { if !node.ty_eq_ty(¶m_ty, self).unwrap() { - node.cast_from_ty(param_ty, self).unwrap(); + node.cast_from_ty(param_ty, self, arena).unwrap(); } } @@ -79,7 +81,8 @@ pub trait CallerHelper: AnalyzerBackend + if let Some(_len_var) = input.array_to_len_var(self) { // bring the length variable along as well - self.get_length(callee_ctx, loc, node, false).unwrap(); + self.get_length(arena, callee_ctx, loc, node, false) + .unwrap(); } let node = node.latest_version(self); @@ -92,12 +95,12 @@ pub trait CallerHelper: AnalyzerBackend + r.range_max().into_owned().cast(r2.range_max().into_owned()); let res = node .latest_version(self) - .try_set_range_min(self, new_min) + .try_set_range_min(self, arena, new_min) .into_expr_err(loc); self.add_if_err(res); let res = node .latest_version(self) - .try_set_range_max(self, new_max) + .try_set_range_max(self, arena, new_max) .into_expr_err(loc); self.add_if_err(res); let res = node @@ -123,6 +126,7 @@ pub trait CallerHelper: AnalyzerBackend + /// Parses input expressions into [`ExprRet`]s and adds them to the expr ret stack fn parse_inputs( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, inputs: &[Expression], @@ -135,10 +139,10 @@ pub trait CallerHelper: AnalyzerBackend + inputs .iter() - .try_for_each(|input| self.parse_input(ctx, loc, input, &append))?; + .try_for_each(|input| self.parse_input(arena, ctx, loc, input, &append))?; if !inputs.is_empty() { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -154,13 +158,14 @@ pub trait CallerHelper: AnalyzerBackend + fn parse_input( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, _loc: Loc, input: &Expression, append: &Rc>, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(input, ctx)?; - self.apply_to_edges(ctx, input.loc(), &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, input, ctx)?; + self.apply_to_edges(ctx, input.loc(), arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -227,6 +232,7 @@ pub trait CallerHelper: AnalyzerBackend + /// Disambiguates a function call by their inputs (length & type) fn disambiguate_fn_call( &mut self, + arena: &mut RangeArena>, fn_name: &str, literals: Vec, input_paths: &ExprRet, @@ -236,7 +242,11 @@ pub trait CallerHelper: AnalyzerBackend + // try to find the function based on naive signature // This doesnt do type inference on NumberLiterals (i.e. 100 could be uintX or intX, and there could // be a function that takes an int256 but we evaled as uint256) - let fn_sig = format!("{}{}", fn_name, input_paths.try_as_func_input_str(self)); + let fn_sig = format!( + "{}{}", + fn_name, + input_paths.try_as_func_input_str(self, arena) + ); if let Some(func) = funcs.iter().find(|func| func.name(self).unwrap() == fn_sig) { return Some(*func); } @@ -296,6 +306,7 @@ pub trait CallerHelper: AnalyzerBackend + /// Handle returns for a function call fn ctx_rets( &mut self, + arena: &mut RangeArena>, loc: Loc, caller_ctx: ContextNode, callee_ctx: ContextNode, @@ -330,8 +341,8 @@ pub trait CallerHelper: AnalyzerBackend + match callee_ctx.underlying(self).into_expr_err(loc)?.child { Some(CallFork::Fork(w1, w2)) => { - self.ctx_rets(loc, caller_ctx, w1)?; - self.ctx_rets(loc, caller_ctx, w2)?; + self.ctx_rets(arena, loc, caller_ctx, w1)?; + self.ctx_rets(arena, loc, caller_ctx, w2)?; Ok(()) } Some(CallFork::Call(c)) @@ -339,7 +350,7 @@ pub trait CallerHelper: AnalyzerBackend + >= caller_ctx.underlying(self).into_expr_err(loc)?.depth => { // follow rabbit hole - self.ctx_rets(loc, caller_ctx, c)?; + self.ctx_rets(arena, loc, caller_ctx, c)?; Ok(()) } _ => { @@ -391,8 +402,7 @@ pub trait CallerHelper: AnalyzerBackend + let func_rets = callee_ctx .associated_fn(self) .into_expr_err(loc)? - .returns(self) - .to_vec(); + .returns(arena, self); func_rets .iter() .filter_map(|ret| { @@ -450,14 +460,12 @@ pub trait CallerHelper: AnalyzerBackend + .parent_ctx .associated_fn(self) .into_expr_err(loc)? - .returns(self) - .to_vec() + .returns(arena, self) } else { callee_ctx .associated_fn(self) .into_expr_err(loc)? - .returns(self) - .to_vec() + .returns(arena, self) }; let ret = rets @@ -471,7 +479,7 @@ pub trait CallerHelper: AnalyzerBackend + let tmp_ret = node .as_tmp(callee_ctx.underlying(self).unwrap().loc, ret_subctx, self) .unwrap(); - tmp_ret.cast_from_ty(target_ty, self).unwrap(); + tmp_ret.cast_from_ty(target_ty, self, arena).unwrap(); tmp_ret.underlying_mut(self).into_expr_err(loc)?.is_return = true; tmp_ret .underlying_mut(self) @@ -495,13 +503,14 @@ pub trait CallerHelper: AnalyzerBackend + /// Inherit the input changes from a function call fn inherit_input_changes( &mut self, + arena: &mut RangeArena>, loc: Loc, to_ctx: ContextNode, from_ctx: ContextNode, renamed_inputs: &BTreeMap, ) -> Result<(), ExprErr> { if to_ctx != from_ctx { - self.apply_to_edges(to_ctx, loc, &|analyzer, to_ctx, loc| { + self.apply_to_edges(to_ctx, loc, arena, &|analyzer, arena, to_ctx, loc| { renamed_inputs .iter() .try_for_each(|(input_var, updated_var)| { @@ -515,11 +524,19 @@ pub trait CallerHelper: AnalyzerBackend + latest_updated.range(analyzer).into_expr_err(loc)? { let res = new_input - .set_range_min(analyzer, updated_var_range.range_min().into_owned()) + .set_range_min( + analyzer, + arena, + updated_var_range.range_min().into_owned(), + ) .into_expr_err(loc); let _ = analyzer.add_if_err(res); let res = new_input - .set_range_max(analyzer, updated_var_range.range_max().into_owned()) + .set_range_max( + analyzer, + arena, + updated_var_range.range_max().into_owned(), + ) .into_expr_err(loc); let _ = analyzer.add_if_err(res); let res = new_input @@ -546,55 +563,67 @@ pub trait CallerHelper: AnalyzerBackend + /// Inherit the storage changes from a function call fn inherit_storage_changes( &mut self, + arena: &mut RangeArena>, loc: Loc, inheritor_ctx: ContextNode, grantor_ctx: ContextNode, ) -> Result<(), ExprErr> { if inheritor_ctx != grantor_ctx { - return self.apply_to_edges(inheritor_ctx, loc, &|analyzer, inheritor_ctx, loc| { - let vars = grantor_ctx.local_vars(analyzer).clone(); - vars.iter().try_for_each(|(name, old_var)| { - let var = old_var.latest_version(analyzer); - let underlying = var.underlying(analyzer).into_expr_err(loc)?; - if var.is_storage(analyzer).into_expr_err(loc)? { - if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { - let inheritor_var = inheritor_var.latest_version(analyzer); - if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { - let new_inheritor_var = analyzer - .advance_var_in_ctx( - inheritor_var, - underlying.loc.expect("No loc for val change"), - inheritor_ctx, - ) - .unwrap(); - let _ = new_inheritor_var - .set_range_min(analyzer, r.range_min().into_owned()); - let _ = new_inheritor_var - .set_range_max(analyzer, r.range_max().into_owned()); - let _ = new_inheritor_var - .set_range_exclusions(analyzer, r.exclusions.clone()); + return self.apply_to_edges( + inheritor_ctx, + loc, + arena, + &|analyzer, arena, inheritor_ctx, loc| { + let vars = grantor_ctx.local_vars(analyzer).clone(); + vars.iter().try_for_each(|(name, old_var)| { + let var = old_var.latest_version(analyzer); + let underlying = var.underlying(analyzer).into_expr_err(loc)?; + if var.is_storage(analyzer).into_expr_err(loc)? { + if let Some(inheritor_var) = inheritor_ctx.var_by_name(analyzer, name) { + let inheritor_var = inheritor_var.latest_version(analyzer); + if let Some(r) = underlying.ty.range(analyzer).into_expr_err(loc)? { + let new_inheritor_var = analyzer + .advance_var_in_ctx( + inheritor_var, + underlying.loc.expect("No loc for val change"), + inheritor_ctx, + ) + .unwrap(); + let _ = new_inheritor_var.set_range_min( + analyzer, + arena, + r.range_min().into_owned(), + ); + let _ = new_inheritor_var.set_range_max( + analyzer, + arena, + r.range_max().into_owned(), + ); + let _ = new_inheritor_var + .set_range_exclusions(analyzer, r.exclusions.clone()); + } + } else { + let new_in_inheritor = + analyzer.add_node(Node::ContextVar(underlying.clone())); + inheritor_ctx + .add_var(new_in_inheritor.into(), analyzer) + .into_expr_err(loc)?; + analyzer.add_edge( + new_in_inheritor, + inheritor_ctx, + Edge::Context(ContextEdge::Variable), + ); + analyzer.add_edge( + new_in_inheritor, + var, + Edge::Context(ContextEdge::InheritedVariable), + ); } - } else { - let new_in_inheritor = - analyzer.add_node(Node::ContextVar(underlying.clone())); - inheritor_ctx - .add_var(new_in_inheritor.into(), analyzer) - .into_expr_err(loc)?; - analyzer.add_edge( - new_in_inheritor, - inheritor_ctx, - Edge::Context(ContextEdge::Variable), - ); - analyzer.add_edge( - new_in_inheritor, - var, - Edge::Context(ContextEdge::InheritedVariable), - ); } - } - Ok(()) - }) - }); + Ok(()) + }) + }, + ); } Ok(()) } diff --git a/crates/solc-expressions/src/func_call/internal_call.rs b/crates/solc-expressions/src/func_call/internal_call.rs index 48b58f39..d771fbab 100644 --- a/crates/solc-expressions/src/func_call/internal_call.rs +++ b/crates/solc-expressions/src/func_call/internal_call.rs @@ -7,9 +7,11 @@ use crate::{ }; use graph::{ + elem::Elem, nodes::{Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, VarType, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Identifier, Loc, NamedArgument}; @@ -25,6 +27,7 @@ pub trait InternalFuncCaller: /// Perform a named function call fn call_internal_named_func( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, ident: &Identifier, @@ -127,8 +130,8 @@ pub trait InternalFuncCaller: .iter() .find(|arg| arg.name.name == field.name(self).unwrap()) .expect("No field in struct in struct construction"); - self.parse_ctx_expr(&input.expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input.expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(assignment) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -140,12 +143,12 @@ pub trait InternalFuncCaller: return Ok(()); } - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &assignment)?; + analyzer.match_assign_sides(arena, ctx, loc, &field_as_ret, &assignment)?; let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; Ok(()) }) })?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, _loc| { + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, _loc| { ctx.push_expr(ExprRet::Single(cvar), analyzer) .into_expr_err(*loc)?; Ok(()) @@ -172,13 +175,13 @@ pub trait InternalFuncCaller: input.expr.clone() }) .collect(); - self.parse_inputs(ctx, *loc, &inputs[..])?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_inputs(arena, ctx, *loc, &inputs[..])?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let inputs = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? .unwrap_or_else(|| ExprRet::Multi(vec![])); - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call(arena, &ident.loc, &inputs, func.into(), ctx, None) }) } else { todo!("Disambiguate named function call"); @@ -188,6 +191,7 @@ pub trait InternalFuncCaller: #[tracing::instrument(level = "trace", skip_all)] fn call_internal_func( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, ident: &Identifier, @@ -232,8 +236,8 @@ pub trait InternalFuncCaller: match possible_funcs.len() { 0 => { // this is a builtin, cast, or unknown function - self.parse_ctx_expr(func_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, func_expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let ret = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? @@ -243,13 +247,13 @@ pub trait InternalFuncCaller: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_intrinsic_fallback(ctx, &loc, &input_exprs, ret) + analyzer.match_intrinsic_fallback(arena, ctx, &loc, &input_exprs, ret) }) } 1 => { // there is only a single possible function - input_exprs.parse(self, ctx, *loc)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, *loc)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let mut inputs = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? @@ -267,6 +271,7 @@ pub trait InternalFuncCaller: return Ok(()); } analyzer.setup_fn_call( + arena, &ident.loc, &inputs, (possible_funcs[0]).into(), @@ -277,8 +282,8 @@ pub trait InternalFuncCaller: } _ => { // this is the annoying case due to function overloading & type inference on number literals - input_exprs.parse(self, ctx, *loc)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, *loc)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let inputs = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? @@ -303,18 +308,19 @@ pub trait InternalFuncCaller: }) .collect(); if let Some(func) = analyzer.disambiguate_fn_call( + arena, &ident.name, resizeables, &inputs, &possible_funcs, ) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call(arena, &loc, &inputs, func.into(), ctx, None) } else { Err(ExprErr::FunctionNotFound( loc, format!( "Could not disambiguate function, default input types: {}, possible functions: {:#?}", - inputs.try_as_func_input_str(analyzer), + inputs.try_as_func_input_str(analyzer, arena), possible_funcs .iter() .map(|i| i.name(analyzer).unwrap()) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs index 80eaee23..589b729d 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/abi.rs @@ -2,9 +2,11 @@ use crate::func_caller::NamedOrUnnamedArgs; use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ - nodes::{Builtin, ContextNode, ContextVar, ExprRet}, + elem::Elem, + nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; @@ -15,6 +17,7 @@ pub trait AbiCaller: AnalyzerBackend + Siz /// Perform an `abi.<..>` function call fn abi_call( &mut self, + arena: &mut RangeArena>, func_name: String, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -90,8 +93,8 @@ pub trait AbiCaller: AnalyzerBackend + Siz } } let input_exprs = input_exprs.unnamed_args().unwrap(); - self.parse_ctx_expr(&input_exprs[1], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs[1], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs index 0c883067..5a3286f4 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/array.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/array.rs @@ -8,6 +8,7 @@ use graph::{ nodes::{Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, Node, }; +use shared::RangeArena; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; @@ -19,6 +20,7 @@ pub trait ArrayCaller: AnalyzerBackend + S /// Perform an `array.<..>` function call fn array_call( &mut self, + arena: &mut RangeArena>, func_name: String, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -29,8 +31,8 @@ pub trait ArrayCaller: AnalyzerBackend + S if input_exprs.len() == 1 { // array.push() is valid syntax. It pushes a new // empty element onto the expr ret stack - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -50,12 +52,13 @@ pub trait ArrayCaller: AnalyzerBackend + S // get length let len = analyzer - .get_length(ctx, loc, arr, true)? + .get_length(arena, ctx, loc, arr, true)? .unwrap() .latest_version(analyzer); // get the index access and add it to the stack - let _ = analyzer.index_into_array_raw(ctx, loc, len, arr, false, false)?; + let _ = analyzer + .index_into_array_raw(arena, ctx, loc, len, arr, false, false)?; // create a temporary 1 variable let cnode = @@ -73,12 +76,13 @@ pub trait ArrayCaller: AnalyzerBackend + S // add 1 to the length let tmp_len = - analyzer.op(loc, len, one, ctx, RangeOp::Add(false), false)?; + analyzer.op(arena, loc, len, one, ctx, RangeOp::Add(false), false)?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; analyzer.set_var_as_length( + arena, ctx, loc, tmp_len, @@ -89,8 +93,8 @@ pub trait ArrayCaller: AnalyzerBackend + S }) } else if input_exprs.len() == 2 { // array.push(value) - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -102,8 +106,12 @@ pub trait ArrayCaller: AnalyzerBackend + S ctx.push_expr(array, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr( + arena, + &input_exprs.unnamed_args().unwrap()[1], + ctx, + )?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(new_elem) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -126,13 +134,13 @@ pub trait ArrayCaller: AnalyzerBackend + S // get length let len = analyzer - .get_length(ctx, loc, arr, true)? + .get_length(arena, ctx, loc, arr, true)? .unwrap() .latest_version(analyzer); // get the index access for the *previous* length let index_access = analyzer - .index_into_array_raw(ctx, loc, len, arr, false, true)? + .index_into_array_raw(arena, ctx, loc, len, arr, false, true)? .unwrap(); // create a temporary 1 variable let cnode = @@ -149,14 +157,22 @@ pub trait ArrayCaller: AnalyzerBackend + S let one = ContextVarNode::from(analyzer.add_node(tmp_one)); // add 1 to the length - let tmp_len = - analyzer.op(loc, len, one, ctx, RangeOp::Add(false), false)?; + let tmp_len = analyzer.op( + arena, + loc, + len, + one, + ctx, + RangeOp::Add(false), + false, + )?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; // set the new length analyzer.set_var_as_length( + arena, ctx, loc, tmp_len, @@ -166,14 +182,15 @@ pub trait ArrayCaller: AnalyzerBackend + S // update the index access's range let elem = Elem::from(pushed_value); index_access - .set_range_min(analyzer, elem.clone()) + .set_range_min(analyzer, arena, elem.clone()) .into_expr_err(loc)?; index_access - .set_range_max(analyzer, elem.clone()) + .set_range_max(analyzer, arena, elem.clone()) .into_expr_err(loc)?; // update the array using the index access analyzer.update_array_from_index_access( + arena, ctx, loc, len, @@ -202,8 +219,8 @@ pub trait ArrayCaller: AnalyzerBackend + S ), )); } - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(array) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -222,7 +239,7 @@ pub trait ArrayCaller: AnalyzerBackend + S // get length let len = analyzer - .get_length(ctx, loc, arr, true)? + .get_length(arena, ctx, loc, arr, true)? .unwrap() .latest_version(analyzer); @@ -235,25 +252,33 @@ pub trait ArrayCaller: AnalyzerBackend + S let one = ContextVarNode::from(analyzer.add_node(tmp_one)); // subtract 1 from the length - let tmp_len = analyzer.op(loc, len, one, ctx, RangeOp::Sub(false), false)?; + let tmp_len = + analyzer.op(arena, loc, len, one, ctx, RangeOp::Sub(false), false)?; let tmp_len = ContextVarNode::from(tmp_len.expect_single().unwrap()); tmp_len.underlying_mut(analyzer).unwrap().is_tmp = false; // get the index access let index_access = analyzer - .index_into_array_raw(ctx, loc, tmp_len, arr, false, true)? + .index_into_array_raw(arena, ctx, loc, tmp_len, arr, false, true)? .unwrap(); - analyzer.set_var_as_length(ctx, loc, tmp_len, arr.latest_version(analyzer))?; + analyzer.set_var_as_length( + arena, + ctx, + loc, + tmp_len, + arr.latest_version(analyzer), + )?; index_access - .set_range_min(analyzer, Elem::Null) + .set_range_min(analyzer, arena, Elem::Null) .into_expr_err(loc)?; index_access - .set_range_max(analyzer, Elem::Null) + .set_range_max(analyzer, arena, Elem::Null) .into_expr_err(loc)?; analyzer.update_array_from_index_access( + arena, ctx, loc, tmp_len, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs index 8b2d2951..36755007 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/block.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/block.rs @@ -2,9 +2,11 @@ use crate::func_caller::NamedOrUnnamedArgs; use crate::{ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{Builtin, ContextNode, ContextVar, ExprRet}, + elem::Elem, + nodes::{Builtin, Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, Node, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; @@ -15,6 +17,7 @@ pub trait BlockCaller: AnalyzerBackend + S /// Perform a `block` function call fn block_call( &mut self, + arena: &mut RangeArena>, func_name: String, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -22,8 +25,8 @@ pub trait BlockCaller: AnalyzerBackend + S ) -> Result<(), ExprErr> { match &*func_name { "blockhash" => { - input_exprs.parse_n(1, self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse_n(arena, 1, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs index bcb5b329..88ce7772 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/constructors.rs @@ -6,10 +6,10 @@ use crate::{ use graph::{ elem::*, - nodes::{ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode}, + nodes::{Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, StructNode}, AnalyzerBackend, ContextEdge, Edge, Node, Range, VarType, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Loc}; @@ -25,14 +25,15 @@ pub trait ConstructorCaller: /// Construct an array fn construct_array( &mut self, + arena: &mut RangeArena>, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { // create a new list - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(len_var) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Array creation failed".to_string())); }; @@ -90,18 +91,18 @@ pub trait ConstructorCaller: // update the length if let Some(r) = arr.ref_range(analyzer).into_expr_err(loc)? { - let min = r.evaled_range_min(analyzer).into_expr_err(loc)?; - let max = r.evaled_range_max(analyzer).into_expr_err(loc)?; + let min = r.evaled_range_min(analyzer, arena).into_expr_err(loc)?; + let max = r.evaled_range_max(analyzer, arena).into_expr_err(loc)?; if let Some(mut rd) = min.maybe_range_dyn() { rd.len = Box::new(Elem::from(len_cvar)); - arr.set_range_min(analyzer, Elem::ConcreteDyn(rd)) + arr.set_range_min(analyzer, arena, Elem::ConcreteDyn(rd)) .into_expr_err(loc)?; } if let Some(mut rd) = max.maybe_range_dyn() { rd.len = Box::new(Elem::from(len_cvar)); - arr.set_range_min(analyzer, Elem::ConcreteDyn(rd)) + arr.set_range_min(analyzer, arena, Elem::ConcreteDyn(rd)) .into_expr_err(loc)?; } } @@ -115,6 +116,7 @@ pub trait ConstructorCaller: /// Construct a contract fn construct_contract( &mut self, + arena: &mut RangeArena>, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -122,9 +124,9 @@ pub trait ConstructorCaller: ) -> Result<(), ExprErr> { // construct a new contract if !input_exprs.is_empty() { - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; } - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { if !input_exprs.is_empty() { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Contract creation failed".to_string())); @@ -163,6 +165,7 @@ pub trait ConstructorCaller: /// Construct a struct fn construct_struct( &mut self, + arena: &mut RangeArena>, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -175,8 +178,8 @@ pub trait ConstructorCaller: ctx.add_var(cvar.into(), self).into_expr_err(loc)?; self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -210,7 +213,7 @@ pub trait ConstructorCaller: analyzer.add_edge(fc_node, ctx, Edge::Context(ContextEdge::Variable)); ctx.add_var(fc_node.into(), analyzer).into_expr_err(loc)?; let field_as_ret = ExprRet::Single(fc_node); - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &input)?; + analyzer.match_assign_sides(arena, ctx, loc, &field_as_ret, &input)?; let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; Ok(()) })?; diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs index ee7c4a09..d7f88fac 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/dyn_builtin.rs @@ -4,10 +4,11 @@ use crate::{ }; use graph::{ - elem::RangeElem, + elem::{Elem, RangeElem}, nodes::{Builtin, Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, SolcRange, VarType, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc}; @@ -19,13 +20,14 @@ pub trait DynBuiltinCaller: AnalyzerBackend>, func_name: String, input_exprs: &NamedOrUnnamedArgs, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { - "concat" => self.concat(&loc, input_exprs, ctx), + "concat" => self.concat(arena, &loc, input_exprs, ctx), _ => Err(ExprErr::FunctionNotFound( loc, format!( @@ -40,6 +42,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend>, loc: &Loc, input_exprs: &NamedOrUnnamedArgs, ctx: ContextNode, @@ -47,8 +50,8 @@ pub trait DynBuiltinCaller: AnalyzerBackend 1 { - analyzer.match_concat(ctx, loc, start.clone(), &inputs[1..], false) + analyzer.match_concat(arena, ctx, loc, start.clone(), &inputs[1..], false) } else { - analyzer.match_concat(ctx, loc, start.clone(), &[], false) + analyzer.match_concat(arena, ctx, loc, start.clone(), &[], false) } } }) @@ -84,6 +87,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend>, ctx: ContextNode, loc: Loc, curr: ExprRet, @@ -111,7 +115,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend Ok(()), ExprRet::Multi(inner) => inner .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, true)), + .try_for_each(|i| self.match_concat(arena, ctx, loc, i, inputs, true)), ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), } } else { @@ -139,11 +143,11 @@ pub trait DynBuiltinCaller: AnalyzerBackend, ExprErr>>()?; // create the length variable - let _ = self.tmp_length(acc.latest_version(self), ctx, loc); + let _ = self.tmp_length(arena, acc.latest_version(self), ctx, loc); Ok(()) } @@ -153,7 +157,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend inner .into_iter() - .try_for_each(|i| self.match_concat(ctx, loc, i, inputs, false)), + .try_for_each(|i| self.match_concat(arena, ctx, loc, i, inputs, false)), ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), } } @@ -162,6 +166,7 @@ pub trait DynBuiltinCaller: AnalyzerBackend>, loc: Loc, accum: ContextVarNode, right: ContextVarNode, @@ -229,8 +234,8 @@ pub trait DynBuiltinCaller: AnalyzerBackend Ok(()), diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs index 381a6ac4..c3c21974 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/intrinsic_caller.rs @@ -14,10 +14,11 @@ use graph::nodes::ContextVarNode; use graph::nodes::ContractNode; use graph::{ - nodes::{Builtin, ContextNode, ExprRet}, + elem::Elem, + nodes::{Builtin, Concrete, ContextNode, ExprRet}, AnalyzerBackend, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Loc}; @@ -63,13 +64,14 @@ pub trait IntrinsicFuncCaller: { fn new_call( &mut self, + arena: &mut RangeArena>, loc: &Loc, ty_expr: &Expression, inputs: &[Expression], ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(ty_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, ty_expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(ty) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -82,7 +84,7 @@ pub trait IntrinsicFuncCaller: match analyzer.node(ty_idx) { Node::Builtin(Builtin::Array(_)) | Node::Builtin(Builtin::DynamicBytes) => { // construct a new list - analyzer.construct_array(ty_idx, &NamedOrUnnamedArgs::Unnamed(inputs), loc, ctx) + analyzer.construct_array(arena,ty_idx, &NamedOrUnnamedArgs::Unnamed(inputs), loc, ctx) } Node::Contract(_c) => { let cnode = ContractNode::from(ty_idx); @@ -92,6 +94,7 @@ pub trait IntrinsicFuncCaller: // call the constructor let inputs = ExprRet::Multi(vec![]); analyzer.func_call( + arena, ctx, loc, &inputs, @@ -99,7 +102,7 @@ pub trait IntrinsicFuncCaller: None, None, )?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let var = match ContextVar::maybe_from_user_ty(analyzer, loc, ty_idx) { Some(v) => v, None => { @@ -118,8 +121,8 @@ pub trait IntrinsicFuncCaller: .into_expr_err(loc) }) } else { - analyzer.parse_inputs(ctx, loc, inputs)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_inputs(arena,ctx, loc, inputs)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -130,6 +133,7 @@ pub trait IntrinsicFuncCaller: }; // call the constructor analyzer.func_call( + arena, ctx, loc, &input_paths, @@ -137,7 +141,7 @@ pub trait IntrinsicFuncCaller: None, None, )?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let var = match ContextVar::maybe_from_user_ty(analyzer, loc, ty_idx) { Some(v) => v, None => { @@ -185,6 +189,7 @@ pub trait IntrinsicFuncCaller: #[tracing::instrument(level = "trace", skip_all)] fn intrinsic_func_call( &mut self, + arena: &mut RangeArena>, loc: &Loc, input_exprs: &NamedOrUnnamedArgs, func_idx: NodeIdx, @@ -196,7 +201,7 @@ pub trait IntrinsicFuncCaller: match &*func_name.name { // abi _ if func_name.name.starts_with("abi.") => { - self.abi_call(func_name.name.clone(), input_exprs, *loc, ctx) + self.abi_call(arena, func_name.name.clone(), input_exprs, *loc, ctx) } // address "delegatecall" | "staticcall" | "call" | "code" | "balance" => { @@ -204,20 +209,25 @@ pub trait IntrinsicFuncCaller: } // array "push" | "pop" => { - self.array_call(func_name.name.clone(), input_exprs, *loc, ctx) + self.array_call(arena, func_name.name.clone(), input_exprs, *loc, ctx) } // block "blockhash" => { - self.block_call(func_name.name.clone(), input_exprs, *loc, ctx) + self.block_call(arena, func_name.name.clone(), input_exprs, *loc, ctx) } // dynamic sized builtins - "concat" => { - self.dyn_builtin_call(func_name.name.clone(), input_exprs, *loc, ctx) - } + "concat" => self.dyn_builtin_call( + arena, + func_name.name.clone(), + input_exprs, + *loc, + ctx, + ), // msg "gasleft" => self.msg_call(func_name.name.clone(), input_exprs, *loc, ctx), // precompiles "sha256" | "ripemd160" | "ecrecover" => self.precompile_call( + arena, func_name.name.clone(), func_idx, input_exprs, @@ -225,11 +235,11 @@ pub trait IntrinsicFuncCaller: ctx, ), // solidity - "keccak256" | "addmod" | "mulmod" | "require" | "assert" => { - self.solidity_call(func_name.name.clone(), input_exprs, *loc, ctx) - } + "keccak256" | "addmod" | "mulmod" | "require" | "assert" => self + .solidity_call(arena, func_name.name.clone(), input_exprs, *loc, ctx), // typing "type" | "wrap" | "unwrap" => self.types_call( + arena, func_name.name.clone(), func_idx, input_exprs, @@ -247,19 +257,19 @@ pub trait IntrinsicFuncCaller: } Node::Builtin(Builtin::Array(_)) => { // construct a new array - self.construct_array(func_idx, input_exprs, *loc, ctx) + self.construct_array(arena, func_idx, input_exprs, *loc, ctx) } Node::Contract(_) => { // construct a new contract - self.construct_contract(func_idx, input_exprs, *loc, ctx) + self.construct_contract(arena, func_idx, input_exprs, *loc, ctx) } Node::Struct(_) => { // construct a struct - self.construct_struct(func_idx, input_exprs, *loc, ctx) + self.construct_struct(arena, func_idx, input_exprs, *loc, ctx) } Node::Builtin(ty) => { // cast to type - self.cast(ty.clone(), func_idx, input_exprs, *loc, ctx) + self.cast(arena, ty.clone(), func_idx, input_exprs, *loc, ctx) } Node::ContextVar(_c) => { // its a user type, just push it onto the stack @@ -269,9 +279,9 @@ pub trait IntrinsicFuncCaller: } Node::Unresolved(_) => { // Try to give a nice error - input_exprs.parse(self, ctx, *loc)?; + input_exprs.parse(arena, self, ctx, *loc)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Function call failed".to_string())) }; @@ -291,7 +301,7 @@ pub trait IntrinsicFuncCaller: format!( "Could not find function: \"{}{}\", context: {}, visible functions: {:#?}", ident.name, - inputs.try_as_func_input_str(analyzer), + inputs.try_as_func_input_str(analyzer, arena), ctx.path(analyzer), visible_funcs ) diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs index 20dbd601..7dcd2249 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/precompile.rs @@ -5,10 +5,11 @@ use crate::{ use graph::nodes::FunctionNode; use graph::{ - nodes::{Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + elem::Elem, + nodes::{Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Loc}; @@ -24,6 +25,7 @@ pub trait PrecompileCaller: /// Perform a precompile's function call, like `ecrecover` fn precompile_call( &mut self, + arena: &mut RangeArena>, func_name: String, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, @@ -32,8 +34,8 @@ pub trait PrecompileCaller: ) -> Result<(), ExprErr> { match &*func_name { "sha256" => { - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -57,8 +59,8 @@ pub trait PrecompileCaller: }) } "ripemd160" => { - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -82,8 +84,8 @@ pub trait PrecompileCaller: }) } "ecrecover" => { - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let cctx = Context::new_subctx( ctx, None, diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs index e024f557..056e3ca0 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/solidity.rs @@ -5,9 +5,11 @@ use crate::{ }; use graph::{ + elem::Elem, nodes::{Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, Node, }; +use shared::RangeArena; use ethers_core::types::H256; use solang_parser::pt::{Expression, Loc}; @@ -24,6 +26,7 @@ pub trait SolidityCaller: /// Perform a solidity intrinsic function call, like `keccak256` fn solidity_call( &mut self, + arena: &mut RangeArena>, func_name: String, input_exprs: &NamedOrUnnamedArgs, loc: Loc, @@ -31,8 +34,8 @@ pub trait SolidityCaller: ) -> Result<(), ExprErr> { match &*func_name { "keccak256" => { - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "No input into keccak256".to_string())); }; @@ -43,12 +46,12 @@ pub trait SolidityCaller: return Err(ExprErr::NoRhs(loc, "No input into keccak256".to_string())); }; - if cvar.is_const(analyzer).into_expr_err(loc)? { + if cvar.is_const(analyzer, arena).into_expr_err(loc)? { let bytes = cvar - .evaled_range_min(analyzer) + .evaled_range_min(analyzer, arena) .unwrap() .unwrap() - .as_bytes(analyzer, true) + .as_bytes(analyzer, true, arena) .unwrap(); let mut out = [0; 32]; keccak_hash::keccak_256(&bytes, &mut out); @@ -77,9 +80,9 @@ pub trait SolidityCaller: } "addmod" => { // TODO: actually calcuate this if possible - input_exprs.parse(self, ctx, loc)?; + input_exprs.parse(arena, self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; let var = ContextVar::new_from_builtin( loc, @@ -95,8 +98,8 @@ pub trait SolidityCaller: } "mulmod" => { // TODO: actually calcuate this if possible - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; let var = ContextVar::new_from_builtin( loc, @@ -110,9 +113,11 @@ pub trait SolidityCaller: Ok(()) }) } - "require" | "assert" => self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.handle_require(input_exprs.unnamed_args().unwrap(), ctx) - }), + "require" | "assert" => { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.handle_require(arena, input_exprs.unnamed_args().unwrap(), ctx) + }) + } _ => Err(ExprErr::FunctionNotFound( loc, format!( diff --git a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs index 73950491..fbc84e29 100644 --- a/crates/solc-expressions/src/func_call/intrinsic_call/types.rs +++ b/crates/solc-expressions/src/func_call/intrinsic_call/types.rs @@ -5,10 +5,12 @@ use graph::nodes::FunctionNode; use graph::{ elem::*, - nodes::{BuiltInNode, Builtin, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode}, - AnalyzerBackend, Node, Range, VarType, + nodes::{ + BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, TyNode, + }, + AnalyzerBackend, Node, VarType, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Loc}; @@ -19,6 +21,7 @@ pub trait TypesCaller: AnalyzerBackend + S /// Perform a type-based intrinsic function call, like `wrap` fn types_call( &mut self, + arena: &mut RangeArena>, func_name: String, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, @@ -26,14 +29,14 @@ pub trait TypesCaller: AnalyzerBackend + S ctx: ContextNode, ) -> Result<(), ExprErr> { match &*func_name { - "type" => self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx), + "type" => self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx), "wrap" => { if input_exprs.len() != 2 { return Err(ExprErr::InvalidFunctionInput(loc, format!("Expected a member type and an input to the wrap function, but got: {:?}", input_exprs))); } - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -63,16 +66,17 @@ pub trait TypesCaller: AnalyzerBackend + S RangeOp::Cast, Elem::from(cvar), )); - next.set_range_min(analyzer, expr.clone()) + next.set_range_min(analyzer, arena, expr.clone()) + .into_expr_err(loc)?; + next.set_range_max(analyzer, arena, expr) .into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) .into_expr_err(loc) }) } "unwrap" => { - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(input) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -114,9 +118,9 @@ pub trait TypesCaller: AnalyzerBackend + S ); let cvar = ContextVarNode::from(analyzer.add_node(Node::ContextVar(var))); - cvar.set_range_min(analyzer, Elem::from(to_be_unwrapped)) + cvar.set_range_min(analyzer, arena, Elem::from(to_be_unwrapped)) .into_expr_err(loc)?; - cvar.set_range_max(analyzer, Elem::from(to_be_unwrapped)) + cvar.set_range_max(analyzer, arena, Elem::from(to_be_unwrapped)) .into_expr_err(loc)?; let next = analyzer.advance_var_in_ctx(cvar, loc, ctx)?; let expr = Elem::Expr(RangeExpr::new( @@ -124,9 +128,10 @@ pub trait TypesCaller: AnalyzerBackend + S RangeOp::Cast, Elem::from(cvar), )); - next.set_range_min(analyzer, expr.clone()) + next.set_range_min(analyzer, arena, expr.clone()) + .into_expr_err(loc)?; + next.set_range_max(analyzer, arena, expr) .into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(cvar.into()), analyzer) .into_expr_err(loc) }) @@ -144,6 +149,7 @@ pub trait TypesCaller: AnalyzerBackend + S /// Perform a cast of a type fn cast( &mut self, + arena: &mut RangeArena>, ty: Builtin, func_idx: NodeIdx, input_exprs: &NamedOrUnnamedArgs, @@ -155,6 +161,7 @@ pub trait TypesCaller: AnalyzerBackend + S ctx: ContextNode, loc: Loc, analyzer: &mut impl ListAccess, + arena: &mut RangeArena>, ty: &Builtin, ret: ExprRet, func_idx: NodeIdx, @@ -169,24 +176,26 @@ pub trait TypesCaller: AnalyzerBackend + S .into_expr_err(loc)?; let v_ty = VarType::try_from_idx(analyzer, func_idx).expect(""); - let maybe_new_range = cvar.cast_exprs(&v_ty, analyzer).into_expr_err(loc)?; + let maybe_new_range = + cvar.cast_exprs(&v_ty, analyzer, arena).into_expr_err(loc)?; new_var.underlying_mut(analyzer).into_expr_err(loc)?.ty = v_ty; if let Some((new_min, new_max)) = maybe_new_range { new_var - .set_range_min(analyzer, new_min) + .set_range_min(analyzer, arena, new_min) .into_expr_err(loc)?; new_var - .set_range_max(analyzer, new_max) + .set_range_max(analyzer, arena, new_max) .into_expr_err(loc)?; } if cvar.is_indexable(analyzer).into_expr_err(loc)? { // input is indexable. get the length attribute, create a new length for the casted type let _ = analyzer.create_length( + arena, ctx, loc, - cvar, + new_var, new_var.latest_version(analyzer), false, )?; @@ -198,12 +207,12 @@ pub trait TypesCaller: AnalyzerBackend + S } ExprRet::Multi(inner) => inner .into_iter() - .try_for_each(|i| cast_match(ctx, loc, analyzer, ty, i, func_idx)), + .try_for_each(|i| cast_match(ctx, loc, analyzer, arena, ty, i, func_idx)), } } - self.parse_ctx_expr(&input_exprs.unnamed_args().unwrap()[0], ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input_exprs.unnamed_args().unwrap()[0], ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Cast had no target type".to_string())); }; @@ -213,7 +222,7 @@ pub trait TypesCaller: AnalyzerBackend + S return Ok(()); } - cast_match(ctx, loc, analyzer, &ty, ret, func_idx) + cast_match(ctx, loc, analyzer, arena, &ty, ret, func_idx) }) } } diff --git a/crates/solc-expressions/src/func_call/join.rs b/crates/solc-expressions/src/func_call/join.rs index 3724f8b2..0aba321d 100644 --- a/crates/solc-expressions/src/func_call/join.rs +++ b/crates/solc-expressions/src/func_call/join.rs @@ -1,20 +1,17 @@ +use crate::context_builder::StatementParser; use crate::member_access::ListAccess; +use crate::variable::Variable; use crate::{helper::CallerHelper, ExprErr, IntoExprErr}; -use graph::elem::Elem; -use graph::elem::RangeElem; -use graph::nodes::Concrete; -use graph::nodes::ContextVar; -use graph::Range; -use graph::SolcRange; -use graph::VarType; -use shared::AnalyzerLike; -use shared::NodeIdx; -use shared::StorageLocation; use graph::{ - nodes::{ContextNode, ContextVarNode, ExprRet, FunctionNode, FunctionParamNode}, - AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, + elem::{Elem, RangeElem, RangeExpr, RangeOp}, + nodes::{ + Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, FunctionNode, + FunctionParamNode, KilledKind, + }, + AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, Range, SolcRange, VarType, }; +use shared::{AnalyzerLike, NodeIdx, RangeArena, StorageLocation}; use solang_parser::pt::{Expression, Loc}; @@ -35,11 +32,13 @@ pub trait FuncJoiner: #[tracing::instrument(level = "trace", skip_all)] fn join( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, func: FunctionNode, params: &[FunctionParamNode], func_inputs: &[ContextVarNode], + seen: &mut Vec, ) -> Result { tracing::trace!( "Trying to join function: {}", @@ -62,327 +61,92 @@ pub trait FuncJoiner: .child .is_some() { + tracing::trace!("Joining function: {}", func.name(self).into_expr_err(loc)?); let edges = body_ctx.successful_edges(self).into_expr_err(loc)?; - if edges.len() == 1 { - tracing::trace!( - "Joining function: {}", - func.name(self).into_expr_err(loc)? - ); - let replacement_map = - self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; - let mut rets: Vec<_> = edges[0] - .return_nodes(self) - .into_expr_err(loc)? - .iter() - .enumerate() - .map(|(i, (_, ret_node))| { - let mut new_var = ret_node.underlying(self).unwrap().clone(); - let new_name = format!("{}.{i}", func.name(self).unwrap()); - new_var.name.clone_from(&new_name); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = - range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); - - range.cache_eval(self).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { - *d = *r - } - }); - } - - let new_cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - - // handle the case where the return node is a struct - if let Ok(fields) = ret_node.struct_to_fields(self) { - if !fields.is_empty() { - fields.iter().for_each(|field| { - let mut new_var = - field.underlying(self).unwrap().clone(); - let new_name = format!( - "{}.{i}.{}", - func.name(self).unwrap(), - field.name(self).unwrap() - ); - new_var.name.clone_from(&new_name); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = range - .take_flattened_range(self) - .unwrap() - .into(); - replacement_map.iter().for_each( - |(replace, replacement)| { - range.replace_dep( - *replace, - replacement.0.clone(), - self, - ); - }, - ); - - range.cache_eval(self).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = - replacement_map.get(&(*d).into()) - { - *d = *r - } - }); - } - let new_field = ContextVarNode::from( - self.add_node(Node::ContextVar(new_var)), - ); - self.add_edge( - new_field, - new_cvar, - Edge::Context(ContextEdge::AttrAccess("field")), - ); - }); + match edges.len() { + 0 => {} + 1 => { + self.join_pure( + arena, + loc, + func, + params, + func_inputs, + body_ctx, + edges[0], + ctx, + false, + )?; + return Ok(true); + } + 2.. => { + tracing::trace!( + "Branching pure join function: {}", + func.name(self).into_expr_err(loc)? + ); + // self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { + let new_forks = ctx.set_join_forks(loc, edges.clone(), self).unwrap(); + edges.into_iter().zip(new_forks.iter()).try_for_each( + |(edge, new_fork)| { + let res = self.join_pure( + arena, + loc, + func, + params, + func_inputs, + body_ctx, + edge, + *new_fork, + true, + )?; + if !res { + new_fork + .kill(self, loc, KilledKind::Unreachable) + .into_expr_err(loc)?; + Ok(()) + } else { + Ok(()) } - } - - self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(new_cvar, self).unwrap(); - ExprRet::Single(new_cvar.into()) - }) - .collect(); - body_ctx - .ctx_deps(self) - .into_expr_err(loc)? - .iter() - .try_for_each(|dep| { - let mut new_var = dep.underlying(self)?.clone(); - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = - range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); - - range.cache_eval(self)?; - new_var.ty.set_range(range)?; - } - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { - *d = *r - } - }); - } - let new_cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(new_cvar, self)?; - ctx.add_ctx_dep(new_cvar, self) - }) - .into_expr_err(loc)?; - - func.returns(self).to_vec().into_iter().for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - rets.push(ExprRet::Single(cvar)); - } - }); - - ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( - "{}.{}.resume{{ {} }}", - ctx.path(self), - edges[0].path(self), - ctx.associated_fn_name(self).unwrap() - ); - ctx.push_expr(ExprRet::Multi(rets), self) - .into_expr_err(loc)?; - self.add_completed_pure(true, false, false, edges[0]); - } else { - tracing::trace!( - "Branching pure join function: {}", - func.name(self).into_expr_err(loc)? - ); - self.add_completed_pure(false, false, true, body_ctx); + }, + )?; + return Ok(true); + } } } else { tracing::trace!( "Childless pure join: {}", func.name(self).into_expr_err(loc)? ); - let replacement_map = - self.basic_inputs_replacement_map(body_ctx, loc, params, func_inputs)?; - // 1. Create a new variable with name `.` - // 2. Set the range to be the copy of the return's simplified range from the function - // 3. Replace the fundamentals with the input data - let mut rets: Vec<_> = body_ctx - .return_nodes(self) - .into_expr_err(loc)? - .iter() - .enumerate() - .map(|(i, (_, ret_node))| { - let mut new_var = ret_node.underlying(self).unwrap().clone(); - let new_name = format!("{}.{i}", func.name(self).unwrap()); - new_var.name.clone_from(&new_name); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = - range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); - - range.cache_eval(self).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { - *d = *r - } - }); - } - - let new_cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(new_cvar, self).unwrap(); - - // handle the case where the return node is a struct - if let Ok(fields) = ret_node.struct_to_fields(self) { - if !fields.is_empty() { - fields.iter().for_each(|field| { - let mut new_var = field.underlying(self).unwrap().clone(); - let new_name = format!( - "{}.{i}.{}", - func.name(self).unwrap(), - field.name(self).unwrap() - ); - new_var.name.clone_from(&new_name); - new_var.display_name = new_name; - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = - range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each( - |(replace, replacement)| { - range.replace_dep( - *replace, - replacement.0.clone(), - self, - ); - }, - ); - - range.cache_eval(self).unwrap(); - - new_var.ty.set_range(range).unwrap(); - } - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = - replacement_map.get(&(*d).into()) - { - *d = *r - } - }); - } - let new_field = ContextVarNode::from( - self.add_node(Node::ContextVar(new_var)), - ); - self.add_edge( - new_field, - new_cvar, - Edge::Context(ContextEdge::AttrAccess("field")), - ); - }); - } - } - - ExprRet::Single(new_cvar.into()) - }) - .collect(); - - // println!("requires:"); - body_ctx - .ctx_deps(self) - .into_expr_err(loc)? - .iter() - .try_for_each(|dep| { - let mut new_var = dep.underlying(self)?.clone(); - if let Some(mut range) = new_var.ty.take_range() { - let mut range: SolcRange = - range.take_flattened_range(self).unwrap().into(); - replacement_map.iter().for_each(|(replace, replacement)| { - range.replace_dep(*replace, replacement.0.clone(), self); - }); - - range.cache_eval(self)?; - new_var.ty.set_range(range)?; - } - - // TODO: the naming isn't correct here and we move variables around - // in a dumb way - - if let Some(ref mut dep_on) = &mut new_var.dep_on { - dep_on.iter_mut().for_each(|d| { - if let Some((_, r)) = replacement_map.get(&(*d).into()) { - *d = *r - } - }); - } - - let new_cvar = - ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); - - self.add_edge(new_cvar, ctx, Edge::Context(ContextEdge::Variable)); - ctx.add_var(new_cvar, self)?; - ctx.add_ctx_dep(new_cvar, self) - }) - .into_expr_err(loc)?; + self.join_pure( + arena, + loc, + func, + params, + func_inputs, + body_ctx, + body_ctx, + ctx, + false, + )?; + return Ok(true); + } + } else { + tracing::trace!("Pure function not processed"); + if ctx.associated_fn(self) == Ok(func) { + return Ok(false); + } - func.returns(self).to_vec().into_iter().for_each(|ret| { - if let Some(var) = ContextVar::maybe_new_from_func_ret( - self, - ret.underlying(self).unwrap().clone(), - ) { - let cvar = self.add_node(Node::ContextVar(var)); - ctx.add_var(cvar.into(), self).unwrap(); - self.add_edge(cvar, ctx, Edge::Context(ContextEdge::Variable)); - rets.push(ExprRet::Single(cvar)); - } - }); + if seen.contains(&func) { + return Ok(false); + } - ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( - "{}.{}.resume{{ {} }}", - ctx.path(self), - func.name(self).unwrap(), - ctx.associated_fn_name(self).unwrap() - ); - ctx.push_expr(ExprRet::Multi(rets), self) - .into_expr_err(loc)?; - self.add_completed_pure(true, true, false, body_ctx); - return Ok(true); + self.handled_funcs_mut().push(func); + if let Some(body) = &func.underlying(self).unwrap().body.clone() { + self.parse_ctx_statement(arena, body, false, Some(func)); } + + seen.push(func); + return self.join(arena, ctx, loc, func, params, func_inputs, seen); } } else if func.is_view(self).into_expr_err(loc)? { if let Some(body_ctx) = func.maybe_body_ctx(self) { @@ -413,6 +177,8 @@ pub trait FuncJoiner: ); self.add_completed_view(false, true, false, body_ctx); } + } else { + tracing::trace!("View function not processed"); } } else if let Some(body_ctx) = func.maybe_body_ctx(self) { if body_ctx @@ -439,13 +205,196 @@ pub trait FuncJoiner: ); self.add_completed_mut(false, true, false, body_ctx); } + } else { + tracing::trace!("Mut function not processed"); } Ok(false) } + fn join_pure( + &mut self, + arena: &mut RangeArena>, + loc: Loc, + func: FunctionNode, + params: &[FunctionParamNode], + func_inputs: &[ContextVarNode], + body_ctx: ContextNode, + resulting_edge: ContextNode, + target_ctx: ContextNode, + forks: bool, + ) -> Result { + let replacement_map = + self.basic_inputs_replacement_map(arena, body_ctx, loc, params, func_inputs)?; + let mut rets: Vec<_> = resulting_edge + .return_nodes(self) + .into_expr_err(loc)? + .iter() + .enumerate() + .map(|(i, (_, ret_node))| { + let mut new_var = ret_node.underlying(self).unwrap().clone(); + let new_name = format!("{}.{i}", func.name(self).unwrap()); + new_var.name.clone_from(&new_name); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + let mut range: SolcRange = + range.take_flattened_range(self, arena).unwrap().into(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.0.clone(), self, arena); + }); + + range.cache_eval(self, arena).unwrap(); + // TODO: change ty here to match ret type + new_var.ty.set_range(range).unwrap(); + } + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } + }); + } + + let mut new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge(new_cvar, target_ctx, Edge::Context(ContextEdge::Variable)); + target_ctx.add_var(new_cvar, self).unwrap(); + + // handle the case where the return node is a struct + if let Ok(fields) = ret_node.struct_to_fields(self) { + if !fields.is_empty() { + fields.iter().for_each(|field| { + let mut new_var = field.underlying(self).unwrap().clone(); + let new_name = format!( + "{}.{i}.{}", + func.name(self).unwrap(), + field.name(self).unwrap() + ); + new_var.name.clone_from(&new_name); + new_var.display_name = new_name; + if let Some(mut range) = new_var.ty.take_range() { + let mut range: SolcRange = + range.take_flattened_range(self, arena).unwrap().into(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.0.clone(), self, arena); + }); + + range.cache_eval(self, arena).unwrap(); + + new_var.ty.set_range(range).unwrap(); + } + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } + }); + } + let new_field = + ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + self.add_edge( + new_field, + new_cvar, + Edge::Context(ContextEdge::AttrAccess("field")), + ); + }); + } + } else { + let next_cvar = self + .advance_var_in_ctx_forcible(new_cvar, loc, target_ctx, true) + .unwrap(); + let casted = Elem::Expr(RangeExpr::new( + Elem::from(new_cvar), + RangeOp::Cast, + Elem::from(*ret_node), + )); + next_cvar + .set_range_min(self, arena, casted.clone()) + .unwrap(); + next_cvar.set_range_max(self, arena, casted).unwrap(); + + new_cvar = next_cvar; + } + + ExprRet::Single(new_cvar.latest_version(self).into()) + }) + .collect(); + + let mut unsat = false; + + resulting_edge + .ctx_deps(self) + .into_expr_err(loc)? + .iter() + .try_for_each(|dep| { + let mut new_var = dep.underlying(self)?.clone(); + if let Some(mut range) = new_var.ty.take_range() { + // let mut range: SolcRange = + // range.take_flattened_range(self).unwrap().into(); + let mut range: SolcRange = + range.flattened_range(self, arena)?.into_owned().into(); + replacement_map.iter().for_each(|(replace, replacement)| { + range.replace_dep(*replace, replacement.0.clone(), self, arena); + }); + + range.cache_eval(self, arena)?; + new_var.ty.set_range(range)?; + } + + if let Some(ref mut dep_on) = &mut new_var.dep_on { + dep_on.iter_mut().for_each(|d| { + if let Some((_, r)) = replacement_map.get(&(*d).into()) { + *d = *r + } + }); + } + let new_cvar = ContextVarNode::from(self.add_node(Node::ContextVar(new_var))); + + if new_cvar.is_const(self, arena)? + && new_cvar.evaled_range_min(self, arena)? + == Some(Elem::from(Concrete::from(false))) + { + unsat = true; + } + self.add_edge(new_cvar, target_ctx, Edge::Context(ContextEdge::Variable)); + target_ctx.add_var(new_cvar, self)?; + target_ctx.add_ctx_dep(new_cvar, self, arena) + }) + .into_expr_err(loc)?; + + if unsat { + return Ok(false); + } + + #[allow(clippy::unnecessary_to_owned)] + func.returns(arena, self).into_iter().for_each(|ret| { + if let Some(var) = + ContextVar::maybe_new_from_func_ret(self, ret.underlying(self).unwrap().clone()) + { + let cvar = self.add_node(Node::ContextVar(var)); + target_ctx.add_var(cvar.into(), self).unwrap(); + self.add_edge(cvar, target_ctx, Edge::Context(ContextEdge::Variable)); + rets.push(ExprRet::Single(cvar)); + } + }); + + target_ctx.underlying_mut(self).into_expr_err(loc)?.path = format!( + "{}.{}.resume{{ {} }}", + target_ctx.path(self), + resulting_edge.path(self), + target_ctx.associated_fn_name(self).unwrap() + ); + target_ctx + .push_expr(ExprRet::Multi(rets), self) + .into_expr_err(loc)?; + self.add_completed_pure(true, false, forks, resulting_edge); + Ok(true) + } + fn basic_inputs_replacement_map( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, params: &[FunctionParamNode], @@ -488,14 +437,15 @@ pub trait FuncJoiner: if let Some(param_ty) = VarType::try_from_idx(self, param.ty(self).unwrap()) { if !replacement.ty_eq_ty(¶m_ty, self).into_expr_err(loc)? { replacement - .cast_from_ty(param_ty, self) + .cast_from_ty(param_ty, self, arena) .into_expr_err(loc)?; } } if let Some(_len_var) = replacement.array_to_len_var(self) { // bring the length variable along as well - self.get_length(ctx, loc, *func_input, false).unwrap(); + self.get_length(arena, ctx, loc, *func_input, false) + .unwrap(); } if let (Some(r), Some(r2)) = @@ -505,11 +455,11 @@ pub trait FuncJoiner: let new_max = r.range_max().into_owned().cast(r2.range_max().into_owned()); replacement .latest_version(self) - .try_set_range_min(self, new_min) + .try_set_range_min(self, arena, new_min) .into_expr_err(loc)?; replacement .latest_version(self) - .try_set_range_max(self, new_max) + .try_set_range_max(self, arena, new_max) .into_expr_err(loc)?; replacement .latest_version(self) @@ -547,7 +497,7 @@ pub trait FuncJoiner: { let mut replacement_field_as_elem = Elem::from(*replacement_field); - replacement_field_as_elem.arenaize(self).unwrap(); + replacement_field_as_elem.arenaize(self, arena).unwrap(); if let Some(next) = field.next_version(self) { replacement_map.insert( next.0.into(), @@ -564,7 +514,9 @@ pub trait FuncJoiner: } let mut replacement_as_elem = Elem::from(replacement); - replacement_as_elem.arenaize(self).into_expr_err(loc)?; + replacement_as_elem + .arenaize(self, arena) + .into_expr_err(loc)?; if let Some(next) = correct_input.next_version(self) { replacement_map diff --git a/crates/solc-expressions/src/func_call/modifier.rs b/crates/solc-expressions/src/func_call/modifier.rs index f0bd2b86..3b355863 100644 --- a/crates/solc-expressions/src/func_call/modifier.rs +++ b/crates/solc-expressions/src/func_call/modifier.rs @@ -6,9 +6,11 @@ use crate::{ }; use graph::{ - nodes::{Context, ContextNode, ExprRet, FunctionNode, ModifierState}, + elem::Elem, + nodes::{Concrete, Context, ContextNode, ExprRet, FunctionNode, ModifierState}, AnalyzerBackend, Edge, GraphBackend, Node, }; +use shared::RangeArena; use solang_parser::pt::{CodeLocation, Expression, Loc}; @@ -32,6 +34,7 @@ pub trait ModifierCaller: #[tracing::instrument(level = "trace", skip_all)] fn call_modifier_for_fn( &mut self, + arena: &mut RangeArena>, loc: Loc, func_ctx: ContextNode, func_node: FunctionNode, @@ -50,8 +53,8 @@ pub trait ModifierCaller: input_exprs .iter() - .try_for_each(|expr| self.parse_ctx_expr(expr, func_ctx))?; - self.apply_to_edges(func_ctx, loc, &|analyzer, ctx, loc| { + .try_for_each(|expr| self.parse_ctx_expr(arena, expr, func_ctx))?; + self.apply_to_edges(func_ctx, loc, arena, &|analyzer, arena, ctx, loc| { let input_paths = if input_exprs.is_empty() { ExprRet::Multi(vec![]) } else { @@ -71,6 +74,7 @@ pub trait ModifierCaller: }; analyzer.func_call( + arena, ctx, loc, &input_paths, @@ -85,6 +89,7 @@ pub trait ModifierCaller: #[tracing::instrument(level = "trace", skip_all)] fn resume_from_modifier( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, modifier_state: ModifierState, ) -> Result<(), ExprErr> { @@ -95,88 +100,98 @@ pub trait ModifierCaller: ); let mods = modifier_state.parent_fn.modifiers(self); - self.apply_to_edges(ctx, modifier_state.loc, &|analyzer, ctx, loc| { - if modifier_state.num + 1 < mods.len() { - // use the next modifier - let mut mstate = modifier_state.clone(); - mstate.num += 1; + self.apply_to_edges( + ctx, + modifier_state.loc, + arena, + &|analyzer, arena, ctx, loc| { + if modifier_state.num + 1 < mods.len() { + // use the next modifier + let mut mstate = modifier_state.clone(); + mstate.num += 1; - let loc = mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc; - - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - loc, - None, - None, - false, - analyzer, - Some(modifier_state.clone()), - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); + let loc = mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc; - new_parent_subctx - .set_continuation_ctx( + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + loc, + None, + None, + false, analyzer, - modifier_state.parent_ctx, - "resume_from_modifier_nonfinal", + Some(modifier_state.clone()), ) - .into_expr_err(loc)?; - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; + .unwrap(); + let new_parent_subctx = + ContextNode::from(analyzer.add_node(Node::Context(pctx))); - analyzer.call_modifier_for_fn( - mods[mstate.num] - .underlying(analyzer) - .into_expr_err(mstate.loc)? - .loc, - new_parent_subctx, - mstate.parent_fn, - mstate, - )?; - Ok(()) - } else { - let pctx = Context::new_subctx( - ctx, - Some(modifier_state.parent_ctx), - modifier_state.loc, - None, - None, - false, - analyzer, - None, - ) - .unwrap(); - let new_parent_subctx = ContextNode::from(analyzer.add_node(Node::Context(pctx))); - new_parent_subctx - .set_continuation_ctx( + new_parent_subctx + .set_continuation_ctx( + analyzer, + modifier_state.parent_ctx, + "resume_from_modifier_nonfinal", + ) + .into_expr_err(loc)?; + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; + + analyzer.call_modifier_for_fn( + arena, + mods[mstate.num] + .underlying(analyzer) + .into_expr_err(mstate.loc)? + .loc, + new_parent_subctx, + mstate.parent_fn, + mstate, + )?; + Ok(()) + } else { + let pctx = Context::new_subctx( + ctx, + Some(modifier_state.parent_ctx), + modifier_state.loc, + None, + None, + false, analyzer, - modifier_state.parent_ctx, - "resume_from_modifier_final", + None, ) - .into_expr_err(loc)?; - ctx.set_child_call(new_parent_subctx, analyzer) - .into_expr_err(modifier_state.loc)?; + .unwrap(); + let new_parent_subctx = + ContextNode::from(analyzer.add_node(Node::Context(pctx))); + new_parent_subctx + .set_continuation_ctx( + analyzer, + modifier_state.parent_ctx, + "resume_from_modifier_final", + ) + .into_expr_err(loc)?; + ctx.set_child_call(new_parent_subctx, analyzer) + .into_expr_err(modifier_state.loc)?; - // actually execute the parent function - analyzer.execute_call_inner( - modifier_state.loc, - ctx, - new_parent_subctx, - modifier_state.parent_fn, - &modifier_state.renamed_inputs, - None, - ) - } - }) + // actually execute the parent function + analyzer.execute_call_inner( + arena, + modifier_state.loc, + ctx, + new_parent_subctx, + modifier_state.parent_fn, + &modifier_state.renamed_inputs, + None, + ) + } + }, + ) } fn modifiers( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, func: FunctionNode, ) -> Result, ExprErr> { @@ -210,15 +225,19 @@ pub trait ModifierCaller: let callee_ctx = ContextNode::from(self.add_node(Node::Context(mctx))); let _res = ctx.set_child_call(callee_ctx, self); - self.parse_ctx_expr(expr, callee_ctx)?; - let f: Vec = - self.take_from_edge(ctx, expr.loc(), &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, callee_ctx)?; + let f: Vec = self.take_from_edge( + ctx, + expr.loc(), + arena, + &|analyzer, arena, ctx, loc| { let ret = ctx .pop_expr_latest(loc, analyzer) .into_expr_err(loc)? .unwrap(); - Ok(ret.try_as_func_input_str(analyzer)) - })?; + Ok(ret.try_as_func_input_str(analyzer, arena)) + }, + )?; ctx.delete_child(self).into_expr_err(expr.loc())?; Ok(f.first().unwrap().clone()) @@ -247,8 +266,13 @@ pub trait ModifierCaller: } /// Sets the modifiers for a function - fn set_modifiers(&mut self, func: FunctionNode, ctx: ContextNode) -> Result<(), ExprErr> { - let modifiers = self.modifiers(ctx, func)?; + fn set_modifiers( + &mut self, + arena: &mut RangeArena>, + func: FunctionNode, + ctx: ContextNode, + ) -> Result<(), ExprErr> { + let modifiers = self.modifiers(arena, ctx, func)?; modifiers .iter() .enumerate() diff --git a/crates/solc-expressions/src/func_call/namespaced_call.rs b/crates/solc-expressions/src/func_call/namespaced_call.rs index fa4c778e..a4c989e7 100644 --- a/crates/solc-expressions/src/func_call/namespaced_call.rs +++ b/crates/solc-expressions/src/func_call/namespaced_call.rs @@ -8,17 +8,18 @@ use crate::{ member_access::MemberAccess, ContextBuilder, ExprErr, ExpressionParser, IntoExprErr, }; -use graph::nodes::ContextVar; +use graph::nodes::{Concrete, ContextVar}; use graph::ContextEdge; use graph::Edge; use graph::VarType; use graph::{ + elem::Elem, nodes::{ContextNode, ContextVarNode, ExprRet, FunctionNode}, AnalyzerBackend, GraphBackend, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Identifier, Loc}; @@ -34,6 +35,7 @@ pub trait NameSpaceFuncCaller: /// Call a namedspaced function, i.e. `MyContract.myFunc(...)` fn call_name_spaced_func( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: &Loc, member_expr: &Expression, @@ -48,7 +50,7 @@ pub trait NameSpaceFuncCaller: let fn_node = self .builtin_fn_or_maybe_add(&func_name) .unwrap_or_else(|| panic!("No builtin function with name {func_name}")); - return self.intrinsic_func_call(loc, &input_exprs, fn_node, ctx); + return self.intrinsic_func_call(arena, loc, &input_exprs, fn_node, ctx); } else if name == "super" { if let Some(contract) = ctx.maybe_associated_contract(self).into_expr_err(*loc)? { let supers = contract.super_contracts(self); @@ -70,8 +72,8 @@ pub trait NameSpaceFuncCaller: "Could not find function in super".to_string(), )); } - input_exprs.parse(self, ctx, *loc)?; - return self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, *loc)?; + return self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let inputs = if let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { @@ -97,7 +99,14 @@ pub trait NameSpaceFuncCaller: .kill(analyzer, loc, inputs.killed_kind().unwrap()) .into_expr_err(loc); } - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call( + arena, + &ident.loc, + &inputs, + func.into(), + ctx, + None, + ) } else { // this is the annoying case due to function overloading & type inference on number literals let mut lits = vec![false]; @@ -124,12 +133,13 @@ pub trait NameSpaceFuncCaller: .into_expr_err(loc); } if let Some(func) = analyzer.disambiguate_fn_call( + arena, &ident.name, lits, &inputs, &possible_funcs, ) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call(arena, &loc, &inputs, func.into(), ctx, None) } else { Err(ExprErr::FunctionNotFound( loc, @@ -142,8 +152,8 @@ pub trait NameSpaceFuncCaller: } } - self.parse_ctx_expr(member_expr, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, member_expr, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -156,13 +166,14 @@ pub trait NameSpaceFuncCaller: return Ok(()); } - analyzer.match_namespaced_member(ctx, loc, member_expr, ident, &input_exprs, ret) + analyzer.match_namespaced_member(arena, ctx, loc, member_expr, ident, &input_exprs, ret) }) } /// Match the expression return for getting the member node fn match_namespaced_member( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, member_expr: &Expression, @@ -173,6 +184,7 @@ pub trait NameSpaceFuncCaller: match ret { ExprRet::Single(inner) | ExprRet::SingleLiteral(inner) => self .call_name_spaced_func_inner( + arena, ctx, loc, member_expr, @@ -182,7 +194,7 @@ pub trait NameSpaceFuncCaller: true, ), ExprRet::Multi(inner) => inner.into_iter().try_for_each(|ret| { - self.match_namespaced_member(ctx, loc, member_expr, ident, input_exprs, ret) + self.match_namespaced_member(arena, ctx, loc, member_expr, ident, input_exprs, ret) }), ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), ExprRet::Null => Err(ExprErr::NoLhs( @@ -196,6 +208,7 @@ pub trait NameSpaceFuncCaller: /// Actually perform the namespaced function call fn call_name_spaced_func_inner( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, member_expr: &Expression, @@ -226,8 +239,8 @@ pub trait NameSpaceFuncCaller: ctx.push_expr(ExprRet::Single(member), self) .into_expr_err(loc)?; - input_exprs.parse(self, ctx, loc)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + input_exprs.parse(arena, self, ctx, loc)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(mut inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -293,11 +306,11 @@ pub trait NameSpaceFuncCaller: return Ok(()); } - analyzer.match_assign_sides(ctx, loc, &field_as_ret, &assignment)?; + analyzer.match_assign_sides(arena, ctx, loc, &field_as_ret, &assignment)?; let _ = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)?; Ok(()) })?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { ctx.push_expr(ExprRet::Single(cvar), analyzer) .into_expr_err(loc)?; Ok(()) @@ -323,7 +336,7 @@ pub trait NameSpaceFuncCaller: } let inputs = ExprRet::Multi(inputs); - let as_input_str = inputs.try_as_func_input_str(analyzer); + let as_input_str = inputs.try_as_func_input_str(analyzer, arena); let lits = inputs.literals_list().into_expr_err(loc)?; if lits.iter().any(|i| *i) { @@ -375,6 +388,7 @@ pub trait NameSpaceFuncCaller: Some(possible_builtins[0]) } else { analyzer.disambiguate_fn_call( + arena, &ident.name, lits, &inputs, @@ -395,8 +409,8 @@ pub trait NameSpaceFuncCaller: .to_string(), }, ); - analyzer.parse_ctx_expr(expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -412,6 +426,7 @@ pub trait NameSpaceFuncCaller: let mut modifier_input_exprs = vec![member_expr.clone()]; modifier_input_exprs.extend(input_exprs.exprs()); analyzer.match_intrinsic_fallback( + arena, ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), @@ -440,8 +455,8 @@ pub trait NameSpaceFuncCaller: name: format!("{}{}", ident.name, as_input_str), }, ); - analyzer.parse_ctx_expr(expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, expr, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -456,6 +471,7 @@ pub trait NameSpaceFuncCaller: let mut modifier_input_exprs = vec![member_expr.clone()]; modifier_input_exprs.extend(input_exprs.exprs()); analyzer.match_intrinsic_fallback( + arena, ctx, &loc, &NamedOrUnnamedArgs::Unnamed(&modifier_input_exprs), @@ -485,7 +501,7 @@ pub trait NameSpaceFuncCaller: .into_expr_err(loc); } - analyzer.setup_fn_call(&ident.loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call(arena, &ident.loc, &inputs, func.into(), ctx, None) } else { // Add the member back in if its a context variable let mut inputs = inputs.as_vec(); @@ -518,9 +534,9 @@ pub trait NameSpaceFuncCaller: .into_expr_err(loc); } if let Some(func) = - analyzer.disambiguate_fn_call(&ident.name, lits, &inputs, &possible_funcs) + analyzer.disambiguate_fn_call(arena, &ident.name, lits, &inputs, &possible_funcs) { - analyzer.setup_fn_call(&loc, &inputs, func.into(), ctx, None) + analyzer.setup_fn_call(arena, &loc, &inputs, func.into(), ctx, None) } else { Err(ExprErr::FunctionNotFound( loc, diff --git a/crates/solc-expressions/src/list.rs b/crates/solc-expressions/src/list.rs index 0544bd07..ef19a590 100644 --- a/crates/solc-expressions/src/list.rs +++ b/crates/solc-expressions/src/list.rs @@ -1,9 +1,11 @@ use crate::{ContextBuilder, ExprErr, ExpressionParser, IntoExprErr}; use graph::{ - nodes::{ContextNode, ContextVar, ExprRet}, + elem::Elem, + nodes::{Concrete, ContextNode, ContextVar, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, VarType, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc, Parameter, ParameterList}; @@ -11,11 +13,17 @@ impl List for T where T: AnalyzerBackend + Sized { #[tracing::instrument(level = "trace", skip_all)] - fn list(&mut self, ctx: ContextNode, loc: Loc, params: &ParameterList) -> Result<(), ExprErr> { + fn list( + &mut self, + arena: &mut RangeArena>, + ctx: ContextNode, + loc: Loc, + params: &ParameterList, + ) -> Result<(), ExprErr> { params.iter().try_for_each(|(loc, input)| { if let Some(input) = input { - self.parse_ctx_expr(&input.ty, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, &input.ty, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -31,13 +39,13 @@ pub trait List: AnalyzerBackend + Sized { }) } else { // create a dummy var - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { ctx.append_tmp_expr(ExprRet::Null, analyzer) .into_expr_err(loc) }) } })?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, diff --git a/crates/solc-expressions/src/literal.rs b/crates/solc-expressions/src/literal.rs index a37e14c3..fb118816 100644 --- a/crates/solc-expressions/src/literal.rs +++ b/crates/solc-expressions/src/literal.rs @@ -5,6 +5,7 @@ use graph::{ nodes::{Builtin, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; +use shared::RangeArena; use ethers_core::types::{Address, H256, I256, U256}; use solang_parser::pt::{HexLiteral, Identifier, Loc}; @@ -38,7 +39,7 @@ pub trait Literal: AnalyzerBackend + Sized { val }; - let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8) as u16; + let size: u16 = ((32 - (val.leading_zeros() / 8)) * 8).max(8) as u16; let concrete_node = if negative { let val = if val == U256::from(2).pow(255.into()) { // no need to set upper bit @@ -76,6 +77,7 @@ pub trait Literal: AnalyzerBackend + Sized { fn rational_number_literal( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, integer: &str, @@ -110,9 +112,9 @@ pub trait Literal: AnalyzerBackend + Sized { ContextVar::new_from_builtin(loc, self.builtin_or_add(Builtin::Uint(256)).into(), self) .into_expr_err(loc)?; let node = ContextVarNode::from(self.add_node(Node::ContextVar(cvar))); - node.set_range_max(self, rational_range.clone()) + node.set_range_max(self, arena, rational_range.clone()) .into_expr_err(loc)?; - node.set_range_min(self, rational_range) + node.set_range_min(self, arena, rational_range) .into_expr_err(loc)?; ctx.add_var(node, self).into_expr_err(loc)?; diff --git a/crates/solc-expressions/src/loops.rs b/crates/solc-expressions/src/loops.rs index e54f50dc..aa6f4488 100644 --- a/crates/solc-expressions/src/loops.rs +++ b/crates/solc-expressions/src/loops.rs @@ -3,9 +3,11 @@ use graph::ContextEdge; use graph::Edge; use graph::{ - nodes::{Context, ContextNode}, + elem::Elem, + nodes::{Concrete, Context, ContextNode}, AnalyzerBackend, GraphBackend, Node, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Loc, Statement}; @@ -22,6 +24,7 @@ pub trait Looper: /// Handles a for loop. Needs improvement fn for_loop( &mut self, + arena: &mut RangeArena>, loc: Loc, ctx: ContextNode, maybe_init: &Option>, @@ -31,12 +34,12 @@ pub trait Looper: ) -> Result<(), ExprErr> { // TODO: improve this if let Some(initer) = maybe_init { - self.parse_ctx_statement(initer, false, Some(ctx)); + self.parse_ctx_statement(arena, initer, false, Some(ctx)); } if let Some(body) = maybe_body { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.reset_vars(loc, ctx, body) + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { + analyzer.reset_vars(arena, loc, ctx, body) }) } else { Ok(()) @@ -44,14 +47,20 @@ pub trait Looper: } /// Resets all variables referenced in the loop because we don't elegantly handle loops - fn reset_vars(&mut self, loc: Loc, ctx: ContextNode, body: &Statement) -> Result<(), ExprErr> { + fn reset_vars( + &mut self, + arena: &mut RangeArena>, + loc: Loc, + ctx: ContextNode, + body: &Statement, + ) -> Result<(), ExprErr> { let og_ctx = ctx; let sctx = Context::new_loop_subctx(ctx, loc, self).into_expr_err(loc)?; let subctx = ContextNode::from(self.add_node(Node::Context(sctx))); ctx.set_child_call(subctx, self).into_expr_err(loc)?; self.add_edge(subctx, ctx, Edge::Context(ContextEdge::Loop)); - self.parse_ctx_statement(body, false, Some(subctx)); - self.apply_to_edges(subctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_statement(arena, body, false, Some(subctx)); + self.apply_to_edges(subctx, loc, arena, &|analyzer, arena, ctx, loc| { let vars = subctx.local_vars(analyzer).clone(); vars.iter().for_each(|(name, var)| { // widen to max range @@ -68,11 +77,11 @@ pub trait Looper: .advance_var_in_ctx(inheritor_var, loc, ctx) .unwrap(); let res = new_inheritor_var - .set_range_min(analyzer, r.min) + .set_range_min(analyzer, arena, r.min) .into_expr_err(loc); let _ = analyzer.add_if_err(res); let res = new_inheritor_var - .set_range_max(analyzer, r.max) + .set_range_max(analyzer, arena, r.max) .into_expr_err(loc); let _ = analyzer.add_if_err(res); } @@ -90,14 +99,15 @@ pub trait Looper: /// Handles a while-loop fn while_loop( &mut self, + arena: &mut RangeArena>, loc: Loc, ctx: ContextNode, _limiter: &Expression, body: &Statement, ) -> Result<(), ExprErr> { // TODO: improve this - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - analyzer.reset_vars(loc, ctx, body) + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { + analyzer.reset_vars(arena, loc, ctx, body) }) } } diff --git a/crates/solc-expressions/src/member_access/list_access.rs b/crates/solc-expressions/src/member_access/list_access.rs index adbbbb8a..ab1be6ad 100644 --- a/crates/solc-expressions/src/member_access/list_access.rs +++ b/crates/solc-expressions/src/member_access/list_access.rs @@ -5,6 +5,7 @@ use graph::{ nodes::{BuiltInNode, Builtin, Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, Range, SolcRange, VarType, }; +use shared::RangeArena; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; @@ -16,12 +17,13 @@ pub trait ListAccess: AnalyzerBackend + Si /// Get the length member of an array/list fn length( &mut self, + arena: &mut RangeArena>, loc: Loc, input_expr: &Expression, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(input_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, input_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -32,7 +34,7 @@ pub trait ListAccess: AnalyzerBackend + Si ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_length(ctx, loc, ret, true) + analyzer.match_length(arena, ctx, loc, ret, true) }) } @@ -40,6 +42,7 @@ pub trait ListAccess: AnalyzerBackend + Si /// Get the length member of an array/list fn match_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, elem_path: ExprRet, @@ -52,7 +55,7 @@ pub trait ListAccess: AnalyzerBackend + Si } ExprRet::CtxKilled(kind) => ctx.kill(self, loc, kind).into_expr_err(loc), ExprRet::Single(arr) => { - self.get_length(ctx, loc, arr.into(), false)?; + self.get_length(arena, ctx, loc, arr.into(), false)?; Ok(()) } e => todo!("here: {e:?}"), @@ -61,6 +64,7 @@ pub trait ListAccess: AnalyzerBackend + Si fn get_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, array: ContextVarNode, @@ -78,7 +82,7 @@ pub trait ListAccess: AnalyzerBackend + Si Ok(Some(len_node)) } } else { - self.create_length(ctx, loc, array, next_arr, return_var) + self.create_length(arena, ctx, loc, array, next_arr, return_var) // no length variable, create one // let name = format!("{}.length", array.name(self).into_expr_err(loc)?); @@ -141,6 +145,7 @@ pub trait ListAccess: AnalyzerBackend + Si fn create_length( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, array: ContextVarNode, @@ -151,7 +156,6 @@ pub trait ListAccess: AnalyzerBackend + Si let name = format!("{}.length", array.name(self).into_expr_err(loc)?); // Create the range from the current length or default to [0, uint256.max] - let len_min = Elem::from(array) .get_length() .max(Elem::from(Concrete::from(U256::zero()))); @@ -192,10 +196,10 @@ pub trait ListAccess: AnalyzerBackend + Si // Update the array next_target_arr - .set_range_min(self, update_array_len.clone()) + .set_range_min(self, arena, update_array_len.clone()) .into_expr_err(loc)?; next_target_arr - .set_range_max(self, update_array_len.clone()) + .set_range_max(self, arena, update_array_len.clone()) .into_expr_err(loc)?; if !return_var { @@ -211,6 +215,7 @@ pub trait ListAccess: AnalyzerBackend + Si /// Get the length member of an array/list and create it as a temporary variable fn tmp_length( &mut self, + arena: &mut RangeArena>, arr: ContextVarNode, array_ctx: ContextNode, loc: Loc, @@ -255,26 +260,26 @@ pub trait ListAccess: AnalyzerBackend + Si .unwrap() { if let Some(r) = next_arr.ref_range(self).unwrap() { - let min = r.simplified_range_min(self).unwrap(); - let max = r.simplified_range_max(self).unwrap(); + let min = r.simplified_range_min(self, arena).unwrap(); + let max = r.simplified_range_max(self, arena).unwrap(); if let Some(mut rd) = min.maybe_range_dyn() { ContextVarNode::from(len_node) - .set_range_min(self, *rd.len.clone()) + .set_range_min(self, arena, *rd.len.clone()) .unwrap(); rd.len = Box::new(Elem::from(len_node)); let res = next_arr - .set_range_min(self, Elem::ConcreteDyn(rd)) + .set_range_min(self, arena, Elem::ConcreteDyn(rd)) .into_expr_err(loc); let _ = self.add_if_err(res); } if let Some(mut rd) = max.maybe_range_dyn() { ContextVarNode::from(len_node) - .set_range_max(self, *rd.len.clone()) + .set_range_max(self, arena, *rd.len.clone()) .unwrap(); rd.len = Box::new(Elem::from(len_node)); let res = next_arr - .set_range_max(self, Elem::ConcreteDyn(rd)) + .set_range_max(self, arena, Elem::ConcreteDyn(rd)) .into_expr_err(loc); let _ = self.add_if_err(res); } diff --git a/crates/solc-expressions/src/member_access/member_trait.rs b/crates/solc-expressions/src/member_access/member_trait.rs index dd192dde..ab26fe1b 100644 --- a/crates/solc-expressions/src/member_access/member_trait.rs +++ b/crates/solc-expressions/src/member_access/member_trait.rs @@ -2,17 +2,16 @@ use crate::{ BuiltinAccess, ContextBuilder, ContractAccess, EnumAccess, Env, ExprErr, ExpressionParser, IntoExprErr, ListAccess, StructAccess, }; -use graph::nodes::Concrete; -use graph::nodes::ConcreteNode; use graph::{ + elem::Elem, nodes::{ - BuiltInNode, ContextNode, ContextVar, ContextVarNode, ContractNode, EnumNode, ExprRet, - FunctionNode, StructNode, TyNode, + BuiltInNode, Concrete, ConcreteNode, ContextNode, ContextVar, ContextVarNode, ContractNode, + EnumNode, ExprRet, FunctionNode, StructNode, TyNode, }, AnalyzerBackend, Node, TypeNode, VarType, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use solang_parser::pt::{Expression, Identifier, Loc}; @@ -40,6 +39,7 @@ pub trait MemberAccess: #[tracing::instrument(level = "trace", skip_all)] fn member_access( &mut self, + arena: &mut RangeArena>, loc: Loc, member_expr: &Expression, ident: &Identifier, @@ -47,11 +47,11 @@ pub trait MemberAccess: ) -> Result<(), ExprErr> { // TODO: this is wrong as it overwrites a function call of the form elem.length(...) i believe if ident.name == "length" { - return self.length(loc, member_expr, ctx); + return self.length(arena, loc, member_expr, ctx); } - self.parse_ctx_expr(member_expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, member_expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, diff --git a/crates/solc-expressions/src/pre_post_in_decrement.rs b/crates/solc-expressions/src/pre_post_in_decrement.rs index 829b2780..275c979a 100644 --- a/crates/solc-expressions/src/pre_post_in_decrement.rs +++ b/crates/solc-expressions/src/pre_post_in_decrement.rs @@ -7,6 +7,7 @@ use graph::{ nodes::{Concrete, ContextNode, ContextVarNode, ExprRet}, AnalyzerBackend, }; +use shared::RangeArena; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc}; @@ -22,12 +23,13 @@ pub trait PrePostIncDecrement: /// Handle a preincrement fn pre_increment( &mut self, + arena: &mut RangeArena>, expr: &Expression, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { tracing::trace!("PreIncrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -40,19 +42,20 @@ pub trait PrePostIncDecrement: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_in_de_crement(ctx, true, true, loc, &ret) + analyzer.match_in_de_crement(arena, ctx, true, true, loc, &ret) }) } /// Handle a postincrement fn post_increment( &mut self, + arena: &mut RangeArena>, expr: &Expression, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { tracing::trace!("PostIncrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -64,19 +67,20 @@ pub trait PrePostIncDecrement: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_in_de_crement(ctx, false, true, loc, &ret) + analyzer.match_in_de_crement(arena, ctx, false, true, loc, &ret) }) } /// Handle a predecrement fn pre_decrement( &mut self, + arena: &mut RangeArena>, expr: &Expression, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { tracing::trace!("PreDecrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -88,19 +92,20 @@ pub trait PrePostIncDecrement: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_in_de_crement(ctx, true, false, loc, &ret) + analyzer.match_in_de_crement(arena, ctx, true, false, loc, &ret) }) } /// Handle a postdecrement fn post_decrement( &mut self, + arena: &mut RangeArena>, expr: &Expression, loc: Loc, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.parse_ctx_expr(expr, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, expr, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { tracing::trace!("PostDecrement variable pop"); let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -112,13 +117,14 @@ pub trait PrePostIncDecrement: ctx.push_expr(ret, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_in_de_crement(ctx, false, false, loc, &ret) + analyzer.match_in_de_crement(arena, ctx, false, false, loc, &ret) }) } /// Match on the [`ExprRet`]s of a pre-or-post in/decrement and performs it fn match_in_de_crement( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, pre: bool, increment: bool, @@ -132,9 +138,9 @@ pub trait PrePostIncDecrement: } ExprRet::SingleLiteral(var) => { ContextVarNode::from(*var) - .try_increase_size(self) + .try_increase_size(self, arena) .into_expr_err(loc)?; - self.match_in_de_crement(ctx, pre, increment, loc, &ExprRet::Single(*var)) + self.match_in_de_crement(arena, ctx, pre, increment, loc, &ExprRet::Single(*var)) } ExprRet::Single(var) => { let cvar = ContextVarNode::from(*var).latest_version(self); @@ -145,31 +151,33 @@ pub trait PrePostIncDecrement: if increment { if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() + one.clone()) + dup.set_range_min(self, arena, elem.clone() + one.clone()) .into_expr_err(loc)?; - dup.set_range_max(self, elem.clone() + one.clone()) + dup.set_range_max(self, arena, elem.clone() + one.clone()) .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar - .set_range_min(self, elem.clone() + one.clone()) + .set_range_min(self, arena, elem.clone() + one.clone()) .into_expr_err(loc)?; new_cvar - .set_range_max(self, elem + one) + .set_range_max(self, arena, elem + one) .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone()).into_expr_err(loc)?; - dup.set_range_max(self, elem.clone()).into_expr_err(loc)?; + dup.set_range_min(self, arena, elem.clone()) + .into_expr_err(loc)?; + dup.set_range_max(self, arena, elem.clone()) + .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; let res = new_cvar - .set_range_min(self, elem.clone() + one.clone()) + .set_range_min(self, arena, elem.clone() + one.clone()) .into_expr_err(loc); let _ = self.add_if_err(res); new_cvar - .set_range_max(self, elem + one) + .set_range_max(self, arena, elem + one) .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; @@ -177,39 +185,41 @@ pub trait PrePostIncDecrement: } } else if pre { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone() - one.clone()) + dup.set_range_min(self, arena, elem.clone() - one.clone()) .into_expr_err(loc)?; - dup.set_range_max(self, elem.clone() - one.clone()) + dup.set_range_max(self, arena, elem.clone() - one.clone()) .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar - .set_range_min(self, elem.clone() - one.clone()) + .set_range_min(self, arena, elem.clone() - one.clone()) .into_expr_err(loc)?; new_cvar - .set_range_max(self, elem - one) + .set_range_max(self, arena, elem - one) .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(dup.latest_version(self).into()), self) .into_expr_err(loc)?; Ok(()) } else { let dup = cvar.as_tmp(loc, ctx, self).into_expr_err(loc)?; - dup.set_range_min(self, elem.clone()).into_expr_err(loc)?; - dup.set_range_max(self, elem.clone()).into_expr_err(loc)?; + dup.set_range_min(self, arena, elem.clone()) + .into_expr_err(loc)?; + dup.set_range_max(self, arena, elem.clone()) + .into_expr_err(loc)?; let new_cvar = self.advance_var_in_ctx(cvar, loc, ctx)?; new_cvar - .set_range_min(self, elem.clone() - one.clone()) + .set_range_min(self, arena, elem.clone() - one.clone()) .into_expr_err(loc)?; new_cvar - .set_range_max(self, elem - one) + .set_range_max(self, arena, elem - one) .into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(dup.into()), self) .into_expr_err(loc)?; Ok(()) } } - ExprRet::Multi(inner) => inner - .iter() - .try_for_each(|expr| self.match_in_de_crement(ctx, pre, increment, loc, expr)), + ExprRet::Multi(inner) => inner.iter().try_for_each(|expr| { + self.match_in_de_crement(arena, ctx, pre, increment, loc, expr) + }), ExprRet::Null => Ok(()), } } diff --git a/crates/solc-expressions/src/require.rs b/crates/solc-expressions/src/require.rs index 1c0478c5..28d4f608 100644 --- a/crates/solc-expressions/src/require.rs +++ b/crates/solc-expressions/src/require.rs @@ -9,6 +9,7 @@ use graph::{ range_string::ToRangeString, AnalyzerBackend, ContextEdge, Edge, Node, Range, RangeEval, SolcRange, VarType, }; +use shared::RangeArena; use ethers_core::types::I256; use solang_parser::{ @@ -46,13 +47,18 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Handles a require expression #[tracing::instrument(level = "trace", skip_all)] - fn handle_require(&mut self, inputs: &[Expression], ctx: ContextNode) -> Result<(), ExprErr> { + fn handle_require( + &mut self, + arena: &mut RangeArena>, + inputs: &[Expression], + ctx: ContextNode, + ) -> Result<(), ExprErr> { ctx.add_gas_cost(self, shared::gas::BIN_OP_GAS) .into_expr_err(inputs[0].loc())?; match inputs.first().expect("No lhs input for require statement") { Expression::Equal(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -68,8 +74,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -84,6 +90,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -96,8 +103,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::NotEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -111,8 +118,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -126,6 +133,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -138,8 +146,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::Less(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -154,8 +162,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -169,6 +177,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -181,8 +190,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::More(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -197,8 +206,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -212,6 +221,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -224,8 +234,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::MoreEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -240,8 +250,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -255,6 +265,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -267,8 +278,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::LessEqual(loc, lhs, rhs) => { - self.parse_ctx_expr(rhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, rhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -283,8 +294,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(lhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, lhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -298,6 +309,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths.flatten(), @@ -310,8 +322,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::Not(loc, lhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, lhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -333,6 +345,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_paths = ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_false)).into()); analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths, @@ -344,8 +357,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::And(loc, lhs, rhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, lhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -359,8 +372,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(rhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, rhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -398,6 +411,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { if let Some(tmp) = underlying.tmp_of { if let Some((op, _inv_op, pair)) = tmp.op.require_parts() { analyzer.handle_require_inner( + arena, ctx, loc, &ExprRet::Single(tmp.lhs.into()), @@ -416,6 +430,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { if let Some(tmp) = underlying.tmp_of { if let Some((op, _inv_op, pair)) = tmp.op.require_parts() { analyzer.handle_require_inner( + arena, ctx, loc, &ExprRet::Single(tmp.lhs.into()), @@ -428,6 +443,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths, @@ -438,6 +454,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { )?; analyzer.handle_require_inner( + arena, ctx, loc, &rhs_paths, @@ -452,8 +469,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } Expression::Or(loc, lhs, rhs) => { - self.parse_ctx_expr(lhs, ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, lhs, ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -466,8 +483,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); } - analyzer.parse_ctx_expr(rhs, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_expr(arena, rhs, ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -547,6 +564,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { analyzer.add_edge(node, ctx, Edge::Context(ContextEdge::Variable)); let rhs_paths = ExprRet::Single(node); analyzer.handle_require_inner( + arena, ctx, loc, &ExprRet::Single(or_var.into()), @@ -559,8 +577,8 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }) } other => { - self.parse_ctx_expr(other, ctx)?; - self.apply_to_edges(ctx, other.loc(), &|analyzer, ctx, loc| { + self.parse_ctx_expr(arena, other, ctx)?; + self.apply_to_edges(ctx, other.loc(), arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -581,6 +599,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_paths = ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); analyzer.handle_require_inner( + arena, ctx, loc, &lhs_paths, @@ -597,6 +616,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Do matching on [`ExprRet`]s to actually perform the require statement evaluation fn handle_require_inner( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, lhs_paths: &ExprRet, @@ -610,9 +630,10 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (_, ExprRet::CtxKilled(..)) | (ExprRet::CtxKilled(..), _) => Ok(()), (ExprRet::SingleLiteral(lhs), ExprRet::Single(rhs)) => { ContextVarNode::from(*lhs) - .cast_from(&ContextVarNode::from(*rhs), self) + .cast_from(&ContextVarNode::from(*rhs), self, arena) .into_expr_err(loc)?; self.handle_require_inner( + arena, ctx, loc, &ExprRet::Single(*lhs), @@ -624,9 +645,10 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } (ExprRet::Single(lhs), ExprRet::SingleLiteral(rhs)) => { ContextVarNode::from(*rhs) - .cast_from(&ContextVarNode::from(*lhs), self) + .cast_from(&ContextVarNode::from(*lhs), self, arena) .into_expr_err(loc)?; self.handle_require_inner( + arena, ctx, loc, lhs_paths, @@ -642,17 +664,35 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_cvar = ContextVarNode::from(*rhs).latest_version(self); let new_rhs = self.advance_var_in_ctx(rhs_cvar, loc, ctx)?; - self.require(new_lhs, new_rhs, ctx, loc, op, rhs_op, recursion_ops)?; + self.require(arena, new_lhs, new_rhs, ctx, loc, op, rhs_op, recursion_ops)?; Ok(()) } (l @ ExprRet::Single(_) | l @ ExprRet::SingleLiteral(_), ExprRet::Multi(rhs_sides)) => { rhs_sides.iter().try_for_each(|expr_ret| { - self.handle_require_inner(ctx, loc, l, expr_ret, op, rhs_op, recursion_ops) + self.handle_require_inner( + arena, + ctx, + loc, + l, + expr_ret, + op, + rhs_op, + recursion_ops, + ) }) } (ExprRet::Multi(lhs_sides), r @ ExprRet::Single(_) | r @ ExprRet::SingleLiteral(_)) => { lhs_sides.iter().try_for_each(|expr_ret| { - self.handle_require_inner(ctx, loc, expr_ret, r, op, rhs_op, recursion_ops) + self.handle_require_inner( + arena, + ctx, + loc, + expr_ret, + r, + op, + rhs_op, + recursion_ops, + ) }) } (ExprRet::Multi(lhs_sides), ExprRet::Multi(rhs_sides)) => { @@ -661,6 +701,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { lhs_sides.iter().zip(rhs_sides.iter()).try_for_each( |(lhs_expr_ret, rhs_expr_ret)| { self.handle_require_inner( + arena, ctx, loc, lhs_expr_ret, @@ -674,6 +715,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } else { rhs_sides.iter().try_for_each(|rhs_expr_ret| { self.handle_require_inner( + arena, ctx, loc, lhs_paths, @@ -698,6 +740,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { #[tracing::instrument(level = "trace", skip_all)] fn require( &mut self, + arena: &mut RangeArena>, mut new_lhs: ContextVarNode, mut new_rhs: ContextVarNode, ctx: ContextNode, @@ -724,11 +767,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let mut new_var_range = lhs_range_fn(lhs_range.clone(), new_rhs); if let Some(rhs_range) = new_rhs.range(self).into_expr_err(loc)? { - let lhs_is_const = new_lhs.is_const(self).into_expr_err(loc)?; - let rhs_is_const = new_rhs.is_const(self).into_expr_err(loc)?; + let lhs_is_const = new_lhs.is_const(self, arena).into_expr_err(loc)?; + let rhs_is_const = new_rhs.is_const(self, arena).into_expr_err(loc)?; match (lhs_is_const, rhs_is_const) { (true, true) => { - if self.const_killable(op, lhs_range, rhs_range) { + if self.const_killable(arena, op, lhs_range, rhs_range) { tracing::trace!("const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); @@ -739,7 +782,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_range_fn = SolcRange::dyn_fn_from_op(rhs_op); new_var_range = rhs_range_fn(rhs_range.clone(), new_lhs); if self.update_nonconst_from_const( - ctx, loc, rhs_op, new_lhs, new_rhs, rhs_range, + arena, ctx, loc, rhs_op, new_lhs, new_rhs, rhs_range, )? { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; @@ -747,9 +790,9 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } } (false, true) => { - if self - .update_nonconst_from_const(ctx, loc, op, new_rhs, new_lhs, lhs_range)? - { + if self.update_nonconst_from_const( + arena, ctx, loc, op, new_rhs, new_lhs, lhs_range, + )? { tracing::trace!("half-const killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); @@ -757,7 +800,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } (false, false) => { if self.update_nonconst_from_nonconst( - ctx, loc, op, new_lhs, new_rhs, lhs_range, rhs_range, + arena, ctx, loc, op, new_lhs, new_rhs, lhs_range, rhs_range, )? { tracing::trace!("nonconst killable"); ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; @@ -889,11 +932,12 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { tmp_cvar = Some(cvar); tracing::trace!("checking unsat"); - any_unsat |= new_var_range.unsat(self); + any_unsat |= new_var_range.unsat(self, arena); - ctx.add_ctx_dep(conditional_cvar, self).into_expr_err(loc)?; + ctx.add_ctx_dep(conditional_cvar, self, arena) + .into_expr_err(loc)?; - if any_unsat || ctx.unreachable(self).into_expr_err(loc)? { + if any_unsat || ctx.unreachable(self, arena).into_expr_err(loc)? { ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(None); } @@ -911,7 +955,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { match tmp.op { RangeOp::Not => {} _ => { - self.uninvertable_range_recursion(tmp, new_lhs, new_rhs, loc, ctx); + self.uninvertable_range_recursion(arena, tmp, new_lhs, new_rhs, loc, ctx); } } } @@ -921,50 +965,56 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } /// Checks and returns whether the require statement is killable (i.e. impossible) - fn const_killable(&mut self, op: RangeOp, lhs_range: SolcRange, rhs_range: SolcRange) -> bool { + fn const_killable( + &mut self, + arena: &mut RangeArena>, + op: RangeOp, + lhs_range: SolcRange, + rhs_range: SolcRange, + ) -> bool { // check that the op is satisfied, return it as a bool match op { RangeOp::Eq => !lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_eq(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), RangeOp::Neq => lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_eq(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_eq(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), RangeOp::Gt => { matches!( lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_ord(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), Some(Ordering::Equal) | Some(Ordering::Less) ) } RangeOp::Gte => { matches!( lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_ord(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), Some(Ordering::Less) ) } RangeOp::Lt => { matches!( lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_ord(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), Some(Ordering::Equal) | Some(Ordering::Greater) ) } RangeOp::Lte => { matches!( lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() - .range_ord(&rhs_range.evaled_range_min(self).unwrap(), self), + .range_ord(&rhs_range.evaled_range_min(self, arena).unwrap(), arena), Some(Ordering::Greater) ) } @@ -976,6 +1026,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { #[tracing::instrument(level = "trace", skip_all)] fn update_nonconst_from_const( &mut self, + arena: &mut RangeArena>, _ctx: ContextNode, loc: Loc, op: RangeOp, @@ -988,19 +1039,23 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { RangeOp::Eq => { // check that the constant is contained in the nonconst var range let elem = Elem::from(const_var.latest_version(self)); - let evaled_min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + let evaled_min = nonconst_range + .evaled_range_min(self, arena) + .into_expr_err(loc)?; if evaled_min.maybe_concrete().is_none() { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Eq). Min: {}", evaled_min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Eq). Min: {}", evaled_min.to_range_string(false, self, arena).s))); } - if !nonconst_range.contains_elem(&elem, self) { + if !nonconst_range.contains_elem(&elem, self, arena) { return Ok(true); } // if its contained, we can set the min & max to it nonconst_var - .set_range_min(self, elem.clone()) + .set_range_min(self, arena, elem.clone()) + .into_expr_err(loc)?; + nonconst_var + .set_range_max(self, arena, elem) .into_expr_err(loc)?; - nonconst_var.set_range_max(self, elem).into_expr_err(loc)?; Ok(false) } RangeOp::Neq => { @@ -1009,35 +1064,43 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // potentially add the const var as a range exclusion if let Some(Ordering::Equal) = nonconst_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .into_expr_err(loc)? - .range_ord(&elem, self) + .range_ord(&elem, arena) { // mins are equivalent, add 1 instead of adding an exclusion - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + let min = nonconst_range + .evaled_range_min(self, arena) + .into_expr_err(loc)?; let Some(min) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq). Min: {}", min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq). Min: {}", min.to_range_string(false, self, arena).s))); }; let one = Concrete::one(&min.val).expect("Cannot increment range elem by one"); let min = nonconst_range.range_min().into_owned() + Elem::from(one); - nonconst_var.set_range_min(self, min).into_expr_err(loc)?; + nonconst_var + .set_range_min(self, arena, min) + .into_expr_err(loc)?; } else if let Some(std::cmp::Ordering::Equal) = nonconst_range - .evaled_range_max(self) + .evaled_range_max(self, arena) .into_expr_err(loc)? - .range_ord(&elem, self) + .range_ord(&elem, arena) { // maxs are equivalent, subtract 1 instead of adding an exclusion - let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; + let max = nonconst_range + .evaled_range_max(self, arena) + .into_expr_err(loc)?; let Some(max) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq 2). Max: {}", max.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Neq 2). Max: {}", max.to_range_string(true, self, arena).s))); }; let one = Concrete::one(&max.val).expect("Cannot decrement range elem by one"); let max = nonconst_range.range_max().into_owned() - Elem::from(one); - nonconst_var.set_range_max(self, max).into_expr_err(loc)?; + nonconst_var + .set_range_max(self, arena, max) + .into_expr_err(loc)?; } else { // just add as an exclusion - let idx = self.range_arena_idx_or_upsert(elem); + let idx = arena.idx_or_upsert(elem, self); nonconst_range.add_range_exclusion(idx); nonconst_var .set_range_exclusions(self, nonconst_range.exclusions) @@ -1050,9 +1113,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let elem = Elem::from(const_var.latest_version(self)); // if nonconst max is <= const, we can't make this true - let max = nonconst_range.evaled_range_max(self).into_expr_err(loc)?; + let max = nonconst_range + .evaled_range_max(self, arena) + .into_expr_err(loc)?; if matches!( - max.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), + max.range_ord(&elem.minimize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Less) | Some(Ordering::Equal) ) { return Ok(true); @@ -1060,7 +1125,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add one to the element because its strict > let Some(max_conc) = const_var - .evaled_range_min(self) + .evaled_range_min(self, arena) .unwrap() .unwrap() .maybe_concrete() @@ -1072,13 +1137,14 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var.display_name(self).unwrap(), op.to_string(), const_var.display_name(self).unwrap(), - const_var.evaled_range_min(self).unwrap().unwrap() + const_var.evaled_range_min(self, arena).unwrap().unwrap() ))); }; let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); nonconst_var .set_range_min( self, + arena, (elem + one.into()).max(nonconst_range.range_min().into_owned()), ) .into_expr_err(loc)?; @@ -1090,16 +1156,20 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // if nonconst max is < const, we can't make this true if matches!( nonconst_range - .evaled_range_max(self) + .evaled_range_max(self, arena) .into_expr_err(loc)? - .range_ord(&elem.minimize(self).into_expr_err(loc)?, self), + .range_ord(&elem.minimize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Less) ) { return Ok(true); } nonconst_var - .set_range_min(self, elem.max(nonconst_range.range_min().into_owned())) + .set_range_min( + self, + arena, + elem.max(nonconst_range.range_min().into_owned()), + ) .into_expr_err(loc)?; Ok(false) } @@ -1107,9 +1177,11 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let elem = Elem::from(const_var.latest_version(self)); // if nonconst min is >= const, we can't make this true - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + let min = nonconst_range + .evaled_range_min(self, arena) + .into_expr_err(loc)?; if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), + min.range_ord(&elem.minimize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Greater) | Some(Ordering::Equal) ) { return Ok(true); @@ -1125,6 +1197,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { nonconst_var .set_range_max( self, + arena, (elem - one.into()).min(nonconst_range.range_max().into_owned()), ) .into_expr_err(loc)?; @@ -1134,16 +1207,22 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let elem = Elem::from(const_var.latest_version(self)); // if nonconst min is > const, we can't make this true - let min = nonconst_range.evaled_range_min(self).into_expr_err(loc)?; + let min = nonconst_range + .evaled_range_min(self, arena) + .into_expr_err(loc)?; if matches!( - min.range_ord(&elem.minimize(self).into_expr_err(loc)?, self), + min.range_ord(&elem.minimize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Greater) ) { return Ok(true); } nonconst_var - .set_range_max(self, elem.min(nonconst_range.range_max().into_owned())) + .set_range_max( + self, + arena, + elem.min(nonconst_range.range_max().into_owned()), + ) .into_expr_err(loc)?; Ok(false) } @@ -1154,6 +1233,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Given a const var and a nonconst range, update the range based on the op. Returns whether its impossible fn update_nonconst_from_nonconst( &mut self, + arena: &mut RangeArena>, _ctx: ContextNode, loc: Loc, op: RangeOp, @@ -1166,26 +1246,28 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { match op { RangeOp::Eq => { // check that there is overlap in the ranges - if !lhs_range.overlaps(&rhs_range, self) { + if !lhs_range.overlaps(&rhs_range, self, arena) { return Ok(true); } // take the tighest range match lhs_range - .evaled_range_min(self) + .evaled_range_min(self, arena) .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_min(self).into_expr_err(loc)?, self) - { + .range_ord( + &rhs_range.evaled_range_min(self, arena).into_expr_err(loc)?, + arena, + ) { Some(Ordering::Greater) => { // take lhs range min as its tigher new_rhs - .set_range_min(self, Elem::from(new_rhs)) + .set_range_min(self, arena, Elem::from(new_rhs)) .into_expr_err(loc)?; } Some(Ordering::Less) => { // take rhs range min as its tigher new_lhs - .set_range_min(self, rhs_range.range_min().into_owned()) + .set_range_min(self, arena, rhs_range.range_min().into_owned()) .into_expr_err(loc)?; } _ => { @@ -1195,20 +1277,22 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // take the tighest range match lhs_range - .evaled_range_max(self) + .evaled_range_max(self, arena) .into_expr_err(loc)? - .range_ord(&rhs_range.evaled_range_max(self).into_expr_err(loc)?, self) - { + .range_ord( + &rhs_range.evaled_range_max(self, arena).into_expr_err(loc)?, + arena, + ) { Some(Ordering::Less) => { // take lhs range min as its tigher new_rhs - .set_range_max(self, lhs_range.range_max().into_owned()) + .set_range_max(self, arena, lhs_range.range_max().into_owned()) .into_expr_err(loc)?; } Some(Ordering::Greater) => { // take rhs range min as its tigher new_lhs - .set_range_max(self, rhs_range.range_max().into_owned()) + .set_range_max(self, arena, rhs_range.range_max().into_owned()) .into_expr_err(loc)?; } _ => { @@ -1225,7 +1309,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let rhs_elem = Elem::from(new_rhs.latest_version(self)); // just add as an exclusion - let idx = self.range_arena_idx_or_upsert(rhs_elem); + let idx = arena.idx_or_upsert(rhs_elem, self); lhs_range.add_range_exclusion(idx); new_lhs .set_range_exclusions(self, lhs_range.exclusions) @@ -1233,7 +1317,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let lhs_elem = Elem::from(new_lhs.latest_version(self)); // just add as an exclusion - let idx = self.range_arena_idx_or_upsert(lhs_elem); + let idx = arena.idx_or_upsert(lhs_elem, self); rhs_range.add_range_exclusion(idx); new_rhs .set_range_exclusions(self, rhs_range.exclusions) @@ -1245,16 +1329,16 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let lhs_elem = Elem::from(new_lhs.latest_version(self)); // if lhs.max is <= rhs.min, we can't make this true - let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; + let max = lhs_range.evaled_range_max(self, arena).into_expr_err(loc)?; if matches!( - max.range_ord(&rhs_elem.minimize(self).into_expr_err(loc)?, self), + max.range_ord(&rhs_elem.minimize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Less) | Some(Ordering::Equal) ) { return Ok(true); } let Some(max_conc) = max.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from nonconst: Gt). Max: {}", max.to_range_string(true, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from nonconst: Gt). Max: {}", max.to_range_string(true, self, arena).s))); }; let one = Concrete::one(&max_conc.val).expect("Cannot decrement range elem by one"); @@ -1264,6 +1348,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_min( self, + arena, (rhs_elem + one.clone().into()).max(lhs_range.range_min().into_owned()), ) .into_expr_err(loc)?; @@ -1271,6 +1356,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_max( self, + arena, (lhs_elem - one.into()).min(rhs_range.range_max().into_owned()), ) .into_expr_err(loc)?; @@ -1285,9 +1371,9 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let lhs_elem = Elem::from(new_lhs.latest_version(self)); // if lhs.max is < rhs.min, we can't make this true - let max = lhs_range.evaled_range_max(self).into_expr_err(loc)?; - let min = rhs_elem.minimize(self).into_expr_err(loc)?; - if let Some(Ordering::Less) = max.range_ord(&min, self) { + let max = lhs_range.evaled_range_max(self, arena).into_expr_err(loc)?; + let min = rhs_elem.minimize(self, arena).into_expr_err(loc)?; + if let Some(Ordering::Less) = max.range_ord(&min, arena) { return Ok(true); } @@ -1306,10 +1392,13 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let new_new_rhs = self.advance_var_in_curr_ctx(new_rhs, loc)?; new_new_lhs - .set_range_min(self, new_min) + .set_range_min(self, arena, new_min.clone()) + .into_expr_err(loc)?; + new_new_rhs + .set_range_min(self, arena, new_max.clone()) .into_expr_err(loc)?; new_new_rhs - .set_range_max(self, new_max) + .set_range_max(self, arena, new_max) .into_expr_err(loc)?; Ok(false) } @@ -1318,9 +1407,9 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let lhs_elem = Elem::from(new_lhs.latest_version(self)); // if lhs min is >= rhs.max, we can't make this true - let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + let min = lhs_range.evaled_range_min(self, arena).into_expr_err(loc)?; if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?, self), + min.range_ord(&rhs_elem.maximize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Greater) | Some(Ordering::Equal) ) { return Ok(true); @@ -1328,7 +1417,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // we add/sub one to the element because its strict > let Some(min_conc) = min.maybe_concrete() else { - return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Lt). Min: {}", min.to_range_string(false, self).s))); + return Err(ExprErr::BadRange(loc, format!("Expected to have a concrete range by now. This is likely a bug (update nonconst from const: Lt). Min: {}", min.to_range_string(false, self, arena).s))); }; let one = Concrete::one(&min_conc.val).expect("Cannot decrement range elem by one"); @@ -1340,6 +1429,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_max( self, + arena, (rhs_elem - one.clone().into()).min(lhs_range.range_max().into_owned()), ) .into_expr_err(loc)?; @@ -1347,6 +1437,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { .latest_version(self) .set_range_min( self, + arena, (lhs_elem + one.into()).max(rhs_range.range_min().into_owned()), ) .into_expr_err(loc)?; @@ -1354,12 +1445,13 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { } RangeOp::Lte => { let rhs_elem = Elem::from(new_rhs.latest_version(self)); - let lhs_elem = Elem::from(new_lhs.latest_version(self)); + let lhs_elem = Elem::from(new_lhs.latest_version(self)) + .max(rhs_range.range_min().into_owned()); // if nonconst min is > const, we can't make this true - let min = lhs_range.evaled_range_min(self).into_expr_err(loc)?; + let min = lhs_range.evaled_range_min(self, arena).into_expr_err(loc)?; if matches!( - min.range_ord(&rhs_elem.maximize(self).into_expr_err(loc)?, self), + min.range_ord(&rhs_elem.maximize(self, arena).into_expr_err(loc)?, arena), Some(Ordering::Greater) ) { return Ok(true); @@ -1367,11 +1459,19 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { new_lhs .latest_version(self) - .set_range_max(self, rhs_elem.min(lhs_range.range_max().into_owned())) + .set_range_max( + self, + arena, + rhs_elem.min(lhs_range.range_max().into_owned()), + ) + .into_expr_err(loc)?; + new_rhs + .latest_version(self) + .set_range_min(self, arena, lhs_elem.clone()) .into_expr_err(loc)?; new_rhs .latest_version(self) - .set_range_min(self, lhs_elem.max(rhs_range.range_min().into_owned())) + .set_range_max(self, arena, lhs_elem) .into_expr_err(loc)?; Ok(false) } @@ -1381,24 +1481,26 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { fn uninvertable_range_recursion( &mut self, + arena: &mut RangeArena>, tmp_construction: TmpConstruction, _new_lhs_core: ContextVarNode, _rhs_cvar: ContextVarNode, loc: Loc, ctx: ContextNode, ) { - if !tmp_construction.lhs.is_const(self).unwrap() { + if !tmp_construction.lhs.is_const(self, arena).unwrap() { // widen to maximum range :( let new_underlying_lhs = self .advance_var_in_ctx(tmp_construction.lhs.latest_version(self), loc, ctx) .unwrap(); if let Some(lhs_range) = tmp_construction.lhs.ref_range(self).unwrap() { - if let Elem::Concrete(c) = lhs_range.evaled_range_min(self).unwrap() { + if let Elem::Concrete(c) = lhs_range.evaled_range_min(self, arena).unwrap() { new_underlying_lhs .set_range_min( self, + arena, Elem::Concrete(RangeConcrete { - val: Concrete::min(&c.val).unwrap_or_else(|| c.val.clone()), + val: Concrete::min_of_type(&c.val).unwrap_or_else(|| c.val.clone()), loc, }), ) @@ -1406,8 +1508,9 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { new_underlying_lhs .set_range_max( self, + arena, Elem::Concrete(RangeConcrete { - val: Concrete::max(&c.val).unwrap_or(c.val), + val: Concrete::max_of_type(&c.val).unwrap_or(c.val), loc, }), ) @@ -1420,6 +1523,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { /// Recursively updates the range for a fn range_recursion( &mut self, + arena: &mut RangeArena>, tmp_construction: TmpConstruction, (flip_op, no_flip_op): (RangeOp, RangeOp), rhs_cvar: ContextVarNode, @@ -1433,10 +1537,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { return Ok(()); }; - if !tmp_construction.lhs.is_const(self).into_expr_err(loc)? { + if !tmp_construction + .lhs + .is_const(self, arena) + .into_expr_err(loc)? + { tracing::trace!("handling lhs range recursion"); let adjusted_gt_rhs = ContextVarNode::from({ let tmp = self.op( + arena, loc, rhs_cvar, tmp_construction.rhs.expect("No rhs in tmp_construction"), @@ -1470,19 +1579,20 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { let new_lhs_range = lhs_range_fn(lhs_range, adjusted_gt_rhs); new_underlying_lhs - .set_range_min(self, new_lhs_range.range_min().into_owned()) + .set_range_min(self, arena, new_lhs_range.range_min().into_owned()) .into_expr_err(loc)?; new_underlying_lhs - .set_range_max(self, new_lhs_range.range_max().into_owned()) + .set_range_max(self, arena, new_lhs_range.range_max().into_owned()) .into_expr_err(loc)?; - if new_lhs_range.unsat(self) { + if new_lhs_range.unsat(self, arena) { *any_unsat = true; ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(()); } if let Some(tmp) = new_underlying_lhs.tmp_of(self).into_expr_err(loc)? { self.range_recursion( + arena, tmp, (flip_op, no_flip_op), adjusted_gt_rhs, @@ -1497,7 +1607,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { // handle rhs if let Some(rhs) = tmp_construction.rhs { - if !rhs.is_const(self).into_expr_err(loc)? { + if !rhs.is_const(self, arena).into_expr_err(loc)? { tracing::trace!("handling rhs range recursion"); let (needs_inverse, adjusted_gt_rhs) = match tmp_construction.op { RangeOp::Sub(..) => { @@ -1511,8 +1621,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ContextVarNode::from(self.add_node(Node::ContextVar(lhs_cvar))); // tmp_rhs = rhs_cvar * -1 - let tmp_rhs = - self.op(loc, rhs_cvar, tmp_lhs, ctx, RangeOp::Mul(false), false)?; + let tmp_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_lhs, + ctx, + RangeOp::Mul(false), + false, + )?; if matches!(tmp_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(tmp_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1521,8 +1638,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { ContextVarNode::from(tmp_rhs.expect_single().into_expr_err(loc)?); // new_rhs = (rhs_cvar * -1) + tmp_construction.lhs - let new_rhs = - self.op(loc, tmp_rhs, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + tmp_rhs, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1532,8 +1656,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (true, new_rhs) } RangeOp::Add(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1543,8 +1674,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Mul(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1554,8 +1692,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Div(..) => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1565,8 +1710,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Shl => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1576,8 +1728,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Shr => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1587,8 +1746,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Eq => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1598,8 +1764,15 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { (false, new_rhs) } RangeOp::Neq => { - let new_rhs = - self.op(loc, rhs_cvar, tmp_construction.lhs, ctx, inverse, false)?; + let new_rhs = self.op( + arena, + loc, + rhs_cvar, + tmp_construction.lhs, + ctx, + inverse, + false, + )?; if matches!(new_rhs, ExprRet::CtxKilled(_)) { ctx.push_expr(new_rhs, self).into_expr_err(loc)?; return Ok(()); @@ -1636,13 +1809,13 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { }; new_underlying_rhs - .set_range_min(self, new_lhs_range.range_min().into_owned()) + .set_range_min(self, arena, new_lhs_range.range_min().into_owned()) .into_expr_err(loc)?; new_underlying_rhs - .set_range_max(self, new_lhs_range.range_max().into_owned()) + .set_range_max(self, arena, new_lhs_range.range_max().into_owned()) .into_expr_err(loc)?; - if new_lhs_range.unsat(self) { + if new_lhs_range.unsat(self, arena) { *any_unsat = true; ctx.kill(self, loc, KilledKind::Revert).into_expr_err(loc)?; return Ok(()); @@ -1650,6 +1823,7 @@ pub trait Require: AnalyzerBackend + Variable + BinOp + Sized { if let Some(tmp) = new_underlying_rhs.tmp_of(self).into_expr_err(loc)? { self.range_recursion( + arena, tmp, (flip_op, no_flip_op), adjusted_gt_rhs, diff --git a/crates/solc-expressions/src/variable.rs b/crates/solc-expressions/src/variable.rs index 18d0956b..d7d774ee 100644 --- a/crates/solc-expressions/src/variable.rs +++ b/crates/solc-expressions/src/variable.rs @@ -1,9 +1,11 @@ use crate::{assign::Assign, env::Env, ContextBuilder, ExprErr, IntoExprErr}; use graph::{ - nodes::{ContextNode, ContextVar, ContextVarNode, ExprRet, VarNode}, + elem::Elem, + nodes::{Concrete, ContextNode, ContextVar, ContextVarNode, ExprRet, VarNode}, AnalyzerBackend, ContextEdge, Edge, GraphError, Node, VarType, }; +use shared::RangeArena; use solang_parser::pt::{Expression, Identifier, Loc, VariableDeclaration}; @@ -14,6 +16,7 @@ pub trait Variable: AnalyzerBackend + Size /// Get a variable based on an identifier fn variable( &mut self, + arena: &mut RangeArena>, ident: &Identifier, ctx: ContextNode, recursion_target: Option, @@ -33,14 +36,19 @@ pub trait Variable: AnalyzerBackend + Size // solang doesnt have `super` as a keyword if let Some(cvar) = ctx.var_by_name(self, &ident.name) { let cvar = cvar.latest_version(self); - self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { - let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; - edge_ctx - .push_expr(ExprRet::Single(var.into()), analyzer) - .into_expr_err(ident.loc) - }) + self.apply_to_edges( + target_ctx, + ident.loc, + arena, + &|analyzer, arena, edge_ctx, _loc| { + let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; + edge_ctx + .push_expr(ExprRet::Single(var.into()), analyzer) + .into_expr_err(ident.loc) + }, + ) } else if ident.name == "_" { - self.env_variable(ident, target_ctx)?; + self.env_variable(arena, ident, target_ctx)?; Ok(()) } else if let Some(cvar) = ctx .var_by_name_or_recurse(self, &ident.name) @@ -48,18 +56,23 @@ pub trait Variable: AnalyzerBackend + Size { // check if we can inherit it let cvar = cvar.latest_version(self); - self.apply_to_edges(target_ctx, ident.loc, &|analyzer, edge_ctx, _loc| { - let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; - edge_ctx - .push_expr(ExprRet::Single(var.into()), analyzer) - .into_expr_err(ident.loc) - }) + self.apply_to_edges( + target_ctx, + ident.loc, + arena, + &|analyzer, arena, edge_ctx, _loc| { + let var = analyzer.advance_var_in_ctx(cvar, ident.loc, edge_ctx)?; + edge_ctx + .push_expr(ExprRet::Single(var.into()), analyzer) + .into_expr_err(ident.loc) + }, + ) // if let Some(recursion_target) = recursion_target { // self.variable(ident, parent_ctx, Some(recursion_target)) // } else { // self.variable(ident, parent_ctx, Some(target_ctx)) // } - } else if (self.env_variable(ident, target_ctx)?).is_some() { + } else if (self.env_variable(arena, ident, target_ctx)?).is_some() { Ok(()) } else if let Some(idx) = self.user_types().get(&ident.name).cloned() { let const_var = if let Node::Var(_v) = self.node(idx) { @@ -141,6 +154,7 @@ pub trait Variable: AnalyzerBackend + Size fn get_unchanged_tmp_variable( &mut self, + arena: &mut RangeArena>, name: &str, ctx: ContextNode, ) -> Result, GraphError> { @@ -151,13 +165,13 @@ pub trait Variable: AnalyzerBackend + Size if let Some(tmp) = var.tmp_of(self)? { if tmp.lhs.latest_version(self) != tmp.lhs { let latest = tmp.lhs.latest_version(self); - let newest_min = latest.evaled_range_min(self)?; - let curr_min = tmp.lhs.evaled_range_min(self)?; + let newest_min = latest.evaled_range_min(self, arena)?; + let curr_min = tmp.lhs.evaled_range_min(self, arena)?; if newest_min != curr_min { return Ok(None); } - let newest_max = latest.evaled_range_max(self)?; - let curr_max = tmp.lhs.evaled_range_max(self)?; + let newest_max = latest.evaled_range_max(self, arena)?; + let curr_max = tmp.lhs.evaled_range_max(self, arena)?; if newest_max != curr_max { return Ok(None); } @@ -166,13 +180,13 @@ pub trait Variable: AnalyzerBackend + Size if let Some(rhs) = tmp.rhs { if rhs.latest_version(self) != rhs { let latest = rhs.latest_version(self); - let newest_min = latest.evaled_range_min(self)?; - let curr_min = rhs.evaled_range_min(self)?; + let newest_min = latest.evaled_range_min(self, arena)?; + let curr_min = rhs.evaled_range_min(self, arena)?; if newest_min != curr_min { return Ok(None); } - let newest_max = latest.evaled_range_max(self)?; - let curr_max = rhs.evaled_range_max(self)?; + let newest_max = latest.evaled_range_max(self, arena)?; + let curr_max = rhs.evaled_range_max(self, arena)?; if newest_max != curr_max { return Ok(None); } @@ -188,6 +202,7 @@ pub trait Variable: AnalyzerBackend + Size /// Match on the [`ExprRet`]s of a variable definition and construct the variable fn match_var_def( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, var_decl: &VariableDeclaration, loc: Loc, @@ -205,6 +220,7 @@ pub trait Variable: AnalyzerBackend + Size let res = rhs_cvar.literal_cast_from_ty(ty, self).into_expr_err(loc); let _ = self.add_if_err(res); self.match_var_def( + arena, ctx, var_decl, loc, @@ -232,8 +248,8 @@ pub trait Variable: AnalyzerBackend + Size self.add_edge(lhs, ctx, Edge::Context(ContextEdge::Variable)); let rhs = ContextVarNode::from(*rhs); - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let _ = analyzer.assign(loc, lhs, rhs, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { + let _ = analyzer.assign(arena, loc, lhs, rhs, ctx)?; // match_assign_ret(analyzer, ctx, ret); Ok(()) })?; @@ -262,19 +278,19 @@ pub trait Variable: AnalyzerBackend + Size } (l @ ExprRet::Single(_lhs), Some(ExprRet::Multi(rhs_sides))) => Ok(rhs_sides .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, l, Some(expr_ret))) + .map(|expr_ret| self.match_var_def(arena, ctx, var_decl, loc, l, Some(expr_ret))) .collect::, ExprErr>>()? .iter() .all(|e| *e)), (ExprRet::Multi(lhs_sides), r @ Some(ExprRet::Single(_))) => Ok(lhs_sides .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, r)) + .map(|expr_ret| self.match_var_def(arena, ctx, var_decl, loc, expr_ret, r)) .collect::, ExprErr>>()? .iter() .all(|e| *e)), (ExprRet::Multi(lhs_sides), None) => Ok(lhs_sides .iter() - .map(|expr_ret| self.match_var_def(ctx, var_decl, loc, expr_ret, None)) + .map(|expr_ret| self.match_var_def(arena, ctx, var_decl, loc, expr_ret, None)) .collect::, ExprErr>>()? .iter() .all(|e| *e)), @@ -285,7 +301,14 @@ pub trait Variable: AnalyzerBackend + Size .iter() .zip(rhs_sides.iter()) .map(|(lhs_expr_ret, rhs_expr_ret)| { - self.match_var_def(ctx, var_decl, loc, lhs_expr_ret, Some(rhs_expr_ret)) + self.match_var_def( + arena, + ctx, + var_decl, + loc, + lhs_expr_ret, + Some(rhs_expr_ret), + ) }) .collect::, ExprErr>>()? .iter() @@ -294,7 +317,14 @@ pub trait Variable: AnalyzerBackend + Size Ok(rhs_sides .iter() .map(|rhs_expr_ret| { - self.match_var_def(ctx, var_decl, loc, lhs_paths, Some(rhs_expr_ret)) + self.match_var_def( + arena, + ctx, + var_decl, + loc, + lhs_paths, + Some(rhs_expr_ret), + ) }) .collect::, ExprErr>>()? .iter() diff --git a/crates/solc-expressions/src/yul/yul_builder.rs b/crates/solc-expressions/src/yul/yul_builder.rs index 2fdf9185..7383337e 100644 --- a/crates/solc-expressions/src/yul/yul_builder.rs +++ b/crates/solc-expressions/src/yul/yul_builder.rs @@ -5,9 +5,13 @@ use crate::{ }; use graph::{ - nodes::{BuiltInNode, Builtin, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, + elem::Elem, + nodes::{ + BuiltInNode, Builtin, Concrete, Context, ContextNode, ContextVar, ContextVarNode, ExprRet, + }, AnalyzerBackend, ContextEdge, Edge, Node, SolcRange, VarType, }; +use shared::RangeArena; use solang_parser::{ helpers::CodeLocation, @@ -24,8 +28,12 @@ pub trait YulBuilder: { #[tracing::instrument(level = "trace", skip_all, fields(ctx = %ctx.path(self)))] /// Parse a yul statement - fn parse_ctx_yul_statement(&mut self, stmt: &YulStatement, ctx: ContextNode) - where + fn parse_ctx_yul_statement( + &mut self, + arena: &mut RangeArena>, + stmt: &YulStatement, + ctx: ContextNode, + ) where Self: Sized, { if let Some(true) = self.add_if_err(ctx.is_ended(self).into_expr_err(stmt.loc())) { @@ -33,10 +41,10 @@ pub trait YulBuilder: } if let Some(live_edges) = self.add_if_err(ctx.live_edges(self).into_expr_err(stmt.loc())) { if live_edges.is_empty() { - self.parse_ctx_yul_stmt_inner(stmt, ctx) + self.parse_ctx_yul_stmt_inner(arena, stmt, ctx) } else { live_edges.iter().for_each(|fork_ctx| { - self.parse_ctx_yul_stmt_inner(stmt, *fork_ctx); + self.parse_ctx_yul_stmt_inner(arena, stmt, *fork_ctx); }); } } @@ -44,8 +52,12 @@ pub trait YulBuilder: #[tracing::instrument(level = "trace", skip_all)] /// After doing some setup in `parse_ctx_yul_statement`, actually parse a yul statement - fn parse_ctx_yul_stmt_inner(&mut self, stmt: &YulStatement, ctx: ContextNode) - where + fn parse_ctx_yul_stmt_inner( + &mut self, + arena: &mut RangeArena>, + stmt: &YulStatement, + ctx: ContextNode, + ) where Self: Sized, { use YulStatement::*; @@ -59,46 +71,60 @@ pub trait YulBuilder: if ctx.is_killed(self).unwrap() { return; } - let ret = self.apply_to_edges(ctx, stmt.loc(), &|analyzer, ctx, _loc| { + let ret = self.apply_to_edges(ctx, stmt.loc(), arena, &|analyzer, arena, ctx, _loc| { match stmt { Assign(loc, yul_exprs, yul_expr) => { match yul_exprs .iter() - .try_for_each(|expr| analyzer.parse_ctx_yul_expr(expr, ctx)) + .try_for_each(|expr| analyzer.parse_ctx_yul_expr(arena, expr, ctx)) { - Ok(()) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let Some(lhs_side) = - ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoLhs( - loc, - "No left hand side assignments in yul block".to_string(), - )); - }; - if matches!(lhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; - return Ok(()); - } - - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { - let Some(rhs_side) = + Ok(()) => analyzer.apply_to_edges( + ctx, + *loc, + arena, + &|analyzer, arena, ctx, loc| { + let Some(lhs_side) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { - return Err(ExprErr::NoRhs( + return Err(ExprErr::NoLhs( loc, - "No right hand side assignments in yul block".to_string(), + "No left hand side assignments in yul block".to_string(), )); }; - - if matches!(rhs_side, ExprRet::CtxKilled(_)) { - ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; + if matches!(lhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(lhs_side, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.match_assign_sides(ctx, loc, &lhs_side, &rhs_side) - }) - }), + analyzer.parse_ctx_yul_expr(arena, yul_expr, ctx)?; + analyzer.apply_to_edges( + ctx, + loc, + arena, + &|analyzer, arena, ctx, loc| { + let Some(rhs_side) = ctx + .pop_expr_latest(loc, analyzer) + .into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "No right hand side assignments in yul block" + .to_string(), + )); + }; + + if matches!(rhs_side, ExprRet::CtxKilled(_)) { + ctx.push_expr(rhs_side, analyzer).into_expr_err(loc)?; + return Ok(()); + } + + analyzer.match_assign_sides( + arena, ctx, loc, &lhs_side, &rhs_side, + ) + }, + ) + }, + ), Err(e) => Err(e), } } @@ -128,8 +154,8 @@ pub trait YulBuilder: .collect::>(); if let Some(yul_expr) = maybe_yul_expr { - analyzer.parse_ctx_yul_expr(yul_expr, ctx)?; - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, yul_expr, ctx)?; + analyzer.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -151,8 +177,8 @@ pub trait YulBuilder: } } If(loc, yul_expr, yul_block) => { - analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { - let ret = analyzer.yul_cond_op_stmt(loc, yul_expr, yul_block, ctx); + analyzer.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { + let ret = analyzer.yul_cond_op_stmt(arena, loc, yul_expr, yul_block, ctx); let _ = analyzer.add_if_err(ret); Ok(()) }) @@ -169,7 +195,7 @@ pub trait YulBuilder: .into_expr_err(*loc)?; let subctx = ContextNode::from(analyzer.add_node(Node::Context(sctx))); ctx.set_child_call(subctx, analyzer).into_expr_err(*loc)?; - analyzer.apply_to_edges(subctx, *loc, &|analyzer, subctx, loc| { + analyzer.apply_to_edges(subctx, *loc, arena, &|analyzer, arena, subctx, loc| { let vars = subctx.local_vars(analyzer).clone(); vars.iter().for_each(|(name, var)| { // widen to max range @@ -186,11 +212,11 @@ pub trait YulBuilder: .advance_var_in_ctx(inheritor_var, loc, ctx) .unwrap(); let res = new_inheritor_var - .set_range_min(analyzer, r.min) + .set_range_min(analyzer, arena, r.min) .into_expr_err(loc); let _ = analyzer.add_if_err(res); let res = new_inheritor_var - .set_range_max(analyzer, r.max) + .set_range_max(analyzer, arena, r.max) .into_expr_err(loc); let _ = analyzer.add_if_err(res); } @@ -204,8 +230,9 @@ pub trait YulBuilder: condition, cases, default, - }) => analyzer.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + }) => analyzer.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { analyzer.yul_switch_stmt( + arena, loc, condition.clone(), cases.to_vec(), @@ -229,14 +256,14 @@ pub trait YulBuilder: yul_block .statements .iter() - .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(stmt, ctx)); + .for_each(|stmt| analyzer.parse_ctx_yul_stmt_inner(arena, stmt, ctx)); Ok(()) } FunctionDefinition(yul_func_def) => Err(ExprErr::Todo( yul_func_def.loc(), "Yul `function` defintions are not currently supported".to_string(), )), - FunctionCall(yul_func_call) => analyzer.yul_func_call(yul_func_call, ctx), + FunctionCall(yul_func_call) => analyzer.yul_func_call(arena, yul_func_call, ctx), Error(loc) => Err(ExprErr::ParseError( *loc, "Could not parse this yul statement".to_string(), @@ -250,6 +277,7 @@ pub trait YulBuilder: /// Parse a yul expression fn parse_ctx_yul_expr( &mut self, + arena: &mut RangeArena>, expr: &YulExpression, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -257,11 +285,11 @@ pub trait YulBuilder: let edges = ctx.live_edges(self).into_expr_err(expr.loc())?; if edges.is_empty() { - self.parse_ctx_yul_expr_inner(expr, ctx) + self.parse_ctx_yul_expr_inner(arena, expr, ctx) } else { edges .iter() - .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(expr, *fork_ctx))?; + .try_for_each(|fork_ctx| self.parse_ctx_yul_expr(arena, expr, *fork_ctx))?; Ok(()) } } @@ -269,6 +297,7 @@ pub trait YulBuilder: /// After performing some setup in `parse_ctx_yul_expr`, actually parse the yul expression fn parse_ctx_yul_expr_inner( &mut self, + arena: &mut RangeArena>, expr: &YulExpression, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -282,8 +311,8 @@ pub trait YulBuilder: HexStringLiteral(lit, _) => self.hex_literals(ctx, &[lit.clone()]), StringLiteral(lit, _) => self.string_literal(ctx, lit.loc, &lit.string), Variable(ident) => { - self.variable(ident, ctx, None)?; - self.apply_to_edges(ctx, ident.loc, &|analyzer, edge_ctx, loc| { + self.variable(arena, ident, ctx, None)?; + self.apply_to_edges(ctx, ident.loc, arena, &|analyzer, arena, edge_ctx, loc| { if let Some(ret) = edge_ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? { if ContextVarNode::from(ret.expect_single().into_expr_err(loc)?) .is_memory(analyzer) @@ -312,11 +341,11 @@ pub trait YulBuilder: } }) } - FunctionCall(yul_func_call) => self.yul_func_call(yul_func_call, ctx), + FunctionCall(yul_func_call) => self.yul_func_call(arena, yul_func_call, ctx), SuffixAccess(loc, yul_member_expr, ident) => { - self.parse_inputs(ctx, *loc, &[*yul_member_expr.clone()])?; + self.parse_inputs(arena, ctx, *loc, &[*yul_member_expr.clone()])?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Ok(Some(lhs)) = ctx.pop_expr_latest(loc, analyzer) else { return Err(ExprErr::NoLhs( loc, diff --git a/crates/solc-expressions/src/yul/yul_cond_op.rs b/crates/solc-expressions/src/yul/yul_cond_op.rs index 9be9fe32..6a63b839 100644 --- a/crates/solc-expressions/src/yul/yul_cond_op.rs +++ b/crates/solc-expressions/src/yul/yul_cond_op.rs @@ -5,7 +5,7 @@ use graph::{ nodes::{Concrete, ConcreteNode, Context, ContextNode, ContextVar, ContextVarNode, ExprRet}, AnalyzerBackend, ContextEdge, Edge, Node, }; -use shared::NodeIdx; +use shared::{NodeIdx, RangeArena}; use ethers_core::types::U256; use solang_parser::pt::{ @@ -26,12 +26,13 @@ pub trait YulCondOp: /// Handle a yul conditional operation statement fn yul_cond_op_stmt( &mut self, + arena: &mut RangeArena>, loc: Loc, if_expr: &YulExpression, true_stmt: &YulBlock, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) .into_expr_err(loc)?; @@ -61,8 +62,8 @@ pub trait YulCondOp: Edge::Context(ContextEdge::Subcontext), ); - analyzer.parse_ctx_yul_expr(if_expr, true_subctx)?; - analyzer.apply_to_edges(true_subctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, if_expr, true_subctx)?; + analyzer.apply_to_edges(true_subctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -75,10 +76,14 @@ pub trait YulCondOp: return Ok(()); } - analyzer.match_yul_true(ctx, if_expr.loc(), &ret) + analyzer.match_yul_true(arena, ctx, if_expr.loc(), &ret) })?; - analyzer.parse_ctx_yul_statement(&YulStatement::Block(true_stmt.clone()), true_subctx); + analyzer.parse_ctx_yul_statement( + arena, + &YulStatement::Block(true_stmt.clone()), + true_subctx, + ); // let false_expr = YulExpression::FunctionCall(Box::new(YulFunctionCall { // loc, // id: Identifier { @@ -87,8 +92,8 @@ pub trait YulCondOp: // }, // arguments: vec![if_expr.clone()], // })); - analyzer.parse_ctx_yul_expr(if_expr, false_subctx)?; - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, if_expr, false_subctx)?; + analyzer.apply_to_edges(false_subctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -101,7 +106,7 @@ pub trait YulCondOp: return Ok(()); } - analyzer.match_yul_false(ctx, if_expr.loc(), &ret) + analyzer.match_yul_false(arena, ctx, if_expr.loc(), &ret) }) }) } @@ -110,11 +115,12 @@ pub trait YulCondOp: /// Handle a yul if-else fn yul_if_else( &mut self, + arena: &mut RangeArena>, loc: Loc, if_else_chain: &IfElseChain, ctx: ContextNode, ) -> Result<(), ExprErr> { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let tctx = Context::new_subctx(ctx, None, loc, Some("true"), None, false, analyzer, None) .into_expr_err(loc)?; @@ -145,42 +151,52 @@ pub trait YulCondOp: ); let if_expr_loc = if_else_chain.if_expr.loc(); - analyzer.apply_to_edges(true_subctx, if_expr_loc, &|analyzer, ctx, loc| { - analyzer.parse_ctx_yul_expr(&if_else_chain.if_expr, true_subctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - let Some(true_vars) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? - else { - return Err(ExprErr::NoRhs( - loc, - "Yul switch statement was missing a case discriminator".to_string(), - )); - }; + analyzer.apply_to_edges( + true_subctx, + if_expr_loc, + arena, + &|analyzer, arena, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, &if_else_chain.if_expr, true_subctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { + let Some(true_vars) = + ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? + else { + return Err(ExprErr::NoRhs( + loc, + "Yul switch statement was missing a case discriminator".to_string(), + )); + }; - if matches!(true_vars, ExprRet::CtxKilled(_)) { - ctx.push_expr(true_vars, analyzer).into_expr_err(loc)?; - return Ok(()); - } - analyzer.match_yul_true(ctx, loc, &true_vars)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(&if_else_chain.true_stmt, ctx); - Ok(()) + if matches!(true_vars, ExprRet::CtxKilled(_)) { + ctx.push_expr(true_vars, analyzer).into_expr_err(loc)?; + return Ok(()); + } + analyzer.match_yul_true(arena, ctx, loc, &true_vars)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_yul_statement(arena, &if_else_chain.true_stmt, ctx); + Ok(()) + }) }) - }) - })?; + }, + )?; if let Some(next) = &if_else_chain.next { match next { - ElseOrDefault::Default(default) => { - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, _loc| { - analyzer.parse_ctx_yul_statement(default, ctx); + ElseOrDefault::Default(default) => analyzer.apply_to_edges( + false_subctx, + loc, + arena, + &|analyzer, arena, ctx, _loc| { + analyzer.parse_ctx_yul_statement(arena, default, ctx); Ok(()) - }) - } - ElseOrDefault::Else(iec) => { - analyzer.apply_to_edges(false_subctx, loc, &|analyzer, ctx, loc| { - analyzer.yul_if_else(loc, iec, ctx) - }) - } + }, + ), + ElseOrDefault::Else(iec) => analyzer.apply_to_edges( + false_subctx, + loc, + arena, + &|analyzer, arena, ctx, loc| analyzer.yul_if_else(arena, loc, iec, ctx), + ), } } else { Ok(()) @@ -191,6 +207,7 @@ pub trait YulCondOp: /// Helper for the `true` evaluation of a yul conditional fn match_yul_true( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, true_cvars: &ExprRet, @@ -209,6 +226,7 @@ pub trait YulCondOp: ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); self.handle_require_inner( + arena, ctx, loc, true_cvars, @@ -224,7 +242,7 @@ pub trait YulCondOp: true_paths .iter() .take(1) - .try_for_each(|expr_ret| self.match_yul_true(ctx, loc, expr_ret))?; + .try_for_each(|expr_ret| self.match_yul_true(arena, ctx, loc, expr_ret))?; } ExprRet::Null => {} } @@ -234,6 +252,7 @@ pub trait YulCondOp: /// Helper for the `false` evaluation of a yul conditional fn match_yul_false( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, false_cvars: &ExprRet, @@ -252,6 +271,7 @@ pub trait YulCondOp: ExprRet::Single(ContextVarNode::from(self.add_node(tmp_true)).into()); self.handle_require_inner( + arena, ctx, loc, false_cvars, @@ -267,7 +287,7 @@ pub trait YulCondOp: false_paths .iter() .take(1) - .try_for_each(|expr_ret| self.match_yul_false(ctx, loc, expr_ret))?; + .try_for_each(|expr_ret| self.match_yul_false(arena, ctx, loc, expr_ret))?; } ExprRet::Null => {} } @@ -279,6 +299,7 @@ pub trait YulCondOp: /// Handle a yul swithc statement by converting it into an if-else chain fn yul_switch_stmt( &mut self, + arena: &mut RangeArena>, loc: Loc, condition: YulExpression, cases: Vec, @@ -286,8 +307,8 @@ pub trait YulCondOp: ctx: ContextNode, ) -> Result<(), ExprErr> { let iec = IfElseChain::from(loc, (condition, cases, default))?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, _loc| { - analyzer.yul_if_else(loc, &iec, ctx) + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, _loc| { + analyzer.yul_if_else(arena, loc, &iec, ctx) }) } } diff --git a/crates/solc-expressions/src/yul/yul_funcs.rs b/crates/solc-expressions/src/yul/yul_funcs.rs index d618174e..6702fb51 100644 --- a/crates/solc-expressions/src/yul/yul_funcs.rs +++ b/crates/solc-expressions/src/yul/yul_funcs.rs @@ -11,7 +11,7 @@ use graph::{ }, AnalyzerBackend, ContextEdge, Edge, GraphBackend, Node, SolcRange, VarType, }; -use shared::StorageLocation; +use shared::{RangeArena, StorageLocation}; use ethers_core::types::U256; use solang_parser::pt::{Expression, Loc, YulExpression, YulFunctionCall}; @@ -28,6 +28,7 @@ pub trait YulFuncCaller: { fn yul_func_call( &mut self, + arena: &mut RangeArena>, func_call: &YulFunctionCall, ctx: ContextNode, ) -> Result<(), ExprErr> { @@ -68,8 +69,8 @@ pub trait YulFuncCaller: ctx.kill(self, *loc, KilledKind::Revert).into_expr_err(*loc) } "return" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(offset) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs(loc, "Yul Return had no offset".to_string())); @@ -78,8 +79,8 @@ pub trait YulFuncCaller: ctx.push_expr(offset, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, &arguments[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(size) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs(loc, "Yul Return had no size".to_string())); @@ -108,8 +109,8 @@ pub trait YulFuncCaller: )); } - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( loc, @@ -121,7 +122,7 @@ pub trait YulFuncCaller: ctx.push_expr(lhs, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.bit_not_inner(ctx, loc, lhs.flatten()) + analyzer.bit_not_inner(arena, ctx, loc, lhs.flatten()) }) } "add" | "sub" | "mul" | "div" | "sdiv" | "mod" | "smod" | "exp" | "and" | "or" @@ -159,8 +160,8 @@ pub trait YulFuncCaller: vec![arguments[0].clone(), arguments[1].clone()] }; - self.parse_inputs(ctx, *loc, &inputs)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_inputs(arena, ctx, *loc, &inputs)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(inputs) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -182,16 +183,17 @@ pub trait YulFuncCaller: let lhs_paths = ContextVarNode::from(inputs[0].expect_single().into_expr_err(loc)?); lhs_paths - .cast_from_ty(cast_ty.clone(), analyzer) + .cast_from_ty(cast_ty.clone(), analyzer, arena) .into_expr_err(loc)?; let rhs_paths = ContextVarNode::from(inputs[1].expect_single().into_expr_err(loc)?); rhs_paths - .cast_from_ty(cast_ty, analyzer) + .cast_from_ty(cast_ty, analyzer, arena) .into_expr_err(loc)?; analyzer.op_match( + arena, ctx, loc, &ExprRet::Single(lhs_paths.latest_version(analyzer).into()), @@ -220,8 +222,8 @@ pub trait YulFuncCaller: )); } - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -235,8 +237,8 @@ pub trait YulFuncCaller: return Ok(()); } - analyzer.parse_ctx_yul_expr(&arguments[1], ctx)?; - analyzer.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + analyzer.parse_ctx_yul_expr(arena, &arguments[1], ctx)?; + analyzer.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(rhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -250,7 +252,7 @@ pub trait YulFuncCaller: ctx.push_expr(rhs_paths, analyzer).into_expr_err(loc)?; return Ok(()); } - analyzer.cmp_inner(ctx, loc, &lhs_paths, op, &rhs_paths)?; + analyzer.cmp_inner(arena, ctx, loc, &lhs_paths, op, &rhs_paths)?; let Some(result) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( @@ -267,9 +269,10 @@ pub trait YulFuncCaller: Elem::from(Concrete::Uint(256, U256::zero())), )); - next.set_range_min(analyzer, expr.clone()) + next.set_range_min(analyzer, arena, expr.clone()) + .into_expr_err(loc)?; + next.set_range_max(analyzer, arena, expr) .into_expr_err(loc)?; - next.set_range_max(analyzer, expr).into_expr_err(loc)?; ctx.push_expr(ExprRet::Single(next.into()), analyzer) .into_expr_err(loc) }) @@ -286,8 +289,8 @@ pub trait YulFuncCaller: )); } - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -310,7 +313,7 @@ pub trait YulFuncCaller: let rhs_paths = ExprRet::Single(ContextVarNode::from(analyzer.add_node(tmp_true)).into()); - analyzer.cmp_inner(ctx, loc, &lhs_paths, RangeOp::Eq, &rhs_paths) + analyzer.cmp_inner(arena, ctx, loc, &lhs_paths, RangeOp::Eq, &rhs_paths) }) } "addmod" | "mulmod" => { @@ -357,8 +360,8 @@ pub trait YulFuncCaller: )); } - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -449,9 +452,13 @@ pub trait YulFuncCaller: let res = latest_var.ty(self).into_expr_err(*loc)?; if let Some(r) = res.default_range(self).unwrap() { let new_var = self.advance_var_in_ctx(latest_var, *loc, ctx).unwrap(); - let res = new_var.set_range_min(self, r.min).into_expr_err(*loc); + let res = new_var + .set_range_min(self, arena, r.min) + .into_expr_err(*loc); let _ = self.add_if_err(res); - let res = new_var.set_range_max(self, r.max).into_expr_err(*loc); + let res = new_var + .set_range_max(self, arena, r.max) + .into_expr_err(*loc); let _ = self.add_if_err(res); } } @@ -473,8 +480,8 @@ pub trait YulFuncCaller: )); } - self.parse_inputs(ctx, *loc, arguments)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_inputs(arena, ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(mut lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { @@ -496,6 +503,7 @@ pub trait YulFuncCaller: if let Some(slot) = cvar.slot_to_storage(analyzer) { analyzer.match_assign_sides( + arena, ctx, loc, &ExprRet::Single(slot.into()), @@ -515,11 +523,13 @@ pub trait YulFuncCaller: if let Some(r) = res.default_range(analyzer).unwrap() { let new_var = analyzer.advance_var_in_ctx(latest_var, loc, ctx).unwrap(); - let res = - new_var.set_range_min(analyzer, r.min).into_expr_err(loc); + let res = new_var + .set_range_min(analyzer, arena, r.min) + .into_expr_err(loc); let _ = analyzer.add_if_err(res); - let res = - new_var.set_range_max(analyzer, r.max).into_expr_err(loc); + let res = new_var + .set_range_max(analyzer, arena, r.max) + .into_expr_err(loc); let _ = analyzer.add_if_err(res); } } @@ -533,8 +543,8 @@ pub trait YulFuncCaller: Ok(()) } "balance" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -581,8 +591,8 @@ pub trait YulFuncCaller: .into_expr_err(*loc) } "extcodesize" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -630,8 +640,8 @@ pub trait YulFuncCaller: )); } - self.parse_inputs(ctx, *loc, arguments)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_inputs(arena, ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -655,8 +665,8 @@ pub trait YulFuncCaller: )); } - self.parse_inputs(ctx, *loc, arguments)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_inputs(arena, ctx, *loc, arguments)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(_lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -669,8 +679,8 @@ pub trait YulFuncCaller: }) } "extcodehash" => { - self.parse_ctx_yul_expr(&arguments[0], ctx)?; - self.apply_to_edges(ctx, *loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, &arguments[0], ctx)?; + self.apply_to_edges(ctx, *loc, arena, &|analyzer, arena, ctx, loc| { let Some(lhs_paths) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoRhs( @@ -752,6 +762,7 @@ pub trait YulFuncCaller: #[tracing::instrument(level = "trace", skip_all)] fn parse_inputs( &mut self, + arena: &mut RangeArena>, ctx: ContextNode, loc: Loc, inputs: &[YulExpression], @@ -763,8 +774,8 @@ pub trait YulFuncCaller: }; inputs.iter().try_for_each(|input| { - self.parse_ctx_yul_expr(input, ctx)?; - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.parse_ctx_yul_expr(arena, input, ctx)?; + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_expr_latest(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc, @@ -784,7 +795,7 @@ pub trait YulFuncCaller: }) })?; if !inputs.is_empty() { - self.apply_to_edges(ctx, loc, &|analyzer, ctx, loc| { + self.apply_to_edges(ctx, loc, arena, &|analyzer, arena, ctx, loc| { let Some(ret) = ctx.pop_tmp_expr(loc, analyzer).into_expr_err(loc)? else { return Err(ExprErr::NoLhs( loc,